106
106
assert(schema_message.has_collation());
108
108
// @todo push this lock down into the engine
109
pthread_mutex_lock(&LOCK_create_db);
111
// Check to see if it exists already.
112
SchemaIdentifier schema_identifier(schema_message.name());
113
if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
110
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
112
// Check to see if it exists already.
113
identifier::Schema schema_identifier(schema_message.name());
114
if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
116
if (not is_if_not_exists)
118
my_error(ER_DB_CREATE_EXISTS, schema_identifier);
123
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
124
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
125
schema_message.name().c_str());
129
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
131
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
115
if (not is_if_not_exists)
117
my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
136
transaction_services.createSchema(session, schema_message);
122
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
123
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
124
schema_message.name().c_str());
140
session.startWaitingGlobalReadLock();
128
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
130
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
135
transaction_services.createSchema(session, schema_message);
139
pthread_mutex_unlock(&LOCK_create_db);
140
start_waiting_global_read_lock(session);
146
146
/* db-name is already validated when we come here */
148
bool alter(Session &session,
149
const message::Schema &schema_message,
150
const message::Schema &original_schema)
148
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
152
150
TransactionServices &transaction_services= TransactionServices::singleton();
155
153
Do not alter database if another thread is holding read lock.
156
Wait for global read lock before acquiring session->catalog()->schemaLock().
154
Wait for global read lock before acquiring LOCK_create_db.
157
155
After wait_if_global_read_lock() we have protection against another
158
global read lock. If we would acquire session->catalog()->schemaLock() first,
156
global read lock. If we would acquire LOCK_create_db first,
159
157
another thread could step in and get the global read lock before we
160
158
reach wait_if_global_read_lock(). If this thread tries the same as we
161
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
159
(admin a db), it would then go and wait on LOCK_create_db...
162
160
Furthermore wait_if_global_read_lock() checks if the current thread
163
161
has the global read lock and refuses the operation with
164
162
ER_CANT_UPDATE_WITH_READLOCK if applicable.
166
if ((session.wait_if_global_read_lock(false, true)))
171
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
173
identifier::Schema schema_idenifier(schema_message.name());
174
if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
176
my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
180
/* Change options if current database is being altered. */
181
success= plugin::StorageEngine::alterSchema(schema_message);
185
transaction_services.alterSchema(session, original_schema, schema_message);
190
my_error(ER_ALTER_SCHEMA, schema_idenifier);
193
session.startWaitingGlobalReadLock();
164
if ((wait_if_global_read_lock(session, 0, 1)))
167
pthread_mutex_lock(&LOCK_create_db);
169
SchemaIdentifier schema_idenifier(schema_message.name());
170
if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
172
my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
176
/* Change options if current database is being altered. */
177
bool success= plugin::StorageEngine::alterSchema(schema_message);
181
transaction_services.rawStatement(session, session->getQueryString());
186
my_error(ER_ALTER_SCHEMA, MYF(0), schema_message.name().c_str());
189
pthread_mutex_unlock(&LOCK_create_db);
190
start_waiting_global_read_lock(session);
216
bool drop(Session &session, identifier::Schema &schema_identifier, const bool if_exists)
213
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
217
plugin::TableNameList dropped_tables;
218
message::Schema schema_proto;
221
221
Do not drop database if another thread is holding read lock.
222
Wait for global read lock before acquiring session->catalog()->schemaLock().
222
Wait for global read lock before acquiring LOCK_create_db.
223
223
After wait_if_global_read_lock() we have protection against another
224
global read lock. If we would acquire session->catalog()->schemaLock() first,
224
global read lock. If we would acquire LOCK_create_db first,
225
225
another thread could step in and get the global read lock before we
226
226
reach wait_if_global_read_lock(). If this thread tries the same as we
227
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
227
(admin a db), it would then go and wait on LOCK_create_db...
228
228
Furthermore wait_if_global_read_lock() checks if the current thread
229
229
has the global read lock and refuses the operation with
230
230
ER_CANT_UPDATE_WITH_READLOCK if applicable.
232
if (session.wait_if_global_read_lock(false, true))
239
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
240
message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier);
242
/* See if the schema exists */
232
if (wait_if_global_read_lock(session, 0, 1))
237
// Lets delete the temporary tables first outside of locks.
238
set<string> set_of_names;
239
session->doGetTableNames(schema_identifier, set_of_names);
241
for (set<string>::iterator iter= set_of_names.begin(); iter != set_of_names.end(); iter++)
243
TableIdentifier identifier(schema_identifier, *iter, message::Table::TEMPORARY);
244
Table *table= session->find_temporary_table(identifier);
245
session->close_temporary_table(table);
248
pthread_mutex_lock(&LOCK_create_db);
251
/* See if the schema exists */
252
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
248
schema_identifier.getSQLPath(path);
250
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
251
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
257
my_error(ER_DB_DROP_EXISTS, schema_identifier);
256
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
257
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
258
schema_identifier.getSQLPath().c_str());
263
error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
263
my_error(ER_DB_DROP_EXISTS, MYF(0), schema_identifier.getSQLPath().c_str());
269
pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
270
remove_db_from_cache(schema_identifier);
271
pthread_mutex_unlock(&LOCK_open);
275
deleted= drop_tables_via_filenames(session, schema_identifier, dropped_tables);
283
assert(! session->query.empty());
285
TransactionServices &transaction_services= TransactionServices::singleton();
286
transaction_services.dropSchema(session, schema_identifier.getSchemaName());
287
session->clear_error();
288
session->server_status|= SERVER_STATUS_DB_DROPPED;
289
session->my_ok((uint32_t) deleted);
290
session->server_status&= ~SERVER_STATUS_DB_DROPPED;
294
char *query, *query_pos, *query_end, *query_data_start;
296
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
297
goto exit; /* not much else we can do */
298
query_pos= query_data_start= strcpy(query,"drop table ")+11;
299
query_end= query + MAX_DROP_TABLE_Q_LEN;
301
TransactionServices &transaction_services= TransactionServices::singleton();
302
for (plugin::TableNameList::iterator it= dropped_tables.begin();
303
it != dropped_tables.end();
306
uint32_t tbl_name_len;
308
/* 3 for the quotes and the comma*/
309
tbl_name_len= (*it).length() + 3;
310
if (query_pos + tbl_name_len + 1 >= query_end)
312
/* These DDL methods and logging protected with LOCK_create_db */
313
transaction_services.rawStatement(session, query);
314
query_pos= query_data_start;
318
query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
323
if (query_pos != query_data_start)
325
/* These DDL methods and logging protected with LOCK_create_db */
326
transaction_services.rawStatement(session, query);
269
332
If this database was the client's selected database, we silently
270
333
change the client's selected database to nothing (to have an empty
271
334
SELECT DATABASE() in the future). For this we free() session->db and set
274
if (not error and schema_identifier.compare(*session.schema()))
275
change_db_impl(session);
277
session.startWaitingGlobalReadLock();
337
if (schema_identifier.compare(session->db))
338
mysql_change_db_impl(session);
339
pthread_mutex_unlock(&LOCK_create_db);
340
start_waiting_global_read_lock(session);
346
static int rm_table_part2(Session *session, TableList *tables)
351
bool foreign_key_error= false;
353
pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
356
If we have the table in the definition cache, we don't have to check the
357
.frm cursor to find if the table is a normal table (not view) and what
361
for (table= tables; table; table= table->next_local)
363
TableIdentifier identifier(table->db, table->table_name);
365
table->db_type= NULL;
366
if ((share= TableShare::getShare(identifier)))
368
table->db_type= share->db_type();
372
if (lock_table_names_exclusively(session, tables))
374
pthread_mutex_unlock(&LOCK_open);
378
/* Don't give warnings for not found errors, as we already generate notes */
379
session->no_warnings_for_error= 1;
381
for (table= tables; table; table= table->next_local)
384
plugin::StorageEngine *table_type;
386
error= session->drop_temporary_table(table);
390
// removed temporary table
394
goto err_with_placeholders;
396
// temporary table not found
400
table_type= table->db_type;
402
TableIdentifier identifier(db, table->table_name);
406
abort_locked_tables(session, db, table->table_name);
407
remove_table_from_cache(session, identifier,
408
RTFC_WAIT_OTHER_THREAD_FLAG |
409
RTFC_CHECK_KILLED_FLAG);
411
If the table was used in lock tables, remember it so that
412
unlock_table_names can free it
414
if ((locked_table= drop_locked_tables(session, db, table->table_name)))
415
table->table= locked_table;
420
goto err_with_placeholders;
423
identifier.getPath();
425
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
427
// Table was not found on disk and table can't be created from engine
428
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
429
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
434
error= plugin::StorageEngine::dropTable(*session, identifier);
436
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
439
session->clear_error();
442
if (error == HA_ERR_ROW_IS_REFERENCED)
444
/* the table is referenced by a foreign key constraint */
445
foreign_key_error= true;
449
if (error == 0 || (foreign_key_error == false))
450
write_bin_log_drop_table(session, true, db, table->table_name);
454
if (wrong_tables.length())
455
wrong_tables.append(',');
456
wrong_tables.append(String(table->table_name,system_charset_info));
460
It's safe to unlock LOCK_open: we have an exclusive lock
463
pthread_mutex_unlock(&LOCK_open);
465
if (wrong_tables.length())
467
if (not foreign_key_error)
468
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
469
wrong_tables.c_ptr());
472
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
477
pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
478
err_with_placeholders:
479
unlock_table_names(tables, NULL);
480
pthread_mutex_unlock(&LOCK_open);
481
session->no_warnings_for_error= 0;
487
Removes files with known extensions plus.
488
session MUST be set when calling this function!
491
static long drop_tables_via_filenames(Session *session,
492
SchemaIdentifier &schema_identifier,
493
plugin::TableNameList &dropped_tables)
496
TableList *tot_list= NULL, **tot_list_next;
498
tot_list_next= &tot_list;
500
plugin::StorageEngine::getTableNames(*session, schema_identifier, dropped_tables);
502
for (plugin::TableNameList::iterator it= dropped_tables.begin();
503
it != dropped_tables.end();
506
size_t db_len= schema_identifier.getSchemaName().size();
508
/* Drop the table nicely */
509
TableList *table_list=(TableList*)
510
session->calloc(sizeof(*table_list) +
517
table_list->db= (char*) (table_list+1);
518
table_list->table_name= strcpy(table_list->db, schema_identifier.getSchemaName().c_str()) + db_len + 1;
519
TableIdentifier::filename_to_tablename((*it).c_str(), table_list->table_name, (*it).size() + 1);
520
table_list->alias= table_list->table_name; // If lower_case_table_names=2
521
table_list->internal_tmp_table= (strncmp((*it).c_str(),
523
strlen(TMP_FILE_PREFIX)) == 0);
525
(*tot_list_next)= table_list;
526
tot_list_next= &table_list->next_local;
534
if (rm_table_part2(session, tot_list))
539
if (not plugin::StorageEngine::dropSchema(schema_identifier))
541
my_error(ER_DROP_SCHEMA, MYF(0), schema_identifier.getSQLPath().c_str());
283
549
@brief Change the current database and its attributes unconditionally.