214
bool rm_db(Session *session, identifier::Schema &schema_identifier, const bool if_exists)
218
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
222
TableIdentifier::vector dropped_tables;
223
message::Schema schema_proto;
219
226
Do not drop database if another thread is holding read lock.
220
Wait for global read lock before acquiring session->catalog()->schemaLock().
227
Wait for global read lock before acquiring LOCK_create_db.
221
228
After wait_if_global_read_lock() we have protection against another
222
global read lock. If we would acquire session->catalog()->schemaLock() first,
229
global read lock. If we would acquire LOCK_create_db first,
223
230
another thread could step in and get the global read lock before we
224
231
reach wait_if_global_read_lock(). If this thread tries the same as we
225
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
232
(admin a db), it would then go and wait on LOCK_create_db...
226
233
Furthermore wait_if_global_read_lock() checks if the current thread
227
234
has the global read lock and refuses the operation with
228
235
ER_CANT_UPDATE_WITH_READLOCK if applicable.
230
237
if (session->wait_if_global_read_lock(false, true))
237
boost::mutex::scoped_lock scopedLock(session->catalog().schemaLock());
242
// Lets delete the temporary tables first outside of locks.
243
set<string> set_of_names;
244
session->doGetTableNames(schema_identifier, set_of_names);
246
for (set<string>::iterator iter= set_of_names.begin(); iter != set_of_names.end(); iter++)
248
TableIdentifier identifier(schema_identifier, *iter, message::Table::TEMPORARY);
249
Table *table= session->find_temporary_table(identifier);
250
session->close_temporary_table(table);
254
boost::mutex::scoped_lock scopedLock(LOCK_create_db);
239
256
/* See if the schema exists */
240
257
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
260
schema_identifier.getSQLPath(path);
245
schema_identifier.getSQLPath(path);
247
264
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
248
265
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
254
my_error(ER_DB_DROP_EXISTS, schema_identifier);
260
error= plugin::StorageEngine::dropSchema(*session, schema_identifier);
266
If this database was the client's selected database, we silently
267
change the client's selected database to nothing (to have an empty
268
SELECT DATABASE() in the future). For this we free() session->db and set
271
if (not error and schema_identifier.compare(*session->schema()))
272
change_db_impl(session);
271
my_error(ER_DB_DROP_EXISTS, MYF(0), path.c_str());
277
/* After deleting database, remove all cache entries related to schema */
278
table::Cache::singleton().removeSchema(schema_identifier);
282
deleted= drop_tables_via_filenames(session, schema_identifier, dropped_tables);
290
assert(not session->getQueryString()->empty());
292
TransactionServices &transaction_services= TransactionServices::singleton();
293
transaction_services.dropSchema(session, schema_identifier.getSchemaName());
294
session->clear_error();
295
session->server_status|= SERVER_STATUS_DB_DROPPED;
296
session->my_ok((uint32_t) deleted);
297
session->server_status&= ~SERVER_STATUS_DB_DROPPED;
301
char *query, *query_pos, *query_end, *query_data_start;
303
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
304
goto exit; /* not much else we can do */
305
query_pos= query_data_start= strcpy(query,"drop table ")+11;
306
query_end= query + MAX_DROP_TABLE_Q_LEN;
308
TransactionServices &transaction_services= TransactionServices::singleton();
309
for (TableIdentifier::vector::iterator it= dropped_tables.begin();
310
it != dropped_tables.end();
313
uint32_t tbl_name_len;
315
/* 3 for the quotes and the comma*/
316
tbl_name_len= (*it).getTableName().length() + 3;
317
if (query_pos + tbl_name_len + 1 >= query_end)
319
/* These DDL methods and logging protected with LOCK_create_db */
320
transaction_services.rawStatement(session, query);
321
query_pos= query_data_start;
325
query_pos= strcpy(query_pos, (*it).getTableName().c_str()) + (tbl_name_len-3);
330
if (query_pos != query_data_start)
332
/* These DDL methods and logging protected with LOCK_create_db */
333
transaction_services.rawStatement(session, query);
339
If this database was the client's selected database, we silently
340
change the client's selected database to nothing (to have an empty
341
SELECT DATABASE() in the future). For this we free() session->db and set
344
if (schema_identifier.compare(session->db))
345
mysql_change_db_impl(session);
274
348
session->startWaitingGlobalReadLock();
354
static int rm_table_part2(Session *session, TableList *tables)
356
TransactionServices &transaction_services= TransactionServices::singleton();
361
bool foreign_key_error= false;
364
table::Cache::singleton().mutex().lock(); /* Part 2 of rm a table */
366
if (session->lock_table_names_exclusively(tables))
368
table::Cache::singleton().mutex().unlock();
372
/* Don't give warnings for not found errors, as we already generate notes */
373
session->no_warnings_for_error= 1;
375
for (table= tables; table; table= table->next_local)
377
const char *db=table->getSchemaName();
378
TableIdentifier identifier(table->getSchemaName(), table->getTableName());
380
plugin::StorageEngine *table_type;
382
error= session->drop_temporary_table(identifier);
386
// removed temporary table
390
tables->unlock_table_names();
391
table::Cache::singleton().mutex().unlock();
392
session->no_warnings_for_error= 0;
396
// temporary table not found
400
table_type= table->getDbType();
404
abort_locked_tables(session, identifier);
405
table::Cache::singleton().removeTable(session, identifier,
406
RTFC_WAIT_OTHER_THREAD_FLAG |
407
RTFC_CHECK_KILLED_FLAG);
409
If the table was used in lock tables, remember it so that
410
unlock_table_names can free it
412
if ((locked_table= drop_locked_tables(session, identifier)))
413
table->table= locked_table;
415
if (session->getKilled())
418
tables->unlock_table_names();
419
table::Cache::singleton().mutex().unlock();
420
session->no_warnings_for_error= 0;
425
identifier.getPath();
427
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
429
// Table was not found on disk and table can't be created from engine
430
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
431
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
432
table->getTableName());
436
error= plugin::StorageEngine::dropTable(*session, identifier);
438
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
441
session->clear_error();
444
if (error == HA_ERR_ROW_IS_REFERENCED)
446
/* the table is referenced by a foreign key constraint */
447
foreign_key_error= true;
451
if (error == 0 || (foreign_key_error == false))
453
transaction_services.dropTable(session, string(db), string(table->getTableName()), true);
458
if (wrong_tables.length())
459
wrong_tables.append(',');
460
wrong_tables.append(String(table->getTableName(),system_charset_info));
464
It's safe to unlock table::Cache::singleton().mutex(): we have an exclusive lock
467
table::Cache::singleton().mutex().unlock();
471
if (wrong_tables.length())
473
if (not foreign_key_error)
474
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
475
wrong_tables.c_ptr());
478
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
484
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* final bit in rm table lock */
485
tables->unlock_table_names();
487
session->no_warnings_for_error= 0;
493
Removes files with known extensions plus.
494
session MUST be set when calling this function!
497
static long drop_tables_via_filenames(Session *session,
498
SchemaIdentifier &schema_identifier,
499
TableIdentifier::vector &dropped_tables)
502
TableList *tot_list= NULL, **tot_list_next;
504
tot_list_next= &tot_list;
506
plugin::StorageEngine::getIdentifiers(*session, schema_identifier, dropped_tables);
508
for (TableIdentifier::vector::iterator it= dropped_tables.begin();
509
it != dropped_tables.end();
512
size_t db_len= schema_identifier.getSchemaName().size();
514
/* Drop the table nicely */
515
TableList *table_list=(TableList*)
516
session->calloc(sizeof(*table_list) +
518
(*it).getTableName().length() + 1);
523
table_list->setSchemaName((char*) (table_list+1));
524
table_list->setTableName(strcpy((char*) (table_list+1), schema_identifier.getSchemaName().c_str()) + db_len + 1);
525
TableIdentifier::filename_to_tablename((*it).getTableName().c_str(), const_cast<char *>(table_list->getTableName()), (*it).getTableName().size() + 1);
526
table_list->alias= table_list->getTableName(); // If lower_case_table_names=2
527
table_list->setInternalTmpTable((strncmp((*it).getTableName().c_str(),
529
strlen(TMP_FILE_PREFIX)) == 0));
531
(*tot_list_next)= table_list;
532
tot_list_next= &table_list->next_local;
535
if (session->getKilled())
540
if (rm_table_part2(session, tot_list))
545
if (not plugin::StorageEngine::dropSchema(schema_identifier))
548
schema_identifier.getSQLPath(path);
549
my_error(ER_DROP_SCHEMA, MYF(0), path.c_str());
280
558
@brief Change the current database and its attributes unconditionally.