216
bool drop(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
TableIdentifiers dropped_tables;
223
message::Schema schema_proto;
221
226
Do not drop database if another thread is holding read lock.
222
Wait for global read lock before acquiring session->catalog()->schemaLock().
227
Wait for global read lock before acquiring LOCK_create_db.
223
228
After wait_if_global_read_lock() we have protection against another
224
global read lock. If we would acquire session->catalog()->schemaLock() first,
229
global read lock. If we would acquire LOCK_create_db first,
225
230
another thread could step in and get the global read lock before we
226
231
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()...
232
(admin a db), it would then go and wait on LOCK_create_db...
228
233
Furthermore wait_if_global_read_lock() checks if the current thread
229
234
has the global read lock and refuses the operation with
230
235
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);
237
if (wait_if_global_read_lock(session, 0, 1))
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);
242
256
/* See if the schema exists */
257
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
248
schema_identifier.getSQLPath(path);
250
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
261
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
251
262
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
263
schema_identifier.getSQLPath().c_str());
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();
268
my_error(ER_DB_DROP_EXISTS, MYF(0), schema_identifier.getSQLPath().c_str());
274
LOCK_open.lock(); /* After deleting database, remove all cache entries related to schema */
275
remove_db_from_cache(schema_identifier);
280
deleted= drop_tables_via_filenames(session, schema_identifier, dropped_tables);
288
assert(! session->query.empty());
290
TransactionServices &transaction_services= TransactionServices::singleton();
291
transaction_services.dropSchema(session, schema_identifier.getSchemaName());
292
session->clear_error();
293
session->server_status|= SERVER_STATUS_DB_DROPPED;
294
session->my_ok((uint32_t) deleted);
295
session->server_status&= ~SERVER_STATUS_DB_DROPPED;
299
char *query, *query_pos, *query_end, *query_data_start;
301
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
302
goto exit; /* not much else we can do */
303
query_pos= query_data_start= strcpy(query,"drop table ")+11;
304
query_end= query + MAX_DROP_TABLE_Q_LEN;
306
TransactionServices &transaction_services= TransactionServices::singleton();
307
for (TableIdentifiers::iterator it= dropped_tables.begin();
308
it != dropped_tables.end();
311
uint32_t tbl_name_len;
313
/* 3 for the quotes and the comma*/
314
tbl_name_len= (*it).getTableName().length() + 3;
315
if (query_pos + tbl_name_len + 1 >= query_end)
317
/* These DDL methods and logging protected with LOCK_create_db */
318
transaction_services.rawStatement(session, query);
319
query_pos= query_data_start;
323
query_pos= strcpy(query_pos, (*it).getTableName().c_str()) + (tbl_name_len-3);
328
if (query_pos != query_data_start)
330
/* These DDL methods and logging protected with LOCK_create_db */
331
transaction_services.rawStatement(session, query);
337
If this database was the client's selected database, we silently
338
change the client's selected database to nothing (to have an empty
339
SELECT DATABASE() in the future). For this we free() session->db and set
342
if (schema_identifier.compare(session->db))
343
mysql_change_db_impl(session);
346
start_waiting_global_read_lock(session);
352
static int rm_table_part2(Session *session, TableList *tables)
357
bool foreign_key_error= false;
359
LOCK_open.lock(); /* Part 2 of rm a table */
362
If we have the table in the definition cache, we don't have to check the
363
.frm cursor to find if the table is a normal table (not view) and what
367
for (table= tables; table; table= table->next_local)
369
TableIdentifier identifier(table->db, table->table_name);
371
table->setDbType(NULL);
372
if ((share= TableShare::getShare(identifier)))
374
table->setDbType(share->db_type());
378
if (lock_table_names_exclusively(session, tables))
384
/* Don't give warnings for not found errors, as we already generate notes */
385
session->no_warnings_for_error= 1;
387
for (table= tables; table; table= table->next_local)
390
plugin::StorageEngine *table_type;
392
error= session->drop_temporary_table(table);
396
// removed temporary table
400
unlock_table_names(tables, NULL);
402
session->no_warnings_for_error= 0;
406
// temporary table not found
410
table_type= table->getDbType();
412
TableIdentifier identifier(db, table->table_name);
416
abort_locked_tables(session, identifier);
417
remove_table_from_cache(session, identifier,
418
RTFC_WAIT_OTHER_THREAD_FLAG |
419
RTFC_CHECK_KILLED_FLAG);
421
If the table was used in lock tables, remember it so that
422
unlock_table_names can free it
424
if ((locked_table= drop_locked_tables(session, identifier)))
425
table->table= locked_table;
430
unlock_table_names(tables, NULL);
432
session->no_warnings_for_error= 0;
437
identifier.getPath();
439
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
441
// Table was not found on disk and table can't be created from engine
442
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
443
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
448
error= plugin::StorageEngine::dropTable(*session, identifier);
450
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
453
session->clear_error();
456
if (error == HA_ERR_ROW_IS_REFERENCED)
458
/* the table is referenced by a foreign key constraint */
459
foreign_key_error= true;
463
if (error == 0 || (foreign_key_error == false))
464
write_bin_log_drop_table(session, true, db, table->table_name);
468
if (wrong_tables.length())
469
wrong_tables.append(',');
470
wrong_tables.append(String(table->table_name,system_charset_info));
474
It's safe to unlock LOCK_open: we have an exclusive lock
479
if (wrong_tables.length())
481
if (not foreign_key_error)
482
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
483
wrong_tables.c_ptr());
486
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
491
LOCK_open.lock(); /* final bit in rm table lock */
492
unlock_table_names(tables, NULL);
494
session->no_warnings_for_error= 0;
500
Removes files with known extensions plus.
501
session MUST be set when calling this function!
504
static long drop_tables_via_filenames(Session *session,
505
SchemaIdentifier &schema_identifier,
506
TableIdentifiers &dropped_tables)
509
TableList *tot_list= NULL, **tot_list_next;
511
tot_list_next= &tot_list;
513
plugin::StorageEngine::getIdentifiers(*session, schema_identifier, dropped_tables);
515
for (TableIdentifiers::iterator it= dropped_tables.begin();
516
it != dropped_tables.end();
519
size_t db_len= schema_identifier.getSchemaName().size();
521
/* Drop the table nicely */
522
TableList *table_list=(TableList*)
523
session->calloc(sizeof(*table_list) +
525
(*it).getTableName().length() + 1);
530
table_list->db= (char*) (table_list+1);
531
table_list->table_name= strcpy(table_list->db, schema_identifier.getSchemaName().c_str()) + db_len + 1;
532
TableIdentifier::filename_to_tablename((*it).getTableName().c_str(), table_list->table_name, (*it).getTableName().size() + 1);
533
table_list->alias= table_list->table_name; // If lower_case_table_names=2
534
table_list->setInternalTmpTable((strncmp((*it).getTableName().c_str(),
536
strlen(TMP_FILE_PREFIX)) == 0));
538
(*tot_list_next)= table_list;
539
tot_list_next= &table_list->next_local;
547
if (rm_table_part2(session, tot_list))
552
if (not plugin::StorageEngine::dropSchema(schema_identifier))
554
my_error(ER_DROP_SCHEMA, MYF(0), schema_identifier.getSQLPath().c_str());
283
562
@brief Change the current database and its attributes unconditionally.