1419
1710
bool mysql_create_table_no_lock(Session *session,
1420
TableIdentifier &identifier,
1711
const char *db, const char *table_name,
1421
1712
HA_CREATE_INFO *create_info,
1422
message::Table &table_proto,
1423
AlterInfo *alter_info,
1713
drizzled::message::Table *table_proto,
1714
Alter_info *alter_info,
1424
1715
bool internal_tmp_table,
1425
uint32_t select_field_count,
1426
bool is_if_not_exists)
1716
uint32_t select_field_count)
1718
char path[FN_REFLEN];
1719
uint32_t path_length;
1428
1720
uint db_options, key_count;
1429
1721
KEY *key_info_buffer;
1430
1723
bool error= true;
1433
1724
/* Check for duplicate fields and check type of table to create */
1434
if (not alter_info->create_list.elements)
1725
if (!alter_info->create_list.elements)
1436
1727
my_message(ER_TABLE_MUST_HAVE_COLUMNS, ER(ER_TABLE_MUST_HAVE_COLUMNS),
1440
assert(identifier.getTableName() == table_proto.name());
1731
assert(strcmp(table_name,table_proto->name().c_str())==0);
1732
if (check_engine(session, table_name, create_info))
1441
1734
db_options= create_info->table_options;
1443
1735
if (create_info->row_type == ROW_TYPE_DYNAMIC)
1444
1736
db_options|=HA_OPTION_PACK_RECORD;
1446
set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1448
/* Build a Table object to pass down to the engine, and the do the actual create. */
1449
if (not mysql_prepare_create_table(session, create_info, table_proto, alter_info,
1737
if (!(file= get_new_handler((TableShare*) 0, session->mem_root,
1738
create_info->db_type)))
1740
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(handler));
1744
set_table_default_charset(create_info, (char*) db);
1746
if (mysql_prepare_create_table(session, create_info, alter_info,
1450
1747
internal_tmp_table,
1452
1749
&key_info_buffer, &key_count,
1453
1750
select_field_count))
1455
pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1456
error= locked_create_event(session,
1463
db_options, key_count,
1465
pthread_mutex_unlock(&LOCK_open);
1753
/* Check if table exists */
1754
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
1756
path_length= build_tmptable_filename(session, path, sizeof(path));
1757
create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
1762
/* check if the table name contains FN_DEVCHAR when defined */
1763
if (strchr(table_name, FN_DEVCHAR))
1765
my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name);
1769
path_length= build_table_filename(path, sizeof(path), db, table_name, internal_tmp_table);
1772
/* Check if table already exists */
1773
if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
1774
session->find_temporary_table(db, table_name))
1776
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
1778
create_info->table_existed= 1; // Mark that table existed
1779
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1780
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1785
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
1789
pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1790
if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
1792
if (StorageEngine::getTableProto(path, NULL)==EEXIST)
1794
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
1797
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1798
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1800
create_info->table_existed= 1; // Mark that table existed
1803
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
1805
goto unlock_and_end;
1808
We don't assert here, but check the result, because the table could be
1809
in the table definition cache and in the same time the .frm could be
1810
missing from the disk, in case of manual intervention which deletes
1811
the .frm file. The user has to use FLUSH TABLES; to clear the cache.
1812
Then she could create the table. This case is pretty obscure and
1813
therefore we don't introduce a new error message only for it.
1815
if (TableShare::getShare(db, table_name))
1817
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
1818
goto unlock_and_end;
1823
Check that table with given name does not already
1824
exist in any storage engine. In such a case it should
1825
be discovered and the error ER_TABLE_EXISTS_ERROR be returned
1826
unless user specified CREATE TABLE IF EXISTS
1827
The LOCK_open mutex has been locked to make sure no
1828
one else is attempting to discover the table. Since
1829
it's not on disk as a frm file, no one could be using it!
1831
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
1833
bool create_if_not_exists =
1834
create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS;
1836
char table_path[FN_REFLEN];
1837
uint32_t table_path_length;
1839
table_path_length= build_table_filename(table_path, sizeof(table_path),
1840
db, table_name, false);
1842
int retcode= StorageEngine::getTableProto(table_path, NULL);
1846
/* Normal case, no table exists. we can go and create it */
1849
if (create_if_not_exists)
1852
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1853
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1855
create_info->table_existed= 1; // Mark that table existed
1856
goto unlock_and_end;
1858
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
1859
goto unlock_and_end;
1861
my_error(retcode, MYF(0),table_name);
1862
goto unlock_and_end;
1866
session->set_proc_info("creating table");
1867
create_info->table_existed= 0; // Mark that table is created
1869
#ifdef HAVE_READLINK
1870
if (test_if_data_home_dir(create_info->data_file_name))
1872
my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY");
1873
goto unlock_and_end;
1875
if (test_if_data_home_dir(create_info->index_file_name))
1877
my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY");
1878
goto unlock_and_end;
1882
#endif /* HAVE_READLINK */
1884
if (create_info->data_file_name)
1885
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, 0,
1886
"DATA DIRECTORY option ignored");
1887
if (create_info->index_file_name)
1888
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, 0,
1889
"INDEX DIRECTORY option ignored");
1890
create_info->data_file_name= create_info->index_file_name= 0;
1892
create_info->table_options=db_options;
1894
if (rea_create_table(session, path, db, table_name,
1896
create_info, alter_info->create_list,
1897
key_count, key_info_buffer))
1898
goto unlock_and_end;
1900
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
1902
/* Open table and put in temporary table list */
1903
if (!(session->open_temporary_table(path, db, table_name, 1, OTM_OPEN)))
1905
(void) session->rm_temporary_table(create_info->db_type, path);
1906
goto unlock_and_end;
1911
Don't write statement if:
1912
- It is an internal temporary table,
1913
- Row-based logging is used and it we are creating a temporary table, or
1914
- The binary log is not open.
1915
Otherwise, the statement shall be binlogged.
1917
if (!internal_tmp_table &&
1918
((!(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
1919
write_bin_log(session, true, session->query, session->query_length);
1922
pthread_mutex_unlock(&LOCK_open);
1468
1925
session->set_proc_info("After create");
1474
@note the following two methods implement create [temporary] table.
1932
Database locking aware wrapper for mysql_create_table_no_lock(),
1476
static bool drizzle_create_table(Session *session,
1477
TableIdentifier &identifier,
1478
HA_CREATE_INFO *create_info,
1479
message::Table &table_proto,
1480
AlterInfo *alter_info,
1481
bool internal_tmp_table,
1482
uint32_t select_field_count,
1483
bool is_if_not_exists)
1935
bool mysql_create_table(Session *session, const char *db, const char *table_name,
1936
HA_CREATE_INFO *create_info,
1937
drizzled::message::Table *table_proto,
1938
Alter_info *alter_info,
1939
bool internal_tmp_table,
1940
uint32_t select_field_count)
1485
1942
Table *name_lock= NULL;
1488
if (session->lock_table_name_if_not_cached(identifier, &name_lock))
1492
else if (name_lock == NULL)
1494
if (is_if_not_exists)
1496
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1497
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1498
identifier.getTableName().c_str());
1499
create_info->table_existed= 1;
1504
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), identifier.getSQLPath().c_str());
1945
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
1947
if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
1510
result= mysql_create_table_no_lock(session,
1952
if (name_lock == NULL)
1954
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
1956
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1957
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
1959
create_info->table_existed= 1;
1964
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
1971
result= mysql_create_table_no_lock(session, db, table_name, create_info,
1975
select_field_count);
1522
1980
pthread_mutex_lock(&LOCK_open); /* Lock for removing name_lock during table create */
2119
bool mysql_create_like_table(Session* session,
2120
TableIdentifier &destination_identifier,
2121
TableList* table, TableList* src_table,
2122
message::Table &create_table_proto,
2123
bool is_if_not_exists,
2592
bool mysql_create_like_table(Session* session, TableList* table, TableList* src_table,
2593
HA_CREATE_INFO *create_info)
2126
2595
Table *name_lock= 0;
2596
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
2597
uint32_t dst_path_length;
2127
2598
char *db= table->db;
2128
2599
char *table_name= table->table_name;
2129
2601
bool res= true;
2130
2602
uint32_t not_used;
2603
drizzled::message::Table src_proto;
2134
2606
By opening source table we guarantee that it exists and no concurrent
2135
2607
DDL operation will mess with it. Later we also take an exclusive
2136
name-lock on target table name, which makes copying of .frm cursor,
2137
call to plugin::StorageEngine::createTable() and binlogging atomic
2138
against concurrent DML and DDL operations on target table.
2139
Thus by holding both these "locks" we ensure that our statement is
2140
properly isolated from all concurrent operations which matter.
2608
name-lock on target table name, which makes copying of .frm file,
2609
call to ha_create_table() and binlogging atomic against concurrent DML
2610
and DDL operations on target table. Thus by holding both these "locks"
2611
we ensure that our statement is properly isolated from all concurrent
2612
operations which matter.
2142
2614
if (session->open_tables_from_list(&src_table, ¬_used))
2145
TableIdentifier src_identifier(src_table->table->s->getSchemaName(),
2146
src_table->table->s->table_name.str, src_table->table->s->tmp_table);
2617
strncpy(src_path, src_table->table->s->path.str, sizeof(src_path));
2151
2620
Check that destination tables does not exist. Note that its name
2152
2621
was already checked when it was added to the table list.
2154
bool table_exists= false;
2155
if (destination_identifier.isTmp())
2623
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
2157
2625
if (session->find_temporary_table(db, table_name))
2627
dst_path_length= build_tmptable_filename(session, dst_path, sizeof(dst_path));
2628
create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
2164
2632
if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
2168
pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2169
session->unlink_open_table(name_lock);
2170
pthread_mutex_unlock(&LOCK_open);
2180
else if (plugin::StorageEngine::doesTableExist(*session, destination_identifier))
2188
if (is_if_not_exists)
2190
char warn_buff[DRIZZLE_ERRMSG_SIZE];
2191
snprintf(warn_buff, sizeof(warn_buff),
2192
ER(ER_TABLE_EXISTS_ERROR), table_name);
2193
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2194
ER_TABLE_EXISTS_ERROR,warn_buff);
2199
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
2202
else // Otherwise we create the table
2204
pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
2205
was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2206
src_identifier, is_engine_set);
2207
pthread_mutex_unlock(&LOCK_open);
2209
// So we blew the creation of the table, and we scramble to clean up
2210
// anything that might have been created (read... it is a hack)
2211
if (not was_created)
2213
if (destination_identifier.isTmp())
2215
(void) session->rm_temporary_table(destination_identifier);
2219
quick_rm_table(*session, destination_identifier);
2222
else if (destination_identifier.isTmp() && not session->open_temporary_table(destination_identifier))
2224
// We created, but we can't open... also, a hack.
2225
(void) session->rm_temporary_table(destination_identifier);
2229
if (not destination_identifier.isTmp())
2231
bool rc= replicateCreateTableLike(session, table, name_lock, (src_table->table->s->tmp_table), is_if_not_exists);
2636
dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
2637
db, table_name, false);
2638
if (StorageEngine::getTableProto(dst_path, NULL)==EEXIST)
2643
Create a new table by copying from source table
2645
Altough exclusive name-lock on target table protects us from concurrent
2646
DML and DDL operations on it we still want to wrap .FRM creation and call
2647
to ha_create_table() in critical section protected by LOCK_open in order
2648
to provide minimal atomicity against operations which disregard name-locks,
2649
like I_S implementation, for example. This is a temporary and should not
2650
be copied. Instead we should fix our code to always honor name-locks.
2652
Also some engines (e.g. NDB cluster) require that LOCK_open should be held
2653
during the call to ha_create_table(). See bug #28614 for more info.
2655
pthread_mutex_lock(&LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
2658
int protoerr= EEXIST;
2660
if (src_table->schema_table)
2662
if (mysql_create_like_schema_frm(session, src_table, create_info,
2665
pthread_mutex_unlock(&LOCK_open);
2671
protoerr= StorageEngine::getTableProto(src_path, &src_proto);
2674
string dst_proto_path(dst_path);
2675
string file_ext = ".dfe";
2677
dst_proto_path.append(file_ext);
2679
if (protoerr == EEXIST)
2681
StorageEngine* engine= ha_resolve_by_name(session,
2682
src_proto.engine().name());
2684
if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY) == false)
2685
protoerr= drizzle_write_proto_file(dst_proto_path.c_str(), &src_proto);
2692
if (my_errno == ENOENT)
2693
my_error(ER_BAD_DB_ERROR,MYF(0),db);
2695
my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
2696
pthread_mutex_unlock(&LOCK_open);
2702
As mysql_truncate don't work on a new table at this stage of
2703
creation, instead create the table directly (for both normal
2704
and temporary tables).
2707
err= ha_create_table(session, dst_path, db, table_name, create_info, 1,
2709
pthread_mutex_unlock(&LOCK_open);
2711
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
2713
if (err || !session->open_temporary_table(dst_path, db, table_name, 1, OTM_OPEN))
2715
(void) session->rm_temporary_table(create_info->db_type, dst_path);
2716
goto err; /* purecov: inspected */
2721
(void) quick_rm_table(create_info->db_type, db,
2722
table_name, false); /* purecov: inspected */
2723
goto err; /* purecov: inspected */
2727
We have to write the query before we unlock the tables.
2731
Since temporary tables are not replicated under row-based
2732
replication, CREATE TABLE ... LIKE ... needs special
2733
treatement. We have four cases to consider, according to the
2734
following decision table:
2736
==== ========= ========= ==============================
2737
Case Target Source Write to binary log
2738
==== ========= ========= ==============================
2739
1 normal normal Original statement
2740
2 normal temporary Generated statement
2741
3 temporary normal Nothing
2742
4 temporary temporary Nothing
2743
==== ========= ========= ==============================
2745
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
2747
if (src_table->table->s->tmp_table) // Case 2
2750
String query(buf, sizeof(buf), system_charset_info);
2751
query.length(0); // Have to zero it since constructor doesn't
2755
Here we open the destination table, on which we already have
2756
name-lock. This is needed for store_create_info() to work.
2757
The table will be closed by unlink_open_table() at the end
2760
table->table= name_lock;
2761
pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
2762
if (session->reopen_name_locked_table(table, false))
2764
pthread_mutex_unlock(&LOCK_open);
2767
pthread_mutex_unlock(&LOCK_open);
2769
int result= store_create_info(table, &query, create_info);
2771
assert(result == 0); // store_create_info() always return 0
2772
write_bin_log(session, true, query.ptr(), query.length());
2775
write_bin_log(session, true, session->query, session->query_length);
2783
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
2785
char warn_buff[DRIZZLE_ERRMSG_SIZE];
2786
snprintf(warn_buff, sizeof(warn_buff),
2787
ER(ER_TABLE_EXISTS_ERROR), table_name);
2788
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2789
ER_TABLE_EXISTS_ERROR,warn_buff);
2793
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
2241
2798
pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2242
2799
session->unlink_open_table(name_lock);
2243
2800
pthread_mutex_unlock(&LOCK_open);
2264
2820
return(mysql_admin_table(session, tables, check_opt,
2265
2821
"check", lock_type,
2267
&Cursor::ha_check));
2822
0, 0, HA_OPEN_FOR_REPAIR, 0,
2823
&handler::ha_check));
2827
/* table_list should contain just one table */
2829
mysql_discard_or_import_tablespace(Session *session,
2830
TableList *table_list,
2831
enum tablespace_op_type tablespace_op)
2838
Note that DISCARD/IMPORT TABLESPACE always is the only operation in an
2842
session->set_proc_info("discard_or_import_tablespace");
2844
discard= test(tablespace_op == DISCARD_TABLESPACE);
2847
We set this flag so that ha_innobase::open and ::external_lock() do
2848
not complain when we lock the table
2850
session->tablespace_op= true;
2851
if (!(table= session->openTableLock(table_list, TL_WRITE)))
2853
session->tablespace_op= false;
2857
error= table->file->ha_discard_or_import_tablespace(discard);
2859
session->set_proc_info("end");
2864
/* The ALTER Table is always in its own transaction */
2865
error = ha_autocommit_or_rollback(session, 0);
2866
if (! session->endActiveTransaction())
2870
write_bin_log(session, false, session->query, session->query_length);
2873
ha_autocommit_or_rollback(session, error);
2874
session->tablespace_op=false;
2882
table->file->print_error(error, MYF(0));
2889
Manages enabling/disabling of indexes for ALTER Table
2892
alter_table_manage_keys()
2894
indexes_were_disabled Whether the indexes of the from table
2896
keys_onoff ENABLE | DISABLE | LEAVE_AS_IS
2904
bool alter_table_manage_keys(Table *table, int indexes_were_disabled,
2905
enum enum_enable_or_disable keys_onoff)
2908
switch (keys_onoff) {
2910
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
2913
if (!indexes_were_disabled)
2915
/* fall-through: disabled indexes */
2917
error= table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
2920
if (error == HA_ERR_WRONG_COMMAND)
2922
push_warning_printf(current_session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
2923
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
2924
table->s->table_name.str);
2927
table->file->print_error(error, MYF(0));
2933
create_temporary_table(Session *session,
2937
HA_CREATE_INFO *create_info,
2938
Alter_info *alter_info,
2942
char index_file[FN_REFLEN], data_file[FN_REFLEN];
2943
StorageEngine *old_db_type, *new_db_type;
2944
old_db_type= table->s->db_type();
2945
new_db_type= create_info->db_type;
2947
Handling of symlinked tables:
2949
Create new data file and index file on the same disk as the
2950
old data and index files.
2952
Rename new data file over old data file and new index file over
2954
Symlinks are not changed.
2957
Create new data file and index file on the same disk as the
2958
old data and index files. Create also symlinks to point at
2961
At end, rename intermediate tables, and symlinks to intermediate
2962
table, to final table name.
2963
Remove old table and old symlinks
2965
If rename is made to another database:
2966
Create new tables in new database.
2968
Remove old table and symlinks.
2970
if (db_changed) // Ignore symlink if db changed
2972
if (create_info->index_file_name)
2974
/* Fix index_file_name to have 'tmp_name' as basename */
2975
strcpy(index_file, tmp_name);
2976
create_info->index_file_name=fn_same(index_file,
2977
create_info->index_file_name,
2980
if (create_info->data_file_name)
2982
/* Fix data_file_name to have 'tmp_name' as basename */
2983
strcpy(data_file, tmp_name);
2984
create_info->data_file_name=fn_same(data_file,
2985
create_info->data_file_name,
2990
create_info->data_file_name=create_info->index_file_name=0;
2993
Create a table with a temporary name.
2994
We don't log the statement, it will be logged later.
2996
drizzled::message::Table table_proto;
2997
table_proto.set_name(tmp_name);
2998
table_proto.set_type(drizzled::message::Table::TEMPORARY);
3000
drizzled::message::Table::StorageEngine *protoengine;
3001
protoengine= table_proto.mutable_engine();
3002
protoengine->set_name(new_db_type->getName());
3004
error= mysql_create_table(session, new_db, tmp_name,
3005
create_info, &table_proto, alter_info, 1, 0);
3012
Prepare column and key definitions for CREATE TABLE in ALTER Table.
3014
This function transforms parse output of ALTER Table - lists of
3015
columns and keys to add, drop or modify into, essentially,
3016
CREATE TABLE definition - a list of columns and keys of the new
3017
table. While doing so, it also performs some (bug not all)
3020
This function is invoked when we know that we're going to
3021
perform ALTER Table via a temporary table -- i.e. fast ALTER Table
3022
is not possible, perhaps because the ALTER statement contains
3023
instructions that require change in table data, not only in
3024
table definition or indexes.
3026
@param[in,out] session thread handle. Used as a memory pool
3027
and source of environment information.
3028
@param[in] table the source table, open and locked
3029
Used as an interface to the storage engine
3030
to acquire additional information about
3032
@param[in,out] create_info A blob with CREATE/ALTER Table
3034
@param[in,out] alter_info Another blob with ALTER/CREATE parameters.
3035
Originally create_info was used only in
3036
CREATE TABLE and alter_info only in ALTER Table.
3037
But since ALTER might end-up doing CREATE,
3038
this distinction is gone and we just carry
3039
around two structures.
3042
Fills various create_info members based on information retrieved
3043
from the storage engine.
3044
Sets create_info->varchar if the table has a VARCHAR column.
3045
Prepares alter_info->create_list and alter_info->key_list with
3046
columns and keys of the new table.
3047
@retval true error, out of memory or a semantical error in ALTER
3049
@retval false success
3053
mysql_prepare_alter_table(Session *session, Table *table,
3054
HA_CREATE_INFO *create_info,
3055
Alter_info *alter_info)
3057
/* New column definitions are added here */
3058
List<CreateField> new_create_list;
3059
/* New key definitions are added here */
3060
List<Key> new_key_list;
3061
List_iterator<Alter_drop> drop_it(alter_info->drop_list);
3062
List_iterator<CreateField> def_it(alter_info->create_list);
3063
List_iterator<Alter_column> alter_it(alter_info->alter_list);
3064
List_iterator<Key> key_it(alter_info->key_list);
3065
List_iterator<CreateField> find_it(new_create_list);
3066
List_iterator<CreateField> field_it(new_create_list);
3067
List<Key_part_spec> key_parts;
3068
uint32_t db_create_options= (table->s->db_create_options
3069
& ~(HA_OPTION_PACK_RECORD));
3070
uint32_t used_fields= create_info->used_fields;
3071
KEY *key_info=table->key_info;
3075
create_info->varchar= false;
3076
/* Let new create options override the old ones */
3077
if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
3078
create_info->min_rows= table->s->min_rows;
3079
if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
3080
create_info->max_rows= table->s->max_rows;
3081
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
3082
create_info->avg_row_length= table->s->avg_row_length;
3083
if (!(used_fields & HA_CREATE_USED_BLOCK_SIZE))
3084
create_info->block_size= table->s->block_size;
3085
if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
3086
create_info->default_table_charset= table->s->table_charset;
3087
if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field)
3089
/* Table has an autoincrement, copy value to new table */
3090
table->file->info(HA_STATUS_AUTO);
3091
create_info->auto_increment_value= table->file->stats.auto_increment_value;
3093
if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
3094
create_info->key_block_size= table->s->key_block_size;
3096
table->restoreRecordAsDefault(); // Empty record for DEFAULT
3100
First collect all fields from table which isn't in drop_list
3102
Field **f_ptr,*field;
3103
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
3105
/* Check if field should be dropped */
3108
while ((drop=drop_it++))
3110
if (drop->type == Alter_drop::COLUMN &&
3111
!my_strcasecmp(system_charset_info,field->field_name, drop->name))
3113
/* Reset auto_increment value if it was dropped */
3114
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
3115
!(used_fields & HA_CREATE_USED_AUTO))
3117
create_info->auto_increment_value=0;
3118
create_info->used_fields|=HA_CREATE_USED_AUTO;
3129
/* Mark that we will read the field */
3130
field->setReadSet();
3132
/* Check if field is changed */
3134
while ((def=def_it++))
3137
!my_strcasecmp(system_charset_info,field->field_name, def->change))
3141
{ // Field is changed
3145
new_create_list.push_back(def);
3152
This field was not dropped and not changed, add it to the list
3155
def= new CreateField(field, field);
3156
new_create_list.push_back(def);
3157
alter_it.rewind(); // Change default if ALTER
3158
Alter_column *alter;
3159
while ((alter=alter_it++))
3161
if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
3166
if (def->sql_type == DRIZZLE_TYPE_BLOB)
3168
my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->change);
3171
if ((def->def=alter->def)) // Use new default
3172
def->flags&= ~NO_DEFAULT_VALUE_FLAG;
3174
def->flags|= NO_DEFAULT_VALUE_FLAG;
3180
while ((def=def_it++)) // Add new columns
3182
if (def->change && ! def->field)
3184
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str);
3188
Check that the DATE/DATETIME not null field we are going to add is
3189
either has a default value or the '0000-00-00' is allowed by the
3191
If the '0000-00-00' value isn't allowed then raise the error_if_not_empty
3192
flag to allow ALTER Table only if the table to be altered is empty.
3194
if ((def->sql_type == DRIZZLE_TYPE_DATE ||
3195
def->sql_type == DRIZZLE_TYPE_DATETIME) &&
3196
!alter_info->datetime_field &&
3197
!(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) &&
3198
session->variables.sql_mode & MODE_NO_ZERO_DATE)
3200
alter_info->datetime_field= def;
3201
alter_info->error_if_not_empty= true;
3204
new_create_list.push_back(def);
3205
else if (def->after == first_keyword)
3206
new_create_list.push_front(def);
3211
while ((find=find_it++)) // Add new columns
3213
if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
3218
my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str);
3221
find_it.after(def); // Put element after this
3223
XXX: hack for Bug#28427.
3224
If column order has changed, force OFFLINE ALTER Table
3225
without querying engine capabilities. If we ever have an
3226
engine that supports online ALTER Table CHANGE COLUMN
3227
<name> AFTER <name1> (Falcon?), this fix will effectively
3228
disable the capability.
3229
TODO: detect the situation in compare_tables, behave based
3230
on engine capabilities.
3232
if (alter_info->build_method == HA_BUILD_ONLINE)
3234
my_error(ER_NOT_SUPPORTED_YET, MYF(0), session->query);
3237
alter_info->build_method= HA_BUILD_OFFLINE;
3240
if (alter_info->alter_list.elements)
3242
my_error(ER_BAD_FIELD_ERROR, MYF(0),
3243
alter_info->alter_list.head()->name, table->s->table_name.str);
3246
if (!new_create_list.elements)
3248
my_message(ER_CANT_REMOVE_ALL_FIELDS, ER(ER_CANT_REMOVE_ALL_FIELDS),
3254
Collect all keys which isn't in drop list. Add only those
3255
for which some fields exists.
3258
for (uint32_t i=0 ; i < table->s->keys ; i++,key_info++)
3260
char *key_name= key_info->name;
3263
while ((drop=drop_it++))
3265
if (drop->type == Alter_drop::KEY &&
3266
!my_strcasecmp(system_charset_info,key_name, drop->name))
3275
KEY_PART_INFO *key_part= key_info->key_part;
3277
for (uint32_t j=0 ; j < key_info->key_parts ; j++,key_part++)
3279
if (!key_part->field)
3280
continue; // Wrong field (from UNIREG)
3281
const char *key_part_name=key_part->field->field_name;
3282
CreateField *cfield;
3284
while ((cfield=field_it++))
3288
if (!my_strcasecmp(system_charset_info, key_part_name,
3292
else if (!my_strcasecmp(system_charset_info,
3293
key_part_name, cfield->field_name))
3297
continue; // Field is removed
3298
uint32_t key_part_length=key_part->length;
3299
if (cfield->field) // Not new field
3302
If the field can't have only a part used in a key according to its
3303
new type, or should not be used partially according to its
3304
previous type, or the field length is less than the key part
3305
length, unset the key part length.
3307
We also unset the key part length if it is the same as the
3308
old field's length, so the whole new field will be used.
3310
BLOBs may have cfield->length == 0, which is why we test it before
3311
checking whether cfield->length < key_part_length (in chars).
3313
if (!Field::type_can_have_key_part(cfield->field->type()) ||
3314
!Field::type_can_have_key_part(cfield->sql_type) ||
3315
(cfield->field->field_length == key_part_length &&
3316
!f_is_blob(key_part->key_type)) ||
3317
(cfield->length && (cfield->length < key_part_length /
3318
key_part->field->charset()->mbmaxlen)))
3319
key_part_length= 0; // Use whole field
3321
key_part_length /= key_part->field->charset()->mbmaxlen;
3322
key_parts.push_back(new Key_part_spec(cfield->field_name,
3323
strlen(cfield->field_name),
3326
if (key_parts.elements)
3328
KEY_CREATE_INFO key_create_info;
3330
enum Key::Keytype key_type;
3331
memset(&key_create_info, 0, sizeof(key_create_info));
3333
key_create_info.algorithm= key_info->algorithm;
3334
if (key_info->flags & HA_USES_BLOCK_SIZE)
3335
key_create_info.block_size= key_info->block_size;
3336
if (key_info->flags & HA_USES_COMMENT)
3337
key_create_info.comment= key_info->comment;
3339
if (key_info->flags & HA_NOSAME)
3341
if (is_primary_key_name(key_name))
3342
key_type= Key::PRIMARY;
3344
key_type= Key::UNIQUE;
3347
key_type= Key::MULTIPLE;
3349
key= new Key(key_type, key_name, strlen(key_name),
3351
test(key_info->flags & HA_GENERATED_KEY),
3353
new_key_list.push_back(key);
3358
while ((key=key_it++)) // Add new keys
3360
if (key->type == Key::FOREIGN_KEY &&
3361
((Foreign_key *)key)->validate(new_create_list))
3363
if (key->type != Key::FOREIGN_KEY)
3364
new_key_list.push_back(key);
3365
if (key->name.str && is_primary_key_name(key->name.str))
3367
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str);
3373
if (alter_info->drop_list.elements)
3375
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
3376
alter_info->drop_list.head()->name);
3379
if (alter_info->alter_list.elements)
3381
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
3382
alter_info->alter_list.head()->name);
3386
if (!create_info->comment.str)
3388
create_info->comment.str= table->s->comment.str;
3389
create_info->comment.length= table->s->comment.length;
3392
table->file->update_create_info(create_info);
3393
if ((create_info->table_options &
3394
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
3395
(used_fields & HA_CREATE_USED_PACK_KEYS))
3396
db_create_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS);
3397
if (create_info->table_options &
3398
(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM))
3399
db_create_options&= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM);
3400
if (create_info->table_options &
3401
(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE))
3402
db_create_options&= ~(HA_OPTION_DELAY_KEY_WRITE |
3403
HA_OPTION_NO_DELAY_KEY_WRITE);
3404
create_info->table_options|= db_create_options;
3406
if (table->s->tmp_table)
3407
create_info->options|=HA_LEX_CREATE_TMP_TABLE;
3410
alter_info->create_list.swap(new_create_list);
3411
alter_info->key_list.swap(new_key_list);
3422
session Thread handle
3423
new_db If there is a RENAME clause
3424
new_name If there is a RENAME clause
3425
create_info Information from the parsing phase about new
3427
table_list The table to change.
3428
alter_info Lists of fields, keys to be changed, added
3430
order_num How many order_st BY fields has been specified.
3431
order List of fields to order_st BY.
3432
ignore Whether we have ALTER IGNORE Table
3435
This is a veery long function and is everything but the kitchen sink :)
3436
It is used to alter a table and not only by ALTER Table but also
3437
CREATE|DROP INDEX are mapped on this function.
3439
When the ALTER Table statement just does a RENAME or ENABLE|DISABLE KEYS,
3440
or both, then this function short cuts its operation by renaming
3441
the table and/or enabling/disabling the keys. In this case, the FRM is
3442
not changed, directly by mysql_alter_table. However, if there is a
3443
RENAME + change of a field, or an index, the short cut is not used.
3444
See how `create_list` is used to generate the new FRM regarding the
3445
structure of the fields. The same is done for the indices of the table.
3447
Important is the fact, that this function tries to do as little work as
3448
possible, by finding out whether a intermediate table is needed to copy
3449
data into and when finishing the altering to use it as the original table.
3450
For this reason the function compare_tables() is called, which decides
3451
based on all kind of data how similar are the new and the original
3459
bool mysql_alter_table(Session *session,
3462
HA_CREATE_INFO *create_info,
3463
TableList *table_list,
3464
Alter_info *alter_info,
3470
Table *new_table= NULL;
3471
Table *name_lock= NULL;
3472
string new_name_str;
3476
char new_name_buff[FN_REFLEN];
3477
char new_alias_buff[FN_REFLEN];
3480
const char *new_alias;
3481
char path[FN_REFLEN];
3484
StorageEngine *old_db_type;
3485
StorageEngine *new_db_type;
3486
StorageEngine *save_old_db_type;
3489
new_name_buff[0]= '\0';
3491
if (table_list && table_list->schema_table)
3493
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
3497
session->set_proc_info("init");
3500
Assign variables table_name, new_name, db, new_db, path
3501
to simplify further comparisons: we want to see if it's a RENAME
3502
later just by comparing the pointers, avoiding the need for strcmp.
3504
table_name= table_list->table_name;
3506
if (! new_db || ! my_strcasecmp(table_alias_charset, new_db, db))
3509
if (alter_info->tablespace_op != NO_TABLESPACE_OP)
3511
/* DISCARD/IMPORT TABLESPACE is always alone in an ALTER Table */
3512
return mysql_discard_or_import_tablespace(session, table_list, alter_info->tablespace_op);
3515
build_table_filename(path, sizeof(path), db, table_name, false);
3518
oss << drizzle_data_home << "/" << db << "/" << table_name;
3520
(void) unpack_filename(new_name_buff, oss.str().c_str());
3523
If this is just a rename of a view, short cut to the
3524
following scenario: 1) lock LOCK_open 2) do a RENAME
3525
2) unlock LOCK_open.
3526
This is a copy-paste added to make sure
3527
ALTER (sic:) Table .. RENAME works for views. ALTER VIEW is handled
3528
as an independent branch in mysql_execute_command. The need
3529
for a copy-paste arose because the main code flow of ALTER Table
3530
... RENAME tries to use openTableLock, which does not work for views
3531
(openTableLock was never modified to merge table lists of child tables
3532
into the main table list, like open_tables does).
3533
This code is wrong and will be removed, please do not copy.
3536
if (!(table= session->openTableLock(table_list, TL_WRITE_ALLOW_READ)))
3539
table->use_all_columns();
3541
/* Check that we are not trying to rename to an existing table */
3544
strcpy(new_name_buff, new_name);
3545
strcpy(new_alias_buff, new_name);
3546
new_alias= new_alias_buff;
3548
my_casedn_str(files_charset_info, new_name_buff);
3549
new_alias= new_name; // Create lower case table name
3550
my_casedn_str(files_charset_info, new_name);
3553
! my_strcasecmp(table_alias_charset, new_name_buff, table_name))
3556
Source and destination table names are equal: make later check
3559
new_alias= new_name= table_name;
3563
if (table->s->tmp_table != NO_TMP_TABLE)
3565
if (session->find_temporary_table(new_db, new_name_buff))
3567
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff);
3573
if (session->lock_table_name_if_not_cached(new_db, new_name, &name_lock))
3578
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
3582
build_table_filename(new_name_buff, sizeof(new_name_buff), new_db, new_name_buff, false);
3584
if (StorageEngine::getTableProto(new_name_buff, NULL) == EEXIST)
3586
/* Table will be closed by Session::executeCommand() */
3587
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
3595
new_alias= table_name;
3596
new_name= table_name;
3599
old_db_type= table->s->db_type();
3600
if (! create_info->db_type)
3602
create_info->db_type= old_db_type;
3605
if (table->s->tmp_table != NO_TMP_TABLE)
3606
create_info->options|= HA_LEX_CREATE_TMP_TABLE;
3608
if (check_engine(session, new_name, create_info))
3611
new_db_type= create_info->db_type;
3613
if (new_db_type != old_db_type &&
3614
!table->file->can_switch_engines())
3617
my_error(ER_ROW_IS_REFERENCED, MYF(0));
3621
if (create_info->row_type == ROW_TYPE_NOT_USED)
3622
create_info->row_type= table->s->row_type;
3624
if (old_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED) ||
3625
new_db_type->check_flag(HTON_BIT_ALTER_NOT_SUPPORTED))
3627
my_error(ER_ILLEGAL_HA, MYF(0), table_name);
3631
session->set_proc_info("setup");
3634
* test if no other bits except ALTER_RENAME and ALTER_KEYS_ONOFF are set
3637
tmp.reset(ALTER_RENAME);
3638
tmp.reset(ALTER_KEYS_ONOFF);
3639
tmp&= alter_info->flags;
3640
if (! (tmp.any()) &&
3641
! table->s->tmp_table) // no need to touch frm
3643
switch (alter_info->keys_onoff)
3649
wait_while_table_is_used() ensures that table being altered is
3650
opened only by this thread and that Table::TableShare::version
3651
of Table object corresponding to this table is 0.
3652
The latter guarantees that no DML statement will open this table
3653
until ALTER Table finishes (i.e. until close_thread_tables())
3654
while the fact that the table is still open gives us protection
3655
from concurrent DDL statements.
3657
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
3658
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
3659
pthread_mutex_unlock(&LOCK_open);
3660
error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3661
/* COND_refresh will be signaled in close_thread_tables() */
3664
pthread_mutex_lock(&LOCK_open); /* DDL wait for/blocker */
3665
wait_while_table_is_used(session, table, HA_EXTRA_FORCE_REOPEN);
3666
pthread_mutex_unlock(&LOCK_open);
3667
error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE);
3668
/* COND_refresh will be signaled in close_thread_tables() */
3676
if (error == HA_ERR_WRONG_COMMAND)
3679
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3680
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
3684
pthread_mutex_lock(&LOCK_open); /* Lock to remove all instances of table from table cache before ALTER */
3686
Unlike to the above case close_cached_table() below will remove ALL
3687
instances of Table from table cache (it will also remove table lock
3688
held by this thread). So to make actual table renaming and writing
3689
to binlog atomic we have to put them into the same critical section
3690
protected by LOCK_open mutex. This also removes gap for races between
3691
access() and mysql_rename_table() calls.
3695
(new_name != table_name || new_db != db))
3697
session->set_proc_info("rename");
3699
Then do a 'simple' rename of the table. First we need to close all
3700
instances of 'source' table.
3702
session->close_cached_table(table);
3704
Then, we want check once again that target table does not exist.
3705
Actually the order of these two steps does not matter since
3706
earlier we took name-lock on the target table, so we do them
3707
in this particular order only to be consistent with 5.0, in which
3708
we don't take this name-lock and where this order really matters.
3709
TODO: Investigate if we need this access() check at all.
3711
if (StorageEngine::getTableProto(new_name, NULL) == EEXIST)
3713
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name);
3718
*fn_ext(new_name)= 0;
3719
if (mysql_rename_table(old_db_type, db, table_name, new_db, new_alias, 0))
3724
if (error == HA_ERR_WRONG_COMMAND)
3727
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
3728
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
3734
write_bin_log(session, true, session->query, session->query_length);
3739
table->file->print_error(error, MYF(0));
3744
session->unlink_open_table(name_lock);
3746
pthread_mutex_unlock(&LOCK_open);
3747
table_list->table= NULL;
3751
/* We have to do full alter table. */
3754
If the old table had partitions and we are doing ALTER Table ...
3755
engine= <new_engine>, the new table must preserve the original
3756
partitioning. That means that the new engine is still the
3757
partitioning engine, not the engine specified in the parser.
3758
This is discovered in prep_alter_part_table, which in such case
3759
updates create_info->db_type.
3760
Now we need to update the stack copy of create_info->db_type,
3761
as otherwise we won't be able to correctly move the files of the
3762
temporary table to the result table files.
3764
new_db_type= create_info->db_type;
3766
if (mysql_prepare_alter_table(session, table, create_info, alter_info))
3769
set_table_default_charset(create_info, db);
3771
alter_info->build_method= HA_BUILD_OFFLINE;
3773
snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
3775
/* Safety fix for innodb */
3776
my_casedn_str(files_charset_info, tmp_name);
3778
/* Create a temporary table with the new format */
3779
error= create_temporary_table(session, table, new_db, tmp_name, create_info, alter_info, ! strcmp(db, new_db));
3784
/* Open the table so we need to copy the data to it. */
3785
if (table->s->tmp_table)
3789
tbl.alias= tmp_name;
3790
tbl.table_name= tmp_name;
3792
/* Table is in session->temporary_tables */
3793
new_table= session->openTable(&tbl, (bool*) 0, DRIZZLE_LOCK_IGNORE_FLUSH);
3797
char tmp_path[FN_REFLEN];
3798
/* table is a normal table: Create temporary table in same directory */
3799
build_table_filename(tmp_path, sizeof(tmp_path), new_db, tmp_name, true);
3800
/* Open our intermediate table */
3801
new_table= session->open_temporary_table(tmp_path, new_db, tmp_name, 0, OTM_OPEN);
3804
if (new_table == NULL)
3807
/* Copy the data if necessary. */
3808
session->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
3809
session->cuted_fields= 0L;
3810
session->set_proc_info("copy to tmp table");
3815
/* We don't want update TIMESTAMP fields during ALTER Table. */
3816
new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
3817
new_table->next_number_field= new_table->found_next_number_field;
3818
error= copy_data_between_tables(table,
3820
alter_info->create_list,
3826
alter_info->keys_onoff,
3827
alter_info->error_if_not_empty);
3829
/* We must not ignore bad input! */
3830
session->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
3832
if (table->s->tmp_table != NO_TMP_TABLE)
3834
/* We changed a temporary table */
3838
/* Close lock if this is a transactional table */
3841
mysql_unlock_tables(session, session->lock);
3845
/* Remove link to old table and rename the new one */
3846
session->close_temporary_table(table, true, true);
3848
/* Should pass the 'new_name' as we store table name in the cache */
3849
if (new_table->rename_temporary_table(new_db, new_name))
3858
Close the intermediate table that will be the new table.
3859
Note that MERGE tables do not have their children attached here.
3861
new_table->intern_close_table();
3865
pthread_mutex_lock(&LOCK_open); /* ALTER TABLE */
3869
quick_rm_table(new_db_type, new_db, tmp_name, true);
3870
pthread_mutex_unlock(&LOCK_open);
3875
Data is copied. Now we:
3876
1) Wait until all other threads close old version of table.
3877
2) Close instances of table open by this thread and replace them
3878
with exclusive name-locks.
3879
3) Rename the old table to a temp name, rename the new one to the
3881
4) If we are under LOCK TABLES and don't do ALTER Table ... RENAME
3882
we reopen new version of table.
3883
5) Write statement to the binary log.
3884
6) If we are under LOCK TABLES and do ALTER Table ... RENAME we
3885
remove name-locks from list of open tables and table cache.
3886
7) If we are not not under LOCK TABLES we rely on close_thread_tables()
3887
call to remove name-locks from table cache and list of open table.
3890
session->set_proc_info("rename result table");
3892
snprintf(old_name, sizeof(old_name), "%s2-%lx-%"PRIx64, TMP_FILE_PREFIX, (unsigned long) current_pid, session->thread_id);
3894
my_casedn_str(files_charset_info, old_name);
3896
wait_while_table_is_used(session, table, HA_EXTRA_PREPARE_FOR_RENAME);
3897
session->close_data_files_and_morph_locks(db, table_name);
3900
save_old_db_type= old_db_type;
3903
This leads to the storage engine (SE) not being notified for renames in
3904
mysql_rename_table(), because we just juggle with the FRM and nothing
3905
more. If we have an intermediate table, then we notify the SE that
3906
it should become the actual table. Later, we will recycle the old table.
3907
However, in case of ALTER Table RENAME there might be no intermediate
3908
table. This is when the old and new tables are compatible, according to
3909
compare_table(). Then, we need one additional call to
3910
mysql_rename_table() with flag NO_FRM_RENAME, which does nothing else but
3911
actual rename in the SE and the FRM is not touched. Note that, if the
3912
table is renamed and the SE is also changed, then an intermediate table
3913
is created and the additional call will not take place.
3915
if (mysql_rename_table(old_db_type, db, table_name, db, old_name, FN_TO_IS_TMP))
3918
quick_rm_table(new_db_type, new_db, tmp_name, true);
3922
if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) != 0)
3924
/* Try to get everything back. */
3926
quick_rm_table(new_db_type, new_db, new_alias, false);
3927
quick_rm_table(new_db_type, new_db, tmp_name, true);
3928
mysql_rename_table(old_db_type, db, old_name, db, table_name, FN_FROM_IS_TMP);
3934
/* This shouldn't happen. But let us play it safe. */
3935
goto err_with_placeholders;
3938
quick_rm_table(old_db_type, db, old_name, true);
3940
pthread_mutex_unlock(&LOCK_open);
3942
session->set_proc_info("end");
3944
write_bin_log(session, true, session->query, session->query_length);
3946
if (old_db_type->check_flag(HTON_BIT_FLUSH_AFTER_RENAME))
3949
For the alter table to be properly flushed to the logs, we
3950
have to open the new table. If not, we get a problem on server
3951
shutdown. But we do not need to attach MERGE children.
3953
char table_path[FN_REFLEN];
3955
build_table_filename(table_path, sizeof(table_path), new_db, table_name, false);
3956
t_table= session->open_temporary_table(table_path, new_db, tmp_name, false, OTM_OPEN);
3959
t_table->intern_close_table();
3963
errmsg_printf(ERRMSG_LVL_WARN, _("Could not open table %s.%s after rename\n"), new_db, table_name);
3965
ha_flush_logs(old_db_type);
3967
table_list->table= NULL;
3971
* Field::store() may have called my_error(). If this is
3972
* the case, we must not send an ok packet, since
3973
* Diagnostics_area::is_set() will fail an assert.
3975
if (! session->is_error())
3977
snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
3978
(ulong) (copied + deleted), (ulong) deleted,
3979
(ulong) session->cuted_fields);
3980
session->my_ok(copied + deleted, 0L, tmp_name);
3981
session->some_tables_deleted=0;
3986
/* my_error() was called. Return true (which means error...) */
3993
/* close_temporary_table() frees the new_table pointer. */
3994
session->close_temporary_table(new_table, true, true);
3997
quick_rm_table(new_db_type, new_db, tmp_name, true);
4001
No default value was provided for a DATE/DATETIME field, the
4002
current sql_mode doesn't allow the '0000-00-00' value and
4003
the table to be altered isn't empty.
4006
if (alter_info->error_if_not_empty && session->row_count)
4008
const char *f_val= 0;
4009
enum enum_drizzle_timestamp_type t_type= DRIZZLE_TIMESTAMP_DATE;
4010
switch (alter_info->datetime_field->sql_type)
4012
case DRIZZLE_TYPE_DATE:
4013
f_val= "0000-00-00";
4014
t_type= DRIZZLE_TIMESTAMP_DATE;
4016
case DRIZZLE_TYPE_DATETIME:
4017
f_val= "0000-00-00 00:00:00";
4018
t_type= DRIZZLE_TIMESTAMP_DATETIME;
4021
/* Shouldn't get here. */
4024
bool save_abort_on_warning= session->abort_on_warning;
4025
session->abort_on_warning= true;
4026
make_truncated_value_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR,
4027
f_val, strlength(f_val), t_type,
4028
alter_info->datetime_field->field_name);
4029
session->abort_on_warning= save_abort_on_warning;
4033
pthread_mutex_lock(&LOCK_open); /* ALTER TABLe */
4034
session->unlink_open_table(name_lock);
4035
pthread_mutex_unlock(&LOCK_open);
4039
err_with_placeholders:
4041
An error happened while we were holding exclusive name-lock on table
4042
being altered. To be safe under LOCK TABLES we should remove placeholders
4043
from list of open tables list and table cache.
4045
session->unlink_open_table(table);
4047
session->unlink_open_table(name_lock);
4048
pthread_mutex_unlock(&LOCK_open);
4051
/* mysql_alter_table */
4054
copy_data_between_tables(Table *from,Table *to,
4055
List<CreateField> &create,
4057
uint32_t order_num, order_st *order,
4060
enum enum_enable_or_disable keys_onoff,
4061
bool error_if_not_empty)
4064
CopyField *copy,*copy_end;
4065
ulong found_count,delete_count;
4066
Session *session= current_session;
4068
SORT_FIELD *sortorder;
4072
List<Item> all_fields;
4073
ha_rows examined_rows;
4074
bool auto_increment_field_copied= 0;
4075
ulong save_sql_mode;
4076
uint64_t prev_insert_id;
4079
Turn off recovery logging since rollback of an alter table is to
4080
delete the new table so there is no need to log the changes to it.
4082
This needs to be done before external_lock
4084
error= ha_enable_transaction(session, false);
4088
if (!(copy= new CopyField[to->s->fields]))
4089
return -1; /* purecov: inspected */
4091
if (to->file->ha_external_lock(session, F_WRLCK))
4094
/* We need external lock before we can disable/enable keys */
4095
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
4097
/* We can abort alter table for any table type */
4098
session->abort_on_warning= !ignore;
4100
from->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
4101
to->file->ha_start_bulk_insert(from->file->stats.records);
4103
save_sql_mode= session->variables.sql_mode;
4105
List_iterator<CreateField> it(create);
4108
for (Field **ptr=to->field ; *ptr ; ptr++)
4113
if (*ptr == to->next_number_field)
4114
auto_increment_field_copied= true;
4116
(copy_end++)->set(*ptr,def->field,0);
4121
found_count=delete_count=0;
4125
if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered())
4127
char warn_buff[DRIZZLE_ERRMSG_SIZE];
4128
snprintf(warn_buff, sizeof(warn_buff),
4129
_("order_st BY ignored because there is a user-defined clustered "
4130
"index in the table '%-.192s'"),
4131
from->s->table_name.str);
4132
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
4137
from->sort.io_cache= new IO_CACHE;
4138
memset(from->sort.io_cache, 0, sizeof(IO_CACHE));
4140
memset(&tables, 0, sizeof(tables));
4142
tables.alias= tables.table_name= from->s->table_name.str;
4143
tables.db= from->s->db.str;
4146
if (session->lex->select_lex.setup_ref_array(session, order_num) ||
4147
setup_order(session, session->lex->select_lex.ref_pointer_array,
4148
&tables, fields, all_fields, order) ||
4149
!(sortorder= make_unireg_sortorder(order, &length, NULL)) ||
4150
(from->sort.found_records= filesort(session, from, sortorder, length,
4151
(SQL_SELECT *) 0, HA_POS_ERROR,
4152
1, &examined_rows)) ==
4158
/* Tell handler that we have values for all columns in the to table */
4159
to->use_all_columns();
4160
init_read_record(&info, session, from, (SQL_SELECT *) 0, 1,1);
4162
to->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
4163
session->row_count= 0;
4164
to->restoreRecordAsDefault(); // Create empty record
4165
while (!(error=info.read_record(&info)))
4167
if (session->killed)
4169
session->send_kill_message();
4173
session->row_count++;
4174
/* Return error if source table isn't empty. */
4175
if (error_if_not_empty)
4180
if (to->next_number_field)
4182
if (auto_increment_field_copied)
4183
to->auto_increment_field_not_null= true;
4185
to->next_number_field->reset();
4188
for (CopyField *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++)
4190
copy_ptr->do_copy(copy_ptr);
4192
prev_insert_id= to->file->next_insert_id;
4193
error=to->file->ha_write_row(to->record[0]);
4194
to->auto_increment_field_not_null= false;
4198
to->file->is_fatal_error(error, HA_CHECK_DUP))
4200
if (!to->file->is_fatal_error(error, HA_CHECK_DUP))
4202
uint32_t key_nr= to->file->get_dup_key(error);
4203
if ((int) key_nr >= 0)
4205
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
4207
(to->key_info[0].key_part[0].field->flags &
4208
AUTO_INCREMENT_FLAG))
4209
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
4210
to->file->print_keydup_error(key_nr, err_msg);
4215
to->file->print_error(error,MYF(0));
4218
to->file->restore_auto_increment(prev_insert_id);
4224
end_read_record(&info);
4225
from->free_io_cache();
4226
delete [] copy; // This is never 0
4228
if (to->file->ha_end_bulk_insert() && error <= 0)
4230
to->file->print_error(my_errno,MYF(0));
4233
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
4235
if (ha_enable_transaction(session, true))
4242
Ensure that the new table is saved properly to disk so that we
4245
if (ha_autocommit_or_rollback(session, 0))
4247
if (! session->endActiveTransaction())
4251
session->variables.sql_mode= save_sql_mode;
4252
session->abort_on_warning= 0;
4253
from->free_io_cache();
4254
*copied= found_count;
4255
*deleted=delete_count;
4256
to->file->ha_release_auto_increment();
4257
if (to->file->ha_external_lock(session,F_UNLCK))
4259
return(error > 0 ? -1 : 0);
4264
Recreates tables by calling mysql_alter_table().
4267
mysql_recreate_table()
4268
session Thread handler
4269
tables Tables to recreate
4272
Like mysql_alter_table().
4274
bool mysql_recreate_table(Session *session, TableList *table_list)
4276
HA_CREATE_INFO create_info;
4277
Alter_info alter_info;
4279
assert(!table_list->next_global);
4281
table_list->table has been closed and freed. Do not reference
4282
uninitialized data. open_tables() could fail.
4284
table_list->table= NULL;
4286
memset(&create_info, 0, sizeof(create_info));
4287
create_info.row_type=ROW_TYPE_NOT_USED;
4288
create_info.default_table_charset=default_charset_info;
4289
/* Force alter table to recreate table */
4290
alter_info.flags.set(ALTER_CHANGE_COLUMN);
4291
alter_info.flags.set(ALTER_RECREATE);
4292
return(mysql_alter_table(session, NULL, NULL, &create_info,
4293
table_list, &alter_info, 0,
4294
(order_st *) 0, 0));
2271
4298
bool mysql_checksum_table(Session *session, TableList *tables,
4299
HA_CHECK_OPT *check_opt)
2274
4301
TableList *table;
2275
4302
List<Item> field_list;
4304
Protocol *protocol= session->protocol;
2278
4306
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
2279
4307
item->maybe_null= 1;
2280
4308
field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
2281
4309
MY_INT64_NUM_DECIMAL_DIGITS));
2282
4310
item->maybe_null= 1;
2283
if (session->client->sendFields(&field_list))
4311
if (protocol->sendFields(&field_list,
4312
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
2286
4315
/* Open one table after the other to keep lock time as short as possible. */
2287
4316
for (table= tables; table; table= table->next_local)