106
104
assert(schema_message.has_collation());
108
106
// @todo push this lock down into the engine
109
pthread_mutex_lock(&LOCK_create_db);
108
boost::mutex::scoped_lock scopedLock(session->catalog().schemaLock());
111
// Check to see if it exists already.
112
SchemaIdentifier schema_identifier(schema_message.name());
113
if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
115
if (not is_if_not_exists)
117
my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
110
// Check to see if it exists already.
111
identifier::Schema schema_identifier(schema_message.name());
112
if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
114
if (not is_if_not_exists)
116
my_error(ER_DB_CREATE_EXISTS, schema_identifier);
121
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
122
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
123
schema_message.name().c_str());
127
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
129
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
122
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
123
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
124
schema_message.name().c_str());
134
transaction_services.createSchema(session, schema_message);
128
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
130
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
135
transaction_services.createSchema(session, schema_message);
139
pthread_mutex_unlock(&LOCK_create_db);
140
start_waiting_global_read_lock(session);
138
session->startWaitingGlobalReadLock();
146
144
/* db-name is already validated when we come here */
148
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
146
bool alter_db(Session *session,
147
const message::Schema &schema_message,
148
const message::schema::shared_ptr &original_schema)
150
150
TransactionServices &transaction_services= TransactionServices::singleton();
153
153
Do not alter database if another thread is holding read lock.
154
Wait for global read lock before acquiring LOCK_create_db.
154
Wait for global read lock before acquiring session->catalog()->schemaLock().
155
155
After wait_if_global_read_lock() we have protection against another
156
global read lock. If we would acquire LOCK_create_db first,
156
global read lock. If we would acquire session->catalog()->schemaLock() first,
157
157
another thread could step in and get the global read lock before we
158
158
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 LOCK_create_db...
159
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
160
160
Furthermore wait_if_global_read_lock() checks if the current thread
161
161
has the global read lock and refuses the operation with
162
162
ER_CANT_UPDATE_WITH_READLOCK if applicable.
164
if ((wait_if_global_read_lock(session, 0, 1)))
167
pthread_mutex_lock(&LOCK_create_db);
169
SchemaIdentifier schema_idenifier(schema_message.name());
170
if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
172
my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
176
/* Change options if current database is being altered. */
177
bool success= plugin::StorageEngine::alterSchema(schema_message);
181
transaction_services.rawStatement(session, session->getQueryString());
186
my_error(ER_ALTER_SCHEMA, MYF(0), schema_message.name().c_str());
189
pthread_mutex_unlock(&LOCK_create_db);
190
start_waiting_global_read_lock(session);
164
if ((session->wait_if_global_read_lock(false, true)))
169
boost::mutex::scoped_lock scopedLock(session->catalog().schemaLock());
171
identifier::Schema schema_idenifier(schema_message.name());
172
if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
174
my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
178
/* Change options if current database is being altered. */
179
success= plugin::StorageEngine::alterSchema(schema_message);
183
transaction_services.alterSchema(session, original_schema, schema_message);
188
my_error(ER_ALTER_SCHEMA, schema_idenifier);
191
session->startWaitingGlobalReadLock();
213
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
214
bool rm_db(Session *session, identifier::Schema &schema_identifier, const bool if_exists)
217
plugin::TableNameList dropped_tables;
218
message::Schema schema_proto;
221
219
Do not drop database if another thread is holding read lock.
222
Wait for global read lock before acquiring LOCK_create_db.
220
Wait for global read lock before acquiring session->catalog()->schemaLock().
223
221
After wait_if_global_read_lock() we have protection against another
224
global read lock. If we would acquire LOCK_create_db first,
222
global read lock. If we would acquire session->catalog()->schemaLock() first,
225
223
another thread could step in and get the global read lock before we
226
224
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 LOCK_create_db...
225
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
228
226
Furthermore wait_if_global_read_lock() checks if the current thread
229
227
has the global read lock and refuses the operation with
230
228
ER_CANT_UPDATE_WITH_READLOCK if applicable.
232
if (wait_if_global_read_lock(session, 0, 1))
237
// Lets delete the temporary tables first outside of locks.
238
set<string> set_of_names;
239
session->doGetTableNames(schema_identifier, set_of_names);
241
for (set<string>::iterator iter= set_of_names.begin(); iter != set_of_names.end(); iter++)
243
TableIdentifier identifier(schema_identifier, *iter, message::Table::TEMPORARY);
244
Table *table= session->find_temporary_table(identifier);
245
session->close_temporary_table(table);
248
pthread_mutex_lock(&LOCK_create_db);
251
/* See if the schema exists */
252
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
230
if (session->wait_if_global_read_lock(false, true))
237
boost::mutex::scoped_lock scopedLock(session->catalog().schemaLock());
239
/* See if the schema exists */
240
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
256
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
257
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
258
schema_identifier.getSQLPath().c_str());
243
schema_identifier.getSQLPath(path);
247
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
248
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
254
my_error(ER_DB_DROP_EXISTS, schema_identifier);
263
my_error(ER_DB_DROP_EXISTS, MYF(0), schema_identifier.getSQLPath().c_str());
269
pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
270
remove_db_from_cache(schema_identifier);
271
pthread_mutex_unlock(&LOCK_open);
275
deleted= mysql_rm_known_files(session, schema_identifier, dropped_tables);
283
assert(! session->query.empty());
285
TransactionServices &transaction_services= TransactionServices::singleton();
286
transaction_services.dropSchema(session, schema_identifier.getSchemaName());
287
session->clear_error();
288
session->server_status|= SERVER_STATUS_DB_DROPPED;
289
session->my_ok((uint32_t) deleted);
290
session->server_status&= ~SERVER_STATUS_DB_DROPPED;
294
char *query, *query_pos, *query_end, *query_data_start;
296
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
297
goto exit; /* not much else we can do */
298
query_pos= query_data_start= strcpy(query,"drop table ")+11;
299
query_end= query + MAX_DROP_TABLE_Q_LEN;
301
TransactionServices &transaction_services= TransactionServices::singleton();
302
for (plugin::TableNameList::iterator it= dropped_tables.begin();
303
it != dropped_tables.end();
306
uint32_t tbl_name_len;
308
/* 3 for the quotes and the comma*/
309
tbl_name_len= (*it).length() + 3;
310
if (query_pos + tbl_name_len + 1 >= query_end)
312
/* These DDL methods and logging protected with LOCK_create_db */
313
transaction_services.rawStatement(session, query);
314
query_pos= query_data_start;
318
query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
323
if (query_pos != query_data_start)
325
/* These DDL methods and logging protected with LOCK_create_db */
326
transaction_services.rawStatement(session, query);
260
error= plugin::StorageEngine::dropSchema(*session, schema_identifier);
332
266
If this database was the client's selected database, we silently
333
267
change the client's selected database to nothing (to have an empty
334
268
SELECT DATABASE() in the future). For this we free() session->db and set
337
if (schema_identifier.compare(session->db))
338
mysql_change_db_impl(session);
339
pthread_mutex_unlock(&LOCK_create_db);
340
start_waiting_global_read_lock(session);
271
if (not error and schema_identifier.compare(*session->schema()))
272
change_db_impl(session);
274
session->startWaitingGlobalReadLock();
346
static int rm_table_part2(Session *session, TableList *tables)
351
bool foreign_key_error= false;
353
pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
356
If we have the table in the definition cache, we don't have to check the
357
.frm cursor to find if the table is a normal table (not view) and what
361
for (table= tables; table; table= table->next_local)
363
TableIdentifier identifier(table->db, table->table_name);
365
table->db_type= NULL;
366
if ((share= TableShare::getShare(identifier)))
368
table->db_type= share->db_type();
372
if (lock_table_names_exclusively(session, tables))
374
pthread_mutex_unlock(&LOCK_open);
378
/* Don't give warnings for not found errors, as we already generate notes */
379
session->no_warnings_for_error= 1;
381
for (table= tables; table; table= table->next_local)
384
plugin::StorageEngine *table_type;
386
error= session->drop_temporary_table(table);
390
// removed temporary table
394
goto err_with_placeholders;
396
// temporary table not found
400
table_type= table->db_type;
404
abort_locked_tables(session, db, table->table_name);
405
remove_table_from_cache(session, db, table->table_name,
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, db, table->table_name)))
413
table->table= locked_table;
418
goto err_with_placeholders;
422
TableIdentifier identifier(db, table->table_name);
423
identifier.getPath();
425
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
427
// Table was not found on disk and table can't be created from engine
428
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
429
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
434
error= plugin::StorageEngine::dropTable(*session, identifier);
436
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
439
session->clear_error();
442
if (error == HA_ERR_ROW_IS_REFERENCED)
444
/* the table is referenced by a foreign key constraint */
445
foreign_key_error= true;
449
if (error == 0 || (foreign_key_error == false))
450
write_bin_log_drop_table(session, true, db, table->table_name);
454
if (wrong_tables.length())
455
wrong_tables.append(',');
456
wrong_tables.append(String(table->table_name,system_charset_info));
460
It's safe to unlock LOCK_open: we have an exclusive lock
463
pthread_mutex_unlock(&LOCK_open);
465
if (wrong_tables.length())
467
if (not foreign_key_error)
468
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
469
wrong_tables.c_ptr());
472
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
477
pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
478
err_with_placeholders:
479
unlock_table_names(tables, NULL);
480
pthread_mutex_unlock(&LOCK_open);
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 mysql_rm_known_files(Session *session,
492
SchemaIdentifier &schema_identifier,
493
plugin::TableNameList &dropped_tables)
496
TableList *tot_list= NULL, **tot_list_next;
498
tot_list_next= &tot_list;
500
plugin::StorageEngine::getTableNames(*session, schema_identifier, dropped_tables);
502
for (plugin::TableNameList::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) +
517
table_list->db= (char*) (table_list+1);
518
table_list->table_name= strcpy(table_list->db, schema_identifier.getSchemaName().c_str()) + db_len + 1;
519
filename_to_tablename((*it).c_str(), table_list->table_name,
521
table_list->alias= table_list->table_name; // If lower_case_table_names=2
522
table_list->internal_tmp_table= (strncmp((*it).c_str(),
524
strlen(TMP_FILE_PREFIX)) == 0);
526
(*tot_list_next)= table_list;
527
tot_list_next= &table_list->next_local;
535
if (rm_table_part2(session, tot_list))
540
if (not plugin::StorageEngine::dropSchema(schema_identifier))
542
my_error(ER_DROP_SCHEMA, MYF(0), schema_identifier.getSQLPath().c_str());
550
280
@brief Change the current database and its attributes unconditionally.