38
38
#include <drizzled/replication_services.h>
39
39
#include <drizzled/message/schema.pb.h>
40
40
#include "drizzled/sql_table.h"
41
#include "drizzled/plugin/info_schema_table.h"
41
#include "drizzled/plugin/storage_engine.h"
42
#include "drizzled/plugin/authorization.h"
42
43
#include "drizzled/global_charset_info.h"
43
44
#include "drizzled/pthread_globals.h"
44
45
#include "drizzled/charset.h"
46
47
#include "drizzled/internal/my_sys.h"
48
#define MY_DB_OPT_FILE "db.opt"
49
49
#define MAX_DROP_TABLE_Q_LEN 1024
51
51
using namespace std;
56
const string del_exts[]= {".dfe", ".blk", ".arz", ".BAK", ".TMD", ".opt"};
57
static set<string> deletable_extentions(del_exts, &del_exts[sizeof(del_exts)/sizeof(del_exts[0])]);
60
static long mysql_rm_known_files(Session *session, CachedDirectory &dirp,
56
static long mysql_rm_known_files(Session *session,
61
57
const string &db, const char *path,
62
TableList **dropped_tables);
58
plugin::TableNameList &dropped_tables);
63
59
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name);
66
Return default database collation.
68
@param session Thread context.
69
@param db_name Database name.
71
@return CHARSET_INFO object. The operation always return valid character
72
set, even if the database does not exist.
75
const CHARSET_INFO *get_default_db_collation(const char *db_name)
79
get_database_metadata(db_name, &db);
81
/* If for some reason the db.opt file lacks a collation,
82
we just return the default */
84
if (db.has_collation())
86
const string buffer= db.collation();
87
const CHARSET_INFO* cs= get_charset_by_name(buffer.c_str());
91
errmsg_printf(ERRMSG_LVL_ERROR,
92
_("Error while loading database options: '%s':"),db_name);
93
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
95
return default_charset_info;
101
return default_charset_info;
104
/* path is path to database, not schema file */
105
static int write_schema_file(const char *path, const message::Schema &db)
107
char schema_file_tmp[FN_REFLEN];
108
string schema_file(path);
110
snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
112
schema_file.append(1, FN_LIBCHAR);
113
schema_file.append(MY_DB_OPT_FILE);
115
int fd= mkstemp(schema_file_tmp);
121
if (!db.SerializeToFileDescriptor(fd))
124
unlink(schema_file_tmp);
128
if (rename(schema_file_tmp, schema_file.c_str()) == -1)
138
int get_database_metadata(const char *dbname, message::Schema *db)
140
char db_opt_path[FN_REFLEN];
144
Pass an empty file name, and the database options file name as extension
145
to avoid table name to file name encoding.
147
length= build_table_filename(db_opt_path, sizeof(db_opt_path),
149
strcpy(db_opt_path + length, MY_DB_OPT_FILE);
151
int fd= open(db_opt_path, O_RDONLY);
156
if (!db->ParseFromFileDescriptor(fd))
187
bool mysql_create_db(Session *session, const char *db, message::Schema *schema_message, bool is_if_not_exists)
82
bool mysql_create_db(Session *session, const message::Schema &schema_message, const bool is_if_not_exists)
189
84
ReplicationServices &replication_services= ReplicationServices::singleton();
192
85
bool error= false;
194
/* do not create 'information_schema' db */
195
if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.c_str()))
197
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
201
schema_message->set_name(db);
204
88
Do not create database if another thread is holding read lock.
205
89
Wait for global read lock before acquiring LOCK_create_db.
215
99
if (wait_if_global_read_lock(session, 0, 1))
104
assert(schema_message.has_name());
105
assert(schema_message.has_collation());
107
// @todo push this lock down into the engine
221
108
pthread_mutex_lock(&LOCK_create_db);
223
/* check directory */
224
char path[FN_REFLEN+16];
226
path_len= build_table_filename(path, sizeof(path), db, "", false);
227
path[path_len-1]= 0; // remove last '/' from path
229
if (mkdir(path, 0777) == -1)
110
// Check to see if it exists already.
111
if (plugin::StorageEngine::doesSchemaExist(schema_message.name()))
233
if (! is_if_not_exists)
235
my_error(ER_DB_CREATE_EXISTS, MYF(0), path);
113
if (not is_if_not_exists)
115
my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
239
120
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
240
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
121
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
122
schema_message.name().c_str());
242
123
session->my_ok();
247
my_error(ER_CANT_CREATE_DB, MYF(0), path, errno);
252
error_erno= write_schema_file(path, *schema_message);
253
if (error_erno && error_erno != EEXIST)
255
if (rmdir(path) >= 0)
264
replication_services.rawStatement(session, session->query, session->query_length);
265
session->my_ok(result);
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);
268
137
pthread_mutex_unlock(&LOCK_create_db);
269
138
start_waiting_global_read_lock(session);
275
144
/* db-name is already validated when we come here */
277
bool mysql_alter_db(Session *session, const char *db, message::Schema *schema_message)
146
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
279
148
ReplicationServices &replication_services= ReplicationServices::singleton();
282
char path[FN_REFLEN+16];
286
151
Do not alter database if another thread is holding read lock.
294
159
has the global read lock and refuses the operation with
295
160
ER_CANT_UPDATE_WITH_READLOCK if applicable.
297
if ((error=wait_if_global_read_lock(session,0,1)))
300
assert(schema_message);
302
schema_message->set_name(db);
162
if ((wait_if_global_read_lock(session, 0, 1)))
304
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());
306
173
/* Change options if current database is being altered. */
307
path_len= build_table_filename(path, sizeof(path), db, "", false);
308
path[path_len-1]= 0; // Remove last '/' from path
310
error= write_schema_file(path, *schema_message);
311
if (error && error != EEXIST)
313
/* TODO: find some witty way of getting back an error message */
314
pthread_mutex_unlock(&LOCK_create_db);
318
replication_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
319
session->my_ok(result);
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());
321
186
pthread_mutex_unlock(&LOCK_create_db);
322
187
start_waiting_global_read_lock(session);
324
return error ? true : false;
345
bool mysql_rm_db(Session *session, char *db, bool if_exists)
210
bool mysql_rm_db(Session *session, const std::string &schema_name, const bool if_exists)
348
213
int error= false;
349
214
char path[FN_REFLEN+16];
351
TableList *dropped_tables= NULL;
353
if (db && (strcmp(db, "information_schema") == 0))
355
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.c_str());
216
plugin::TableNameList dropped_tables;
217
message::Schema schema_proto;
361
220
Do not drop database if another thread is holding read lock.
377
236
pthread_mutex_lock(&LOCK_create_db);
379
239
length= build_table_filename(path, sizeof(path),
381
strcpy(path+length, MY_DB_OPT_FILE); // Append db option file name
240
schema_name.c_str(), "", false);
383
241
path[length]= '\0'; // Remove file name
385
/* See if the directory exists */
386
CachedDirectory dirp(path);
243
/* See if the schema exists */
244
if (not plugin::StorageEngine::doesSchemaExist(schema_name))
248
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
249
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
392
255
my_error(ER_DB_DROP_EXISTS, MYF(0), path);
396
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
397
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
402
261
pthread_mutex_lock(&LOCK_open); /* After deleting database, remove all cache entries related to schema */
403
remove_db_from_cache(db);
262
remove_db_from_cache(schema_name);
404
263
pthread_mutex_unlock(&LOCK_open);
408
deleted= mysql_rm_known_files(session, dirp, db,
409
path, &dropped_tables);
267
deleted= mysql_rm_known_files(session, schema_name,
268
path, dropped_tables);
410
269
if (deleted >= 0)
412
plugin::StorageEngine::dropDatabase(path);
416
274
if (deleted >= 0)
419
uint32_t query_length;
421
assert(session->query);
423
query= session->query;
424
query_length= session->query_length;
276
assert(! session->query.empty());
426
278
ReplicationServices &replication_services= ReplicationServices::singleton();
427
replication_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
279
replication_services.dropSchema(session, schema_name);
428
280
session->clear_error();
429
281
session->server_status|= SERVER_STATUS_DB_DROPPED;
430
282
session->my_ok((uint32_t) deleted);
435
287
char *query, *query_pos, *query_end, *query_data_start;
439
290
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
440
291
goto exit; /* not much else we can do */
441
292
query_pos= query_data_start= strcpy(query,"drop table ")+11;
442
293
query_end= query + MAX_DROP_TABLE_Q_LEN;
294
db_len= schema_name.length();
445
296
ReplicationServices &replication_services= ReplicationServices::singleton();
446
for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
297
for (plugin::TableNameList::iterator it= dropped_tables.begin();
298
it != dropped_tables.end();
448
301
uint32_t tbl_name_len;
450
303
/* 3 for the quotes and the comma*/
451
tbl_name_len= strlen(tbl->table_name) + 3;
304
tbl_name_len= (*it).length() + 3;
452
305
if (query_pos + tbl_name_len + 1 >= query_end)
454
307
/* These DDL methods and logging protected with LOCK_create_db */
455
replication_services.rawStatement(session, query, (size_t) (query_pos -1 - query));
308
replication_services.rawStatement(session, query);
456
309
query_pos= query_data_start;
459
312
*query_pos++ = '`';
460
query_pos= strcpy(query_pos,tbl->table_name) + (tbl_name_len-3);
313
query_pos= strcpy(query_pos, (*it).c_str()) + (tbl_name_len-3);
461
314
*query_pos++ = '`';
462
315
*query_pos++ = ',';
560
TableIdentifier identifier(db, table->table_name, table->internal_tmp_table ? INTERNAL_TMP_TABLE : NO_TMP_TABLE);
414
TableIdentifier identifier(db, table->table_name);
562
if ((table_type == NULL
563
&& (plugin::StorageEngine::getTableDefinition(*session,
564
identifier) != EEXIST)))
416
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
566
418
// Table was not found on disk and table can't be created from engine
567
419
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
629
479
session MUST be set when calling this function!
632
static long mysql_rm_known_files(Session *session, CachedDirectory &dirp,
482
static long mysql_rm_known_files(Session *session,
633
483
const string &db,
634
484
const char *org_path,
635
TableList **dropped_tables)
485
plugin::TableNameList &dropped_tables)
487
CachedDirectory dirp(org_path);
640
char filePath[FN_REFLEN];
641
492
TableList *tot_list= NULL, **tot_list_next;
643
494
tot_list_next= &tot_list;
645
for (CachedDirectory::Entries::const_iterator iter= dirp.getEntries().begin();
646
iter != dirp.getEntries().end() && !session->killed;
496
plugin::StorageEngine::getTableNames(db, dropped_tables);
498
for (plugin::TableNameList::iterator it= dropped_tables.begin();
499
it != dropped_tables.end();
649
string filename((*iter)->filename);
651
/* skiping . and .. */
652
if (filename[0] == '.' && (!filename[1] ||
653
(filename[1] == '.' && !filename[2])))
656
string extension("");
657
size_t ext_pos= filename.rfind('.');
658
if (ext_pos != string::npos)
660
extension= filename.substr(ext_pos);
662
if (deletable_extentions.find(extension) == deletable_extentions.end())
667
strange checking for magic extensions that are then deleted if
668
not reg_ext (i.e. .frm).
670
and (previously) we'd err out on drop database if files not matching
671
engine ha_known_exts() or deletable_extensions were present.
673
presumably this was to avoid deleting other user data... except if that
674
data happened to be in files ending in .BAK, .opt or .TMD. *fun*
678
/* just for safety we use files_charset_info */
679
if (!my_strcasecmp(files_charset_info, extension.c_str(), ".dfe"))
681
size_t db_len= db.size();
683
/* Drop the table nicely */
684
filename.erase(ext_pos);
685
TableList *table_list=(TableList*)
686
session->calloc(sizeof(*table_list) +
688
filename.size() + 1);
692
table_list->db= (char*) (table_list+1);
693
table_list->table_name= strcpy(table_list->db, db.c_str()) + db_len + 1;
694
filename_to_tablename(filename.c_str(), table_list->table_name,
695
filename.size() + 1);
696
table_list->alias= table_list->table_name; // If lower_case_table_names=2
697
table_list->internal_tmp_table= (strncmp(filename.c_str(),
699
strlen(TMP_FILE_PREFIX)) == 0);
701
(*tot_list_next)= table_list;
702
tot_list_next= &table_list->next_local;
707
sprintf(filePath, "%s/%s", org_path, filename.c_str());
708
if (internal::my_delete_with_symlink(filePath,MYF(MY_WME)))
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;
714
526
if (session->killed)
794
603
@retval true Error
797
bool mysql_change_db(Session *session, const LEX_STRING *new_db_name, bool force_switch)
606
bool mysql_change_db(Session *session, const std::string &new_db_name)
799
LEX_STRING new_db_file_name;
800
const CHARSET_INFO *db_default_cl;
803
assert(new_db_name->length);
805
if (my_strcasecmp(system_charset_info, new_db_name->str,
806
INFORMATION_SCHEMA_NAME.c_str()) == 0)
609
assert(not new_db_name.empty());
611
if (not plugin::Authorization::isAuthorized(session->getSecurityContext(),
808
/* Switch the current database to INFORMATION_SCHEMA. */
809
/* const_cast<> is safe here: mysql_change_db_impl does a copy */
810
LEX_STRING is_name= { const_cast<char *>(INFORMATION_SCHEMA_NAME.c_str()),
811
INFORMATION_SCHEMA_NAME.length() };
812
mysql_change_db_impl(session, &is_name);
614
/* Error message is set in isAuthorized */
818
620
Now we need to make a copy because check_db_name requires a
819
621
non-constant argument. Actually, it takes database file name.
821
623
TODO: fix check_db_name().
824
new_db_file_name.length= new_db_name->length;
825
new_db_file_name.str= (char *)malloc(new_db_name->length + 1);
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);
826
629
if (new_db_file_name.str == NULL)
827
630
return true; /* the error is set */
828
memcpy(new_db_file_name.str, new_db_name->str, new_db_name->length);
829
new_db_file_name.str[new_db_name->length]= 0;
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;
843
646
my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
844
647
free(new_db_file_name.str);
847
mysql_change_db_impl(session, NULL);
852
if (check_db_dir_existence(new_db_file_name.str))
652
if (not plugin::StorageEngine::doesSchemaExist(new_db_file_name.str))
856
/* Throw a warning and free new_db_file_name. */
858
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
859
ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
860
new_db_file_name.str);
862
free(new_db_file_name.str);
864
/* Change db to NULL. */
866
mysql_change_db_impl(session, NULL);
868
/* The operation succeed. */
874
/* Report an error and free new_db_file_name. */
876
my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
877
free(new_db_file_name.str);
879
/* The operation failed. */
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);
659
/* The operation failed. */
885
db_default_cl= get_default_db_collation(new_db_file_name.str);
887
664
mysql_change_db_impl(session, &new_db_file_name);
888
665
free(new_db_file_name.str);
894
Check if there is directory for the database name.
897
check_db_dir_existence()
898
db_name database name
901
false There is directory for the specified database name.
902
true The directory does not exist.
905
bool check_db_dir_existence(const char *db_name)
907
char db_dir_path[FN_REFLEN];
908
uint32_t db_dir_path_len;
910
db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
913
if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
914
db_dir_path[db_dir_path_len - 1]= 0;
918
return access(db_dir_path, F_OK);
922
671
@brief Internal implementation: switch current database to a valid one.