17
17
/* create and drop of databases */
22
#include <sys/types.h>
18
#include <drizzled/global.h>
28
#include <drizzled/message/schema.pb.h>
29
#include "drizzled/error.h"
23
#include <drizzled/serialize/serialize.h>
25
#include <drizzled/server_includes.h>
26
#include <mysys/mysys_err.h>
27
#include <mysys/my_dir.h>
28
#include <drizzled/error.h>
30
29
#include <drizzled/gettext.h>
31
#include <drizzled/my_hash.h>
32
#include "drizzled/internal/m_string.h"
30
#include <mysys/hash.h>
33
31
#include <drizzled/session.h>
34
32
#include <drizzled/db.h>
35
33
#include <drizzled/sql_base.h>
36
34
#include <drizzled/lock.h>
37
35
#include <drizzled/errmsg_print.h>
38
#include <drizzled/transaction_services.h>
39
#include <drizzled/message/schema.pb.h>
40
#include "drizzled/sql_table.h"
41
#include "drizzled/plugin/storage_engine.h"
42
#include "drizzled/plugin/authorization.h"
43
#include "drizzled/global_charset_info.h"
44
#include "drizzled/pthread_globals.h"
45
#include "drizzled/charset.h"
47
#include "drizzled/internal/my_sys.h"
36
#include <drizzled/replicator.h>
38
#define MY_DB_OPT_FILE "db.opt"
49
39
#define MAX_DROP_TABLE_Q_LEN 1024
56
static long mysql_rm_known_files(Session *session,
57
SchemaIdentifier &schema_identifier,
58
plugin::TableNameList &dropped_tables);
59
static void mysql_change_db_impl(Session *session);
60
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier);
41
const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NULL};
42
static TYPELIB deletable_extentions=
43
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
45
static long mysql_rm_known_files(Session *session, MY_DIR *dirp,
46
const char *db, const char *path,
48
TableList **dropped_tables);
50
static bool rm_dir_w_symlink(const char *org_path, bool send_error);
51
static void mysql_change_db_impl(Session *session,
52
LEX_STRING *new_db_name,
53
const CHARSET_INFO * const new_db_charset);
56
/* Database lock hash */
58
pthread_mutex_t LOCK_lock_db;
59
bool dbcache_init= false;
60
int creating_database= 0; // how many database locks are made
63
/* Structure for database lock */
64
typedef struct my_dblock_st
66
char *name; /* Database name */
67
uint32_t name_length; /* Database length name */
75
extern "C" unsigned char* lock_db_get_key(my_dblock_t *, size_t *, bool not_used);
77
unsigned char* lock_db_get_key(my_dblock_t *ptr, size_t *length,
80
*length= ptr->name_length;
81
return (unsigned char*) ptr->name;
86
Free lock_db hash element.
89
extern "C" void lock_db_free_element(void *ptr);
91
void lock_db_free_element(void *ptr)
98
Delete a database lock entry from hash.
101
void lock_db_delete(const char *name, uint32_t length)
104
safe_mutex_assert_owner(&LOCK_lock_db);
105
if ((opt= (my_dblock_t *)hash_search(&lock_db_cache,
106
(const unsigned char*) name, length)))
107
hash_delete(&lock_db_cache, (unsigned char*) opt);
111
Helper function to write a query to binlog used by mysql_rm_db()
114
static inline void write_to_binlog(Session *session, char *query, uint32_t query_length, char *, uint32_t)
116
(void)replicator_statement(session, query, query_length);
120
Initialize database option hash and locked database hash.
126
Must be called before any other database function is called.
133
bool my_database_names_init(void)
139
error= hash_init(&lock_db_cache, lower_case_table_names ?
140
&my_charset_bin : system_charset_info,
141
32, 0, 0, (hash_get_key) lock_db_get_key,
142
lock_db_free_element,0);
149
Return default database collation.
151
@param session Thread context.
152
@param db_name Database name.
154
@return CHARSET_INFO object. The operation always return valid character
155
set, even if the database does not exist.
158
const CHARSET_INFO *get_default_db_collation(Session *session, const char *db_name)
160
HA_CREATE_INFO db_info;
162
if (session->db != NULL && strcmp(db_name, session->db) == 0)
163
return session->db_charset;
166
db_info.default_table_charset contains valid character set
170
load_db_opt_by_name(session, db_name, &db_info);
172
return db_info.default_table_charset;
175
/* path is path to database, not schema file */
176
static int write_schema_file(Session *session,
177
const char *path, const char *name,
178
HA_CREATE_INFO *create)
181
char schema_file_tmp[FN_REFLEN];
182
string schema_file(path);
188
snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
190
schema_file.append(1, FN_LIBCHAR);
191
schema_file.append(MY_DB_OPT_FILE);
193
int fd= mkstemp(schema_file_tmp);
198
if (!create->default_table_charset)
199
create->default_table_charset= session->variables.collation_server;
202
db.set_collation(create->default_table_charset->name);
204
if (!db.SerializeToFileDescriptor(fd))
207
unlink(schema_file_tmp);
211
if (rename(schema_file_tmp, schema_file.c_str()) == -1)
221
int load_db_opt(Session *session, const char *path, HA_CREATE_INFO *create)
226
memset(create, 0, sizeof(*create));
227
create->default_table_charset= session->variables.collation_server;
229
int fd= open(path, O_RDONLY);
234
if (!db.ParseFromFileDescriptor(fd))
241
buffer= db.collation();
242
if (!(create->default_table_charset= get_charset_by_name(buffer.c_str())))
244
errmsg_printf(ERRMSG_LVL_ERROR,
245
_("Error while loading database options: '%s':"),path);
246
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
247
create->default_table_charset= default_charset_info;
254
int load_db_opt_by_name(Session *session, const char *db_name,
255
HA_CREATE_INFO *db_create_info)
257
char db_opt_path[FN_REFLEN];
260
Pass an empty file name, and the database options file name as extension
261
to avoid table name to file name encoding.
263
(void) build_table_filename(db_opt_path, sizeof(db_opt_path),
264
db_name, "", MY_DB_OPT_FILE, 0);
266
return load_db_opt(session, db_opt_path, db_create_info);
83
bool mysql_create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
294
int mysql_create_db(Session *session, char *db, HA_CREATE_INFO *create_info, bool silent)
85
TransactionServices &transaction_services= TransactionServices::singleton();
296
char path[FN_REFLEN+16];
297
char tmp_query[FN_REFLEN+16];
300
uint32_t create_options= create_info ? create_info->options : 0;
303
/* do not create 'information_schema' db */
304
if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.c_str()))
306
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
89
311
Do not create database if another thread is holding read lock.
90
Wait for global read lock before acquiring LOCK_create_db.
312
Wait for global read lock before acquiring LOCK_drizzleclient_create_db.
91
313
After wait_if_global_read_lock() we have protection against another
92
global read lock. If we would acquire LOCK_create_db first,
314
global read lock. If we would acquire LOCK_drizzleclient_create_db first,
93
315
another thread could step in and get the global read lock before we
94
316
reach wait_if_global_read_lock(). If this thread tries the same as we
95
(admin a db), it would then go and wait on LOCK_create_db...
317
(admin a db), it would then go and wait on LOCK_drizzleclient_create_db...
96
318
Furthermore wait_if_global_read_lock() checks if the current thread
97
319
has the global read lock and refuses the operation with
98
320
ER_CANT_UPDATE_WITH_READLOCK if applicable.
100
322
if (wait_if_global_read_lock(session, 0, 1))
105
assert(schema_message.has_name());
106
assert(schema_message.has_collation());
108
// @todo push this lock down into the engine
109
pthread_mutex_lock(&LOCK_create_db);
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());
328
pthread_mutex_lock(&LOCK_drizzleclient_create_db);
330
/* Check directory */
331
path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
332
path[path_len-1]= 0; // Remove last '/' from path
334
if (mkdir(path,0777) == -1)
338
if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
340
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
344
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
345
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
352
my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
357
error= write_schema_file(session, path, db, create_info);
358
if (error && error != EEXIST)
360
if (rmdir(path) >= 0)
370
uint32_t query_length;
372
if (!session->query) // Only in replication
375
query_length= sprintf(tmp_query, "create database `%s`", db);
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());
379
query= session->query;
380
query_length= session->query_length;
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);
383
(void)replicator_statement(session, query, query_length);
384
session->my_ok(result);
388
pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
140
389
start_waiting_global_read_lock(session);
146
395
/* db-name is already validated when we come here */
148
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
397
bool mysql_alter_db(Session *session, const char *db, HA_CREATE_INFO *create_info)
150
TransactionServices &transaction_services= TransactionServices::singleton();
401
char path[FN_REFLEN+16];
153
405
Do not alter database if another thread is holding read lock.
154
Wait for global read lock before acquiring LOCK_create_db.
406
Wait for global read lock before acquiring LOCK_drizzleclient_create_db.
155
407
After wait_if_global_read_lock() we have protection against another
156
global read lock. If we would acquire LOCK_create_db first,
408
global read lock. If we would acquire LOCK_drizzleclient_create_db first,
157
409
another thread could step in and get the global read lock before we
158
410
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...
411
(admin a db), it would then go and wait on LOCK_drizzleclient_create_db...
160
412
Furthermore wait_if_global_read_lock() checks if the current thread
161
413
has the global read lock and refuses the operation with
162
414
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());
416
if ((error=wait_if_global_read_lock(session,0,1)))
419
pthread_mutex_lock(&LOCK_drizzleclient_create_db);
176
421
/* 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);
422
path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
423
path[path_len-1]= 0; // Remove last '/' from path
425
error= write_schema_file(session, path, db, create_info);
426
if (error && error != EEXIST)
428
/* TODO: find some witty way of getting back an error message */
429
pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
433
if (session->db && !strcmp(session->db,db))
435
session->db_charset= create_info->default_table_charset ?
436
create_info->default_table_charset :
437
session->variables.collation_server;
438
session->variables.collation_database= session->db_charset;
441
(void)replicator_statement(session, session->query, session->query_length);
442
session->my_ok(result);
444
pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
190
445
start_waiting_global_read_lock(session);
213
bool mysql_rm_db(Session *session, SchemaIdentifier &schema_identifier, const bool if_exists)
468
bool mysql_rm_db(Session *session,char *db,bool if_exists, bool silent)
216
471
int error= false;
217
plugin::TableNameList dropped_tables;
218
message::Schema schema_proto;
472
char path[FN_REFLEN+16];
475
TableList* dropped_tables= 0;
477
if (db && (strcmp(db, "information_schema") == 0))
479
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
221
484
Do not drop database if another thread is holding read lock.
222
Wait for global read lock before acquiring LOCK_create_db.
485
Wait for global read lock before acquiring LOCK_drizzleclient_create_db.
223
486
After wait_if_global_read_lock() we have protection against another
224
global read lock. If we would acquire LOCK_create_db first,
487
global read lock. If we would acquire LOCK_drizzleclient_create_db first,
225
488
another thread could step in and get the global read lock before we
226
489
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...
490
(admin a db), it would then go and wait on LOCK_drizzleclient_create_db...
228
491
Furthermore wait_if_global_read_lock() checks if the current thread
229
492
has the global read lock and refuses the operation with
230
493
ER_CANT_UPDATE_WITH_READLOCK if applicable.
232
495
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))
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());
501
pthread_mutex_lock(&LOCK_drizzleclient_create_db);
503
length= build_table_filename(path, sizeof(path), db, "", "", 0);
504
strcpy(path+length, MY_DB_OPT_FILE); // Append db option file name
506
path[length]= '\0'; // Remove file name
508
/* See if the directory exists */
509
if (!(dirp= my_dir(path,MYF(MY_DONT_SORT))))
263
my_error(ER_DB_DROP_EXISTS, MYF(0), schema_identifier.getSQLPath().c_str());
514
my_error(ER_DB_DROP_EXISTS, MYF(0), db);
518
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
519
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
269
pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
270
remove_db_from_cache(schema_identifier);
523
pthread_mutex_lock(&LOCK_open);
524
remove_db_from_cache(db);
271
525
pthread_mutex_unlock(&LOCK_open);
275
deleted= mysql_rm_known_files(session, schema_identifier, dropped_tables);
529
if ((deleted= mysql_rm_known_files(session, dirp, db, path, 0,
530
&dropped_tables)) >= 0)
532
ha_drop_database(path);
536
if (!silent && deleted>=0)
283
assert(! session->query.empty());
285
TransactionServices &transaction_services= TransactionServices::singleton();
286
transaction_services.dropSchema(session, schema_identifier.getSchemaName());
539
uint32_t query_length;
542
/* The client used the old obsolete mysql_drop_db() call */
544
query_length= sprintf(path, "drop database `%s`", db);
548
query= session->query;
549
query_length= session->query_length;
551
(void)replicator_statement(session, session->query, session->query_length);
287
552
session->clear_error();
288
553
session->server_status|= SERVER_STATUS_DB_DROPPED;
289
554
session->my_ok((uint32_t) deleted);
294
559
char *query, *query_pos, *query_end, *query_data_start;
296
563
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
297
564
goto exit; /* not much else we can do */
298
565
query_pos= query_data_start= strcpy(query,"drop table ")+11;
299
566
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();
569
for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
306
571
uint32_t tbl_name_len;
308
573
/* 3 for the quotes and the comma*/
309
tbl_name_len= (*it).length() + 3;
574
tbl_name_len= strlen(tbl->table_name) + 3;
310
575
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);
577
/* These DDL methods and logging protected with LOCK_drizzleclient_create_db */
578
write_to_binlog(session, query, query_pos -1 - query, db, db_len);
314
579
query_pos= query_data_start;
317
582
*query_pos++ = '`';
318
query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
583
query_pos= strcpy(query_pos,tbl->table_name) + (tbl_name_len-3);
319
584
*query_pos++ = '`';
320
585
*query_pos++ = ',';
323
588
if (query_pos != query_data_start)
325
/* These DDL methods and logging protected with LOCK_create_db */
326
transaction_services.rawStatement(session, query);
590
/* These DDL methods and logging protected with LOCK_drizzleclient_create_db */
591
write_to_binlog(session, query, query_pos -1 - query, db, db_len);
334
599
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);
602
if (session->db && !strcmp(session->db, db))
603
mysql_change_db_impl(session, NULL, session->variables.collation_server);
604
pthread_mutex_unlock(&LOCK_drizzleclient_create_db);
340
605
start_waiting_global_read_lock(session);
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;
488
612
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)
615
static long mysql_rm_known_files(Session *session, MY_DIR *dirp, const char *db,
616
const char *org_path, uint32_t level,
617
TableList **dropped_tables)
496
TableList *tot_list= NULL, **tot_list_next;
620
uint32_t found_other_files=0;
621
char filePath[FN_REFLEN];
622
TableList *tot_list=0, **tot_list_next;
498
624
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());
626
for (uint32_t idx=0 ;
627
idx < (uint32_t) dirp->number_off_files && !session->killed ;
630
FILEINFO *file=dirp->dir_entry+idx;
633
/* skiping . and .. */
634
if (file->name[0] == '.' && (!file->name[1] ||
635
(file->name[1] == '.' && !file->name[2])))
638
if (!(extension= strrchr(file->name, '.')))
639
extension= strchr(file->name, '\0');
640
if (find_type(extension, &deletable_extentions,1+2) <= 0)
645
strange checking for magic extensions that are then deleted if
646
not reg_ext (i.e. .frm).
648
and (previously) we'd err out on drop database if files not matching
649
engine ha_known_exts() or deletable_extensions were present.
651
presumably this was to avoid deleting other user data... except if that
652
data happened to be in files ending in .BAK, .opt or .TMD. *fun*
654
find_type(extension, ha_known_exts(),1+2);
657
/* just for safety we use files_charset_info */
658
if (db && !my_strcasecmp(files_charset_info,
661
uint32_t db_len= strlen(db);
663
/* Drop the table nicely */
664
*extension= 0; // Remove extension
665
TableList *table_list=(TableList*)
666
session->calloc(sizeof(*table_list) +
668
MYSQL50_TABLE_NAME_PREFIX_LENGTH +
669
strlen(file->name) + 1);
673
table_list->db= (char*) (table_list+1);
674
table_list->table_name= strcpy(table_list->db, db) + db_len + 1;
675
filename_to_tablename(file->name, table_list->table_name,
676
MYSQL50_TABLE_NAME_PREFIX_LENGTH +
677
strlen(file->name) + 1);
678
table_list->alias= table_list->table_name; // If lower_case_table_names=2
679
table_list->internal_tmp_table= is_prefix(file->name, TMP_FILE_PREFIX);
681
(*tot_list_next)= table_list;
682
tot_list_next= &table_list->next_local;
687
sprintf(filePath, "%s/%s", org_path, file->name);
688
if (my_delete_with_symlink(filePath,MYF(MY_WME)))
694
if (session->killed ||
695
(tot_list && mysql_rm_table_part2(session, tot_list, 1, 0, 1)))
701
*dropped_tables= tot_list;
704
If the directory is a symbolic link, remove the link first, then
705
remove the directory the symbolic link pointed at
707
if (found_other_files)
709
my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST);
714
/* Don't give errors if we can't delete 'RAID' directory */
715
if (rm_dir_w_symlink(org_path, level == 0))
728
Remove directory with symlink
732
org_path path of derictory
733
send_error send errors
739
static bool rm_dir_w_symlink(const char *org_path, bool send_error)
741
char tmp_path[FN_REFLEN], *pos;
742
char *path= tmp_path;
743
unpack_filename(tmp_path, org_path);
746
char tmp2_path[FN_REFLEN];
748
/* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
749
pos= strchr(path, '\0');
750
if (pos > path && pos[-1] == FN_LIBCHAR)
753
if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)
757
if (my_delete(path, MYF(send_error ? MY_WME : 0)))
761
/* Delete directory symbolic link pointed at */
765
/* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
766
pos= strchr(path, '\0');
768
if (pos > path && pos[-1] == FN_LIBCHAR)
770
if (rmdir(path) < 0 && send_error)
772
my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
780
@brief Internal implementation: switch current database to a valid one.
782
@param session Thread context.
783
@param new_db_name Name of the database to switch to. The function will
784
take ownership of the name (the caller must not free
785
the allocated memory). If the name is NULL, we're
786
going to switch to NULL db.
787
@param new_db_charset Character set of the new database.
790
static void mysql_change_db_impl(Session *session,
791
LEX_STRING *new_db_name,
792
const CHARSET_INFO * const new_db_charset)
794
/* 1. Change current database in Session. */
796
if (new_db_name == NULL)
799
Session::set_db() does all the job -- it frees previous database name and
803
session->set_db(NULL, 0);
805
else if (my_strcasecmp(system_charset_info, new_db_name->str,
806
INFORMATION_SCHEMA_NAME.c_str()) == 0)
809
Here we must use Session::set_db(), because we want to copy
810
INFORMATION_SCHEMA_NAME constant.
813
session->set_db(INFORMATION_SCHEMA_NAME.c_str(),
814
INFORMATION_SCHEMA_NAME.length());
819
Here we already have a copy of database name to be used in Session. So,
820
we just call Session::reset_db(). Since Session::reset_db() does not releases
821
the previous database name, we should do it explicitly.
827
session->reset_db(new_db_name->str, new_db_name->length);
830
/* 3. Update db-charset environment variables. */
832
session->db_charset= new_db_charset;
833
session->variables.collation_database= new_db_charset;
839
Backup the current database name before switch.
841
@param[in] session thread handle
842
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
843
the old database name, "length" contains the
845
OUT: if the current (default) database is
846
not NULL, its name is copied to the
847
buffer pointed at by "str"
848
and "length" is updated accordingly.
849
Otherwise "str" is set to NULL and
850
"length" is set to 0.
853
static void backup_current_db_name(Session *session,
854
LEX_STRING *saved_db_name)
858
/* No current (default) database selected. */
860
saved_db_name->str= NULL;
861
saved_db_name->length= 0;
865
strncpy(saved_db_name->str, session->db, saved_db_name->length - 1);
866
saved_db_name->length= session->db_length;
872
Return true if db1_name is equal to db2_name, false otherwise.
874
The function allows to compare database names according to the MySQL
875
rules. The database names db1 and db2 are equal if:
876
- db1 is NULL and db2 is NULL;
878
- db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
879
db2 in system character set (UTF8).
883
cmp_db_names(const char *db1_name,
884
const char *db2_name)
887
/* db1 is NULL and db2 is NULL */
888
(!db1_name && !db2_name) ||
890
/* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
891
(db1_name && db2_name && my_strcasecmp(system_charset_info, db1_name, db2_name) == 0);
550
896
@brief Change the current database and its attributes unconditionally.
608
954
@retval true Error
611
bool mysql_change_db(Session *session, SchemaIdentifier &schema_identifier)
957
bool mysql_change_db(Session *session, const LEX_STRING *new_db_name, bool force_switch)
614
if (not plugin::Authorization::isAuthorized(session->getSecurityContext(), schema_identifier))
616
/* Error message is set in isAuthorized */
620
if (not check_db_name(schema_identifier))
622
my_error(ER_WRONG_DB_NAME, MYF(0), schema_identifier.getSQLPath().c_str());
627
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
629
/* Report an error and free new_db_file_name. */
631
my_error(ER_BAD_DB_ERROR, MYF(0), schema_identifier.getSQLPath().c_str());
633
/* The operation failed. */
638
mysql_change_db_impl(session, schema_identifier);
959
LEX_STRING new_db_file_name;
960
const CHARSET_INFO *db_default_cl;
962
if (new_db_name == NULL ||
963
new_db_name->length == 0)
968
This can happen only if we're switching the current database back
969
after loading stored program. The thing is that loading of stored
970
program can happen when there is no current database.
972
TODO: actually, new_db_name and new_db_name->str seem to be always
973
non-NULL. In case of stored program, new_db_name->str == "" and
974
new_db_name->length == 0.
977
mysql_change_db_impl(session, NULL, session->variables.collation_server);
983
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
989
if (my_strcasecmp(system_charset_info, new_db_name->str,
990
INFORMATION_SCHEMA_NAME.c_str()) == 0)
992
/* Switch the current database to INFORMATION_SCHEMA. */
993
/* const_cast<> is safe here: mysql_change_db_impl does a copy */
994
LEX_STRING is_name= { const_cast<char *>(INFORMATION_SCHEMA_NAME.c_str()),
995
INFORMATION_SCHEMA_NAME.length() };
996
mysql_change_db_impl(session, &is_name, system_charset_info);
1002
Now we need to make a copy because check_db_name requires a
1003
non-constant argument. Actually, it takes database file name.
1005
TODO: fix check_db_name().
1008
new_db_file_name.length= new_db_name->length;
1009
new_db_file_name.str= (char *)malloc(new_db_name->length + 1);
1010
if (new_db_file_name.str == NULL)
1011
return(true); /* the error is set */
1012
memcpy(new_db_file_name.str, new_db_name->str, new_db_name->length);
1013
new_db_file_name.str[new_db_name->length]= 0;
1017
NOTE: if check_db_name() fails, we should throw an error in any case,
1018
even if we are called from sp_head::execute().
1020
It's next to impossible however to get this error when we are called
1021
from sp_head::execute(). But let's switch the current database to NULL
1022
in this case to be sure.
1025
if (check_db_name(&new_db_file_name))
1027
my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
1028
free(new_db_file_name.str);
1031
mysql_change_db_impl(session, NULL, session->variables.collation_server);
1036
if (check_db_dir_existence(new_db_file_name.str))
1040
/* Throw a warning and free new_db_file_name. */
1042
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1043
ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
1044
new_db_file_name.str);
1046
free(new_db_file_name.str);
1048
/* Change db to NULL. */
1050
mysql_change_db_impl(session, NULL, session->variables.collation_server);
1052
/* The operation succeed. */
1058
/* Report an error and free new_db_file_name. */
1060
my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
1061
free(new_db_file_name.str);
1063
/* The operation failed. */
1070
NOTE: in mysql_change_db_impl() new_db_file_name is assigned to Session
1071
attributes and will be freed in Session::~Session().
1074
db_default_cl= get_default_db_collation(session, new_db_file_name.str);
1076
mysql_change_db_impl(session, &new_db_file_name, db_default_cl);
644
@brief Internal implementation: switch current database to a valid one.
646
@param session Thread context.
647
@param new_db_name Name of the database to switch to. The function will
648
take ownership of the name (the caller must not free
649
the allocated memory). If the name is NULL, we're
650
going to switch to NULL db.
651
@param new_db_charset Character set of the new database.
654
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier)
656
/* 1. Change current database in Session. */
659
if (new_db_name == NULL)
662
Session::set_db() does all the job -- it frees previous database name and
666
session->set_db(NULL, 0);
672
Here we already have a copy of database name to be used in Session. So,
673
we just call Session::reset_db(). Since Session::reset_db() does not releases
674
the previous database name, we should do it explicitly.
677
session->set_db(schema_identifier.getLower());
681
static void mysql_change_db_impl(Session *session)
683
session->set_db(string());
686
} /* namespace drizzled */
1083
Change the current database and its attributes if needed.
1085
@param session thread handle
1086
@param new_db_name database name
1087
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
1088
the old database name, "length" contains the
1090
OUT: if the current (default) database is
1091
not NULL, its name is copied to the
1092
buffer pointed at by "str"
1093
and "length" is updated accordingly.
1094
Otherwise "str" is set to NULL and
1095
"length" is set to 0.
1096
@param force_switch @see mysql_change_db()
1097
@param[out] cur_db_changed out-flag to indicate whether the current
1098
database has been changed (valid only if
1099
the function suceeded)
1102
bool mysql_opt_change_db(Session *session,
1103
const LEX_STRING *new_db_name,
1104
LEX_STRING *saved_db_name,
1106
bool *cur_db_changed)
1108
*cur_db_changed= !cmp_db_names(session->db, new_db_name->str);
1110
if (!*cur_db_changed)
1113
backup_current_db_name(session, saved_db_name);
1115
return mysql_change_db(session, new_db_name, force_switch);
1120
Check if there is directory for the database name.
1123
check_db_dir_existence()
1124
db_name database name
1127
false There is directory for the specified database name.
1128
true The directory does not exist.
1131
bool check_db_dir_existence(const char *db_name)
1133
char db_dir_path[FN_REFLEN];
1134
uint32_t db_dir_path_len;
1136
db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
1137
db_name, "", "", 0);
1139
if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
1140
db_dir_path[db_dir_path_len - 1]= 0;
1144
return my_access(db_dir_path, F_OK);