218
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
216
bool drop(Session &session, identifier::Schema &schema_identifier, const bool if_exists)
222
TableIdentifier::vector dropped_tables;
223
message::Schema schema_proto;
226
221
Do not drop database if another thread is holding read lock.
227
Wait for global read lock before acquiring LOCK_create_db.
222
Wait for global read lock before acquiring session->catalog()->schemaLock().
228
223
After wait_if_global_read_lock() we have protection against another
229
global read lock. If we would acquire LOCK_create_db first,
224
global read lock. If we would acquire session->catalog()->schemaLock() first,
230
225
another thread could step in and get the global read lock before we
231
226
reach wait_if_global_read_lock(). If this thread tries the same as we
232
(admin a db), it would then go and wait on LOCK_create_db...
227
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
233
228
Furthermore wait_if_global_read_lock() checks if the current thread
234
229
has the global read lock and refuses the operation with
235
230
ER_CANT_UPDATE_WITH_READLOCK if applicable.
237
if (session->wait_if_global_read_lock(false, true))
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);
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);
256
242
/* See if the schema exists */
257
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
260
schema_identifier.getSQLPath(path);
264
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
248
schema_identifier.getSQLPath(path);
250
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
265
251
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
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->schema()))
345
mysql_change_db_impl(session);
348
session->startWaitingGlobalReadLock();
257
my_error(ER_DB_DROP_EXISTS, schema_identifier);
263
error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
269
If this database was the client's selected database, we silently
270
change the client's selected database to nothing (to have an empty
271
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();
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());
558
283
@brief Change the current database and its attributes unconditionally.