18
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
#include <drizzled/server_includes.h>
27
22
#include <drizzled/show.h>
28
23
#include <drizzled/lock.h>
29
24
#include <drizzled/session.h>
30
25
#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>
44
#include <drizzled/plugin/storage_engine.h>
45
#include <drizzled/copy_field.h>
47
#include <drizzled/transaction_services.h>
49
#include <drizzled/filesort.h>
51
#include <drizzled/message.h>
58
extern pid_t current_pid;
60
static int copy_data_between_tables(Session *session,
61
Table *from,Table *to,
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,
62
35
List<CreateField> &create,
64
37
uint32_t order_num,
68
41
enum enum_enable_or_disable keys_onoff,
69
42
bool error_if_not_empty);
71
static bool prepare_alter_table(Session *session,
43
static bool mysql_prepare_alter_table(Session *session,
73
45
HA_CREATE_INFO *create_info,
74
const message::Table &original_proto,
75
message::Table &table_message,
46
message::Table *table_proto,
76
47
AlterInfo *alter_info);
78
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier);
82
AlterTable::AlterTable(Session *in_session, Table_ident *ident, drizzled::ha_build_method build_arg) :
83
CreateTable(in_session)
85
in_session->getLex()->sql_command= SQLCOM_ALTER_TABLE;
87
alter_info.build_method= build_arg;
90
} // namespace statement
48
static int create_temporary_table(Session *session,
52
HA_CREATE_INFO *create_info,
53
message::Table *create_proto,
54
AlterInfo *alter_info);
92
56
bool statement::AlterTable::execute()
94
TableList *first_table= (TableList *) getSession()->getLex()->select_lex.table_list.first;
95
TableList *all_tables= getSession()->getLex()->query_tables;
58
TableList *first_table= (TableList *) session->lex->select_lex.table_list.first;
59
TableList *all_tables= session->lex->query_tables;
96
60
assert(first_table == all_tables && first_table != 0);
97
Select_Lex *select_lex= &getSession()->getLex()->select_lex;
61
Select_Lex *select_lex= &session->lex->select_lex;
98
62
bool need_start_waiting= false;
100
is_engine_set= not createTableMessage().engine().name().empty();
65
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
66
so we have to use a copy of this structure to make execution
67
prepared statement- safe. A shallow copy is enough as no memory
68
referenced from this structure will be modified.
70
HA_CREATE_INFO create_info(session->lex->create_info);
71
AlterInfo alter_info(session->lex->alter_info, session->mem_root);
73
if (session->is_fatal_error) /* out of memory creating a copy of alter_info */
104
create_info().db_type=
105
plugin::StorageEngine::findByName(*getSession(), createTableMessage().engine().name());
107
if (create_info().db_type == NULL)
109
my_error(createTableMessage().engine().name(), ER_UNKNOWN_STORAGE_ENGINE, MYF(0));
115
78
/* Must be set in the parser */
116
79
assert(select_lex->db);
118
/* Chicken/Egg... we need to search for the table, to know if the table exists, so we can build a full identifier from it */
119
message::table::shared_ptr original_table_message;
121
identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
122
if (not (original_table_message= plugin::StorageEngine::getTableMessage(*getSession(), identifier)))
124
my_error(ER_BAD_TABLE_ERROR, identifier);
128
if (not create_info().db_type)
130
create_info().db_type=
131
plugin::StorageEngine::findByName(*getSession(), original_table_message->engine().name());
133
if (not create_info().db_type)
135
my_error(ER_BAD_TABLE_ERROR, identifier);
141
if (not validateCreateTableOption())
144
if (getSession()->inTransaction())
146
my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
150
if (not (need_start_waiting= not getSession()->wait_if_global_read_lock(0, 1)))
154
if (original_table_message->type() == message::Table::STANDARD )
156
identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName());
157
identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
158
getSession()->getLex()->name.str ? getSession()->getLex()->name.str : first_table->getTableName());
160
res= alter_table(getSession(),
164
*original_table_message,
165
createTableMessage(),
168
select_lex->order_list.elements,
169
(Order *) select_lex->order_list.first,
170
getSession()->getLex()->ignore);
174
identifier::Table catch22(first_table->getSchemaName(), first_table->getTableName());
175
Table *table= getSession()->find_temporary_table(catch22);
178
identifier::Table identifier(first_table->getSchemaName(), first_table->getTableName(), table->getMutableShare()->getPath());
179
identifier::Table new_identifier(select_lex->db ? select_lex->db : first_table->getSchemaName(),
180
getSession()->getLex()->name.str ? getSession()->getLex()->name.str : first_table->getTableName(),
181
table->getMutableShare()->getPath());
183
res= alter_table(getSession(),
187
*original_table_message,
188
createTableMessage(),
191
select_lex->order_list.elements,
192
(Order *) select_lex->order_list.first,
193
getSession()->getLex()->ignore);
81
/* ALTER TABLE ends previous transaction */
82
if (! session->endActiveTransaction())
87
if (! (need_start_waiting= ! wait_if_global_read_lock(session, 0, 1)))
92
bool res= mysql_alter_table(session,
94
session->lex->name.str,
96
session->lex->create_table_proto,
99
select_lex->order_list.elements,
100
(order_st *) select_lex->order_list.first,
101
session->lex->ignore);
198
103
Release the protection against the global read lock and wake
199
104
everyone, who might want to set a global read lock.
201
getSession()->startWaitingGlobalReadLock();
106
start_waiting_global_read_lock(session);
208
111
Prepare column and key definitions for CREATE TABLE in ALTER Table.
904
static bool internal_alter_table(Session *session,
906
identifier::Table &original_table_identifier,
907
identifier::Table &new_table_identifier,
908
HA_CREATE_INFO *create_info,
909
const message::Table &original_proto,
910
message::Table &create_proto,
911
TableList *table_list,
912
AlterInfo *alter_info,
646
bool mysql_alter_table(Session *session,
649
HA_CREATE_INFO *create_info,
650
message::Table *create_proto,
651
TableList *table_list,
652
AlterInfo *alter_info,
658
Table *new_table= NULL;
659
Table *name_lock= NULL;
918
662
char tmp_name[80];
919
663
char old_name[32];
664
char new_name_buff[FN_REFLEN];
665
char new_alias_buff[FN_REFLEN];
668
const char *new_alias;
669
char path[FN_REFLEN];
920
670
ha_rows copied= 0;
921
671
ha_rows deleted= 0;
923
if (not original_table_identifier.isValid())
926
if (not new_table_identifier.isValid())
672
plugin::StorageEngine *old_db_type;
673
plugin::StorageEngine *new_db_type;
674
plugin::StorageEngine *save_old_db_type;
677
new_name_buff[0]= '\0';
679
if (table_list && table_list->schema_table)
681
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
929
685
session->set_proc_info("init");
688
Assign variables table_name, new_name, db, new_db, path
689
to simplify further comparisons: we want to see if it's a RENAME
690
later just by comparing the pointers, avoiding the need for strcmp.
692
table_name= table_list->table_name;
694
if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
697
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
699
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
700
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
703
build_table_filename(path, sizeof(path), db, table_name, false);
706
oss << drizzle_data_home << "/" << db << "/" << table_name;
708
(void) unpack_filename(new_name_buff, oss.str().c_str());
711
If this is just a rename of a view, short cut to the
712
following scenario: 1) lock LOCK_open 2) do a RENAME
714
This is a copy-paste added to make sure
715
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
716
as an independent branch in mysql_execute_command. The need
717
for a copy-paste arose because the main code flow of ALTER Table
718
... RENAME tries to use openTableLock, which does not work for views
719
(openTableLock was never modified to merge table lists of child tables
720
into the main table list, like open_tables does).
721
This code is wrong and will be removed, please do not copy.
724
if (!(table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
931
727
table->use_all_columns();
933
plugin::StorageEngine *new_engine;
934
plugin::StorageEngine *original_engine;
936
original_engine= table->getMutableShare()->getEngine();
938
if (not create_info->db_type)
940
create_info->db_type= original_engine;
942
new_engine= create_info->db_type;
945
create_proto.set_schema(new_table_identifier.getSchemaName());
946
create_proto.set_type(new_table_identifier.getType());
949
@todo Have a check on the table definition for FK in the future
950
to remove the need for the cursor. (aka can_switch_engines())
952
if (new_engine != original_engine &&
953
not table->cursor->can_switch_engines())
729
/* Check that we are not trying to rename to an existing table */
732
strcpy(new_name_buff, new_name);
733
strcpy(new_alias_buff, new_name);
734
new_alias= new_alias_buff;
736
my_casedn_str(files_charset_info, new_name_buff);
737
new_alias= new_name; // Create lower case table name
738
my_casedn_str(files_charset_info, new_name);
741
! my_strcasecmp(table_alias_charset, new_name_buff, table_name))
744
Source and destination table names are equal: make later check
747
new_alias= new_name= table_name;
751
if (table->s->tmp_table != NO_TMP_TABLE)
753
if (session->find_temporary_table(new_db, new_name_buff))
755
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
761
if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
766
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
770
build_table_filename(new_name_buff, sizeof(new_name_buff), new_db, new_name_buff, false);
772
plugin::Registry &plugins= plugin::Registry::singleton();
773
if (plugins.storage_engine.getTableProto(new_name_buff, NULL) == EEXIST)
775
/* Table will be closed by Session::executeCommand() */
776
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
784
new_alias= table_name;
785
new_name= table_name;
788
old_db_type= table->s->db_type();
789
if (! create_info->db_type)
791
create_info->db_type= old_db_type;
794
if (table->s->tmp_table != NO_TMP_TABLE)
795
create_info->options|= HA_LEX_CREATE_TMP_TABLE;
797
if (check_engine(session, new_name, create_info))
800
new_db_type= create_info->db_type;
802
if (new_db_type != old_db_type &&
803
!table->file->can_switch_engines())
956
806
my_error(ER_ROW_IS_REFERENCED, MYF(0));
961
if (original_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
962
new_engine->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
810
if (create_info->row_type == ROW_TYPE_NOT_USED)
811
create_info->row_type= table->s->row_type;
813
if (old_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
814
new_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
964
my_error(ER_ILLEGAL_HA, new_table_identifier);
816
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
969
820
session->set_proc_info("setup");
972
823
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
826
tmp.reset(ALTER_RENAME);
827
tmp.reset(ALTER_KEYS_ONOFF);
828
tmp&= alter_info->flags;
830
! table->s->tmp_table) // no need to touch frm
978
tmp.reset(ALTER_RENAME);
979
tmp.reset(ALTER_KEYS_ONOFF);
980
tmp&= alter_info->flags;
982
if (not (tmp.any()) && not table->getShare()->getType()) // no need to touch frm
984
switch (alter_info->keys_onoff)
991
wait_while_table_is_used() ensures that table being altered is
992
opened only by this thread and that Table::TableShare::version
993
of Table object corresponding to this table is 0.
994
The latter guarantees that no DML statement will open this table
995
until ALTER Table finishes (i.e. until close_thread_tables())
996
while the fact that the table is still open gives us protection
997
from concurrent DDL statements.
1000
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
1001
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
1003
error= table->cursor->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1005
/* COND_refresh will be signaled in close_thread_tables() */
1010
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* DDL wait for/blocker */
1011
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
1013
error= table->cursor->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
1015
/* COND_refresh will be signaled in close_thread_tables() */
1019
if (error == HA_ERR_WRONG_COMMAND)
1022
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1023
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1027
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* Lock to remove all instances of table from table cache before ALTER */
1029
Unlike to the above case close_cached_table() below will remove ALL
1030
instances of Table from table cache (it will also remove table lock
1031
held by this thread). So to make actual table renaming and writing
1032
to binlog atomic we have to put them into the same critical section
1033
protected by table::Cache::singleton().mutex() mutex. This also removes gap for races between
1034
access() and rename_table() calls.
1037
if (not error && not (original_table_identifier == new_table_identifier))
1039
session->set_proc_info("rename");
1041
Then do a 'simple' rename of the table. First we need to close all
1042
instances of 'source' table.
1044
session->close_cached_table(table);
1046
Then, we want check once again that target table does not exist.
1047
Actually the order of these two steps does not matter since
1048
earlier we took name-lock on the target table, so we do them
1049
in this particular order only to be consistent with 5.0, in which
1050
we don't take this name-lock and where this order really matters.
1051
@todo Investigate if we need this access() check at all.
1053
if (plugin::StorageEngine::doesTableExist(*session, new_table_identifier))
1055
my_error(ER_TABLE_EXISTS_ERROR, new_table_identifier);
832
switch (alter_info->keys_onoff)
838
wait_while_table_is_used() ensures that table being altered is
839
opened only by this thread and that Table::TableShare::version
840
of Table object corresponding to this table is 0.
841
The latter guarantees that no DML statement will open this table
842
until ALTER Table finishes (i.e. until close_thread_tables())
843
while the fact that the table is still open gives us protection
844
from concurrent DDL statements.
846
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
847
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
848
pthread_mutex_unlock(&LOCK_open);
849
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
850
/* COND_refresh will be signaled in close_thread_tables() */
853
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
854
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
855
pthread_mutex_unlock(&LOCK_open);
856
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
857
/* COND_refresh will be signaled in close_thread_tables() */
865
if (error == HA_ERR_WRONG_COMMAND)
868
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
869
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
873
pthread_mutex_lock(&LOCK_open); /* Lock to remove all instances of table from table cache before ALTER */
875
Unlike to the above case close_cached_table() below will remove ALL
876
instances of Table from table cache (it will also remove table lock
877
held by this thread). So to make actual table renaming and writing
878
to binlog atomic we have to put them into the same critical section
879
protected by LOCK_open mutex. This also removes gap for races between
880
access() and mysql_rename_table() calls.
884
(new_name != table_name || new_db != db))
886
session->set_proc_info("rename");
888
Then do a 'simple' rename of the table. First we need to close all
889
instances of 'source' table.
891
session->close_cached_table(table);
893
Then, we want check once again that target table does not exist.
894
Actually the order of these two steps does not matter since
895
earlier we took name-lock on the target table, so we do them
896
in this particular order only to be consistent with 5.0, in which
897
we don't take this name-lock and where this order really matters.
898
TODO: Investigate if we need this access() check at all.
900
plugin::Registry &plugins= plugin::Registry::singleton();
901
if (plugins.storage_engine.getTableProto(new_name, NULL) == EEXIST)
903
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
908
*fn_ext(new_name)= 0;
909
if (mysql_rename_table(old_db_type, db, table_name, new_db, new_alias, 0))
1060
if (rename_table(*session, original_engine, original_table_identifier, new_table_identifier))
1067
if (error == HA_ERR_WRONG_COMMAND)
1070
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1071
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
1077
TransactionServices &transaction_services= TransactionServices::singleton();
1078
transaction_services.allocateNewTransactionId();
1079
write_bin_log(session, *session->getQueryString());
1082
else if (error > EE_OK) // If we have already set the error, we pass along -1
1084
table->print_error(error, MYF(0));
1087
table_list->table= NULL;
914
if (error == HA_ERR_WRONG_COMMAND)
917
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
918
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
924
write_bin_log(session, true, session->query, session->query_length);
929
table->file->print_error(error, MYF(0));
934
session->unlink_open_table(name_lock);
936
pthread_mutex_unlock(&LOCK_open);
937
table_list->table= NULL;
1093
941
/* We have to do full alter table. */
1094
new_engine= create_info->db_type;
1096
if (prepare_alter_table(session, table, create_info, original_proto, create_proto, alter_info))
1101
set_table_default_charset(create_info, new_table_identifier.getSchemaName().c_str());
944
If the old table had partitions and we are doing ALTER Table ...
945
engine= <new_engine>, the new table must preserve the original
946
partitioning. That means that the new engine is still the
947
partitioning engine, not the engine specified in the parser.
948
This is discovered in prep_alter_part_table, which in such case
949
updates create_info->db_type.
950
Now we need to update the stack copy of create_info->db_type,
951
as otherwise we won't be able to correctly move the files of the
952
temporary table to the result table files.
954
new_db_type= create_info->db_type;
956
if (mysql_prepare_alter_table(session, table, create_info, create_proto,
960
set_table_default_charset(create_info, db);
1103
962
alter_info->build_method= HA_BUILD_OFFLINE;
1105
964
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
966
/* Safety fix for innodb */
967
my_casedn_str(files_charset_info, tmp_name);
1107
969
/* Create a temporary table with the new format */
1109
@note we make an internal temporary table unless the table is a temporary table. In last
1110
case we just use it as is. Neither of these tables require locks in order to be
1113
identifier::Table new_table_as_temporary(original_table_identifier.getSchemaName(),
1115
create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1116
message::Table::TEMPORARY);
1119
Create a table with a temporary name.
1120
We don't log the statement, it will be logged later.
1122
create_proto.set_name(new_table_as_temporary.getTableName());
1123
create_proto.mutable_engine()->set_name(create_info->db_type->getName());
1125
error= create_table(session,
1126
new_table_as_temporary,
1127
create_info, create_proto, alter_info, true, 0, false);
970
error= create_temporary_table(session, table, new_db, tmp_name, create_info, create_proto, alter_info);
1134
974
/* Open the table so we need to copy the data to it. */
1135
Table *new_table= open_alter_table(session, table, new_table_as_temporary);
1140
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
975
if (table->s->tmp_table)
980
tbl.table_name= tmp_name;
982
/* Table is in session->temporary_tables */
983
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
987
char tmp_path[FN_REFLEN];
988
/* table is a normal table: Create temporary table in same directory */
989
build_table_filename(tmp_path, sizeof(tmp_path), new_db, tmp_name, true);
990
/* Open our intermediate table */
991
new_table= session->open_temporary_table(tmp_path, new_db, tmp_name, 0, OTM_OPEN);
994
if (new_table == NULL)
1144
997
/* Copy the data if necessary. */
1146
/* We must not ignore bad input! */
1147
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; // calc cuted fields
1148
session->cuted_fields= 0L;
1149
session->set_proc_info("copy to tmp table");
1152
/* We don't want update TIMESTAMP fields during ALTER Table. */
1153
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1154
new_table->next_number_field= new_table->found_next_number_field;
1155
error= copy_data_between_tables(session,
1158
alter_info->create_list,
1164
alter_info->keys_onoff,
1165
alter_info->error_if_not_empty);
1167
/* We must not ignore bad input! */
1168
assert(session->count_cuted_fields == CHECK_FIELD_ERROR_FOR_NULL);
1171
/* Now we need to resolve what just happened with the data copy. */
1177
No default value was provided for new fields.
1179
if (alter_info->error_if_not_empty && session->row_count)
1181
my_error(ER_INVALID_ALTER_TABLE_FOR_NOT_NULL, MYF(0));
1184
if (original_table_identifier.isTmp())
1188
/* close_temporary_table() frees the new_table pointer. */
1189
session->close_temporary_table(new_table);
1193
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1203
Close the intermediate table that will be the new table.
1204
Note that MERGE tables do not have their children attached here.
1206
new_table->intern_close_table();
1207
if (new_table->hasShare())
1209
delete new_table->getMutableShare();
1215
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1217
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1222
// Temporary table and success
1223
else if (original_table_identifier.isTmp())
998
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
999
session->cuted_fields= 0L;
1000
session->set_proc_info("copy to tmp table");
1005
/* We don't want update TIMESTAMP fields during ALTER Table. */
1006
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1007
new_table->next_number_field= new_table->found_next_number_field;
1008
error= copy_data_between_tables(table,
1010
alter_info->create_list,
1016
alter_info->keys_onoff,
1017
alter_info->error_if_not_empty);
1019
/* We must not ignore bad input! */
1020
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
1022
if (table->s->tmp_table != NO_TMP_TABLE)
1024
/* We changed a temporary table */
1225
1028
/* Close lock if this is a transactional table */
1226
1029
if (session->lock)
1228
session->unlockTables(session->lock);
1031
mysql_unlock_tables(session, session->lock);
1229
1032
session->lock= 0;
1232
1035
/* Remove link to old table and rename the new one */
1233
session->close_temporary_table(table);
1036
session->close_temporary_table(table, true, true);
1235
1038
/* Should pass the 'new_name' as we store table name in the cache */
1236
new_table->getMutableShare()->setIdentifier(new_table_identifier);
1238
new_table_identifier.setPath(new_table_as_temporary.getPath());
1240
if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1245
// Normal table success
1039
if (new_table->rename_temporary_table(new_db, new_name))
1048
Close the intermediate table that will be the new table.
1049
Note that MERGE tables do not have their children attached here.
1051
new_table->intern_close_table();
1055
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
1059
quick_rm_table(new_db_type, new_db, tmp_name, true);
1060
pthread_mutex_unlock(&LOCK_open);
1065
Data is copied. Now we:
1066
1) Wait until all other threads close old version of table.
1067
2) Close instances of table open by this thread and replace them
1068
with exclusive name-locks.
1069
3) Rename the old table to a temp name, rename the new one to the
1071
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1072
we reopen new version of table.
1073
5) Write statement to the binary log.
1074
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1075
remove name-locks from list of open tables and table cache.
1076
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1077
call to remove name-locks from table cache and list of open table.
1080
session->set_proc_info("rename result table");
1082
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1084
my_casedn_str(files_charset_info, old_name);
1086
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1087
session->close_data_files_and_morph_locks(db, table_name);
1090
save_old_db_type= old_db_type;
1093
This leads to the storage engine (SE) not being notified for renames in
1094
mysql_rename_table(), because we just juggle with the FRM and nothing
1095
more. If we have an intermediate table, then we notify the SE that
1096
it should become the actual table. Later, we will recycle the old table.
1097
However, in case of ALTER Table RENAME there might be no intermediate
1098
table. This is when the old and new tables are compatible, according to
1099
compare_table(). Then, we need one additional call to
1100
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
1101
actual rename in the SE and the FRM is not touched. Note that, if the
1102
table is renamed and the SE is also changed, then an intermediate table
1103
is created and the additional call will not take place.
1105
if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
1108
quick_rm_table(new_db_type, new_db, tmp_name, true);
1251
Close the intermediate table that will be the new table.
1252
Note that MERGE tables do not have their children attached here.
1254
new_table->intern_close_table();
1256
if (new_table->hasShare())
1258
delete new_table->getMutableShare();
1265
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* ALTER TABLE */
1267
Data is copied. Now we:
1268
1) Wait until all other threads close old version of table.
1269
2) Close instances of table open by this thread and replace them
1270
with exclusive name-locks.
1271
3) Rename the old table to a temp name, rename the new one to the
1273
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
1274
we reopen new version of table.
1275
5) Write statement to the binary log.
1276
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
1277
remove name-locks from list of open tables and table cache.
1278
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
1279
call to remove name-locks from table cache and list of open table.
1282
session->set_proc_info("rename result table");
1284
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
1286
my_casedn_str(files_charset_info, old_name);
1288
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
1289
session->close_data_files_and_morph_locks(original_table_identifier);
1294
This leads to the storage engine (SE) not being notified for renames in
1295
rename_table(), because we just juggle with the FRM and nothing
1296
more. If we have an intermediate table, then we notify the SE that
1297
it should become the actual table. Later, we will recycle the old table.
1298
However, in case of ALTER Table RENAME there might be no intermediate
1299
table. This is when the old and new tables are compatible, according to
1300
compare_table(). Then, we need one additional call to
1302
identifier::Table original_table_to_drop(original_table_identifier.getSchemaName(),
1303
old_name, create_proto.type() != message::Table::TEMPORARY ? message::Table::INTERNAL :
1304
message::Table::TEMPORARY);
1306
drizzled::error_t rename_error= EE_OK;
1307
if (rename_table(*session, original_engine, original_table_identifier, original_table_to_drop))
1309
error= ER_ERROR_ON_RENAME;
1310
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1314
if (rename_table(*session, new_engine, new_table_as_temporary, new_table_identifier) != 0)
1316
/* Try to get everything back. */
1317
rename_error= ER_ERROR_ON_RENAME;
1319
plugin::StorageEngine::dropTable(*session, new_table_identifier);
1321
plugin::StorageEngine::dropTable(*session, new_table_as_temporary);
1323
rename_table(*session, original_engine, original_table_to_drop, original_table_identifier);
1327
plugin::StorageEngine::dropTable(*session, original_table_to_drop);
1334
An error happened while we were holding exclusive name-lock on table
1335
being altered. To be safe under LOCK TABLES we should remove placeholders
1336
from list of open tables list and table cache.
1338
session->unlink_open_table(table);
1344
session->set_proc_info("end");
1346
write_bin_log(session, *session->getQueryString());
1347
table_list->table= NULL;
1112
if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
1114
/* Try to get everything back. */
1116
quick_rm_table(new_db_type, new_db, new_alias, false);
1117
quick_rm_table(new_db_type, new_db, tmp_name, true);
1118
mysql_rename_table(old_db_type, db, old_name, db, table_name, FN_FROM_IS_TMP);
1124
/* This shouldn't happen. But let us play it safe. */
1125
goto err_with_placeholders;
1128
quick_rm_table(old_db_type, db, old_name, true);
1130
pthread_mutex_unlock(&LOCK_open);
1132
session->set_proc_info("end");
1134
write_bin_log(session, true, session->query, session->query_length);
1136
if (old_db_type->check_flag(HTON_BIT_FLUSH_AFTER_RENAME))
1139
For the alter table to be properly flushed to the logs, we
1140
have to open the new table. If not, we get a problem on server
1141
shutdown. But we do not need to attach MERGE children.
1143
char table_path[FN_REFLEN];
1145
build_table_filename(table_path, sizeof(table_path), new_db, table_name, false);
1146
t_table= session->open_temporary_table(table_path, new_db, tmp_name, false, OTM_OPEN);
1149
t_table->intern_close_table();
1153
errmsg_printf(ERRMSG_LVL_WARN, _("Could not open table %s.%s after rename\n"), new_db, table_name);
1155
ha_flush_logs(old_db_type);
1157
table_list->table= NULL;
1351
1161
* Field::store() may have called my_error(). If this is
1352
1162
* the case, we must not send an ok packet, since
1353
1163
* Diagnostics_area::is_set() will fail an assert.
1355
if (session->is_error())
1165
if (! session->is_error())
1167
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1168
(ulong) (copied + deleted), (ulong) deleted,
1169
(ulong) session->cuted_fields);
1170
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1171
session->some_tables_deleted=0;
1357
1176
/* my_error() was called. Return true (which means error...) */
1361
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
1362
(ulong) (copied + deleted), (ulong) deleted,
1363
(ulong) session->cuted_fields);
1364
session->my_ok(copied + deleted, 0, 0L, tmp_name);
1365
session->some_tables_deleted= false;
1370
bool alter_table(Session *session,
1371
identifier::Table &original_table_identifier,
1372
identifier::Table &new_table_identifier,
1373
HA_CREATE_INFO *create_info,
1374
const message::Table &original_proto,
1375
message::Table &create_proto,
1376
TableList *table_list,
1377
AlterInfo *alter_info,
1385
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
1387
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
1388
return discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
1391
session->set_proc_info("init");
1393
if (not (table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
1396
session->set_proc_info("gained write lock on table");
1399
Check that we are not trying to rename to an existing table,
1400
if one existed we get a lock, if we can't we error.
1403
Table *name_lock= NULL;
1405
if (not lockTableIfDifferent(*session, original_table_identifier, new_table_identifier, name_lock))
1410
error= internal_alter_table(session,
1412
original_table_identifier,
1413
new_table_identifier,
1425
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
1426
session->unlink_open_table(name_lock);
1183
/* close_temporary_table() frees the new_table pointer. */
1184
session->close_temporary_table(new_table, true, true);
1187
quick_rm_table(new_db_type, new_db, tmp_name, true);
1191
No default value was provided for a DATE/DATETIME field, the
1192
current sql_mode doesn't allow the '0000-00-00' value and
1193
the table to be altered isn't empty.
1196
if (alter_info->error_if_not_empty && session->row_count)
1198
const char *f_val= 0;
1199
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
1200
switch (alter_info->datetime_field->sql_type)
1202
case DRIZZLE_TYPE_DATE:
1203
f_val= "0000-00-00";
1204
t_type= DRIZZLE_TIMESTAMP_DATE;
1206
case DRIZZLE_TYPE_DATETIME:
1207
f_val= "0000-00-00 00:00:00";
1208
t_type= DRIZZLE_TIMESTAMP_DATETIME;
1211
/* Shouldn't get here. */
1214
bool save_abort_on_warning= session->abort_on_warning;
1215
session->abort_on_warning= true;
1216
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
1217
f_val, strlength(f_val), t_type,
1218
alter_info->datetime_field->field_name);
1219
session->abort_on_warning= save_abort_on_warning;
1223
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
1224
session->unlink_open_table(name_lock);
1225
pthread_mutex_unlock(&LOCK_open);
1229
err_with_placeholders:
1231
An error happened while we were holding exclusive name-lock on table
1232
being altered. To be safe under LOCK TABLES we should remove placeholders
1233
from list of open tables list and table cache.
1235
session->unlink_open_table(table);
1237
session->unlink_open_table(name_lock);
1238
pthread_mutex_unlock(&LOCK_open);
1241
/* mysql_alter_table */
1435
copy_data_between_tables(Session *session,
1436
Table *from, Table *to,
1437
List<CreateField> &create,
1244
copy_data_between_tables(Table *from,Table *to,
1245
List<CreateField> &create,
1439
uint32_t order_num, Order *order,
1247
uint32_t order_num, order_st *order,
1442
1250
enum enum_enable_or_disable keys_onoff,
1443
1251
bool error_if_not_empty)
1446
1254
CopyField *copy,*copy_end;
1447
1255
ulong found_count,delete_count;
1256
Session *session= current_session;
1448
1257
uint32_t length= 0;
1449
SortField *sortorder;
1258
SORT_FIELD *sortorder;
1451
1260
TableList tables;
1452
1261
List<Item> fields;
1453
1262
List<Item> all_fields;
1506
1308
found_count=delete_count=0;
1512
if (to->getShare()->hasPrimaryKey() && to->cursor->primary_key_is_clustered())
1514
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1515
snprintf(warn_buff, sizeof(warn_buff),
1516
_("order_st BY ignored because there is a user-defined clustered "
1517
"index in the table '%-.192s'"),
1518
from->getMutableShare()->getTableName());
1519
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1312
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
1314
char warn_buff[DRIZZLE_ERRMSG_SIZE];
1315
snprintf(warn_buff, sizeof(warn_buff),
1316
_("order_st BY ignored because there is a user-defined clustered "
1317
"index in the table '%-.192s'"),
1318
from->s->table_name.str);
1319
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1324
from->sort.io_cache= new IO_CACHE;
1325
memset(from->sort.io_cache, 0, sizeof(IO_CACHE));
1327
memset(&tables, 0, sizeof(tables));
1329
tables.alias= tables.table_name= from->s->table_name.str;
1330
tables.db= from->s->db.str;
1333
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
1334
setup_order(session, session->lex->select_lex.ref_pointer_array,
1335
&tables, fields, all_fields, order) ||
1336
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1337
(from->sort.found_records= filesort(session, from, sortorder, length,
1338
(SQL_SELECT *) 0, HA_POS_ERROR,
1339
1, &examined_rows)) ==
1345
/* Tell handler that we have values for all columns in the to table */
1346
to->use_all_columns();
1347
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
1349
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
1350
session->row_count= 0;
1351
to->restoreRecordAsDefault(); // Create empty record
1352
while (!(error=info.read_record(&info)))
1354
if (session->killed)
1356
session->send_kill_message();
1360
session->row_count++;
1361
/* Return error if source table isn't empty. */
1362
if (error_if_not_empty)
1367
if (to->next_number_field)
1369
if (auto_increment_field_copied)
1370
to->auto_increment_field_not_null= true;
1524
FileSort filesort(*session);
1525
from->sort.io_cache= new internal::IO_CACHE;
1528
tables.setTableName(from->getMutableShare()->getTableName());
1529
tables.alias= tables.getTableName();
1530
tables.setSchemaName(const_cast<char *>(from->getMutableShare()->getSchemaName()));
1533
if (session->getLex()->select_lex.setup_ref_array(session, order_num) ||
1534
setup_order(session, session->getLex()->select_lex.ref_pointer_array,
1535
&tables, fields, all_fields, order) ||
1536
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
1537
(from->sort.found_records= filesort.run(from, sortorder, length,
1538
(optimizer::SqlSelect *) 0, HA_POS_ERROR,
1539
1, examined_rows)) == HA_POS_ERROR)
1546
/* Tell handler that we have values for all columns in the to table */
1547
to->use_all_columns();
1549
error= info.init_read_record(session, from, (optimizer::SqlSelect *) 0, 1, true);
1372
to->next_number_field->reset();
1375
for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
1377
copy_ptr->do_copy(copy_ptr);
1379
prev_insert_id= to->file->next_insert_id;
1380
error=to->file->ha_write_row(to->record[0]);
1381
to->auto_increment_field_not_null= false;
1552
to->print_error(errno, MYF(0));
1559
to->cursor->extra(HA_EXTRA_IGNORE_DUP_KEY);
1562
session->row_count= 0;
1563
to->restoreRecordAsDefault(); // Create empty record
1564
while (not (error=info.read_record(&info)))
1566
if (session->getKilled())
1568
session->send_kill_message();
1572
session->row_count++;
1573
/* Return error if source table isn't empty. */
1574
if (error_if_not_empty)
1579
if (to->next_number_field)
1581
if (auto_increment_field_copied)
1582
to->auto_increment_field_not_null= true;
1584
to->next_number_field->reset();
1587
for (CopyField *copy_ptr= copy; copy_ptr != copy_end ; copy_ptr++)
1589
if (not copy->to_field->hasDefault() and copy->from_null_ptr and *copy->from_null_ptr & copy->from_bit)
1591
copy->to_field->set_warning(DRIZZLE_ERROR::WARN_LEVEL_WARN,
1592
ER_WARN_DATA_TRUNCATED, 1);
1593
copy->to_field->reset();
1598
copy_ptr->do_copy(copy_ptr);
1606
prev_insert_id= to->cursor->next_insert_id;
1607
error= to->cursor->insertRecord(to->record[0]);
1608
to->auto_increment_field_not_null= false;
1612
if (!ignore || to->cursor->is_fatal_error(error, HA_CHECK_DUP))
1614
to->print_error(error, MYF(0));
1617
to->cursor->restore_auto_increment(prev_insert_id);
1626
info.end_read_record();
1627
from->free_io_cache();
1628
delete [] copy; // This is never 0
1630
if (to->cursor->ha_end_bulk_insert() && error <= 0)
1632
to->print_error(errno, MYF(0));
1635
to->cursor->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1638
Ensure that the new table is saved properly to disk so that we
1641
if (transaction_services.autocommitOrRollback(*session, false))
1644
if (not session->endActiveTransaction())
1649
session->setAbortOnWarning(false);
1385
to->file->is_fatal_error(error, HA_CHECK_DUP))
1387
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
1389
uint32_t key_nr= to->file->get_dup_key(error);
1390
if ((int) key_nr >= 0)
1392
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
1394
(to->key_info[0].key_part[0].field->flags &
1395
AUTO_INCREMENT_FLAG))
1396
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
1397
to->file->print_keydup_error(key_nr, err_msg);
1402
to->file->print_error(error,MYF(0));
1405
to->file->restore_auto_increment(prev_insert_id);
1411
end_read_record(&info);
1412
from->free_io_cache();
1413
delete [] copy; // This is never 0
1415
if (to->file->ha_end_bulk_insert() && error <= 0)
1417
to->file->print_error(my_errno,MYF(0));
1420
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
1422
if (ha_enable_transaction(session, true))
1429
Ensure that the new table is saved properly to disk so that we
1432
if (ha_autocommit_or_rollback(session, 0))
1434
if (! session->endActiveTransaction())
1438
session->abort_on_warning= 0;
1650
1439
from->free_io_cache();
1651
1440
*copied= found_count;
1652
1441
*deleted=delete_count;
1653
to->cursor->ha_release_auto_increment();
1655
if (to->cursor->ha_external_lock(session, F_UNLCK))
1442
to->file->ha_release_auto_increment();
1443
if (to->file->ha_external_lock(session,F_UNLCK))
1660
1445
return(error > 0 ? -1 : 0);
1663
static Table *open_alter_table(Session *session, Table *table, identifier::Table &identifier)
1667
/* Open the table so we need to copy the data to it. */
1668
if (table->getShare()->getType())
1671
tbl.setSchemaName(const_cast<char *>(identifier.getSchemaName().c_str()));
1672
tbl.alias= const_cast<char *>(identifier.getTableName().c_str());
1673
tbl.setTableName(const_cast<char *>(identifier.getTableName().c_str()));
1675
/* Table is in session->temporary_tables */
1676
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
1449
create_temporary_table(Session *session,
1453
HA_CREATE_INFO *create_info,
1454
message::Table *create_proto,
1455
AlterInfo *alter_info)
1458
plugin::StorageEngine *old_db_type, *new_db_type;
1459
old_db_type= table->s->db_type();
1460
new_db_type= create_info->db_type;
1462
Create a table with a temporary name.
1463
We don't log the statement, it will be logged later.
1465
create_proto->set_name(tmp_name);
1466
create_proto->set_type(message::Table::TEMPORARY);
1468
message::Table::StorageEngine *protoengine;
1469
protoengine= create_proto->mutable_engine();
1470
protoengine->set_name(new_db_type->getName());
1472
error= mysql_create_table(session, new_db, tmp_name,
1473
create_info, create_proto, alter_info, 1, 0);
1478
/** @TODO This will soon die. */
1479
bool mysql_create_like_schema_frm(Session* session,
1480
TableList* schema_table,
1481
HA_CREATE_INFO *create_info,
1482
message::Table* table_proto)
1484
HA_CREATE_INFO local_create_info;
1485
AlterInfo alter_info;
1486
bool tmp_table= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
1487
uint32_t keys= schema_table->table->s->keys;
1488
uint32_t db_options= 0;
1490
memset(&local_create_info, 0, sizeof(local_create_info));
1491
local_create_info.db_type= schema_table->table->s->db_type();
1492
local_create_info.row_type= schema_table->table->s->row_type;
1493
local_create_info.default_table_charset=default_charset_info;
1494
alter_info.flags.set(ALTER_CHANGE_COLUMN);
1495
alter_info.flags.set(ALTER_RECREATE);
1496
schema_table->table->use_all_columns();
1497
if (mysql_prepare_alter_table(session, schema_table->table,
1498
&local_create_info, table_proto, &alter_info))
1501
/* I_S tables are created with MAX_ROWS for some efficiency drive.
1502
When CREATE LIKE, we don't want to keep it coming across */
1503
message::Table::TableOptions *table_options;
1504
table_options= table_proto->mutable_options();
1505
table_options->clear_max_rows();
1507
if (mysql_prepare_create_table(session, &local_create_info, &alter_info,
1508
tmp_table, &db_options,
1509
schema_table->table->file,
1510
&schema_table->table->s->key_info, &keys, 0))
1513
table_proto->set_name("system_stupid_i_s_fix_nonsense");
1515
table_proto->set_type(message::Table::TEMPORARY);
1517
table_proto->set_type(message::Table::STANDARD);
1680
/* Open our intermediate table */
1681
new_table= session->open_temporary_table(identifier, false);
1520
message::Table::StorageEngine *protoengine;
1521
protoengine= table_proto->mutable_engine();
1523
plugin::StorageEngine *engine= local_create_info.db_type;
1525
protoengine->set_name(engine->getName());
1528
if (fill_table_proto(table_proto, "system_stupid_i_s_fix_nonsense",
1529
alter_info.create_list, &local_create_info,
1530
keys, schema_table->table->s->key_info))
1687
} /* namespace drizzled */