106
105
assert(schema_message.has_collation());
108
107
// @todo push this lock down into the engine
108
pthread_mutex_lock(&LOCK_create_db);
110
// Check to see if it exists already.
111
if (plugin::StorageEngine::doesSchemaExist(schema_message.name()))
110
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
112
// Check to see if it exists already.
113
identifier::Schema schema_identifier(schema_message.name());
114
if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
116
if (not is_if_not_exists)
118
my_error(ER_DB_CREATE_EXISTS, schema_identifier);
123
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
124
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
125
schema_message.name().c_str());
129
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
131
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
113
if (not is_if_not_exists)
115
my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
136
transaction_services.createSchema(session, schema_message);
120
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
121
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
122
schema_message.name().c_str());
140
session.startWaitingGlobalReadLock();
126
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
128
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
133
replication_services.createSchema(session, schema_message);
137
pthread_mutex_unlock(&LOCK_create_db);
138
start_waiting_global_read_lock(session);
146
144
/* db-name is already validated when we come here */
148
bool alter(Session &session,
149
const message::Schema &schema_message,
150
const message::Schema &original_schema)
146
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
152
TransactionServices &transaction_services= TransactionServices::singleton();
148
ReplicationServices &replication_services= ReplicationServices::singleton();
155
151
Do not alter database if another thread is holding read lock.
156
Wait for global read lock before acquiring session->catalog()->schemaLock().
152
Wait for global read lock before acquiring LOCK_create_db.
157
153
After wait_if_global_read_lock() we have protection against another
158
global read lock. If we would acquire session->catalog()->schemaLock() first,
154
global read lock. If we would acquire LOCK_create_db first,
159
155
another thread could step in and get the global read lock before we
160
156
reach wait_if_global_read_lock(). If this thread tries the same as we
161
(admin a db), it would then go and wait on session->catalog()->schemaLock()...
157
(admin a db), it would then go and wait on LOCK_create_db...
162
158
Furthermore wait_if_global_read_lock() checks if the current thread
163
159
has the global read lock and refuses the operation with
164
160
ER_CANT_UPDATE_WITH_READLOCK if applicable.
166
if ((session.wait_if_global_read_lock(false, true)))
171
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
173
identifier::Schema schema_idenifier(schema_message.name());
174
if (not plugin::StorageEngine::doesSchemaExist(schema_idenifier))
176
my_error(ER_SCHEMA_DOES_NOT_EXIST, schema_idenifier);
180
/* Change options if current database is being altered. */
181
success= plugin::StorageEngine::alterSchema(schema_message);
185
transaction_services.alterSchema(session, original_schema, schema_message);
190
my_error(ER_ALTER_SCHEMA, schema_idenifier);
193
session.startWaitingGlobalReadLock();
162
if ((wait_if_global_read_lock(session, 0, 1)))
165
pthread_mutex_lock(&LOCK_create_db);
167
if (not plugin::StorageEngine::doesSchemaExist(schema_message.name()))
169
my_error(ER_SCHEMA_DOES_NOT_EXIST, MYF(0), schema_message.name().c_str());
173
/* Change options if current database is being altered. */
174
bool success= plugin::StorageEngine::alterSchema(schema_message);
178
replication_services.rawStatement(session, session->getQueryString());
183
my_error(ER_ALTER_SCHEMA, MYF(0), schema_message.name().c_str());
186
pthread_mutex_unlock(&LOCK_create_db);
187
start_waiting_global_read_lock(session);
216
bool drop(Session &session, identifier::Schema &schema_identifier, const bool if_exists)
210
bool mysql_rm_db(Session *session, const std::string &schema_name, const bool if_exists)
214
char path[FN_REFLEN+16];
216
plugin::TableNameList dropped_tables;
217
message::Schema schema_proto;
221
220
Do not drop database if another thread is holding read lock.
222
Wait for global read lock before acquiring session->catalog()->schemaLock().
221
Wait for global read lock before acquiring LOCK_create_db.
223
222
After wait_if_global_read_lock() we have protection against another
224
global read lock. If we would acquire session->catalog()->schemaLock() first,
223
global read lock. If we would acquire LOCK_create_db first,
225
224
another thread could step in and get the global read lock before we
226
225
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()...
226
(admin a db), it would then go and wait on LOCK_create_db...
228
227
Furthermore wait_if_global_read_lock() checks if the current thread
229
228
has the global read lock and refuses the operation with
230
229
ER_CANT_UPDATE_WITH_READLOCK if applicable.
232
if (session.wait_if_global_read_lock(false, true))
231
if (wait_if_global_read_lock(session, 0, 1))
236
pthread_mutex_lock(&LOCK_create_db);
239
length= build_table_filename(path, sizeof(path),
240
schema_name.c_str(), "", false);
241
path[length]= '\0'; // Remove file name
243
/* See if the schema exists */
244
if (not plugin::StorageEngine::doesSchemaExist(schema_name))
239
boost::mutex::scoped_lock scopedLock(session.catalog().schemaLock());
240
message::schema::shared_ptr message= plugin::StorageEngine::getSchemaDefinition(schema_identifier);
242
/* See if the schema exists */
248
schema_identifier.getSQLPath(path);
250
push_warning_printf(&session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
251
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
257
my_error(ER_DB_DROP_EXISTS, schema_identifier);
248
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
249
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
263
error= plugin::StorageEngine::dropSchema(session, schema_identifier, *message);
255
my_error(ER_DB_DROP_EXISTS, MYF(0), path);
261
pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
262
remove_db_from_cache(schema_name);
263
pthread_mutex_unlock(&LOCK_open);
267
deleted= mysql_rm_known_files(session, schema_name,
268
path, dropped_tables);
276
assert(! session->query.empty());
278
ReplicationServices &replication_services= ReplicationServices::singleton();
279
replication_services.dropSchema(session, schema_name);
280
session->clear_error();
281
session->server_status|= SERVER_STATUS_DB_DROPPED;
282
session->my_ok((uint32_t) deleted);
283
session->server_status&= ~SERVER_STATUS_DB_DROPPED;
287
char *query, *query_pos, *query_end, *query_data_start;
290
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
291
goto exit; /* not much else we can do */
292
query_pos= query_data_start= strcpy(query,"drop table ")+11;
293
query_end= query + MAX_DROP_TABLE_Q_LEN;
294
db_len= schema_name.length();
296
ReplicationServices &replication_services= ReplicationServices::singleton();
297
for (plugin::TableNameList::iterator it= dropped_tables.begin();
298
it != dropped_tables.end();
301
uint32_t tbl_name_len;
303
/* 3 for the quotes and the comma*/
304
tbl_name_len= (*it).length() + 3;
305
if (query_pos + tbl_name_len + 1 >= query_end)
307
/* These DDL methods and logging protected with LOCK_create_db */
308
replication_services.rawStatement(session, query);
309
query_pos= query_data_start;
313
query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
318
if (query_pos != query_data_start)
320
/* These DDL methods and logging protected with LOCK_create_db */
321
replication_services.rawStatement(session, query);
269
327
If this database was the client's selected database, we silently
270
328
change the client's selected database to nothing (to have an empty
271
329
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();
332
if (not session->db.empty() && session->db.compare(schema_name) == 0)
333
mysql_change_db_impl(session, NULL);
334
pthread_mutex_unlock(&LOCK_create_db);
335
start_waiting_global_read_lock(session);
341
static int rm_table_part2(Session *session, TableList *tables)
346
bool foreign_key_error= false;
348
pthread_mutex_lock(&LOCK_open); /* Part 2 of rm a table */
351
If we have the table in the definition cache, we don't have to check the
352
.frm cursor to find if the table is a normal table (not view) and what
356
for (table= tables; table; table= table->next_local)
359
table->db_type= NULL;
360
if ((share= TableShare::getShare(table->db, table->table_name)))
361
table->db_type= share->db_type();
364
if (lock_table_names_exclusively(session, tables))
366
pthread_mutex_unlock(&LOCK_open);
370
/* Don't give warnings for not found errors, as we already generate notes */
371
session->no_warnings_for_error= 1;
373
for (table= tables; table; table= table->next_local)
376
plugin::StorageEngine *table_type;
378
error= session->drop_temporary_table(table);
382
// removed temporary table
386
goto err_with_placeholders;
388
// temporary table not found
392
table_type= table->db_type;
396
abort_locked_tables(session, db, table->table_name);
397
remove_table_from_cache(session, db, table->table_name,
398
RTFC_WAIT_OTHER_THREAD_FLAG |
399
RTFC_CHECK_KILLED_FLAG);
401
If the table was used in lock tables, remember it so that
402
unlock_table_names can free it
404
if ((locked_table= drop_locked_tables(session, db, table->table_name)))
405
table->table= locked_table;
410
goto err_with_placeholders;
414
TableIdentifier identifier(db, table->table_name);
416
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
418
// Table was not found on disk and table can't be created from engine
419
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
420
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
425
error= plugin::StorageEngine::dropTable(*session, identifier);
427
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
430
session->clear_error();
433
if (error == HA_ERR_ROW_IS_REFERENCED)
435
/* the table is referenced by a foreign key constraint */
436
foreign_key_error= true;
440
if (error == 0 || (foreign_key_error == false))
441
write_bin_log_drop_table(session, true, db, table->table_name);
445
if (wrong_tables.length())
446
wrong_tables.append(',');
447
wrong_tables.append(String(table->table_name,system_charset_info));
451
It's safe to unlock LOCK_open: we have an exclusive lock
454
pthread_mutex_unlock(&LOCK_open);
456
if (wrong_tables.length())
458
if (not foreign_key_error)
459
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
460
wrong_tables.c_ptr());
463
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
468
pthread_mutex_lock(&LOCK_open); /* final bit in rm table lock */
469
err_with_placeholders:
470
unlock_table_names(tables, NULL);
471
pthread_mutex_unlock(&LOCK_open);
472
session->no_warnings_for_error= 0;
478
Removes files with known extensions plus.
479
session MUST be set when calling this function!
482
static long mysql_rm_known_files(Session *session,
484
const char *org_path,
485
plugin::TableNameList &dropped_tables)
487
CachedDirectory dirp(org_path);
492
TableList *tot_list= NULL, **tot_list_next;
494
tot_list_next= &tot_list;
496
plugin::StorageEngine::getTableNames(db, dropped_tables);
498
for (plugin::TableNameList::iterator it= dropped_tables.begin();
499
it != dropped_tables.end();
502
size_t db_len= db.size();
504
/* Drop the table nicely */
505
TableList *table_list=(TableList*)
506
session->calloc(sizeof(*table_list) +
513
table_list->db= (char*) (table_list+1);
514
table_list->table_name= strcpy(table_list->db, db.c_str()) + db_len + 1;
515
filename_to_tablename((*it).c_str(), table_list->table_name,
517
table_list->alias= table_list->table_name; // If lower_case_table_names=2
518
table_list->internal_tmp_table= (strncmp((*it).c_str(),
520
strlen(TMP_FILE_PREFIX)) == 0);
522
(*tot_list_next)= table_list;
523
tot_list_next= &table_list->next_local;
531
if (rm_table_part2(session, tot_list))
535
if (not plugin::StorageEngine::dropSchema(db))
537
my_error(ER_DROP_SCHEMA, MYF(0), db.c_str());
283
545
@brief Change the current database and its attributes unconditionally.
341
603
@retval true Error
344
bool change(Session &session, identifier::Schema &schema_identifier)
606
bool mysql_change_db(Session *session, const std::string &new_db_name)
347
if (not plugin::Authorization::isAuthorized(*session.user(), schema_identifier))
609
assert(not new_db_name.empty());
611
if (not plugin::Authorization::isAuthorized(session->getSecurityContext(),
349
614
/* Error message is set in isAuthorized */
353
if (not check(session, schema_identifier))
620
Now we need to make a copy because check_db_name requires a
621
non-constant argument. Actually, it takes database file name.
623
TODO: fix check_db_name().
626
LEX_STRING new_db_file_name;
627
new_db_file_name.length= new_db_name.length();
628
new_db_file_name.str= (char *)malloc(new_db_name.length() + 1);
629
if (new_db_file_name.str == NULL)
630
return true; /* the error is set */
631
memcpy(new_db_file_name.str, new_db_name.c_str(), new_db_name.length());
632
new_db_file_name.str[new_db_name.length()]= 0;
636
NOTE: if check_db_name() fails, we should throw an error in any case,
637
even if we are called from sp_head::execute().
639
It's next to impossible however to get this error when we are called
640
from sp_head::execute(). But let's switch the current database to NULL
641
in this case to be sure.
644
if (check_db_name(&new_db_file_name))
355
my_error(ER_WRONG_DB_NAME, schema_identifier);
646
my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
647
free(new_db_file_name.str);
360
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
652
if (not plugin::StorageEngine::doesSchemaExist(new_db_file_name.str))
362
my_error(ER_BAD_DB_ERROR, schema_identifier);
654
/* Report an error and free new_db_file_name. */
656
my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
657
free(new_db_file_name.str);
364
659
/* The operation failed. */
369
change_db_impl(session, schema_identifier);
664
mysql_change_db_impl(session, &new_db_file_name);
665
free(new_db_file_name.str);