144
150
/* db-name is already validated when we come here */
146
bool alter_db(Session *session,
147
const message::Schema &schema_message,
148
const message::schema::shared_ptr &original_schema)
152
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
150
154
TransactionServices &transaction_services= TransactionServices::singleton();
153
157
Do not alter database if another thread is holding read lock.
154
Wait for global read lock before acquiring session->catalog()->schemaLock().
158
Wait for global read lock before acquiring LOCK_create_db.
155
159
After wait_if_global_read_lock() we have protection against another
156
global read lock. If we would acquire session->catalog()->schemaLock() first,
160
global read lock. If we would acquire LOCK_create_db first,
157
161
another thread could step in and get the global read lock before we
158
162
reach wait_if_global_read_lock(). If this thread tries the same as we
159
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
163
(admin a db), it would then go and wait on LOCK_create_db...
160
164
Furthermore wait_if_global_read_lock() checks if the current thread
161
165
has the global read lock and refuses the operation with
162
166
ER_CANT_UPDATE_WITH_READLOCK if applicable.
164
if ((session->wait_if_global_read_lock(false, true)))
168
if ((wait_if_global_read_lock(session, 0, 1)))
169
boost::mutex::scoped_lock scopedLock(session->catalog().schemaLock());
173
boost::mutex::scoped_lock scopedLock(LOCK_create_db);
171
identifier::Schema schema_idenifier(schema_message.name());
175
SchemaIdentifier schema_idenifier(schema_message.name());
172
176
if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
174
my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
178
my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
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
TableIdentifiers 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
if (session->wait_if_global_read_lock(false, true))
237
boost::mutex::scoped_lock scopedLock(session->catalog().schemaLock());
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);
239
256
/* See if the schema exists */
240
257
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
245
schema_identifier.getSQLPath(path);
247
261
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
248
262
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
263
schema_identifier.getSQLPath().c_str());
254
my_error(ER_DB_DROP_EXISTS, schema_identifier);
260
error= plugin::StorageEngine::dropSchema(*session, schema_identifier);
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
table::Cache::singleton().removeSchema(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)
354
TransactionServices &transaction_services= TransactionServices::singleton();
359
bool foreign_key_error= false;
361
LOCK_open.lock(); /* Part 2 of rm a table */
363
if (lock_table_names_exclusively(session, tables))
369
/* Don't give warnings for not found errors, as we already generate notes */
370
session->no_warnings_for_error= 1;
372
for (table= tables; table; table= table->next_local)
374
const char *db=table->getSchemaName();
375
TableIdentifier identifier(table->getSchemaName(), table->getTableName());
377
plugin::StorageEngine *table_type;
379
error= session->drop_temporary_table(identifier);
383
// removed temporary table
387
unlock_table_names(tables, NULL);
389
session->no_warnings_for_error= 0;
393
// temporary table not found
397
table_type= table->getDbType();
401
abort_locked_tables(session, identifier);
402
table::Cache::singleton().removeTable(session, identifier,
403
RTFC_WAIT_OTHER_THREAD_FLAG |
404
RTFC_CHECK_KILLED_FLAG);
406
If the table was used in lock tables, remember it so that
407
unlock_table_names can free it
409
if ((locked_table= drop_locked_tables(session, identifier)))
410
table->table= locked_table;
415
unlock_table_names(tables, NULL);
417
session->no_warnings_for_error= 0;
422
identifier.getPath();
424
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
426
// Table was not found on disk and table can't be created from engine
427
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
428
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
429
table->getTableName());
433
error= plugin::StorageEngine::dropTable(*session, identifier);
435
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
438
session->clear_error();
441
if (error == HA_ERR_ROW_IS_REFERENCED)
443
/* the table is referenced by a foreign key constraint */
444
foreign_key_error= true;
448
if (error == 0 || (foreign_key_error == false))
450
transaction_services.dropTable(session, string(db), string(table->getTableName()), true);
455
if (wrong_tables.length())
456
wrong_tables.append(',');
457
wrong_tables.append(String(table->getTableName(),system_charset_info));
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
461
It's safe to unlock LOCK_open: we have an exclusive lock
271
if (not error and schema_identifier.compare(*session->schema()))
272
change_db_impl(session);
274
session->startWaitingGlobalReadLock();
466
if (wrong_tables.length())
468
if (not foreign_key_error)
469
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
470
wrong_tables.c_ptr());
473
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
478
LOCK_open.lock(); /* final bit in rm table lock */
479
unlock_table_names(tables, NULL);
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
TableIdentifiers &dropped_tables)
496
TableList *tot_list= NULL, **tot_list_next;
498
tot_list_next= &tot_list;
500
plugin::StorageEngine::getIdentifiers(*session, schema_identifier, dropped_tables);
502
for (TableIdentifiers::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) +
512
(*it).getTableName().length() + 1);
517
table_list->setSchemaName((char*) (table_list+1));
518
table_list->setTableName(strcpy((char*) (table_list+1), schema_identifier.getSchemaName().c_str()) + db_len + 1);
519
TableIdentifier::filename_to_tablename((*it).getTableName().c_str(), const_cast<char *>(table_list->getTableName()), (*it).getTableName().size() + 1);
520
table_list->alias= table_list->getTableName(); // If lower_case_table_names=2
521
table_list->setInternalTmpTable((strncmp((*it).getTableName().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());