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);
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);
274
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)
354
TransactionServices &transaction_services= TransactionServices::singleton();
359
bool foreign_key_error= false;
361
LOCK_open.lock(); /* Part 2 of rm a table */
364
If we have the table in the definition cache, we don't have to check the
365
.frm cursor to find if the table is a normal table (not view) and what
369
for (table= tables; table; table= table->next_local)
371
TableIdentifier identifier(table->db, table->table_name);
373
table->setDbType(NULL);
374
if ((share= TableShare::getShare(identifier)))
376
table->setDbType(share->db_type());
380
if (lock_table_names_exclusively(session, tables))
386
/* Don't give warnings for not found errors, as we already generate notes */
387
session->no_warnings_for_error= 1;
389
for (table= tables; table; table= table->next_local)
392
plugin::StorageEngine *table_type;
394
error= session->drop_temporary_table(table);
398
// removed temporary table
402
unlock_table_names(tables, NULL);
404
session->no_warnings_for_error= 0;
408
// temporary table not found
412
table_type= table->getDbType();
414
TableIdentifier identifier(db, table->table_name);
418
abort_locked_tables(session, identifier);
419
remove_table_from_cache(session, identifier,
420
RTFC_WAIT_OTHER_THREAD_FLAG |
421
RTFC_CHECK_KILLED_FLAG);
423
If the table was used in lock tables, remember it so that
424
unlock_table_names can free it
426
if ((locked_table= drop_locked_tables(session, identifier)))
427
table->table= locked_table;
432
unlock_table_names(tables, NULL);
434
session->no_warnings_for_error= 0;
439
identifier.getPath();
441
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
443
// Table was not found on disk and table can't be created from engine
444
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
445
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
450
error= plugin::StorageEngine::dropTable(*session, identifier);
452
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
455
session->clear_error();
458
if (error == HA_ERR_ROW_IS_REFERENCED)
460
/* the table is referenced by a foreign key constraint */
461
foreign_key_error= true;
465
if (error == 0 || (foreign_key_error == false))
467
transaction_services.dropTable(session, string(db), string(table->table_name), true);
472
if (wrong_tables.length())
473
wrong_tables.append(',');
474
wrong_tables.append(String(table->table_name,system_charset_info));
478
It's safe to unlock LOCK_open: we have an exclusive lock
483
if (wrong_tables.length())
485
if (not foreign_key_error)
486
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
487
wrong_tables.c_ptr());
490
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
495
LOCK_open.lock(); /* final bit in rm table lock */
496
unlock_table_names(tables, NULL);
498
session->no_warnings_for_error= 0;
504
Removes files with known extensions plus.
505
session MUST be set when calling this function!
508
static long drop_tables_via_filenames(Session *session,
509
SchemaIdentifier &schema_identifier,
510
TableIdentifiers &dropped_tables)
513
TableList *tot_list= NULL, **tot_list_next;
515
tot_list_next= &tot_list;
517
plugin::StorageEngine::getIdentifiers(*session, schema_identifier, dropped_tables);
519
for (TableIdentifiers::iterator it= dropped_tables.begin();
520
it != dropped_tables.end();
523
size_t db_len= schema_identifier.getSchemaName().size();
525
/* Drop the table nicely */
526
TableList *table_list=(TableList*)
527
session->calloc(sizeof(*table_list) +
529
(*it).getTableName().length() + 1);
534
table_list->db= (char*) (table_list+1);
535
table_list->table_name= strcpy(table_list->db, schema_identifier.getSchemaName().c_str()) + db_len + 1;
536
TableIdentifier::filename_to_tablename((*it).getTableName().c_str(), table_list->table_name, (*it).getTableName().size() + 1);
537
table_list->alias= table_list->table_name; // If lower_case_table_names=2
538
table_list->setInternalTmpTable((strncmp((*it).getTableName().c_str(),
540
strlen(TMP_FILE_PREFIX)) == 0));
542
(*tot_list_next)= table_list;
543
tot_list_next= &table_list->next_local;
551
if (rm_table_part2(session, tot_list))
556
if (not plugin::StorageEngine::dropSchema(schema_identifier))
558
my_error(ER_DROP_SCHEMA, MYF(0), schema_identifier.getSQLPath().c_str());
280
566
@brief Change the current database and its attributes unconditionally.