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
21
#include <drizzled/server_includes.h>
22
#include <drizzled/show.h>
23
#include <drizzled/lock.h>
24
#include <drizzled/session.h>
25
#include <drizzled/statement/alter_table.h>
27
#include "drizzled/gettext.h"
28
#include "drizzled/data_home.h"
29
#include "drizzled/sql_table.h"
30
#include "drizzled/table_proto.h"
37
static int copy_data_between_tables(Table *from,Table *to,
38
List<CreateField> &create,
44
enum enum_enable_or_disable keys_onoff,
45
bool error_if_not_empty);
46
static bool mysql_prepare_alter_table(Session *session,
48
HA_CREATE_INFO *create_info,
49
message::Table *table_proto,
50
AlterInfo *alter_info);
51
static int create_temporary_table(Session *session,
55
HA_CREATE_INFO *create_info,
56
message::Table *create_proto,
57
AlterInfo *alter_info);
59
bool statement::AlterTable::execute()
61
TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
62
TableList *all_tables= session->lex->query_tables;
63
assert(first_table == all_tables && first_table != 0);
64
Select_Lex *select_lex= &session->lex->select_lex;
65
bool need_start_waiting= false;
67
/* Must be set in the parser */
68
assert(select_lex->db);
70
/* ALTER TABLE ends previous transaction */
71
if (! session->endActiveTransaction())
76
if (! (need_start_waiting= ! wait_if_global_read_lock(session, 0, 1)))
81
bool res= alter_table(session,
83
session->lex->name.str,
88
select_lex->order_list.elements,
89
(order_st *) select_lex->order_list.first,
90
session->lex->ignore);
92
Release the protection against the global read lock and wake
93
everyone, who might want to set a global read lock.
95
start_waiting_global_read_lock(session);
101
Prepare column and key definitions for CREATE TABLE in ALTER Table.
103
This function transforms parse output of ALTER Table - lists of
104
columns and keys to add, drop or modify into, essentially,
105
CREATE TABLE definition - a list of columns and keys of the new
106
table. While doing so, it also performs some (bug not all)
109
This function is invoked when we know that we're going to
110
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
111
is not possible, perhaps because the ALTER statement contains
112
instructions that require change in table data, not only in
113
table definition or indexes.
115
@param[in,out] session thread handle. Used as a memory pool
116
and source of environment information.
117
@param[in] table the source table, open and locked
118
Used as an interface to the storage engine
119
to acquire additional information about
121
@param[in,out] create_info A blob with CREATE/ALTER Table
123
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
124
Originally create_info was used only in
125
CREATE TABLE and alter_info only in ALTER Table.
126
But since ALTER might end-up doing CREATE,
127
this distinction is gone and we just carry
128
around two structures.
131
Fills various create_info members based on information retrieved
132
from the storage engine.
133
Sets create_info->varchar if the table has a VARCHAR column.
134
Prepares alter_info->create_list and alter_info->key_list with
135
columns and keys of the new table.
136
@retval true error, out of memory or a semantical error in ALTER
138
@retval false success
140
static bool mysql_prepare_alter_table(Session *session,
142
HA_CREATE_INFO *create_info,
143
message::Table *table_proto,
144
AlterInfo *alter_info)
146
/* New column definitions are added here */
147
List<CreateField> new_create_list;
148
/* New key definitions are added here */
149
List<Key> new_key_list;
150
List_iterator<AlterDrop> drop_it(alter_info->drop_list);
151
List_iterator<CreateField> def_it(alter_info->create_list);
152
List_iterator<AlterColumn> alter_it(alter_info->alter_list);
153
List_iterator<Key> key_it(alter_info->key_list);
154
List_iterator<CreateField> find_it(new_create_list);
155
List_iterator<CreateField> field_it(new_create_list);
156
List<Key_part_spec> key_parts;
157
uint32_t used_fields= create_info->used_fields;
158
KEY *key_info= table->key_info;
161
/* Let new create options override the old ones */
162
message::Table::TableOptions *table_options;
163
table_options= table_proto->mutable_options();
165
if (! (used_fields & HA_CREATE_USED_BLOCK_SIZE))
166
table_options->set_block_size(table->s->block_size);
167
if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
168
create_info->default_table_charset= table->s->table_charset;
169
if (! (used_fields & HA_CREATE_USED_AUTO) &&
170
table->found_next_number_field)
172
/* Table has an autoincrement, copy value to new table */
173
table->file->info(HA_STATUS_AUTO);
174
create_info->auto_increment_value= table->file->stats.auto_increment_value;
176
if (! (used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
177
create_info->key_block_size= table->s->key_block_size;
179
table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
182
/* First collect all fields from table which isn't in drop_list */
185
for (f_ptr= table->field; (field= *f_ptr); f_ptr++)
187
/* Check if field should be dropped */
190
while ((drop= drop_it++))
192
if (drop->type == AlterDrop::COLUMN &&
193
! my_strcasecmp(system_charset_info, field->field_name, drop->name))
195
/* Reset auto_increment value if it was dropped */
196
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
197
! (used_fields & HA_CREATE_USED_AUTO))
199
create_info->auto_increment_value= 0;
200
create_info->used_fields|= HA_CREATE_USED_AUTO;
211
/* Mark that we will read the field */
214
/* Check if field is changed */
216
while ((def= def_it++))
219
! my_strcasecmp(system_charset_info, field->field_name, def->change))
224
/* Field is changed */
228
new_create_list.push_back(def);
235
This field was not dropped and not changed, add it to the list
238
def= new CreateField(field, field);
239
new_create_list.push_back(def);
240
alter_it.rewind(); /* Change default if ALTER */
242
while ((alter= alter_it++))
244
if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
249
if (def->sql_type == DRIZZLE_TYPE_BLOB)
251
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
254
if ((def->def= alter->def))
256
/* Use new default */
257
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
260
def->flags|= NO_DEFAULT_VALUE_FLAG;
266
while ((def= def_it++)) /* Add new columns */
268
if (def->change && ! def->field)
270
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
274
Check that the DATE/DATETIME not null field we are going to add is
275
either has a default value or the '0000-00-00' is allowed by the
277
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
278
flag to allow ALTER Table only if the table to be altered is empty.
280
if ((def->sql_type == DRIZZLE_TYPE_DATE ||
281
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
282
! alter_info->datetime_field &&
283
! (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
284
session->variables.sql_mode & MODE_NO_ZERO_DATE)
286
alter_info->datetime_field= def;
287
alter_info->error_if_not_empty= true;
290
new_create_list.push_back(def);
291
else if (def->after == first_keyword)
292
new_create_list.push_front(def);
297
while ((find= find_it++)) /* Add new columns */
299
if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
304
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
307
find_it.after(def); /* Put element after this */
309
XXX: hack for Bug#28427.
310
If column order has changed, force OFFLINE ALTER Table
311
without querying engine capabilities. If we ever have an
312
engine that supports online ALTER Table CHANGE COLUMN
313
<name> AFTER <name1> (Falcon?), this fix will effectively
314
disable the capability.
315
TODO: detect the situation in compare_tables, behave based
316
on engine capabilities.
318
if (alter_info->build_method == HA_BUILD_ONLINE)
320
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
323
alter_info->build_method= HA_BUILD_OFFLINE;
326
if (alter_info->alter_list.elements)
328
my_error(ER_BAD_FIELD_ERROR,
330
alter_info->alter_list.head()->name,
331
table->s->table_name.str);
334
if (! new_create_list.elements)
336
my_message(ER_CANT_REMOVE_ALL_FIELDS,
337
ER(ER_CANT_REMOVE_ALL_FIELDS),
343
Collect all keys which isn't in drop list. Add only those
344
for which some fields exists.
346
for (uint32_t i= 0; i < table->s->keys; i++, key_info++)
348
char *key_name= key_info->name;
351
while ((drop= drop_it++))
353
if (drop->type == AlterDrop::KEY &&
354
! my_strcasecmp(system_charset_info, key_name, drop->name))
363
KEY_PART_INFO *key_part= key_info->key_part;
365
for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
367
if (! key_part->field)
368
continue; /* Wrong field (from UNIREG) */
370
const char *key_part_name= key_part->field->field_name;
373
while ((cfield= field_it++))
377
if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
380
else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
384
continue; /* Field is removed */
386
uint32_t key_part_length= key_part->length;
387
if (cfield->field) /* Not new field */
390
If the field can't have only a part used in a key according to its
391
new type, or should not be used partially according to its
392
previous type, or the field length is less than the key part
393
length, unset the key part length.
395
We also unset the key part length if it is the same as the
396
old field's length, so the whole new field will be used.
398
BLOBs may have cfield->length == 0, which is why we test it before
399
checking whether cfield->length < key_part_length (in chars).
401
if (! Field::type_can_have_key_part(cfield->field->type()) ||
402
! Field::type_can_have_key_part(cfield->sql_type) ||
403
(cfield->field->field_length == key_part_length &&
404
! f_is_blob(key_part->key_type)) ||
406
(cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
407
key_part_length= 0; /* Use whole field */
409
key_part_length/= key_part->field->charset()->mbmaxlen;
410
key_parts.push_back(new Key_part_spec(cfield->field_name,
411
strlen(cfield->field_name),
414
if (key_parts.elements)
416
KEY_CREATE_INFO key_create_info;
418
enum Key::Keytype key_type;
419
memset(&key_create_info, 0, sizeof(key_create_info));
421
key_create_info.algorithm= key_info->algorithm;
422
if (key_info->flags & HA_USES_BLOCK_SIZE)
423
key_create_info.block_size= key_info->block_size;
424
if (key_info->flags & HA_USES_COMMENT)
425
key_create_info.comment= key_info->comment;
427
if (key_info->flags & HA_NOSAME)
429
if (is_primary_key_name(key_name))
430
key_type= Key::PRIMARY;
432
key_type= Key::UNIQUE;
435
key_type= Key::MULTIPLE;
437
key= new Key(key_type,
441
test(key_info->flags & HA_GENERATED_KEY),
443
new_key_list.push_back(key);
448
while ((key= key_it++)) /* Add new keys */
450
if (key->type == Key::FOREIGN_KEY &&
451
((Foreign_key *)key)->validate(new_create_list))
453
if (key->type != Key::FOREIGN_KEY)
454
new_key_list.push_back(key);
455
if (key->name.str && is_primary_key_name(key->name.str))
457
my_error(ER_WRONG_NAME_FOR_INDEX,
465
if (alter_info->drop_list.elements)
467
my_error(ER_CANT_DROP_FIELD_OR_KEY,
469
alter_info->drop_list.head()->name);
472
if (alter_info->alter_list.elements)
474
my_error(ER_CANT_DROP_FIELD_OR_KEY,
476
alter_info->alter_list.head()->name);
480
if (! table_proto->options().has_comment()
481
&& table->s->hasComment())
482
table_options->set_comment(table->s->getComment());
484
if (table->s->tmp_table)
485
create_info->options|= HA_LEX_CREATE_TMP_TABLE;
488
alter_info->create_list.swap(new_create_list);
489
alter_info->key_list.swap(new_key_list);
494
/* table_list should contain just one table */
495
static int mysql_discard_or_import_tablespace(Session *session,
496
TableList *table_list,
497
enum tablespace_op_type tablespace_op)
504
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
508
session->set_proc_info("discard_or_import_tablespace");
510
discard= test(tablespace_op == DISCARD_TABLESPACE);
513
We set this flag so that ha_innobase::open and ::external_lock() do
514
not complain when we lock the table
516
session->tablespace_op= true;
517
if (!(table= session->openTableLock(table_list, TL_WRITE)))
519
session->tablespace_op= false;
523
error= table->file->ha_discard_or_import_tablespace(discard);
525
session->set_proc_info("end");
530
/* The ALTER Table is always in its own transaction */
531
error = ha_autocommit_or_rollback(session, 0);
532
if (! session->endActiveTransaction())
536
write_bin_log(session, false, session->query, session->query_length);
539
ha_autocommit_or_rollback(session, error);
540
session->tablespace_op=false;
548
table->file->print_error(error, MYF(0));
554
Manages enabling/disabling of indexes for ALTER Table
557
alter_table_manage_keys()
559
indexes_were_disabled Whether the indexes of the from table
561
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
567
static bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
568
enum enum_enable_or_disable keys_onoff)
571
switch (keys_onoff) {
573
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
576
if (!indexes_were_disabled)
578
/* fall-through: disabled indexes */
580
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
583
if (error == HA_ERR_WRONG_COMMAND)
585
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
586
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
587
table->s->table_name.str);
590
table->file->print_error(error, MYF(0));
600
session Thread handle
601
new_db If there is a RENAME clause
602
new_name If there is a RENAME clause
603
create_info Information from the parsing phase about new
605
table_list The table to change.
606
alter_info Lists of fields, keys to be changed, added
608
order_num How many order_st BY fields has been specified.
609
order List of fields to order_st BY.
610
ignore Whether we have ALTER IGNORE Table
613
This is a veery long function and is everything but the kitchen sink :)
614
It is used to alter a table and not only by ALTER Table but also
615
CREATE|DROP INDEX are mapped on this function.
617
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
618
or both, then this function short cuts its operation by renaming
619
the table and/or enabling/disabling the keys. In this case, the FRM is
620
not changed, directly by alter_table. However, if there is a
621
RENAME + change of a field, or an index, the short cut is not used.
622
See how `create_list` is used to generate the new FRM regarding the
623
structure of the fields. The same is done for the indices of the table.
625
Important is the fact, that this function tries to do as little work as
626
possible, by finding out whether a intermediate table is needed to copy
627
data into and when finishing the altering to use it as the original table.
628
For this reason the function compare_tables() is called, which decides
629
based on all kind of data how similar are the new and the original
636
bool alter_table(Session *session,
639
HA_CREATE_INFO *create_info,
640
message::Table *create_proto,
641
TableList *table_list,
642
AlterInfo *alter_info,
648
Table *new_table= NULL;
649
Table *name_lock= NULL;
654
char new_name_buff[FN_REFLEN];
655
char new_alias_buff[FN_REFLEN];
658
const char *new_alias;
659
char path[FN_REFLEN];
662
plugin::StorageEngine *old_db_type;
663
plugin::StorageEngine *new_db_type;
664
plugin::StorageEngine *save_old_db_type;
667
new_name_buff[0]= '\0';
669
if (table_list && table_list->schema_table)
671
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
675
session->set_proc_info("init");
678
Assign variables table_name, new_name, db, new_db, path
679
to simplify further comparisons: we want to see if it's a RENAME
680
later just by comparing the pointers, avoiding the need for strcmp.
682
table_name= table_list->table_name;
684
if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
687
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
689
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
690
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
693
build_table_filename(path, sizeof(path), db, table_name, false);
696
oss << drizzle_data_home << "/" << db << "/" << table_name;
698
(void) unpack_filename(new_name_buff, oss.str().c_str());
701
If this is just a rename of a view, short cut to the
702
following scenario: 1) lock LOCK_open 2) do a RENAME
704
This is a copy-paste added to make sure
705
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
706
as an independent branch in mysql_execute_command. The need
707
for a copy-paste arose because the main code flow of ALTER Table
708
... RENAME tries to use openTableLock, which does not work for views
709
(openTableLock was never modified to merge table lists of child tables
710
into the main table list, like open_tables does).
711
This code is wrong and will be removed, please do not copy.
714
if (!(table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
717
table->use_all_columns();
719
/* Check that we are not trying to rename to an existing table */
722
strcpy(new_name_buff, new_name);
723
strcpy(new_alias_buff, new_name);
724
new_alias= new_alias_buff;
726
my_casedn_str(files_charset_info, new_name_buff);
727
new_alias= new_name; // Create lower case table name
728
my_casedn_str(files_charset_info, new_name);
731
! my_strcasecmp(table_alias_charset, new_name_buff, table_name))
734
Source and destination table names are equal: make later check
737
new_alias= new_name= table_name;
741
if (table->s->tmp_table != NO_TMP_TABLE)
743
if (session->find_temporary_table(new_db, new_name_buff))
745
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
751
if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
756
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
760
build_table_filename(new_name_buff, sizeof(new_name_buff), new_db, new_name_buff, false);
762
if (plugin::StorageEngine::getTableProto(new_name_buff, NULL) == EEXIST)
764
/* Table will be closed by Session::executeCommand() */
765
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
773
new_alias= table_name;
774
new_name= table_name;
777
old_db_type= table->s->db_type();
778
if (! create_info->db_type)
780
create_info->db_type= old_db_type;
783
if (table->s->tmp_table != NO_TMP_TABLE)
784
create_info->options|= HA_LEX_CREATE_TMP_TABLE;
786
if (check_engine(session, new_name, create_info))
789
new_db_type= create_info->db_type;
791
if (new_db_type != old_db_type &&
792
!table->file->can_switch_engines())
795
my_error(ER_ROW_IS_REFERENCED, MYF(0));
799
if (create_info->row_type == ROW_TYPE_NOT_USED)
800
create_info->row_type= table->s->row_type;
802
if (old_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
803
new_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
805
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
809
session->set_proc_info("setup");
812
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
815
tmp.reset(ALTER_RENAME);
816
tmp.reset(ALTER_KEYS_ONOFF);
817
tmp&= alter_info->flags;
819
! table->s->tmp_table) // no need to touch frm
821
switch (alter_info->keys_onoff)
827
wait_while_table_is_used() ensures that table being altered is
828
opened only by this thread and that Table::TableShare::version
829
of Table object corresponding to this table is 0.
830
The latter guarantees that no DML statement will open this table
831
until ALTER Table finishes (i.e. until close_thread_tables())
832
while the fact that the table is still open gives us protection
833
from concurrent DDL statements.
835
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
836
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
837
pthread_mutex_unlock(&LOCK_open);
838
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
839
/* COND_refresh will be signaled in close_thread_tables() */
842
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
843
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
844
pthread_mutex_unlock(&LOCK_open);
845
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
846
/* COND_refresh will be signaled in close_thread_tables() */
854
if (error == HA_ERR_WRONG_COMMAND)
857
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
858
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
862
pthread_mutex_lock(&LOCK_open); /* Lock to remove all instances of table from table cache before ALTER */
864
Unlike to the above case close_cached_table() below will remove ALL
865
instances of Table from table cache (it will also remove table lock
866
held by this thread). So to make actual table renaming and writing
867
to binlog atomic we have to put them into the same critical section
868
protected by LOCK_open mutex. This also removes gap for races between
869
access() and mysql_rename_table() calls.
873
(new_name != table_name || new_db != db))
875
session->set_proc_info("rename");
877
Then do a 'simple' rename of the table. First we need to close all
878
instances of 'source' table.
880
session->close_cached_table(table);
882
Then, we want check once again that target table does not exist.
883
Actually the order of these two steps does not matter since
884
earlier we took name-lock on the target table, so we do them
885
in this particular order only to be consistent with 5.0, in which
886
we don't take this name-lock and where this order really matters.
887
TODO: Investigate if we need this access() check at all.
889
if (plugin::StorageEngine::getTableProto(new_name, NULL) == EEXIST)
891
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
896
*fn_ext(new_name)= 0;
897
if (mysql_rename_table(old_db_type, db, table_name, new_db, new_alias, 0))
902
if (error == HA_ERR_WRONG_COMMAND)
905
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
906
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
912
write_bin_log(session, true, session->query, session->query_length);
917
table->file->print_error(error, MYF(0));
922
session->unlink_open_table(name_lock);
924
pthread_mutex_unlock(&LOCK_open);
925
table_list->table= NULL;
929
/* We have to do full alter table. */
932
If the old table had partitions and we are doing ALTER Table ...
933
engine= <new_engine>, the new table must preserve the original
934
partitioning. That means that the new engine is still the
935
partitioning engine, not the engine specified in the parser.
936
This is discovered in prep_alter_part_table, which in such case
937
updates create_info->db_type.
938
Now we need to update the stack copy of create_info->db_type,
939
as otherwise we won't be able to correctly move the files of the
940
temporary table to the result table files.
942
new_db_type= create_info->db_type;
944
if (mysql_prepare_alter_table(session, table, create_info, create_proto,
948
set_table_default_charset(create_info, db);
950
alter_info->build_method= HA_BUILD_OFFLINE;
952
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
954
/* Safety fix for innodb */
955
my_casedn_str(files_charset_info, tmp_name);
957
/* Create a temporary table with the new format */
958
error= create_temporary_table(session, table, new_db, tmp_name, create_info, create_proto, alter_info);
962
/* Open the table so we need to copy the data to it. */
963
if (table->s->tmp_table)
968
tbl.table_name= tmp_name;
970
/* Table is in session->temporary_tables */
971
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
975
char tmp_path[FN_REFLEN];
976
/* table is a normal table: Create temporary table in same directory */
977
build_table_filename(tmp_path, sizeof(tmp_path), new_db, tmp_name, true);
978
/* Open our intermediate table */
979
new_table= session->open_temporary_table(tmp_path, new_db, tmp_name, 0, OTM_OPEN);
982
if (new_table == NULL)
985
/* Copy the data if necessary. */
986
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
987
session->cuted_fields= 0L;
988
session->set_proc_info("copy to tmp table");
993
/* We don't want update TIMESTAMP fields during ALTER Table. */
994
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
995
new_table->next_number_field= new_table->found_next_number_field;
996
error= copy_data_between_tables(table,
998
alter_info->create_list,
1004
alter_info->keys_onoff,
1005
alter_info->error_if_not_empty);
1007
/* We must not ignore bad input! */
1008
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
1010
if (table->s->tmp_table != NO_TMP_TABLE)
1012
/* We changed a temporary table */
1016
/* Close lock if this is a transactional table */
1019
mysql_unlock_tables(session, session->lock);
1023
/* Remove link to old table and rename the new one */
1024
session->close_temporary_table(table, true, true);
1026
/* Should pass the 'new_name' as we store table name in the cache */
1027
if (new_table->rename_temporary_table(new_db, new_name))
1036
Close the intermediate table that will be the new table.
1037
Note that MERGE tables do not have their children attached here.
1039
new_table->intern_close_table();
1043
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1047
quick_rm_table(new_db_type, new_db, tmp_name, true);
1048
pthread_mutex_unlock(&LOCK_open);
1053
Data is copied. Now we:
1054
1) Wait until all other threads close old version of table.
1055
2) Close instances of table open by this thread and replace them
1056
with exclusive name-locks.
1057
3) Rename the old table to a temp name, rename the new one to the
1059
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1060
we reopen new version of table.
1061
5) Write statement to the binary log.
1062
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1063
remove name-locks from list of open tables and table cache.
1064
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1065
call to remove name-locks from table cache and list of open table.
1068
session->set_proc_info("rename result table");
1070
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1072
my_casedn_str(files_charset_info, old_name);
1074
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1075
session->close_data_files_and_morph_locks(db, table_name);
1078
save_old_db_type= old_db_type;
1081
This leads to the storage engine (SE) not being notified for renames in
1082
mysql_rename_table(), because we just juggle with the FRM and nothing
1083
more. If we have an intermediate table, then we notify the SE that
1084
it should become the actual table. Later, we will recycle the old table.
1085
However, in case of ALTER Table RENAME there might be no intermediate
1086
table. This is when the old and new tables are compatible, according to
1087
compare_table(). Then, we need one additional call to
1088
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
1089
actual rename in the SE and the FRM is not touched. Note that, if the
1090
table is renamed and the SE is also changed, then an intermediate table
1091
is created and the additional call will not take place.
1093
if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
1096
quick_rm_table(new_db_type, new_db, tmp_name, true);
1100
if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
1102
/* Try to get everything back. */
1104
quick_rm_table(new_db_type, new_db, new_alias, false);
1105
quick_rm_table(new_db_type, new_db, tmp_name, true);
1106
mysql_rename_table(old_db_type, db, old_name, db, table_name, FN_FROM_IS_TMP);
1112
/* This shouldn't happen. But let us play it safe. */
1113
goto err_with_placeholders;
1116
quick_rm_table(old_db_type, db, old_name, true);
1118
pthread_mutex_unlock(&LOCK_open);
1120
session->set_proc_info("end");
1122
write_bin_log(session, true, session->query, session->query_length);
1124
if (old_db_type->check_flag(HTON_BIT_FLUSH_AFTER_RENAME))
1127
For the alter table to be properly flushed to the logs, we
1128
have to open the new table. If not, we get a problem on server
1129
shutdown. But we do not need to attach MERGE children.
1131
char table_path[FN_REFLEN];
1133
build_table_filename(table_path, sizeof(table_path), new_db, table_name, false);
1134
t_table= session->open_temporary_table(table_path, new_db, tmp_name, false, OTM_OPEN);
1137
t_table->intern_close_table();
1141
errmsg_printf(ERRMSG_LVL_WARN, _("Could not open table %s.%s after rename\n"), new_db, table_name);
1143
ha_flush_logs(old_db_type);
1145
table_list->table= NULL;
1149
* Field::store() may have called my_error(). If this is
1150
* the case, we must not send an ok packet, since
1151
* Diagnostics_area::is_set() will fail an assert.
1153
if (! session->is_error())
1155
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1156
(ulong) (copied + deleted), (ulong) deleted,
1157
(ulong) session->cuted_fields);
1158
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1159
session->some_tables_deleted=0;
1164
/* my_error() was called. Return true (which means error...) */
1171
/* close_temporary_table() frees the new_table pointer. */
1172
session->close_temporary_table(new_table, true, true);
1175
quick_rm_table(new_db_type, new_db, tmp_name, true);
1179
No default value was provided for a DATE/DATETIME field, the
1180
current sql_mode doesn't allow the '0000-00-00' value and
1181
the table to be altered isn't empty.
1184
if (alter_info->error_if_not_empty && session->row_count)
1186
const char *f_val= 0;
1187
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1188
switch (alter_info->datetime_field->sql_type)
1190
case DRIZZLE_TYPE_DATE:
1191
f_val= "0000-00-00";
1192
t_type= DRIZZLE_TIMESTAMP_DATE;
1194
case DRIZZLE_TYPE_DATETIME:
1195
f_val= "0000-00-00 00:00:00";
1196
t_type= DRIZZLE_TIMESTAMP_DATETIME;
1199
/* Shouldn't get here. */
1202
bool save_abort_on_warning= session->abort_on_warning;
1203
session->abort_on_warning= true;
1204
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1205
f_val, strlength(f_val), t_type,
1206
alter_info->datetime_field->field_name);
1207
session->abort_on_warning= save_abort_on_warning;
1211
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
1212
session->unlink_open_table(name_lock);
1213
pthread_mutex_unlock(&LOCK_open);
1217
err_with_placeholders:
1219
An error happened while we were holding exclusive name-lock on table
1220
being altered. To be safe under LOCK TABLES we should remove placeholders
1221
from list of open tables list and table cache.
1223
session->unlink_open_table(table);
1225
session->unlink_open_table(name_lock);
1226
pthread_mutex_unlock(&LOCK_open);
1232
copy_data_between_tables(Table *from,Table *to,
1233
List<CreateField> &create,
1235
uint32_t order_num, order_st *order,
1238
enum enum_enable_or_disable keys_onoff,
1239
bool error_if_not_empty)
1242
CopyField *copy,*copy_end;
1243
ulong found_count,delete_count;
1244
Session *session= current_session;
1246
SORT_FIELD *sortorder;
1250
List<Item> all_fields;
1251
ha_rows examined_rows;
1252
bool auto_increment_field_copied= 0;
1253
uint64_t prev_insert_id;
1256
Turn off recovery logging since rollback of an alter table is to
1257
delete the new table so there is no need to log the changes to it.
1259
This needs to be done before external_lock
1261
error= ha_enable_transaction(session, false);
1265
if (!(copy= new CopyField[to->s->fields]))
1268
if (to->file->ha_external_lock(session, F_WRLCK))
1271
/* We need external lock before we can disable/enable keys */
1272
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
1274
/* We can abort alter table for any table type */
1275
session->abort_on_warning= !ignore;
1277
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1278
to->file->ha_start_bulk_insert(from->file->stats.records);
1280
List_iterator<CreateField> it(create);
1283
for (Field **ptr=to->field ; *ptr ; ptr++)
1288
if (*ptr == to->next_number_field)
1289
auto_increment_field_copied= true;
1291
(copy_end++)->set(*ptr,def->field,0);
1296
found_count=delete_count=0;
1300
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
1302
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1303
snprintf(warn_buff, sizeof(warn_buff),
1304
_("order_st BY ignored because there is a user-defined clustered "
1305
"index in the table '%-.192s'"),
1306
from->s->table_name.str);
1307
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1312
from->sort.io_cache= new IO_CACHE;
1313
memset(from->sort.io_cache, 0, sizeof(IO_CACHE));
1315
memset(&tables, 0, sizeof(tables));
1317
tables.alias= tables.table_name= from->s->table_name.str;
1318
tables.db= from->s->db.str;
1321
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1322
setup_order(session, session->lex->select_lex.ref_pointer_array,
1323
&tables, fields, all_fields, order) ||
1324
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1325
(from->sort.found_records= filesort(session, from, sortorder, length,
1326
(SQL_SELECT *) 0, HA_POS_ERROR,
1327
1, &examined_rows)) ==
1333
/* Tell handler that we have values for all columns in the to table */
1334
to->use_all_columns();
1335
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
1337
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
1338
session->row_count= 0;
1339
to->restoreRecordAsDefault(); // Create empty record
1340
while (!(error=info.read_record(&info)))
1342
if (session->killed)
1344
session->send_kill_message();
1348
session->row_count++;
1349
/* Return error if source table isn't empty. */
1350
if (error_if_not_empty)
1355
if (to->next_number_field)
1357
if (auto_increment_field_copied)
1358
to->auto_increment_field_not_null= true;
1360
to->next_number_field->reset();
1363
for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
1365
copy_ptr->do_copy(copy_ptr);
1367
prev_insert_id= to->file->next_insert_id;
1368
error=to->file->ha_write_row(to->record[0]);
1369
to->auto_increment_field_not_null= false;
1373
to->file->is_fatal_error(error, HA_CHECK_DUP))
1375
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
1377
uint32_t key_nr= to->file->get_dup_key(error);
1378
if ((int) key_nr >= 0)
1380
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
1382
(to->key_info[0].key_part[0].field->flags &
1383
AUTO_INCREMENT_FLAG))
1384
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
1385
to->file->print_keydup_error(key_nr, err_msg);
1390
to->file->print_error(error,MYF(0));
1393
to->file->restore_auto_increment(prev_insert_id);
1399
end_read_record(&info);
1400
from->free_io_cache();
1401
delete [] copy; // This is never 0
1403
if (to->file->ha_end_bulk_insert() && error <= 0)
1405
to->file->print_error(my_errno,MYF(0));
1408
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1410
if (ha_enable_transaction(session, true))
1417
Ensure that the new table is saved properly to disk so that we
1420
if (ha_autocommit_or_rollback(session, 0))
1422
if (! session->endActiveTransaction())
1426
session->abort_on_warning= 0;
1427
from->free_io_cache();
1428
*copied= found_count;
1429
*deleted=delete_count;
1430
to->file->ha_release_auto_increment();
1431
if (to->file->ha_external_lock(session,F_UNLCK))
1433
return(error > 0 ? -1 : 0);
1437
create_temporary_table(Session *session,
1441
HA_CREATE_INFO *create_info,
1442
message::Table *create_proto,
1443
AlterInfo *alter_info)
1446
plugin::StorageEngine *old_db_type, *new_db_type;
1447
old_db_type= table->s->db_type();
1448
new_db_type= create_info->db_type;
1450
Create a table with a temporary name.
1451
We don't log the statement, it will be logged later.
1453
create_proto->set_name(tmp_name);
1454
create_proto->set_type(message::Table::TEMPORARY);
1456
message::Table::StorageEngine *protoengine;
1457
protoengine= create_proto->mutable_engine();
1458
protoengine->set_name(new_db_type->getName());
1460
error= mysql_create_table(session, new_db, tmp_name,
1461
create_info, create_proto, alter_info, 1, 0);
1466
/** @TODO This will soon die. */
1467
bool create_like_schema_frm(Session* session,
1468
TableList* schema_table,
1469
HA_CREATE_INFO *create_info,
1470
message::Table* table_proto)
1472
HA_CREATE_INFO local_create_info;
1473
AlterInfo alter_info;
1474
bool tmp_table= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
1475
uint32_t keys= schema_table->table->s->keys;
1476
uint32_t db_options= 0;
1478
memset(&local_create_info, 0, sizeof(local_create_info));
1479
local_create_info.db_type= schema_table->table->s->db_type();
1480
local_create_info.row_type= schema_table->table->s->row_type;
1481
local_create_info.default_table_charset=default_charset_info;
1482
alter_info.flags.set(ALTER_CHANGE_COLUMN);
1483
alter_info.flags.set(ALTER_RECREATE);
1484
schema_table->table->use_all_columns();
1485
if (mysql_prepare_alter_table(session, schema_table->table,
1486
&local_create_info, table_proto, &alter_info))
1489
/* I_S tables are created with MAX_ROWS for some efficiency drive.
1490
When CREATE LIKE, we don't want to keep it coming across */
1491
message::Table::TableOptions *table_options;
1492
table_options= table_proto->mutable_options();
1493
table_options->clear_max_rows();
1495
if (mysql_prepare_create_table(session, &local_create_info, &alter_info,
1496
tmp_table, &db_options,
1497
schema_table->table->file,
1498
&schema_table->table->s->key_info, &keys, 0))
1501
table_proto->set_name("system_stupid_i_s_fix_nonsense");
1503
table_proto->set_type(message::Table::TEMPORARY);
1505
table_proto->set_type(message::Table::STANDARD);
1508
message::Table::StorageEngine *protoengine;
1509
protoengine= table_proto->mutable_engine();
1511
plugin::StorageEngine *engine= local_create_info.db_type;
1513
protoengine->set_name(engine->getName());
1516
if (fill_table_proto(table_proto, "system_stupid_i_s_fix_nonsense",
1517
alter_info.create_list, &local_create_info,
1518
keys, schema_table->table->s->key_info))
1524
} /* namespace drizzled */