12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
16
/* drop and alter of tables */
36
36
#include "drizzled/transaction_services.h"
37
37
#include <drizzled/table_proto.h>
38
38
#include <drizzled/plugin/client.h>
39
#include <drizzled/table_identifier.h>
39
#include <drizzled/identifier.h>
40
40
#include "drizzled/internal/m_string.h"
41
41
#include "drizzled/global_charset_info.h"
42
42
#include "drizzled/charset.h"
49
49
#include <algorithm>
52
#include <boost/unordered_set.hpp>
52
54
using namespace std;
57
extern plugin::StorageEngine *myisam_engine;
58
59
extern pid_t current_pid;
60
bool is_primary_key(KEY *key_info)
61
bool is_primary_key(KeyInfo *key_info)
62
63
static const char * primary_key_name="PRIMARY";
63
64
return (strcmp(key_info->name, primary_key_name)==0);
75
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
76
static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
76
static bool check_if_keyname_exists(const char *name,KeyInfo *start, KeyInfo *end);
77
static char *make_unique_key_name(const char *field_name,KeyInfo *start,KeyInfo *end);
78
79
static bool prepare_blob_field(Session *session, CreateField *sql_field);
111
112
transaction_services.rawStatement(session, query);
115
/* Should should be refactored to go away */
116
void write_bin_log_drop_table(Session *session, bool if_exists, const char *db_name, const char *table_name)
118
TransactionServices &transaction_services= TransactionServices::singleton();
122
built_query.append("DROP TABLE IF EXISTS ");
124
built_query.append("DROP TABLE ");
126
built_query.append("`");
127
if (session->db.empty() || strcmp(db_name, session->db.c_str()) != 0)
129
built_query.append(db_name);
130
built_query.append("`.`");
133
built_query.append(table_name);
134
built_query.append("`");
135
transaction_services.rawStatement(session, built_query);
139
116
Execute the drop of a normal or temporary table
171
148
bool foreign_key_error= false;
173
pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
176
If we have the table in the definition cache, we don't have to check the
177
.frm cursor to find if the table is a normal table (not view) and what
181
for (table= tables; table; table= table->next_local)
183
TableIdentifier identifier(table->db, table->table_name);
185
table->db_type= NULL;
187
if ((share= TableShare::getShare(identifier)))
189
table->db_type= share->db_type();
150
LOCK_open.lock(); /* Part 2 of rm a table */
193
152
if (not drop_temporary && lock_table_names_exclusively(session, tables))
195
pthread_mutex_unlock(&LOCK_open);
220
179
if (drop_temporary == false)
222
181
Table *locked_table;
223
abort_locked_tables(session, db, table->table_name);
224
remove_table_from_cache(session, db, table->table_name,
182
TableIdentifier identifier(db, table->table_name);
183
abort_locked_tables(session, identifier);
184
remove_table_from_cache(session, identifier,
225
185
RTFC_WAIT_OTHER_THREAD_FLAG |
226
186
RTFC_CHECK_KILLED_FLAG);
228
188
If the table was used in lock tables, remember it so that
229
189
unlock_table_names can free it
231
if ((locked_table= drop_locked_tables(session, db, table->table_name)))
191
if ((locked_table= drop_locked_tables(session, identifier)))
232
192
table->table= locked_table;
234
194
if (session->killed)
237
197
goto err_with_placeholders;
240
TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? message::Table::INTERNAL : message::Table::STANDARD);
200
TableIdentifier identifier(db, table->table_name, table->getInternalTmpTable() ? message::Table::INTERNAL : message::Table::STANDARD);
242
202
if (drop_temporary || not plugin::StorageEngine::doesTableExist(*session, identifier))
359
class typelib_set_member
363
const CHARSET_INFO * const cs;
365
typelib_set_member(const char* value, unsigned int length,
366
const CHARSET_INFO * const charset)
372
static bool operator==(typelib_set_member const& a, typelib_set_member const& b)
374
return (my_strnncoll(a.cs,
375
(const unsigned char*)a.s.c_str(), a.s.length(),
376
(const unsigned char*)b.s.c_str(), b.s.length())==0);
382
class typelib_set_member_hasher
384
boost::hash<string> hasher;
386
std::size_t operator()(const typelib_set_member& t) const
399
393
static bool check_duplicates_in_interval(const char *set_or_name,
400
394
const char *name, TYPELIB *typelib,
401
395
const CHARSET_INFO * const cs,
406
400
unsigned int *cur_length= typelib->type_lengths;
407
401
*dup_val_count= 0;
409
for ( ; tmp.count > 1; cur_value++, cur_length++)
403
boost::unordered_set<typelib_set_member, typelib_set_member_hasher> interval_set;
405
for ( ; tmp.count > 0; cur_value++, cur_length++)
411
407
tmp.type_names++;
412
408
tmp.type_lengths++;
414
if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs))
410
if (interval_set.find(typelib_set_member(*cur_value, *cur_length, cs)) != interval_set.end())
416
412
my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0),
417
413
name,*cur_value,set_or_name);
417
interval_set.insert(typelib_set_member(*cur_value, *cur_length, cs));
490
488
switch (sql_field->sql_type) {
491
489
case DRIZZLE_TYPE_BLOB:
492
sql_field->pack_flag= pack_length_to_packflag(sql_field->pack_length - portable_sizeof_char_ptr);
493
490
sql_field->length= 8; // Unireg field length
494
491
(*blob_columns)++;
496
493
case DRIZZLE_TYPE_VARCHAR:
497
sql_field->pack_flag=0;
499
495
case DRIZZLE_TYPE_ENUM:
500
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length);
501
496
if (check_duplicates_in_interval("ENUM",
502
497
sql_field->field_name,
503
498
sql_field->interval,
552
546
CreateField *sql_field,*dup_field;
553
547
uint field,null_fields,blob_columns,max_key_length;
554
548
ulong record_offset= 0;
556
KEY_PART_INFO *key_part_info;
550
KeyPartInfo *key_part_info;
557
551
int timestamps= 0, timestamps_with_niladic= 0;
558
552
int field_no,dup_no;
559
553
int select_field_pos,auto_increment=0;
667
661
uint32_t cnv_errs;
668
662
conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
669
interval->type_names[i]= strmake_root(session->mem_root, conv.ptr(),
663
interval->type_names[i]= session->mem_root->strmake_root(conv.ptr(), conv.length());
671
664
interval->type_lengths[i]= conv.length();
775
768
/** @todo Get rid of this MyISAM-specific crap. */
776
769
if (not create_proto.engine().name().compare("MyISAM") &&
777
770
((sql_field->flags & BLOB_FLAG) ||
778
(sql_field->sql_type == DRIZZLE_TYPE_VARCHAR && create_info->row_type != ROW_TYPE_FIXED)))
771
(sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)))
779
772
(*db_options)|= HA_OPTION_PACK_RECORD;
878
882
key2->name.str != ignore_key &&
879
883
!foreign_key_prefix(key, key2)))
881
/* TODO: issue warning message */
885
/* @todo issue warning message */
882
886
/* mark that the generated key should be ignored */
883
887
if (!key2->generated ||
884
888
(key->generated && key->columns.elements <
915
(*key_info_buffer)= key_info= (KEY*) memory::sql_calloc(sizeof(KEY) * (*key_count));
916
key_part_info=(KEY_PART_INFO*) memory::sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
919
(*key_info_buffer)= key_info= (KeyInfo*) memory::sql_calloc(sizeof(KeyInfo) * (*key_count));
920
key_part_info=(KeyPartInfo*) memory::sql_calloc(sizeof(KeyPartInfo)*key_parts);
917
921
if (!*key_info_buffer || ! key_part_info)
918
922
return(true); // Out of memory
953
957
key_info->usable_key_parts= key_number;
954
958
key_info->algorithm= key->key_create_info.algorithm;
956
/* Take block size from key part or table part */
958
TODO: Add warning if block size changes. We can't do it here, as
959
this may depend on the size of the key
961
key_info->block_size= (key->key_create_info.block_size ?
962
key->key_create_info.block_size :
963
create_proto.options().key_block_size());
965
if (key_info->block_size)
966
key_info->flags|= HA_USES_BLOCK_SIZE;
968
960
uint32_t tmp_len= system_charset_info->cset->charpos(system_charset_info,
969
961
key->key_create_info.comment.str,
970
962
key->key_create_info.comment.str +
1142
1134
key_part_info->length=(uint16_t) length;
1143
1135
/* Use packed keys for long strings on the first column */
1144
1136
if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) &&
1145
(length >= KEY_DEFAULT_PACK_LENGTH &&
1146
(sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
1147
sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
1137
(length >= KEY_DEFAULT_PACK_LENGTH &&
1138
(sql_field->sql_type == DRIZZLE_TYPE_VARCHAR ||
1139
sql_field->sql_type == DRIZZLE_TYPE_BLOB)))
1149
1141
if ((column_nr == 0 && sql_field->sql_type == DRIZZLE_TYPE_BLOB) ||
1150
1142
sql_field->sql_type == DRIZZLE_TYPE_VARCHAR)
1151
1144
key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
1153
1148
key_info->flags|= HA_PACK_KEY;
1155
1151
/* Check if the key segment is partial, set the key flag accordingly */
1156
1152
if (length != sql_field->key_length)
1440
1435
assert(identifier.getTableName() == table_proto.name());
1441
1436
db_options= create_info->table_options;
1443
if (create_info->row_type == ROW_TYPE_DYNAMIC)
1444
db_options|=HA_OPTION_PACK_RECORD;
1446
1438
set_table_default_charset(create_info, identifier.getSchemaName().c_str());
1448
1440
/* Build a Table object to pass down to the engine, and the do the actual create. */
1452
1444
&key_info_buffer, &key_count,
1453
1445
select_field_count))
1455
pthread_mutex_lock(&LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1447
boost_unique_lock_t lock(LOCK_open); /* CREATE TABLE (some confussion on naming, double check) */
1456
1448
error= locked_create_event(session,
1571
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
1561
check_if_keyname_exists(const char *name, KeyInfo *start, KeyInfo *end)
1573
for (KEY *key=start ; key != end ; key++)
1563
for (KeyInfo *key=start ; key != end ; key++)
1574
1564
if (!my_strcasecmp(system_charset_info,name,key->name))
1615
1605
mysql_rename_table()
1616
1607
base The plugin::StorageEngine handle.
1617
1608
old_db The old database name.
1618
1609
old_name The old table name.
1619
1610
new_db The new database name.
1620
1611
new_name The new table name.
1621
flags flags for build_table_filename().
1622
FN_FROM_IS_TMP old_name is temporary.
1623
FN_TO_IS_TMP new_name is temporary.
1685
1672
enum ha_extra_function function)
1688
safe_mutex_assert_owner(&LOCK_open);
1675
safe_mutex_assert_owner(LOCK_open.native_handle());
1690
1677
table->cursor->extra(function);
1691
1678
/* Mark all tables that are in use as 'old' */
1692
1679
mysql_lock_abort(session, table); /* end threads waiting on lock */
1694
1681
/* Wait until all there are no other threads that has this table open */
1695
remove_table_from_cache(session, table->s->getSchemaName(),
1696
table->s->table_name.str,
1697
RTFC_WAIT_OTHER_THREAD_FLAG);
1682
TableIdentifier identifier(table->getMutableShare()->getSchemaName(), table->getMutableShare()->getTableName());
1683
remove_table_from_cache(session, identifier, RTFC_WAIT_OTHER_THREAD_FLAG);
1789
1775
Time zone tables and SP tables can be add to lex->query_tables list,
1790
1776
so it have to be prepared.
1791
TODO: Investigate if we can put extra tables into argument instead of
1792
using lex->query_tables
1777
@todo Investigate if we can put extra tables into argument instead of using lex->query_tables
1794
1779
lex->query_tables= table;
1795
1780
lex->query_tables_last= &table->next_global;
1829
1814
length= snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
1831
1816
session->client->store(buff, length);
1832
transaction_services.ha_autocommit_or_rollback(session, false);
1817
transaction_services.autocommitOrRollback(session, false);
1833
1818
session->endTransaction(COMMIT);
1834
1819
session->close_thread_tables();
1835
1820
lex->reset_query_tables_list(false);
1842
1827
/* Close all instances of the table to allow repair to rename files */
1843
if (lock_type == TL_WRITE && table->table->s->version)
1828
if (lock_type == TL_WRITE && table->table->getShare()->getVersion())
1845
pthread_mutex_lock(&LOCK_open); /* Lock type is TL_WRITE and we lock to repair the table */
1846
const char *old_message=session->enter_cond(&COND_refresh, &LOCK_open,
1847
"Waiting to get writelock");
1830
LOCK_open.lock(); /* Lock type is TL_WRITE and we lock to repair the table */
1831
const char *old_message=session->enter_cond(COND_refresh, LOCK_open,
1832
"Waiting to get writelock");
1848
1833
mysql_lock_abort(session,table->table);
1849
remove_table_from_cache(session, table->table->s->getSchemaName(),
1850
table->table->s->table_name.str,
1834
TableIdentifier identifier(table->table->getMutableShare()->getSchemaName(), table->table->getMutableShare()->getTableName());
1835
remove_table_from_cache(session, identifier,
1851
1836
RTFC_WAIT_OTHER_THREAD_FLAG |
1852
1837
RTFC_CHECK_KILLED_FLAG);
1853
1838
session->exit_cond(old_message);
1938
1923
if (table->table)
1940
1925
if (fatal_error)
1941
table->table->s->version=0; // Force close of table
1927
table->table->getMutableShare()->resetVersion(); // Force close of table
1942
1929
else if (open_for_modify)
1944
if (table->table->s->tmp_table)
1931
if (table->table->getShare()->getType())
1945
1933
table->table->cursor->info(HA_STATUS_CONST);
1948
pthread_mutex_lock(&LOCK_open);
1949
remove_table_from_cache(session, table->table->s->getSchemaName(),
1950
table->table->s->table_name.str, RTFC_NO_FLAG);
1951
pthread_mutex_unlock(&LOCK_open);
1937
boost::unique_lock<boost::mutex> lock(LOCK_open);
1938
TableIdentifier identifier(table->table->getMutableShare()->getSchemaName(), table->table->getMutableShare()->getTableName());
1939
remove_table_from_cache(session, identifier, RTFC_NO_FLAG);
1955
transaction_services.ha_autocommit_or_rollback(session, false);
1943
transaction_services.autocommitOrRollback(session, false);
1956
1944
session->endTransaction(COMMIT);
1957
1945
session->close_thread_tables();
1958
1946
table->table=0; // For query cache
1976
We have to write the query before we unlock the named table.
1978
Since temporary tables are not replicated under row-based
1979
replication, CREATE TABLE ... LIKE ... needs special
1980
treatement. We have four cases to consider, according to the
1981
following decision table:
1983
==== ========= ========= ==============================
1984
Case Target Source Write to binary log
1985
==== ========= ========= ==============================
1986
1 normal normal Original statement
1987
2 normal temporary Generated statement
1988
3 temporary normal Nothing
1989
4 temporary temporary Nothing
1990
==== ========= ========= ==============================
1992
static bool replicateCreateTableLike(Session *session, TableList *table, Table *name_lock,
1993
bool is_src_table_tmp, bool is_if_not_exists)
1995
if (is_src_table_tmp)
1998
String query(buf, sizeof(buf), system_charset_info);
1999
query.length(0); // Have to zero it since constructor doesn't
2003
Here we open the destination table, on which we already have
2004
name-lock. This is needed for store_create_info() to work.
2005
The table will be closed by unlink_open_table() at the end
2008
table->table= name_lock;
2009
pthread_mutex_lock(&LOCK_open); /* Open new table we have just acquired */
2010
if (session->reopen_name_locked_table(table, false))
2012
pthread_mutex_unlock(&LOCK_open);
2015
pthread_mutex_unlock(&LOCK_open);
2017
int result= store_create_info(table, &query, is_if_not_exists);
2019
assert(result == 0); // store_create_info() always return 0
2020
write_bin_log(session, query.ptr());
2024
write_bin_log(session, session->query.c_str());
2031
1964
Create a new table by copying from source table
2142
2076
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);
2079
TableIdentifier src_identifier(src_table->table->getMutableShare()->getSchemaName(),
2080
src_table->table->getMutableShare()->getTableName(), src_table->table->getMutableShare()->getType());
2151
2085
Check that destination tables does not exist. Note that its name
2152
2086
was already checked when it was added to the table list.
2088
For temporary tables we don't aim to grab locks.
2154
2090
bool table_exists= false;
2155
2091
if (destination_identifier.isTmp())
2159
2095
table_exists= true;
2099
bool was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2100
src_identifier, is_engine_set);
2101
if (not was_created) // This is pretty paranoid, but we assume something might not clean up after itself
2103
(void) session->rm_temporary_table(destination_identifier, true);
2105
else if (not session->open_temporary_table(destination_identifier))
2107
// We created, but we can't open... also, a hack.
2108
(void) session->rm_temporary_table(destination_identifier, true);
2116
else // Standard table which will require locks.
2164
if (session->lock_table_name_if_not_cached(db, table_name, &name_lock))
2118
Table *name_lock= 0;
2120
if (session->lock_table_name_if_not_cached(destination_identifier, &name_lock))
2168
pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2124
boost_unique_lock_t lock(LOCK_open); /* unlink open tables for create table like*/
2169
2125
session->unlink_open_table(name_lock);
2170
pthread_mutex_unlock(&LOCK_open);
2182
2137
table_exists= true;
2139
else // Otherwise we create the table
2143
boost_unique_lock_t lock(LOCK_open); /* We lock for CREATE TABLE LIKE to copy table definition */
2144
was_created= create_table_wrapper(*session, create_table_proto, destination_identifier,
2145
src_identifier, is_engine_set);
2148
// So we blew the creation of the table, and we scramble to clean up
2149
// anything that might have been created (read... it is a hack)
2150
if (not was_created)
2152
quick_rm_table(*session, destination_identifier);
2162
boost_unique_lock_t lock(LOCK_open); /* unlink open tables for create table like*/
2163
session->unlink_open_table(name_lock);
2186
2167
if (table_exists)
2199
2180
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);
2241
pthread_mutex_lock(&LOCK_open); /* unlink open tables for create table like*/
2242
session->unlink_open_table(name_lock);
2243
pthread_mutex_unlock(&LOCK_open);
2267
2205
&Cursor::ha_check));
2271
bool mysql_checksum_table(Session *session, TableList *tables,
2275
List<Item> field_list;
2278
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
2279
item->maybe_null= 1;
2280
field_list.push_back(item= new Item_int("Checksum", (int64_t) 1,
2281
MY_INT64_NUM_DECIMAL_DIGITS));
2282
item->maybe_null= 1;
2283
if (session->client->sendFields(&field_list))
2286
/* Open one table after the other to keep lock time as short as possible. */
2287
for (table= tables; table; table= table->next_local)
2289
char table_name[NAME_LEN*2+2];
2292
snprintf(table_name, sizeof(table_name), "%s.%s",table->db,table->table_name);
2294
t= table->table= session->openTableLock(table, TL_READ);
2295
session->clear_error(); // these errors shouldn't get client
2297
session->client->store(table_name);
2301
/* Table didn't exist */
2302
session->client->store();
2303
session->clear_error();
2308
@note if the engine keeps a checksum then we return the checksum, otherwise we calculate
2310
if (t->cursor->getEngine()->check_flag(HTON_BIT_HAS_CHECKSUM))
2312
session->client->store((uint64_t)t->cursor->checksum());
2316
/* calculating table's checksum */
2317
internal::ha_checksum crc= 0;
2318
unsigned char null_mask=256 - (1 << t->s->last_null_bit_pos);
2320
t->use_all_columns();
2322
if (t->cursor->ha_rnd_init(1))
2323
session->client->store();
2328
internal::ha_checksum row_crc= 0;
2329
int error= t->cursor->rnd_next(t->record[0]);
2330
if (unlikely(error))
2332
if (error == HA_ERR_RECORD_DELETED)
2336
if (t->s->null_bytes)
2338
/* fix undefined null bits */
2339
t->record[0][t->s->null_bytes-1] |= null_mask;
2340
if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD))
2341
t->record[0][0] |= 1;
2343
row_crc= internal::my_checksum(row_crc, t->record[0], t->s->null_bytes);
2346
for (uint32_t i= 0; i < t->s->fields; i++ )
2348
Field *f= t->field[i];
2349
if ((f->type() == DRIZZLE_TYPE_BLOB) ||
2350
(f->type() == DRIZZLE_TYPE_VARCHAR))
2354
row_crc= internal::my_checksum(row_crc, (unsigned char*) tmp.ptr(), tmp.length());
2357
row_crc= internal::my_checksum(row_crc, f->ptr,
2363
session->client->store((uint64_t)crc);
2364
t->cursor->ha_rnd_end();
2367
session->clear_error();
2368
session->close_thread_tables();
2369
table->table=0; // For query cache
2371
if (session->client->flush())
2379
session->close_thread_tables(); // Shouldn't be needed
2385
2208
} /* namespace drizzled */