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"
32
using namespace drizzled;
34
static int copy_data_between_tables(Table *from,Table *to,
35
List<CreateField> &create,
41
enum enum_enable_or_disable keys_onoff,
42
bool error_if_not_empty);
43
static bool mysql_prepare_alter_table(Session *session,
45
HA_CREATE_INFO *create_info,
46
message::Table *table_proto,
47
AlterInfo *alter_info);
48
static int create_temporary_table(Session *session,
52
HA_CREATE_INFO *create_info,
53
message::Table *create_proto,
54
AlterInfo *alter_info);
56
bool statement::AlterTable::execute()
58
TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
59
TableList *all_tables= session->lex->query_tables;
60
assert(first_table == all_tables && first_table != 0);
61
Select_Lex *select_lex= &session->lex->select_lex;
62
bool need_start_waiting= false;
64
/* Must be set in the parser */
65
assert(select_lex->db);
67
/* ALTER TABLE ends previous transaction */
68
if (! session->endActiveTransaction())
73
if (! (need_start_waiting= ! wait_if_global_read_lock(session, 0, 1)))
78
bool res= mysql_alter_table(session,
80
session->lex->name.str,
85
select_lex->order_list.elements,
86
(order_st *) select_lex->order_list.first,
87
session->lex->ignore);
89
Release the protection against the global read lock and wake
90
everyone, who might want to set a global read lock.
92
start_waiting_global_read_lock(session);
97
Prepare column and key definitions for CREATE TABLE in ALTER Table.
99
This function transforms parse output of ALTER Table - lists of
100
columns and keys to add, drop or modify into, essentially,
101
CREATE TABLE definition - a list of columns and keys of the new
102
table. While doing so, it also performs some (bug not all)
105
This function is invoked when we know that we're going to
106
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
107
is not possible, perhaps because the ALTER statement contains
108
instructions that require change in table data, not only in
109
table definition or indexes.
111
@param[in,out] session thread handle. Used as a memory pool
112
and source of environment information.
113
@param[in] table the source table, open and locked
114
Used as an interface to the storage engine
115
to acquire additional information about
117
@param[in,out] create_info A blob with CREATE/ALTER Table
119
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
120
Originally create_info was used only in
121
CREATE TABLE and alter_info only in ALTER Table.
122
But since ALTER might end-up doing CREATE,
123
this distinction is gone and we just carry
124
around two structures.
127
Fills various create_info members based on information retrieved
128
from the storage engine.
129
Sets create_info->varchar if the table has a VARCHAR column.
130
Prepares alter_info->create_list and alter_info->key_list with
131
columns and keys of the new table.
132
@retval true error, out of memory or a semantical error in ALTER
134
@retval false success
136
static bool mysql_prepare_alter_table(Session *session,
138
HA_CREATE_INFO *create_info,
139
message::Table *table_proto,
140
AlterInfo *alter_info)
142
/* New column definitions are added here */
143
List<CreateField> new_create_list;
144
/* New key definitions are added here */
145
List<Key> new_key_list;
146
List_iterator<AlterDrop> drop_it(alter_info->drop_list);
147
List_iterator<CreateField> def_it(alter_info->create_list);
148
List_iterator<AlterColumn> alter_it(alter_info->alter_list);
149
List_iterator<Key> key_it(alter_info->key_list);
150
List_iterator<CreateField> find_it(new_create_list);
151
List_iterator<CreateField> field_it(new_create_list);
152
List<Key_part_spec> key_parts;
153
uint32_t used_fields= create_info->used_fields;
154
KEY *key_info= table->key_info;
157
/* Let new create options override the old ones */
158
message::Table::TableOptions *table_options;
159
table_options= table_proto->mutable_options();
161
if (! (used_fields & HA_CREATE_USED_BLOCK_SIZE))
162
table_options->set_block_size(table->s->block_size);
163
if (! (used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
164
create_info->default_table_charset= table->s->table_charset;
165
if (! (used_fields & HA_CREATE_USED_AUTO) &&
166
table->found_next_number_field)
168
/* Table has an autoincrement, copy value to new table */
169
table->file->info(HA_STATUS_AUTO);
170
create_info->auto_increment_value= table->file->stats.auto_increment_value;
172
if (! (used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
173
create_info->key_block_size= table->s->key_block_size;
175
table->restoreRecordAsDefault(); /* Empty record for DEFAULT */
178
/* First collect all fields from table which isn't in drop_list */
181
for (f_ptr= table->field; (field= *f_ptr); f_ptr++)
183
/* Check if field should be dropped */
186
while ((drop= drop_it++))
188
if (drop->type == AlterDrop::COLUMN &&
189
! my_strcasecmp(system_charset_info, field->field_name, drop->name))
191
/* Reset auto_increment value if it was dropped */
192
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
193
! (used_fields & HA_CREATE_USED_AUTO))
195
create_info->auto_increment_value= 0;
196
create_info->used_fields|= HA_CREATE_USED_AUTO;
207
/* Mark that we will read the field */
210
/* Check if field is changed */
212
while ((def= def_it++))
215
! my_strcasecmp(system_charset_info, field->field_name, def->change))
220
/* Field is changed */
224
new_create_list.push_back(def);
231
This field was not dropped and not changed, add it to the list
234
def= new CreateField(field, field);
235
new_create_list.push_back(def);
236
alter_it.rewind(); /* Change default if ALTER */
238
while ((alter= alter_it++))
240
if (! my_strcasecmp(system_charset_info,field->field_name, alter->name))
245
if (def->sql_type == DRIZZLE_TYPE_BLOB)
247
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
250
if ((def->def= alter->def))
252
/* Use new default */
253
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
256
def->flags|= NO_DEFAULT_VALUE_FLAG;
262
while ((def= def_it++)) /* Add new columns */
264
if (def->change && ! def->field)
266
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
270
Check that the DATE/DATETIME not null field we are going to add is
271
either has a default value or the '0000-00-00' is allowed by the
273
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
274
flag to allow ALTER Table only if the table to be altered is empty.
276
if ((def->sql_type == DRIZZLE_TYPE_DATE ||
277
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
278
! alter_info->datetime_field &&
279
! (~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
280
session->variables.sql_mode & MODE_NO_ZERO_DATE)
282
alter_info->datetime_field= def;
283
alter_info->error_if_not_empty= true;
286
new_create_list.push_back(def);
287
else if (def->after == first_keyword)
288
new_create_list.push_front(def);
293
while ((find= find_it++)) /* Add new columns */
295
if (! my_strcasecmp(system_charset_info,def->after, find->field_name))
300
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
303
find_it.after(def); /* Put element after this */
305
XXX: hack for Bug#28427.
306
If column order has changed, force OFFLINE ALTER Table
307
without querying engine capabilities. If we ever have an
308
engine that supports online ALTER Table CHANGE COLUMN
309
<name> AFTER <name1> (Falcon?), this fix will effectively
310
disable the capability.
311
TODO: detect the situation in compare_tables, behave based
312
on engine capabilities.
314
if (alter_info->build_method == HA_BUILD_ONLINE)
316
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
319
alter_info->build_method= HA_BUILD_OFFLINE;
322
if (alter_info->alter_list.elements)
324
my_error(ER_BAD_FIELD_ERROR,
326
alter_info->alter_list.head()->name,
327
table->s->table_name.str);
330
if (! new_create_list.elements)
332
my_message(ER_CANT_REMOVE_ALL_FIELDS,
333
ER(ER_CANT_REMOVE_ALL_FIELDS),
339
Collect all keys which isn't in drop list. Add only those
340
for which some fields exists.
342
for (uint32_t i= 0; i < table->s->keys; i++, key_info++)
344
char *key_name= key_info->name;
347
while ((drop= drop_it++))
349
if (drop->type == AlterDrop::KEY &&
350
! my_strcasecmp(system_charset_info, key_name, drop->name))
359
KEY_PART_INFO *key_part= key_info->key_part;
361
for (uint32_t j= 0; j < key_info->key_parts; j++, key_part++)
363
if (! key_part->field)
364
continue; /* Wrong field (from UNIREG) */
366
const char *key_part_name= key_part->field->field_name;
369
while ((cfield= field_it++))
373
if (! my_strcasecmp(system_charset_info, key_part_name, cfield->change))
376
else if (! my_strcasecmp(system_charset_info, key_part_name, cfield->field_name))
380
continue; /* Field is removed */
382
uint32_t key_part_length= key_part->length;
383
if (cfield->field) /* Not new field */
386
If the field can't have only a part used in a key according to its
387
new type, or should not be used partially according to its
388
previous type, or the field length is less than the key part
389
length, unset the key part length.
391
We also unset the key part length if it is the same as the
392
old field's length, so the whole new field will be used.
394
BLOBs may have cfield->length == 0, which is why we test it before
395
checking whether cfield->length < key_part_length (in chars).
397
if (! Field::type_can_have_key_part(cfield->field->type()) ||
398
! Field::type_can_have_key_part(cfield->sql_type) ||
399
(cfield->field->field_length == key_part_length &&
400
! f_is_blob(key_part->key_type)) ||
402
(cfield->length < key_part_length / key_part->field->charset()->mbmaxlen)))
403
key_part_length= 0; /* Use whole field */
405
key_part_length/= key_part->field->charset()->mbmaxlen;
406
key_parts.push_back(new Key_part_spec(cfield->field_name,
407
strlen(cfield->field_name),
410
if (key_parts.elements)
412
KEY_CREATE_INFO key_create_info;
414
enum Key::Keytype key_type;
415
memset(&key_create_info, 0, sizeof(key_create_info));
417
key_create_info.algorithm= key_info->algorithm;
418
if (key_info->flags & HA_USES_BLOCK_SIZE)
419
key_create_info.block_size= key_info->block_size;
420
if (key_info->flags & HA_USES_COMMENT)
421
key_create_info.comment= key_info->comment;
423
if (key_info->flags & HA_NOSAME)
425
if (is_primary_key_name(key_name))
426
key_type= Key::PRIMARY;
428
key_type= Key::UNIQUE;
431
key_type= Key::MULTIPLE;
433
key= new Key(key_type,
437
test(key_info->flags & HA_GENERATED_KEY),
439
new_key_list.push_back(key);
444
while ((key= key_it++)) /* Add new keys */
446
if (key->type == Key::FOREIGN_KEY &&
447
((Foreign_key *)key)->validate(new_create_list))
449
if (key->type != Key::FOREIGN_KEY)
450
new_key_list.push_back(key);
451
if (key->name.str && is_primary_key_name(key->name.str))
453
my_error(ER_WRONG_NAME_FOR_INDEX,
461
if (alter_info->drop_list.elements)
463
my_error(ER_CANT_DROP_FIELD_OR_KEY,
465
alter_info->drop_list.head()->name);
468
if (alter_info->alter_list.elements)
470
my_error(ER_CANT_DROP_FIELD_OR_KEY,
472
alter_info->alter_list.head()->name);
476
if (! table_proto->options().has_comment()
477
&& table->s->hasComment())
478
table_options->set_comment(table->s->getComment());
480
if (table->s->tmp_table)
481
create_info->options|= HA_LEX_CREATE_TMP_TABLE;
484
alter_info->create_list.swap(new_create_list);
485
alter_info->key_list.swap(new_key_list);
490
/* table_list should contain just one table */
491
static int mysql_discard_or_import_tablespace(Session *session,
492
TableList *table_list,
493
enum tablespace_op_type tablespace_op)
500
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
504
session->set_proc_info("discard_or_import_tablespace");
506
discard= test(tablespace_op == DISCARD_TABLESPACE);
509
We set this flag so that ha_innobase::open and ::external_lock() do
510
not complain when we lock the table
512
session->tablespace_op= true;
513
if (!(table= session->openTableLock(table_list, TL_WRITE)))
515
session->tablespace_op= false;
519
error= table->file->ha_discard_or_import_tablespace(discard);
521
session->set_proc_info("end");
526
/* The ALTER Table is always in its own transaction */
527
error = ha_autocommit_or_rollback(session, 0);
528
if (! session->endActiveTransaction())
532
write_bin_log(session, false, session->query, session->query_length);
535
ha_autocommit_or_rollback(session, error);
536
session->tablespace_op=false;
544
table->file->print_error(error, MYF(0));
550
Manages enabling/disabling of indexes for ALTER Table
553
alter_table_manage_keys()
555
indexes_were_disabled Whether the indexes of the from table
557
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
563
static bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
564
enum enum_enable_or_disable keys_onoff)
567
switch (keys_onoff) {
569
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
572
if (!indexes_were_disabled)
574
/* fall-through: disabled indexes */
576
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
579
if (error == HA_ERR_WRONG_COMMAND)
581
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
582
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
583
table->s->table_name.str);
586
table->file->print_error(error, MYF(0));
596
session Thread handle
597
new_db If there is a RENAME clause
598
new_name If there is a RENAME clause
599
create_info Information from the parsing phase about new
601
table_list The table to change.
602
alter_info Lists of fields, keys to be changed, added
604
order_num How many order_st BY fields has been specified.
605
order List of fields to order_st BY.
606
ignore Whether we have ALTER IGNORE Table
609
This is a veery long function and is everything but the kitchen sink :)
610
It is used to alter a table and not only by ALTER Table but also
611
CREATE|DROP INDEX are mapped on this function.
613
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
614
or both, then this function short cuts its operation by renaming
615
the table and/or enabling/disabling the keys. In this case, the FRM is
616
not changed, directly by mysql_alter_table. However, if there is a
617
RENAME + change of a field, or an index, the short cut is not used.
618
See how `create_list` is used to generate the new FRM regarding the
619
structure of the fields. The same is done for the indices of the table.
621
Important is the fact, that this function tries to do as little work as
622
possible, by finding out whether a intermediate table is needed to copy
623
data into and when finishing the altering to use it as the original table.
624
For this reason the function compare_tables() is called, which decides
625
based on all kind of data how similar are the new and the original
632
bool mysql_alter_table(Session *session,
635
HA_CREATE_INFO *create_info,
636
message::Table *create_proto,
637
TableList *table_list,
638
AlterInfo *alter_info,
644
Table *new_table= NULL;
645
Table *name_lock= NULL;
650
char new_name_buff[FN_REFLEN];
651
char new_alias_buff[FN_REFLEN];
654
const char *new_alias;
655
char path[FN_REFLEN];
658
plugin::StorageEngine *old_db_type;
659
plugin::StorageEngine *new_db_type;
660
plugin::StorageEngine *save_old_db_type;
663
new_name_buff[0]= '\0';
665
if (table_list && table_list->schema_table)
667
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
671
session->set_proc_info("init");
674
Assign variables table_name, new_name, db, new_db, path
675
to simplify further comparisons: we want to see if it's a RENAME
676
later just by comparing the pointers, avoiding the need for strcmp.
678
table_name= table_list->table_name;
680
if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
683
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
685
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
686
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
689
build_table_filename(path, sizeof(path), db, table_name, false);
692
oss << drizzle_data_home << "/" << db << "/" << table_name;
694
(void) unpack_filename(new_name_buff, oss.str().c_str());
697
If this is just a rename of a view, short cut to the
698
following scenario: 1) lock LOCK_open 2) do a RENAME
700
This is a copy-paste added to make sure
701
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
702
as an independent branch in mysql_execute_command. The need
703
for a copy-paste arose because the main code flow of ALTER Table
704
... RENAME tries to use openTableLock, which does not work for views
705
(openTableLock was never modified to merge table lists of child tables
706
into the main table list, like open_tables does).
707
This code is wrong and will be removed, please do not copy.
710
if (!(table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
713
table->use_all_columns();
715
/* Check that we are not trying to rename to an existing table */
718
strcpy(new_name_buff, new_name);
719
strcpy(new_alias_buff, new_name);
720
new_alias= new_alias_buff;
722
my_casedn_str(files_charset_info, new_name_buff);
723
new_alias= new_name; // Create lower case table name
724
my_casedn_str(files_charset_info, new_name);
727
! my_strcasecmp(table_alias_charset, new_name_buff, table_name))
730
Source and destination table names are equal: make later check
733
new_alias= new_name= table_name;
737
if (table->s->tmp_table != NO_TMP_TABLE)
739
if (session->find_temporary_table(new_db, new_name_buff))
741
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
747
if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
752
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
756
build_table_filename(new_name_buff, sizeof(new_name_buff), new_db, new_name_buff, false);
758
if (plugin::StorageEngine::getTableProto(new_name_buff, NULL) == EEXIST)
760
/* Table will be closed by Session::executeCommand() */
761
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
769
new_alias= table_name;
770
new_name= table_name;
773
old_db_type= table->s->db_type();
774
if (! create_info->db_type)
776
create_info->db_type= old_db_type;
779
if (table->s->tmp_table != NO_TMP_TABLE)
780
create_info->options|= HA_LEX_CREATE_TMP_TABLE;
782
if (check_engine(session, new_name, create_info))
785
new_db_type= create_info->db_type;
787
if (new_db_type != old_db_type &&
788
!table->file->can_switch_engines())
791
my_error(ER_ROW_IS_REFERENCED, MYF(0));
795
if (create_info->row_type == ROW_TYPE_NOT_USED)
796
create_info->row_type= table->s->row_type;
798
if (old_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
799
new_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
801
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
805
session->set_proc_info("setup");
808
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
811
tmp.reset(ALTER_RENAME);
812
tmp.reset(ALTER_KEYS_ONOFF);
813
tmp&= alter_info->flags;
815
! table->s->tmp_table) // no need to touch frm
817
switch (alter_info->keys_onoff)
823
wait_while_table_is_used() ensures that table being altered is
824
opened only by this thread and that Table::TableShare::version
825
of Table object corresponding to this table is 0.
826
The latter guarantees that no DML statement will open this table
827
until ALTER Table finishes (i.e. until close_thread_tables())
828
while the fact that the table is still open gives us protection
829
from concurrent DDL statements.
831
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
832
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
833
pthread_mutex_unlock(&LOCK_open);
834
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
835
/* COND_refresh will be signaled in close_thread_tables() */
838
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
839
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
840
pthread_mutex_unlock(&LOCK_open);
841
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
842
/* COND_refresh will be signaled in close_thread_tables() */
850
if (error == HA_ERR_WRONG_COMMAND)
853
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
854
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
858
pthread_mutex_lock(&LOCK_open); /* Lock to remove all instances of table from table cache before ALTER */
860
Unlike to the above case close_cached_table() below will remove ALL
861
instances of Table from table cache (it will also remove table lock
862
held by this thread). So to make actual table renaming and writing
863
to binlog atomic we have to put them into the same critical section
864
protected by LOCK_open mutex. This also removes gap for races between
865
access() and mysql_rename_table() calls.
869
(new_name != table_name || new_db != db))
871
session->set_proc_info("rename");
873
Then do a 'simple' rename of the table. First we need to close all
874
instances of 'source' table.
876
session->close_cached_table(table);
878
Then, we want check once again that target table does not exist.
879
Actually the order of these two steps does not matter since
880
earlier we took name-lock on the target table, so we do them
881
in this particular order only to be consistent with 5.0, in which
882
we don't take this name-lock and where this order really matters.
883
TODO: Investigate if we need this access() check at all.
885
if (plugin::StorageEngine::getTableProto(new_name, NULL) == EEXIST)
887
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
892
*fn_ext(new_name)= 0;
893
if (mysql_rename_table(old_db_type, db, table_name, new_db, new_alias, 0))
898
if (error == HA_ERR_WRONG_COMMAND)
901
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
902
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
908
write_bin_log(session, true, session->query, session->query_length);
913
table->file->print_error(error, MYF(0));
918
session->unlink_open_table(name_lock);
920
pthread_mutex_unlock(&LOCK_open);
921
table_list->table= NULL;
925
/* We have to do full alter table. */
928
If the old table had partitions and we are doing ALTER Table ...
929
engine= <new_engine>, the new table must preserve the original
930
partitioning. That means that the new engine is still the
931
partitioning engine, not the engine specified in the parser.
932
This is discovered in prep_alter_part_table, which in such case
933
updates create_info->db_type.
934
Now we need to update the stack copy of create_info->db_type,
935
as otherwise we won't be able to correctly move the files of the
936
temporary table to the result table files.
938
new_db_type= create_info->db_type;
940
if (mysql_prepare_alter_table(session, table, create_info, create_proto,
944
set_table_default_charset(create_info, db);
946
alter_info->build_method= HA_BUILD_OFFLINE;
948
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
950
/* Safety fix for innodb */
951
my_casedn_str(files_charset_info, tmp_name);
953
/* Create a temporary table with the new format */
954
error= create_temporary_table(session, table, new_db, tmp_name, create_info, create_proto, alter_info);
958
/* Open the table so we need to copy the data to it. */
959
if (table->s->tmp_table)
964
tbl.table_name= tmp_name;
966
/* Table is in session->temporary_tables */
967
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
971
char tmp_path[FN_REFLEN];
972
/* table is a normal table: Create temporary table in same directory */
973
build_table_filename(tmp_path, sizeof(tmp_path), new_db, tmp_name, true);
974
/* Open our intermediate table */
975
new_table= session->open_temporary_table(tmp_path, new_db, tmp_name, 0, OTM_OPEN);
978
if (new_table == NULL)
981
/* Copy the data if necessary. */
982
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
983
session->cuted_fields= 0L;
984
session->set_proc_info("copy to tmp table");
989
/* We don't want update TIMESTAMP fields during ALTER Table. */
990
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
991
new_table->next_number_field= new_table->found_next_number_field;
992
error= copy_data_between_tables(table,
994
alter_info->create_list,
1000
alter_info->keys_onoff,
1001
alter_info->error_if_not_empty);
1003
/* We must not ignore bad input! */
1004
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
1006
if (table->s->tmp_table != NO_TMP_TABLE)
1008
/* We changed a temporary table */
1012
/* Close lock if this is a transactional table */
1015
mysql_unlock_tables(session, session->lock);
1019
/* Remove link to old table and rename the new one */
1020
session->close_temporary_table(table, true, true);
1022
/* Should pass the 'new_name' as we store table name in the cache */
1023
if (new_table->rename_temporary_table(new_db, new_name))
1032
Close the intermediate table that will be the new table.
1033
Note that MERGE tables do not have their children attached here.
1035
new_table->intern_close_table();
1039
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1043
quick_rm_table(new_db_type, new_db, tmp_name, true);
1044
pthread_mutex_unlock(&LOCK_open);
1049
Data is copied. Now we:
1050
1) Wait until all other threads close old version of table.
1051
2) Close instances of table open by this thread and replace them
1052
with exclusive name-locks.
1053
3) Rename the old table to a temp name, rename the new one to the
1055
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1056
we reopen new version of table.
1057
5) Write statement to the binary log.
1058
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1059
remove name-locks from list of open tables and table cache.
1060
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1061
call to remove name-locks from table cache and list of open table.
1064
session->set_proc_info("rename result table");
1066
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1068
my_casedn_str(files_charset_info, old_name);
1070
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1071
session->close_data_files_and_morph_locks(db, table_name);
1074
save_old_db_type= old_db_type;
1077
This leads to the storage engine (SE) not being notified for renames in
1078
mysql_rename_table(), because we just juggle with the FRM and nothing
1079
more. If we have an intermediate table, then we notify the SE that
1080
it should become the actual table. Later, we will recycle the old table.
1081
However, in case of ALTER Table RENAME there might be no intermediate
1082
table. This is when the old and new tables are compatible, according to
1083
compare_table(). Then, we need one additional call to
1084
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
1085
actual rename in the SE and the FRM is not touched. Note that, if the
1086
table is renamed and the SE is also changed, then an intermediate table
1087
is created and the additional call will not take place.
1089
if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
1092
quick_rm_table(new_db_type, new_db, tmp_name, true);
1096
if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
1098
/* Try to get everything back. */
1100
quick_rm_table(new_db_type, new_db, new_alias, false);
1101
quick_rm_table(new_db_type, new_db, tmp_name, true);
1102
mysql_rename_table(old_db_type, db, old_name, db, table_name, FN_FROM_IS_TMP);
1108
/* This shouldn't happen. But let us play it safe. */
1109
goto err_with_placeholders;
1112
quick_rm_table(old_db_type, db, old_name, true);
1114
pthread_mutex_unlock(&LOCK_open);
1116
session->set_proc_info("end");
1118
write_bin_log(session, true, session->query, session->query_length);
1120
if (old_db_type->check_flag(HTON_BIT_FLUSH_AFTER_RENAME))
1123
For the alter table to be properly flushed to the logs, we
1124
have to open the new table. If not, we get a problem on server
1125
shutdown. But we do not need to attach MERGE children.
1127
char table_path[FN_REFLEN];
1129
build_table_filename(table_path, sizeof(table_path), new_db, table_name, false);
1130
t_table= session->open_temporary_table(table_path, new_db, tmp_name, false, OTM_OPEN);
1133
t_table->intern_close_table();
1137
errmsg_printf(ERRMSG_LVL_WARN, _("Could not open table %s.%s after rename\n"), new_db, table_name);
1139
ha_flush_logs(old_db_type);
1141
table_list->table= NULL;
1145
* Field::store() may have called my_error(). If this is
1146
* the case, we must not send an ok packet, since
1147
* Diagnostics_area::is_set() will fail an assert.
1149
if (! session->is_error())
1151
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1152
(ulong) (copied + deleted), (ulong) deleted,
1153
(ulong) session->cuted_fields);
1154
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1155
session->some_tables_deleted=0;
1160
/* my_error() was called. Return true (which means error...) */
1167
/* close_temporary_table() frees the new_table pointer. */
1168
session->close_temporary_table(new_table, true, true);
1171
quick_rm_table(new_db_type, new_db, tmp_name, true);
1175
No default value was provided for a DATE/DATETIME field, the
1176
current sql_mode doesn't allow the '0000-00-00' value and
1177
the table to be altered isn't empty.
1180
if (alter_info->error_if_not_empty && session->row_count)
1182
const char *f_val= 0;
1183
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1184
switch (alter_info->datetime_field->sql_type)
1186
case DRIZZLE_TYPE_DATE:
1187
f_val= "0000-00-00";
1188
t_type= DRIZZLE_TIMESTAMP_DATE;
1190
case DRIZZLE_TYPE_DATETIME:
1191
f_val= "0000-00-00 00:00:00";
1192
t_type= DRIZZLE_TIMESTAMP_DATETIME;
1195
/* Shouldn't get here. */
1198
bool save_abort_on_warning= session->abort_on_warning;
1199
session->abort_on_warning= true;
1200
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1201
f_val, strlength(f_val), t_type,
1202
alter_info->datetime_field->field_name);
1203
session->abort_on_warning= save_abort_on_warning;
1207
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
1208
session->unlink_open_table(name_lock);
1209
pthread_mutex_unlock(&LOCK_open);
1213
err_with_placeholders:
1215
An error happened while we were holding exclusive name-lock on table
1216
being altered. To be safe under LOCK TABLES we should remove placeholders
1217
from list of open tables list and table cache.
1219
session->unlink_open_table(table);
1221
session->unlink_open_table(name_lock);
1222
pthread_mutex_unlock(&LOCK_open);
1225
/* mysql_alter_table */
1228
copy_data_between_tables(Table *from,Table *to,
1229
List<CreateField> &create,
1231
uint32_t order_num, order_st *order,
1234
enum enum_enable_or_disable keys_onoff,
1235
bool error_if_not_empty)
1238
CopyField *copy,*copy_end;
1239
ulong found_count,delete_count;
1240
Session *session= current_session;
1242
SORT_FIELD *sortorder;
1246
List<Item> all_fields;
1247
ha_rows examined_rows;
1248
bool auto_increment_field_copied= 0;
1249
uint64_t prev_insert_id;
1252
Turn off recovery logging since rollback of an alter table is to
1253
delete the new table so there is no need to log the changes to it.
1255
This needs to be done before external_lock
1257
error= ha_enable_transaction(session, false);
1261
if (!(copy= new CopyField[to->s->fields]))
1264
if (to->file->ha_external_lock(session, F_WRLCK))
1267
/* We need external lock before we can disable/enable keys */
1268
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
1270
/* We can abort alter table for any table type */
1271
session->abort_on_warning= !ignore;
1273
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
1274
to->file->ha_start_bulk_insert(from->file->stats.records);
1276
List_iterator<CreateField> it(create);
1279
for (Field **ptr=to->field ; *ptr ; ptr++)
1284
if (*ptr == to->next_number_field)
1285
auto_increment_field_copied= true;
1287
(copy_end++)->set(*ptr,def->field,0);
1292
found_count=delete_count=0;
1296
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
1298
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1299
snprintf(warn_buff, sizeof(warn_buff),
1300
_("order_st BY ignored because there is a user-defined clustered "
1301
"index in the table '%-.192s'"),
1302
from->s->table_name.str);
1303
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1308
from->sort.io_cache= new IO_CACHE;
1309
memset(from->sort.io_cache, 0, sizeof(IO_CACHE));
1311
memset(&tables, 0, sizeof(tables));
1313
tables.alias= tables.table_name= from->s->table_name.str;
1314
tables.db= from->s->db.str;
1317
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1318
setup_order(session, session->lex->select_lex.ref_pointer_array,
1319
&tables, fields, all_fields, order) ||
1320
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1321
(from->sort.found_records= filesort(session, from, sortorder, length,
1322
(SQL_SELECT *) 0, HA_POS_ERROR,
1323
1, &examined_rows)) ==
1329
/* Tell handler that we have values for all columns in the to table */
1330
to->use_all_columns();
1331
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
1333
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
1334
session->row_count= 0;
1335
to->restoreRecordAsDefault(); // Create empty record
1336
while (!(error=info.read_record(&info)))
1338
if (session->killed)
1340
session->send_kill_message();
1344
session->row_count++;
1345
/* Return error if source table isn't empty. */
1346
if (error_if_not_empty)
1351
if (to->next_number_field)
1353
if (auto_increment_field_copied)
1354
to->auto_increment_field_not_null= true;
1356
to->next_number_field->reset();
1359
for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
1361
copy_ptr->do_copy(copy_ptr);
1363
prev_insert_id= to->file->next_insert_id;
1364
error=to->file->ha_write_row(to->record[0]);
1365
to->auto_increment_field_not_null= false;
1369
to->file->is_fatal_error(error, HA_CHECK_DUP))
1371
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
1373
uint32_t key_nr= to->file->get_dup_key(error);
1374
if ((int) key_nr >= 0)
1376
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
1378
(to->key_info[0].key_part[0].field->flags &
1379
AUTO_INCREMENT_FLAG))
1380
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
1381
to->file->print_keydup_error(key_nr, err_msg);
1386
to->file->print_error(error,MYF(0));
1389
to->file->restore_auto_increment(prev_insert_id);
1395
end_read_record(&info);
1396
from->free_io_cache();
1397
delete [] copy; // This is never 0
1399
if (to->file->ha_end_bulk_insert() && error <= 0)
1401
to->file->print_error(my_errno,MYF(0));
1404
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1406
if (ha_enable_transaction(session, true))
1413
Ensure that the new table is saved properly to disk so that we
1416
if (ha_autocommit_or_rollback(session, 0))
1418
if (! session->endActiveTransaction())
1422
session->abort_on_warning= 0;
1423
from->free_io_cache();
1424
*copied= found_count;
1425
*deleted=delete_count;
1426
to->file->ha_release_auto_increment();
1427
if (to->file->ha_external_lock(session,F_UNLCK))
1429
return(error > 0 ? -1 : 0);
1433
create_temporary_table(Session *session,
1437
HA_CREATE_INFO *create_info,
1438
message::Table *create_proto,
1439
AlterInfo *alter_info)
1442
plugin::StorageEngine *old_db_type, *new_db_type;
1443
old_db_type= table->s->db_type();
1444
new_db_type= create_info->db_type;
1446
Create a table with a temporary name.
1447
We don't log the statement, it will be logged later.
1449
create_proto->set_name(tmp_name);
1450
create_proto->set_type(message::Table::TEMPORARY);
1452
message::Table::StorageEngine *protoengine;
1453
protoengine= create_proto->mutable_engine();
1454
protoengine->set_name(new_db_type->getName());
1456
error= mysql_create_table(session, new_db, tmp_name,
1457
create_info, create_proto, alter_info, 1, 0);
1462
/** @TODO This will soon die. */
1463
bool mysql_create_like_schema_frm(Session* session,
1464
TableList* schema_table,
1465
HA_CREATE_INFO *create_info,
1466
message::Table* table_proto)
1468
HA_CREATE_INFO local_create_info;
1469
AlterInfo alter_info;
1470
bool tmp_table= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
1471
uint32_t keys= schema_table->table->s->keys;
1472
uint32_t db_options= 0;
1474
memset(&local_create_info, 0, sizeof(local_create_info));
1475
local_create_info.db_type= schema_table->table->s->db_type();
1476
local_create_info.row_type= schema_table->table->s->row_type;
1477
local_create_info.default_table_charset=default_charset_info;
1478
alter_info.flags.set(ALTER_CHANGE_COLUMN);
1479
alter_info.flags.set(ALTER_RECREATE);
1480
schema_table->table->use_all_columns();
1481
if (mysql_prepare_alter_table(session, schema_table->table,
1482
&local_create_info, table_proto, &alter_info))
1485
/* I_S tables are created with MAX_ROWS for some efficiency drive.
1486
When CREATE LIKE, we don't want to keep it coming across */
1487
message::Table::TableOptions *table_options;
1488
table_options= table_proto->mutable_options();
1489
table_options->clear_max_rows();
1491
if (mysql_prepare_create_table(session, &local_create_info, &alter_info,
1492
tmp_table, &db_options,
1493
schema_table->table->file,
1494
&schema_table->table->s->key_info, &keys, 0))
1497
table_proto->set_name("system_stupid_i_s_fix_nonsense");
1499
table_proto->set_type(message::Table::TEMPORARY);
1501
table_proto->set_type(message::Table::STANDARD);
1504
message::Table::StorageEngine *protoengine;
1505
protoengine= table_proto->mutable_engine();
1507
plugin::StorageEngine *engine= local_create_info.db_type;
1509
protoengine->set_name(engine->getName());
1512
if (fill_table_proto(table_proto, "system_stupid_i_s_fix_nonsense",
1513
alter_info.create_list, &local_create_info,
1514
keys, schema_table->table->s->key_info))