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::TablePtr original_table_message;
112
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
113
if (plugin::StorageEngine::getTableDefinition(*session, identifier, original_table_message) != EEXIST)
115
my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
119
if (not create_info.db_type)
122
plugin::StorageEngine::findByName(*session, original_table_message->engine().name());
124
if (not create_info.db_type)
126
my_error(ER_BAD_TABLE_ERROR, MYF(0), identifier.getSQLPath().c_str());
132
if (not validateCreateTableOption())
137
/* ALTER TABLE ends previous transaction */
138
if (not session->endActiveTransaction())
143
if (not (need_start_waiting= not session->wait_if_global_read_lock(0, 1)))
149
if (original_table_message->type() == message::Table::STANDARD )
151
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName());
152
TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
153
session->lex->name.str ? session->lex->name.str : first_table->getTableName());
155
res= alter_table(session,
159
*original_table_message,
160
create_table_message,
163
select_lex->order_list.elements,
164
(Order *) select_lex->order_list.first,
165
session->lex->ignore);
169
TableIdentifier catch22(first_table->getSchemaName(), first_table->getTableName());
170
Table *table= session->find_temporary_table(catch22);
173
TableIdentifier identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
174
TableIdentifier new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
175
session->lex->name.str ? session->lex->name.str : first_table->getTableName(),
176
table->getMutableShare()->getPath());
178
res= alter_table(session,
182
*original_table_message,
183
create_table_message,
186
select_lex->order_list.elements,
187
(Order *) select_lex->order_list.first,
188
session->lex->ignore);
193
Release the protection against the global read lock and wake
194
everyone, who might want to set a global read lock.
196
session->startWaitingGlobalReadLock();
203
Prepare column and key definitions for CREATE TABLE in ALTER Table.
205
This function transforms parse output of ALTER Table - lists of
206
columns and keys to add, drop or modify into, essentially,
207
CREATE TABLE definition - a list of columns and keys of the new
208
table. While doing so, it also performs some (bug not all)
211
This function is invoked when we know that we're going to
212
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
213
is not possible, perhaps because the ALTER statement contains
214
instructions that require change in table data, not only in
215
table definition or indexes.
217
@param[in,out] session thread handle. Used as a memory pool
218
and source of environment information.
219
@param[in] table the source table, open and locked
220
Used as an interface to the storage engine
221
to acquire additional information about
223
@param[in,out] create_info A blob with CREATE/ALTER Table
225
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
226
Originally create_info was used only in
227
CREATE TABLE and alter_info only in ALTER Table.
228
But since ALTER might end-up doing CREATE,
229
this distinction is gone and we just carry
230
around two structures.
233
Fills various create_info members based on information retrieved
234
from the storage engine.
235
Sets create_info->varchar if the table has a VARCHAR column.
236
Prepares alter_info->create_list and alter_info->key_list with
237
columns and keys of the new table.
238
@retval true error, out of memory or a semantical error in ALTER
240
@retval false success
242
static bool mysql_prepare_alter_table(Session *session,
244
HA_CREATE_INFO *create_info,
245
const message::Table &original_proto,
246
message::Table &table_message,
247
AlterInfo *alter_info)
249
/* New column definitions are added here */
250
List<CreateField> new_create_list;
251
/* New key definitions are added here */
252
List<Key> new_key_list;
253
List_iterator<AlterDrop> drop_it(alter_info->drop_list);
254
List_iterator<CreateField> def_it(alter_info->create_list);
255
List_iterator<AlterColumn> alter_it(alter_info->alter_list);
256
List_iterator<Key> key_it(alter_info->key_list);
257
List_iterator<CreateField> find_it(new_create_list);
258
List_iterator<CreateField> field_it(new_create_list);
259
List<Key_part_spec> key_parts;
260
uint32_t used_fields= create_info->used_fields;
261
KeyInfo *key_info= table->key_info;
264
/* Let new create options override the old ones */
265
message::Table::TableOptions *table_options;
266
table_options= table_message.mutable_options();
268
if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
269
create_info->default_table_charset= table->getShare()->table_charset;
270
if (! (used_fields & HA_CREATE_USED_AUTO) &&
271
table->found_next_number_field)
273
/* Table has an autoincrement, copy value to new table */
274
table->cursor->info(HA_STATUS_AUTO);
275
create_info->auto_increment_value= table->cursor->stats.auto_increment_value;
276
if (create_info->auto_increment_value != original_proto.options().auto_increment_value())
277
table_options->set_has_user_set_auto_increment_value(false);
279
table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
282
/* First collect all fields from table which isn't in drop_list */
285
for (f_ptr= table->getFields(); (field= *f_ptr); f_ptr++)
287
/* Check if field should be dropped */
290
while ((drop= drop_it++))
292
if (drop->type == AlterDrop::COLUMN &&
293
! my_strcasecmp(system_charset_info, field->field_name, drop->name))
295
/* Reset auto_increment value if it was dropped */
296
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
297
! (used_fields & HA_CREATE_USED_AUTO))
299
create_info->auto_increment_value= 0;
300
create_info->used_fields|= HA_CREATE_USED_AUTO;
311
/* Mark that we will read the field */
314
/* Check if field is changed */
316
while ((def= def_it++))
319
! my_strcasecmp(system_charset_info, field->field_name, def->change))
324
/* Field is changed */
328
new_create_list.push_back(def);
335
This field was not dropped and not changed, add it to the list
338
def= new CreateField(field, field);
339
new_create_list.push_back(def);
340
alter_it.rewind(); /* Change default if ALTER */
342
while ((alter= alter_it++))
344
if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
349
if (def->sql_type == DRIZZLE_TYPE_BLOB)
351
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
354
if ((def->def= alter->def))
356
/* Use new default */
357
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
360
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
Check that the DATE/DATETIME not null field we are going to add is
375
either has a default value or the '0000-00-00' is allowed by the
377
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
378
flag to allow ALTER Table only if the table to be altered is empty.
380
if ((def->sql_type == DRIZZLE_TYPE_DATE ||
381
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
382
! alter_info->datetime_field &&
383
! (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)))
385
alter_info->datetime_field= def;
386
alter_info->error_if_not_empty= true;
389
new_create_list.push_back(def);
390
else if (def->after == first_keyword)
391
new_create_list.push_front(def);
396
while ((find= find_it++)) /* Add new columns */
398
if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
403
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->getMutableShare()->getTableName());
406
find_it.after(def); /* Put element after this */
408
XXX: hack for Bug#28427.
409
If column order has changed, force OFFLINE ALTER Table
410
without querying engine capabilities. If we ever have an
411
engine that supports online ALTER Table CHANGE COLUMN
412
<name> AFTER <name1> (Falcon?), this fix will effectively
413
disable the capability.
414
TODO: detect the situation in compare_tables, behave based
415
on engine capabilities.
417
if (alter_info->build_method == HA_BUILD_ONLINE)
419
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->getQueryString()->c_str());
422
alter_info->build_method= HA_BUILD_OFFLINE;
425
if (alter_info->alter_list.elements)
427
my_error(ER_BAD_FIELD_ERROR,
429
alter_info->alter_list.head()->name,
430
table->getMutableShare()->getTableName());
433
if (! new_create_list.elements)
435
my_message(ER_CANT_REMOVE_ALL_FIELDS,
436
ER(ER_CANT_REMOVE_ALL_FIELDS),
442
Collect all keys which isn't in drop list. Add only those
443
for which some fields exists.
445
for (uint32_t i= 0; i < table->getShare()->sizeKeys(); i++, key_info++)
447
char *key_name= key_info->name;
450
while ((drop= drop_it++))
452
if (drop->type == AlterDrop::KEY &&
453
! my_strcasecmp(system_charset_info, key_name, drop->name))
462
KeyPartInfo *key_part= key_info->key_part;
464
for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
466
if (! key_part->field)
467
continue; /* Wrong field (from UNIREG) */
469
const char *key_part_name= key_part->field->field_name;
472
while ((cfield= field_it++))
476
if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
479
else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
483
continue; /* Field is removed */
485
uint32_t key_part_length= key_part->length;
486
if (cfield->field) /* Not new field */
489
If the field can't have only a part used in a key according to its
490
new type, or should not be used partially according to its
491
previous type, or the field length is less than the key part
492
length, unset the key part length.
494
We also unset the key part length if it is the same as the
495
old field's length, so the whole new field will be used.
497
BLOBs may have cfield->length == 0, which is why we test it before
498
checking whether cfield->length < key_part_length (in chars).
500
if (! Field::type_can_have_key_part(cfield->field->type()) ||
501
! Field::type_can_have_key_part(cfield->sql_type) ||
502
(cfield->field->field_length == key_part_length) ||
504
(cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
505
key_part_length= 0; /* Use whole field */
507
key_part_length/= key_part->field->charset()->mbmaxlen;
508
key_parts.push_back(new Key_part_spec(cfield->field_name,
509
strlen(cfield->field_name),
512
if (key_parts.elements)
514
KEY_CREATE_INFO key_create_info;
516
enum Key::Keytype key_type;
517
memset(&key_create_info, 0, sizeof(key_create_info));
519
key_create_info.algorithm= key_info->algorithm;
520
if (key_info->flags & HA_USES_BLOCK_SIZE)
521
key_create_info.block_size= key_info->block_size;
522
if (key_info->flags & HA_USES_COMMENT)
523
key_create_info.comment= key_info->comment;
525
if (key_info->flags & HA_NOSAME)
527
if (is_primary_key_name(key_name))
528
key_type= Key::PRIMARY;
530
key_type= Key::UNIQUE;
533
key_type= Key::MULTIPLE;
535
key= new Key(key_type,
539
test(key_info->flags & HA_GENERATED_KEY),
541
new_key_list.push_back(key);
545
/* Copy over existing foreign keys */
546
for (int j= 0; j < original_proto.fk_constraint_size(); j++)
550
while ((drop= drop_it++))
552
if (drop->type == AlterDrop::FOREIGN_KEY &&
553
! my_strcasecmp(system_charset_info, original_proto.fk_constraint(j).name().c_str(), drop->name))
564
message::Table::ForeignKeyConstraint *pfkey= table_message.add_fk_constraint();
565
*pfkey= original_proto.fk_constraint(j);
570
while ((key= key_it++)) /* Add new keys */
572
if (key->type == Key::FOREIGN_KEY)
574
if (((Foreign_key *)key)->validate(new_create_list))
577
Foreign_key *fkey= (Foreign_key*)key;
578
add_foreign_key_to_table_message(&table_message,
588
if (key->type != Key::FOREIGN_KEY)
589
new_key_list.push_back(key);
591
if (key->name.str && is_primary_key_name(key->name.str))
593
my_error(ER_WRONG_NAME_FOR_INDEX,
601
/* Fix names of foreign keys being added */
602
for (int j= 0; j < table_message.fk_constraint_size(); j++)
604
if (! table_message.fk_constraint(j).has_name())
606
std::string name(table->getMutableShare()->getTableName());
609
name.append("_ibfk_");
610
snprintf(number, sizeof(number), "%d", j+1);
613
message::Table::ForeignKeyConstraint *pfkey= table_message.mutable_fk_constraint(j);
614
pfkey->set_name(name);
618
if (alter_info->drop_list.elements)
620
my_error(ER_CANT_DROP_FIELD_OR_KEY,
622
alter_info->drop_list.head()->name);
625
if (alter_info->alter_list.elements)
627
my_error(ER_CANT_DROP_FIELD_OR_KEY,
629
alter_info->alter_list.head()->name);
633
if (not table_message.options().has_comment()
634
&& table->getMutableShare()->hasComment())
635
table_options->set_comment(table->getMutableShare()->getComment());
637
if (table->getShare()->getType())
639
table_message.set_type(message::Table::TEMPORARY);
642
table_message.set_creation_timestamp(table->getShare()->getTableProto()->creation_timestamp());
643
table_message.set_version(table->getShare()->getTableProto()->version());
644
table_message.set_uuid(table->getShare()->getTableProto()->uuid());
647
alter_info->create_list.swap(new_create_list);
648
alter_info->key_list.swap(new_key_list);
651
size_t num_engine_options= table_message.engine().options_size();
652
size_t original_num_engine_options= original_proto.engine().options_size();
653
for (size_t x= 0; x < original_num_engine_options; ++x)
657
for (size_t y= 0; y < num_engine_options; ++y)
659
found= not table_message.engine().options(y).name().compare(original_proto.engine().options(x).name());
667
message::Engine::Option *opt= table_message.mutable_engine()->add_options();
669
opt->set_name(original_proto.engine().options(x).name());
670
opt->set_state(original_proto.engine().options(x).state());
674
drizzled::message::update(table_message);
679
/* table_list should contain just one table */
680
static int mysql_discard_or_import_tablespace(Session *session,
681
TableList *table_list,
682
enum tablespace_op_type tablespace_op)
689
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
693
TransactionServices &transaction_services= TransactionServices::singleton();
694
session->set_proc_info("discard_or_import_tablespace");
696
discard= test(tablespace_op == DISCARD_TABLESPACE);
699
We set this flag so that ha_innobase::open and ::external_lock() do
700
not complain when we lock the table
702
session->tablespace_op= true;
703
if (!(table= session->openTableLock(table_list, TL_WRITE)))
705
session->tablespace_op= false;
709
error= table->cursor->ha_discard_or_import_tablespace(discard);
711
session->set_proc_info("end");
716
/* The ALTER Table is always in its own transaction */
717
error= transaction_services.autocommitOrRollback(session, false);
718
if (not session->endActiveTransaction())
724
write_bin_log(session, *session->getQueryString());
727
(void) transaction_services.autocommitOrRollback(session, error);
728
session->tablespace_op=false;
736
table->print_error(error, MYF(0));
742
Manages enabling/disabling of indexes for ALTER Table
745
alter_table_manage_keys()
747
indexes_were_disabled Whether the indexes of the from table
749
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
755
static bool alter_table_manage_keys(Session *session,
756
Table *table, int indexes_were_disabled,
757
enum enum_enable_or_disable keys_onoff)
760
switch (keys_onoff) {
762
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
765
if (not indexes_were_disabled)
767
/* fall-through: disabled indexes */
769
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
772
if (error == HA_ERR_WRONG_COMMAND)
774
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
775
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
776
table->getMutableShare()->getTableName());
779
table->print_error(error, MYF(0));
784
static bool lockTableIfDifferent(Session &session,
785
TableIdentifier &original_table_identifier,
786
TableIdentifier &new_table_identifier,
789
/* Check that we are not trying to rename to an existing table */
790
if (not (original_table_identifier == new_table_identifier))
792
if (original_table_identifier.isTmp())
795
if (session.find_temporary_table(new_table_identifier))
797
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
803
if (session.lock_table_name_if_not_cached(new_table_identifier, &name_lock))
810
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
814
if (plugin::StorageEngine::doesTableExist(session, new_table_identifier))
816
/* Table will be closed by Session::executeCommand() */
817
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
819
LOCK_open.lock(); /* ALTER TABLe */
820
session.unlink_open_table(name_lock);
836
session Thread handle
837
new_db If there is a RENAME clause
838
new_name If there is a RENAME clause
839
create_info Information from the parsing phase about new
841
table_list The table to change.
842
alter_info Lists of fields, keys to be changed, added
844
order_num How many ORDER BY fields has been specified.
845
order List of fields to order_st BY.
846
ignore Whether we have ALTER IGNORE Table
849
This is a veery long function and is everything but the kitchen sink :)
850
It is used to alter a table and not only by ALTER Table but also
851
CREATE|DROP INDEX are mapped on this function.
853
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
854
or both, then this function short cuts its operation by renaming
855
the table and/or enabling/disabling the keys. In this case, the FRM is
856
not changed, directly by alter_table. However, if there is a
857
RENAME + change of a field, or an index, the short cut is not used.
858
See how `create_list` is used to generate the new FRM regarding the
859
structure of the fields. The same is done for the indices of the table.
861
Important is the fact, that this function tries to do as little work as
862
possible, by finding out whether a intermediate table is needed to copy
863
data into and when finishing the altering to use it as the original table.
864
For this reason the function compare_tables() is called, which decides
865
based on all kind of data how similar are the new and the original
873
static bool internal_alter_table(Session *session,
875
TableIdentifier &original_table_identifier,
876
TableIdentifier &new_table_identifier,
877
HA_CREATE_INFO *create_info,
878
const message::Table &original_proto,
879
message::Table &create_proto,
880
TableList *table_list,
881
AlterInfo *alter_info,
892
session->set_proc_info("init");
894
table->use_all_columns();
896
plugin::StorageEngine *new_engine;
897
plugin::StorageEngine *original_engine;
899
original_engine= table->getMutableShare()->getEngine();
901
if (not create_info->db_type)
903
create_info->db_type= original_engine;
905
new_engine= create_info->db_type;
908
create_proto.set_schema(new_table_identifier.getSchemaName());
909
create_proto.set_type(new_table_identifier.getType());
912
@todo Have a check on the table definition for FK in the future
913
to remove the need for the cursor. (aka can_switch_engines())
915
if (new_engine != original_engine &&
916
not table->cursor->can_switch_engines())
919
my_error(ER_ROW_IS_REFERENCED, MYF(0));
924
if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
925
new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
927
my_error(ER_ILLEGAL_HA, MYF(0), new_table_identifier.getSQLPath().c_str());
932
session->set_proc_info("setup");
935
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
941
tmp.reset(ALTER_RENAME);
942
tmp.reset(ALTER_KEYS_ONOFF);
943
tmp&= alter_info->flags;
945
if (! (tmp.any()) && ! table->getShare()->getType()) // no need to touch frm
947
switch (alter_info->keys_onoff)
953
wait_while_table_is_used() ensures that table being altered is
954
opened only by this thread and that Table::TableShare::version
955
of Table object corresponding to this table is 0.
956
The latter guarantees that no DML statement will open this table
957
until ALTER Table finishes (i.e. until close_thread_tables())
958
while the fact that the table is still open gives us protection
959
from concurrent DDL statements.
961
LOCK_open.lock(); /* DDL wait for/blocker */
962
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
964
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
965
/* COND_refresh will be signaled in close_thread_tables() */
968
LOCK_open.lock(); /* DDL wait for/blocker */
969
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
971
error=table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
972
/* COND_refresh will be signaled in close_thread_tables() */
980
if (error == HA_ERR_WRONG_COMMAND)
983
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
984
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
988
LOCK_open.lock(); /* Lock to remove all instances of table from table cache before ALTER */
990
Unlike to the above case close_cached_table() below will remove ALL
991
instances of Table from table cache (it will also remove table lock
992
held by this thread). So to make actual table renaming and writing
993
to binlog atomic we have to put them into the same critical section
994
protected by LOCK_open mutex. This also removes gap for races between
995
access() and mysql_rename_table() calls.
998
if (error == 0 && not (original_table_identifier == new_table_identifier))
1000
session->set_proc_info("rename");
1002
Then do a 'simple' rename of the table. First we need to close all
1003
instances of 'source' table.
1005
session->close_cached_table(table);
1007
Then, we want check once again that target table does not exist.
1008
Actually the order of these two steps does not matter since
1009
earlier we took name-lock on the target table, so we do them
1010
in this particular order only to be consistent with 5.0, in which
1011
we don't take this name-lock and where this order really matters.
1012
@todo Investigate if we need this access() check at all.
1014
if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1016
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_table_identifier.getSQLPath().c_str());
1021
if (mysql_rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1028
if (error == HA_ERR_WRONG_COMMAND)
1031
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1032
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1038
TransactionServices &transaction_services= TransactionServices::singleton();
1039
transaction_services.allocateNewTransactionId();
1040
write_bin_log(session, *session->getQueryString());
1045
table->print_error(error, MYF(0));
1050
table_list->table= NULL;
1056
/* We have to do full alter table. */
1057
new_engine= create_info->db_type;
1059
if (mysql_prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
1064
set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
1066
alter_info->build_method= HA_BUILD_OFFLINE;
1068
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1070
/* Create a temporary table with the new format */
1072
@note we make an internal temporary table unless the table is a temporary table. In last
1073
case we just use it as is. Neither of these tables require locks in order to be
1076
TableIdentifier new_table_as_temporary(original_table_identifier.getSchemaName(),
1078
create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1079
message::Table::TEMPORARY);
1081
error= create_temporary_table(session, new_table_as_temporary, create_info, create_proto, alter_info);
1088
/* Open the table so we need to copy the data to it. */
1089
Table *new_table= open_alter_table(session, table, new_table_as_temporary);
1094
quick_rm_table(*session, new_table_as_temporary);
1098
/* Copy the data if necessary. */
1100
/* We must not ignore bad input! */
1101
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; // calc cuted fields
1102
session->cuted_fields= 0L;
1103
session->set_proc_info("copy to tmp table");
1106
/* We don't want update TIMESTAMP fields during ALTER Table. */
1107
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1108
new_table->next_number_field= new_table->found_next_number_field;
1109
error= copy_data_between_tables(session,
1112
alter_info->create_list,
1118
alter_info->keys_onoff,
1119
alter_info->error_if_not_empty);
1121
/* We must not ignore bad input! */
1122
assert(session->count_cuted_fields == CHECK_FIELD_ERROR_FOR_NULL);
1125
/* Now we need to resolve what just happened with the data copy. */
1131
No default value was provided for a DATE/DATETIME field, the
1132
current sql_mode doesn't allow the '0000-00-00' value and
1133
the table to be altered isn't empty.
1136
if (alter_info->error_if_not_empty && session->row_count)
1138
const char *f_val= 0;
1139
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1141
switch (alter_info->datetime_field->sql_type)
1143
case DRIZZLE_TYPE_DATE:
1144
f_val= "0000-00-00";
1145
t_type= DRIZZLE_TIMESTAMP_DATE;
1147
case DRIZZLE_TYPE_DATETIME:
1148
f_val= "0000-00-00 00:00:00";
1149
t_type= DRIZZLE_TIMESTAMP_DATETIME;
1152
/* Shouldn't get here. */
1155
bool save_abort_on_warning= session->abort_on_warning;
1156
session->abort_on_warning= true;
1157
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1158
f_val, internal::strlength(f_val), t_type,
1159
alter_info->datetime_field->field_name);
1160
session->abort_on_warning= save_abort_on_warning;
1163
if (original_table_identifier.isTmp())
1167
/* close_temporary_table() frees the new_table pointer. */
1168
session->close_temporary_table(new_table);
1172
quick_rm_table(*session, new_table_as_temporary);
1182
Close the intermediate table that will be the new table.
1183
Note that MERGE tables do not have their children attached here.
1185
new_table->intern_close_table();
1186
if (new_table->hasShare())
1188
delete new_table->getMutableShare();
1194
LOCK_open.lock(); /* ALTER TABLE */
1196
quick_rm_table(*session, new_table_as_temporary);
1202
// Temporary table and success
1203
else if (original_table_identifier.isTmp())
1205
/* Close lock if this is a transactional table */
1208
session->unlockTables(session->lock);
1212
/* Remove link to old table and rename the new one */
1213
session->close_temporary_table(table);
1215
/* Should pass the 'new_name' as we store table name in the cache */
1216
new_table->getMutableShare()->setIdentifier(new_table_identifier);
1218
new_table_identifier.setPath(new_table_as_temporary.getPath());
1220
if (mysql_rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1225
// Normal table success
1231
Close the intermediate table that will be the new table.
1232
Note that MERGE tables do not have their children attached here.
1234
new_table->intern_close_table();
1236
if (new_table->hasShare())
1238
delete new_table->getMutableShare();
1244
LOCK_open.lock(); /* ALTER TABLE */
1247
Data is copied. Now we:
1248
1) Wait until all other threads close old version of table.
1249
2) Close instances of table open by this thread and replace them
1250
with exclusive name-locks.
1251
3) Rename the old table to a temp name, rename the new one to the
1253
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1254
we reopen new version of table.
1255
5) Write statement to the binary log.
1256
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1257
remove name-locks from list of open tables and table cache.
1258
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1259
call to remove name-locks from table cache and list of open table.
1262
session->set_proc_info("rename result table");
1264
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1266
my_casedn_str(files_charset_info, old_name);
1268
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1269
session->close_data_files_and_morph_locks(original_table_identifier);
1274
This leads to the storage engine (SE) not being notified for renames in
1275
mysql_rename_table(), because we just juggle with the FRM and nothing
1276
more. If we have an intermediate table, then we notify the SE that
1277
it should become the actual table. Later, we will recycle the old table.
1278
However, in case of ALTER Table RENAME there might be no intermediate
1279
table. This is when the old and new tables are compatible, according to
1280
compare_table(). Then, we need one additional call to
1282
TableIdentifier original_table_to_drop(original_table_identifier.getSchemaName(),
1283
old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1284
message::Table::TEMPORARY);
1286
if (mysql_rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1289
quick_rm_table(*session, new_table_as_temporary);
1293
if (mysql_rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1295
/* Try to get everything back. */
1298
quick_rm_table(*session, new_table_identifier);
1300
quick_rm_table(*session, new_table_as_temporary);
1302
mysql_rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1306
quick_rm_table(*session, original_table_to_drop);
1313
An error happened while we were holding exclusive name-lock on table
1314
being altered. To be safe under LOCK TABLES we should remove placeholders
1315
from list of open tables list and table cache.
1317
session->unlink_open_table(table);
1325
session->set_proc_info("end");
1327
write_bin_log(session, *session->getQueryString());
1328
table_list->table= NULL;
1332
* Field::store() may have called my_error(). If this is
1333
* the case, we must not send an ok packet, since
1334
* Diagnostics_area::is_set() will fail an assert.
1336
if (session->is_error())
1338
/* my_error() was called. Return true (which means error...) */
1342
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1343
(ulong) (copied + deleted), (ulong) deleted,
1344
(ulong) session->cuted_fields);
1345
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1346
session->some_tables_deleted= 0;
1351
bool alter_table(Session *session,
1352
TableIdentifier &original_table_identifier,
1353
TableIdentifier &new_table_identifier,
1354
HA_CREATE_INFO *create_info,
1355
const message::Table &original_proto,
1356
message::Table &create_proto,
1357
TableList *table_list,
1358
AlterInfo *alter_info,
1366
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1368
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1369
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1372
session->set_proc_info("init");
1374
if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
1377
session->set_proc_info("gained write lock on table");
1380
Check that we are not trying to rename to an existing table,
1381
if one existed we get a lock, if we can't we error.
1384
Table *name_lock= NULL;
1386
if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
1391
error= internal_alter_table(session,
1393
original_table_identifier,
1394
new_table_identifier,
1406
LOCK_open.lock(); /* ALTER TABLe */
1407
session->unlink_open_table(name_lock);
1417
copy_data_between_tables(Session *session,
1418
Table *from, Table *to,
1419
List<CreateField> &create,
1421
uint32_t order_num, Order *order,
1424
enum enum_enable_or_disable keys_onoff,
1425
bool error_if_not_empty)
1428
CopyField *copy,*copy_end;
1429
ulong found_count,delete_count;
1431
SortField *sortorder;
1435
List<Item> all_fields;
1436
ha_rows examined_rows;
1437
bool auto_increment_field_copied= 0;
1438
uint64_t prev_insert_id;
1441
Turn off recovery logging since rollback of an alter table is to
1442
delete the new table so there is no need to log the changes to it.
1444
This needs to be done before external_lock
1446
TransactionServices &transaction_services= TransactionServices::singleton();
1451
* Since open_temporary_table() doesn't invoke lockTables(), we
1452
* don't get the usual automatic call to StorageEngine::startStatement(), so
1453
* we manually call it here...
1455
to->getMutableShare()->getEngine()->startStatement(session);
1457
if (!(copy= new CopyField[to->getShare()->sizeFields()]))
1460
if (to->cursor->ha_external_lock(session, F_WRLCK))
1463
/* We need external lock before we can disable/enable keys */
1464
alter_table_manage_keys(session, to, from->cursor->indexes_are_disabled(), keys_onoff);
1466
/* We can abort alter table for any table type */
1467
session->abort_on_warning= !ignore;
1469
from->cursor->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1470
to->cursor->ha_start_bulk_insert(from->cursor->stats.records);
1472
List_iterator<CreateField> it(create);
1475
for (Field **ptr= to->getFields(); *ptr ; ptr++)
1480
if (*ptr == to->next_number_field)
1481
auto_increment_field_copied= true;
1483
(copy_end++)->set(*ptr,def->field,0);
1488
found_count=delete_count=0;
1492
if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1494
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1495
snprintf(warn_buff, sizeof(warn_buff),
1496
_("order_st BY ignored because there is a user-defined clustered "
1497
"index in the table '%-.192s'"),
1498
from->getMutableShare()->getTableName());
1499
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1504
FileSort filesort(*session);
1505
from->sort.io_cache= new internal::IO_CACHE;
1507
memset(&tables, 0, sizeof(tables));
1509
tables.setTableName(const_cast<char *>(from->getMutableShare()->getTableName()));
1510
tables.alias= const_cast<char *>(tables.getTableName());
1511
tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1514
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1515
setup_order(session, session->lex->select_lex.ref_pointer_array,
1516
&tables, fields, all_fields, order) ||
1517
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1518
(from->sort.found_records= filesort.run(from, sortorder, length,
1519
(optimizer::SqlSelect *) 0, HA_POS_ERROR,
1520
1, examined_rows)) == HA_POS_ERROR)
1527
/* Tell handler that we have values for all columns in the to table */
1528
to->use_all_columns();
1529
info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1531
to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1532
session->row_count= 0;
1533
to->restoreRecordAsDefault(); // Create empty record
1534
while (!(error=info.read_record(&info)))
1536
if (session->getKilled())
1538
session->send_kill_message();
1542
session->row_count++;
1543
/* Return error if source table isn't empty. */
1544
if (error_if_not_empty)
1549
if (to->next_number_field)
1551
if (auto_increment_field_copied)
1552
to->auto_increment_field_not_null= true;
1554
to->next_number_field->reset();
1557
for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
1559
copy_ptr->do_copy(copy_ptr);
1561
prev_insert_id= to->cursor->next_insert_id;
1562
error= to->cursor->insertRecord(to->record[0]);
1563
to->auto_increment_field_not_null= false;
1568
to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1570
to->print_error(error, MYF(0));
1573
to->cursor->restore_auto_increment(prev_insert_id);
1582
info.end_read_record();
1583
from->free_io_cache();
1584
delete [] copy; // This is never 0
1586
if (to->cursor->ha_end_bulk_insert() && error <= 0)
1588
to->print_error(errno, MYF(0));
1591
to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1594
Ensure that the new table is saved properly to disk so that we
1597
if (transaction_services.autocommitOrRollback(session, false))
1599
if (! session->endActiveTransaction())
1603
session->abort_on_warning= 0;
1604
from->free_io_cache();
1605
*copied= found_count;
1606
*deleted=delete_count;
1607
to->cursor->ha_release_auto_increment();
1608
if (to->cursor->ha_external_lock(session,F_UNLCK))
1611
return(error > 0 ? -1 : 0);
1615
create_temporary_table(Session *session,
1616
TableIdentifier &identifier,
1617
HA_CREATE_INFO *create_info,
1618
message::Table &create_proto,
1619
AlterInfo *alter_info)
1624
Create a table with a temporary name.
1625
We don't log the statement, it will be logged later.
1627
create_proto.set_name(identifier.getTableName());
1629
create_proto.mutable_engine()->set_name(create_info->db_type->getName());
1631
error= mysql_create_table(session,
1633
create_info, create_proto, alter_info, true, 0, false);
1638
static Table *open_alter_table(Session *session, Table *table, TableIdentifier &identifier)
1642
/* Open the table so we need to copy the data to it. */
1643
if (table->getShare()->getType())
1646
tbl.setSchemaName(const_cast<char *>(identifier.getSchemaName().c_str()));
1647
tbl.alias= const_cast<char *>(identifier.getTableName().c_str());
1648
tbl.setTableName(const_cast<char *>(identifier.getTableName().c_str()));
1650
/* Table is in session->temporary_tables */
1651
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
1655
/* Open our intermediate table */
1656
new_table= session->open_temporary_table(identifier, false);
1662
} /* namespace drizzled */