12
12
You should have received a copy of the GNU General Public License
13
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
17
/* create and drop of databases */
22
#include <sys/types.h>
18
#include <drizzled/global.h>
28
23
#include <drizzled/message/schema.pb.h>
29
#include "drizzled/error.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
36
#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 <boost/thread/mutex.hpp>
49
boost::mutex LOCK_create_db;
51
#include "drizzled/internal/my_sys.h"
38
extern drizzled::TransactionServices transaction_services;
40
#define MY_DB_OPT_FILE "db.opt"
53
41
#define MAX_DROP_TABLE_Q_LEN 1024
60
static long drop_tables_via_filenames(Session *session,
61
SchemaIdentifier &schema_identifier,
62
TableIdentifier::vector &dropped_tables);
63
static void mysql_change_db_impl(Session *session);
64
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier);
43
const char *del_exts[]= {".dfe", ".BAK", ".TMD",".opt", NULL};
44
static TYPELIB deletable_extentions=
45
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
47
static long mysql_rm_known_files(Session *session, MY_DIR *dirp,
48
const char *db, const char *path,
49
TableList **dropped_tables);
51
static bool rm_dir_w_symlink(const char *org_path);
52
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name);
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
Initialize database option hash and locked database hash.
117
Must be called before any other database function is called.
124
bool my_database_names_init(void)
130
error= hash_init(&lock_db_cache, lower_case_table_names ?
131
&my_charset_bin : system_charset_info,
132
32, 0, 0, (hash_get_key) lock_db_get_key,
133
lock_db_free_element,0);
140
Return default database collation.
142
@param session Thread context.
143
@param db_name Database name.
145
@return CHARSET_INFO object. The operation always return valid character
146
set, even if the database does not exist.
149
const CHARSET_INFO *get_default_db_collation(const char *db_name)
151
HA_CREATE_INFO db_info;
154
db_info.default_table_charset contains valid character set
158
load_db_opt_by_name(db_name, &db_info);
160
return db_info.default_table_charset;
163
/* path is path to database, not schema file */
164
static int write_schema_file(Session *session,
165
const char *path, const char *name,
166
HA_CREATE_INFO *create)
168
drizzled::message::Schema db;
169
char schema_file_tmp[FN_REFLEN];
170
string schema_file(path);
176
snprintf(schema_file_tmp, FN_REFLEN, "%s%c%s.tmpXXXXXX", path, FN_LIBCHAR, MY_DB_OPT_FILE);
178
schema_file.append(1, FN_LIBCHAR);
179
schema_file.append(MY_DB_OPT_FILE);
181
int fd= mkstemp(schema_file_tmp);
186
if (!create->default_table_charset)
187
create->default_table_charset= session->variables.collation_server;
190
db.set_collation(create->default_table_charset->name);
192
if (!db.SerializeToFileDescriptor(fd))
195
unlink(schema_file_tmp);
199
if (rename(schema_file_tmp, schema_file.c_str()) == -1)
209
int load_db_opt(const char *path, HA_CREATE_INFO *create)
211
drizzled::message::Schema db;
213
memset(create, 0, sizeof(*create));
214
create->default_table_charset= default_charset_info;
216
int fd= open(path, O_RDONLY);
221
if (!db.ParseFromFileDescriptor(fd))
228
/* If for some reason the db.opt file lacks a collation, we just return the default */
229
if (db.has_collation())
232
buffer= db.collation();
233
if (!(create->default_table_charset= get_charset_by_name(buffer.c_str())))
235
errmsg_printf(ERRMSG_LVL_ERROR,
236
_("Error while loading database options: '%s':"),path);
237
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
238
create->default_table_charset= default_charset_info;
246
int load_db_opt_by_name(const char *db_name, HA_CREATE_INFO *db_create_info)
248
char db_opt_path[FN_REFLEN];
251
Pass an empty file name, and the database options file name as extension
252
to avoid table name to file name encoding.
254
(void) build_table_filename(db_opt_path, sizeof(db_opt_path),
255
db_name, "", MY_DB_OPT_FILE, 0);
257
return load_db_opt(db_opt_path, db_create_info);
101
310
has the global read lock and refuses the operation with
102
311
ER_CANT_UPDATE_WITH_READLOCK if applicable.
104
if (session->wait_if_global_read_lock(false, true))
109
assert(schema_message.has_name());
110
assert(schema_message.has_collation());
112
// @todo push this lock down into the engine
114
boost::mutex::scoped_lock scopedLock(LOCK_create_db);
116
// Check to see if it exists already.
117
SchemaIdentifier schema_identifier(schema_message.name());
118
if (plugin::StorageEngine::doesSchemaExist(schema_identifier))
120
if (not is_if_not_exists)
122
my_error(ER_DB_CREATE_EXISTS, MYF(0), schema_message.name().c_str());
127
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
128
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS),
129
schema_message.name().c_str());
133
else if (not plugin::StorageEngine::createSchema(schema_message)) // Try to create it
135
my_error(ER_CANT_CREATE_DB, MYF(0), schema_message.name().c_str(), errno);
140
transaction_services.createSchema(session, schema_message);
144
session->startWaitingGlobalReadLock();
313
if (wait_if_global_read_lock(session, 0, 1))
319
pthread_mutex_lock(&LOCK_create_db);
321
/* Check directory */
322
path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
323
path[path_len-1]= 0; // Remove last '/' from path
325
if (mkdir(path,0777) == -1)
329
if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
331
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
335
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
336
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
343
my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
348
error= write_schema_file(session, path, db, create_info);
349
if (error && error != EEXIST)
351
if (rmdir(path) >= 0)
361
uint32_t query_length;
363
if (!session->query) // Only in replication
366
query_length= sprintf(tmp_query, "create database `%s`", db);
370
query= session->query;
371
query_length= session->query_length;
374
transaction_services.rawStatement(session, query, query_length);
375
session->my_ok(result);
379
pthread_mutex_unlock(&LOCK_create_db);
380
start_waiting_global_read_lock(session);
150
386
/* db-name is already validated when we come here */
152
bool mysql_alter_db(Session *session, const message::Schema &schema_message)
388
bool mysql_alter_db(Session *session, const char *db, HA_CREATE_INFO *create_info)
154
TransactionServices &transaction_services= TransactionServices::singleton();
392
char path[FN_REFLEN+16];
157
396
Do not alter database if another thread is holding read lock.
234
475
has the global read lock and refuses the operation with
235
476
ER_CANT_UPDATE_WITH_READLOCK if applicable.
237
if (session->wait_if_global_read_lock(false, true))
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);
256
/* See if the schema exists */
257
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
260
schema_identifier.getSQLPath(path);
264
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
265
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS),
271
my_error(ER_DB_DROP_EXISTS, MYF(0), path.c_str());
277
/* After deleting database, remove all cache entries related to schema */
278
table::Cache::singleton().removeSchema(schema_identifier);
478
if (wait_if_global_read_lock(session, 0, 1))
484
pthread_mutex_lock(&LOCK_create_db);
486
length= build_table_filename(path, sizeof(path), db, "", "", 0);
487
strcpy(path+length, MY_DB_OPT_FILE); // Append db option file name
489
path[length]= '\0'; // Remove file name
491
/* See if the directory exists */
492
if (!(dirp= my_dir(path,MYF(MY_DONT_SORT))))
282
deleted= drop_tables_via_filenames(session, schema_identifier, dropped_tables);
290
assert(not session->getQueryString()->empty());
292
TransactionServices &transaction_services= TransactionServices::singleton();
293
transaction_services.dropSchema(session, schema_identifier.getSchemaName());
294
session->clear_error();
295
session->server_status|= SERVER_STATUS_DB_DROPPED;
296
session->my_ok((uint32_t) deleted);
297
session->server_status&= ~SERVER_STATUS_DB_DROPPED;
301
char *query, *query_pos, *query_end, *query_data_start;
303
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
304
goto exit; /* not much else we can do */
305
query_pos= query_data_start= strcpy(query,"drop table ")+11;
306
query_end= query + MAX_DROP_TABLE_Q_LEN;
308
TransactionServices &transaction_services= TransactionServices::singleton();
309
for (TableIdentifier::vector::iterator it= dropped_tables.begin();
310
it != dropped_tables.end();
313
uint32_t tbl_name_len;
315
/* 3 for the quotes and the comma*/
316
tbl_name_len= (*it).getTableName().length() + 3;
317
if (query_pos + tbl_name_len + 1 >= query_end)
319
/* These DDL methods and logging protected with LOCK_create_db */
320
transaction_services.rawStatement(session, query);
321
query_pos= query_data_start;
325
query_pos= strcpy(query_pos, (*it).getTableName().c_str()) + (tbl_name_len-3);
330
if (query_pos != query_data_start)
497
my_error(ER_DB_DROP_EXISTS, MYF(0), db);
501
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
502
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
506
pthread_mutex_lock(&LOCK_open);
507
remove_db_from_cache(db);
508
pthread_mutex_unlock(&LOCK_open);
512
if ((deleted= mysql_rm_known_files(session, dirp, db, path, &dropped_tables)) >= 0)
514
ha_drop_database(path);
518
if (!silent && deleted>=0)
521
uint32_t query_length;
524
/* The client used the old obsolete mysql_drop_db() call */
526
query_length= sprintf(path, "drop database `%s`", db);
530
query= session->query;
531
query_length= session->query_length;
533
transaction_services.rawStatement(session, session->getQueryString(), session->getQueryLength());
534
session->clear_error();
535
session->server_status|= SERVER_STATUS_DB_DROPPED;
536
session->my_ok((uint32_t) deleted);
537
session->server_status&= ~SERVER_STATUS_DB_DROPPED;
541
char *query, *query_pos, *query_end, *query_data_start;
545
if (!(query= (char*) session->alloc(MAX_DROP_TABLE_Q_LEN)))
546
goto exit; /* not much else we can do */
547
query_pos= query_data_start= strcpy(query,"drop table ")+11;
548
query_end= query + MAX_DROP_TABLE_Q_LEN;
551
for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
553
uint32_t tbl_name_len;
555
/* 3 for the quotes and the comma*/
556
tbl_name_len= strlen(tbl->table_name) + 3;
557
if (query_pos + tbl_name_len + 1 >= query_end)
332
559
/* These DDL methods and logging protected with LOCK_create_db */
333
transaction_services.rawStatement(session, query);
560
transaction_services.rawStatement(session, query, (size_t) (query_pos -1 - query));
561
query_pos= query_data_start;
565
query_pos= strcpy(query_pos,tbl->table_name) + (tbl_name_len-3);
570
if (query_pos != query_data_start)
572
/* These DDL methods and logging protected with LOCK_create_db */
573
transaction_services.rawStatement(session, query, (size_t) (query_pos -1 - query));
339
If this database was the client's selected database, we silently
340
change the client's selected database to nothing (to have an empty
341
SELECT DATABASE() in the future). For this we free() session->db and set
344
if (schema_identifier.compare(*session->schema()))
345
mysql_change_db_impl(session);
348
session->startWaitingGlobalReadLock();
354
static int rm_table_part2(Session *session, TableList *tables)
356
TransactionServices &transaction_services= TransactionServices::singleton();
361
bool foreign_key_error= false;
364
table::Cache::singleton().mutex().lock(); /* Part 2 of rm a table */
366
if (session->lock_table_names_exclusively(tables))
368
table::Cache::singleton().mutex().unlock();
372
/* Don't give warnings for not found errors, as we already generate notes */
373
session->no_warnings_for_error= 1;
375
for (table= tables; table; table= table->next_local)
377
const char *db=table->getSchemaName();
378
TableIdentifier identifier(table->getSchemaName(), table->getTableName());
380
plugin::StorageEngine *table_type;
382
error= session->drop_temporary_table(identifier);
386
// removed temporary table
390
tables->unlock_table_names();
391
table::Cache::singleton().mutex().unlock();
392
session->no_warnings_for_error= 0;
396
// temporary table not found
400
table_type= table->getDbType();
404
abort_locked_tables(session, identifier);
405
table::Cache::singleton().removeTable(session, identifier,
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, identifier)))
413
table->table= locked_table;
415
if (session->getKilled())
418
tables->unlock_table_names();
419
table::Cache::singleton().mutex().unlock();
420
session->no_warnings_for_error= 0;
425
identifier.getPath();
427
if (table_type == NULL && not plugin::StorageEngine::doesTableExist(*session, identifier))
429
// Table was not found on disk and table can't be created from engine
430
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
431
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
432
table->getTableName());
436
error= plugin::StorageEngine::dropTable(*session, identifier);
438
if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE))
441
session->clear_error();
444
if (error == HA_ERR_ROW_IS_REFERENCED)
446
/* the table is referenced by a foreign key constraint */
447
foreign_key_error= true;
451
if (error == 0 || (foreign_key_error == false))
453
transaction_services.dropTable(session, string(db), string(table->getTableName()), true);
458
if (wrong_tables.length())
459
wrong_tables.append(',');
460
wrong_tables.append(String(table->getTableName(),system_charset_info));
464
It's safe to unlock table::Cache::singleton().mutex(): we have an exclusive lock
467
table::Cache::singleton().mutex().unlock();
471
if (wrong_tables.length())
473
if (not foreign_key_error)
474
my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0),
475
wrong_tables.c_ptr());
478
my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0));
484
boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex()); /* final bit in rm table lock */
485
tables->unlock_table_names();
487
session->no_warnings_for_error= 0;
579
If this database was the client's selected database, we silently
580
change the client's selected database to nothing (to have an empty
581
SELECT DATABASE() in the future). For this we free() session->db and set
584
if (session->db && !strcmp(session->db, db))
585
mysql_change_db_impl(session, NULL);
586
pthread_mutex_unlock(&LOCK_create_db);
587
start_waiting_global_read_lock(session);
494
594
session MUST be set when calling this function!
497
static long drop_tables_via_filenames(Session *session,
498
SchemaIdentifier &schema_identifier,
499
TableIdentifier::vector &dropped_tables)
597
static long mysql_rm_known_files(Session *session, MY_DIR *dirp, const char *db,
598
const char *org_path,
599
TableList **dropped_tables)
502
TableList *tot_list= NULL, **tot_list_next;
602
char filePath[FN_REFLEN];
603
TableList *tot_list=0, **tot_list_next;
504
605
tot_list_next= &tot_list;
506
plugin::StorageEngine::getIdentifiers(*session, schema_identifier, dropped_tables);
508
for (TableIdentifier::vector::iterator it= dropped_tables.begin();
509
it != dropped_tables.end();
512
size_t db_len= schema_identifier.getSchemaName().size();
514
/* Drop the table nicely */
515
TableList *table_list=(TableList*)
516
session->calloc(sizeof(*table_list) +
518
(*it).getTableName().length() + 1);
523
table_list->setSchemaName((char*) (table_list+1));
524
table_list->setTableName(strcpy((char*) (table_list+1), schema_identifier.getSchemaName().c_str()) + db_len + 1);
525
TableIdentifier::filename_to_tablename((*it).getTableName().c_str(), const_cast<char *>(table_list->getTableName()), (*it).getTableName().size() + 1);
526
table_list->alias= table_list->getTableName(); // If lower_case_table_names=2
527
table_list->setInternalTmpTable((strncmp((*it).getTableName().c_str(),
529
strlen(TMP_FILE_PREFIX)) == 0));
531
(*tot_list_next)= table_list;
532
tot_list_next= &table_list->next_local;
535
if (session->getKilled())
540
if (rm_table_part2(session, tot_list))
545
if (not plugin::StorageEngine::dropSchema(schema_identifier))
548
schema_identifier.getSQLPath(path);
549
my_error(ER_DROP_SCHEMA, MYF(0), path.c_str());
607
for (uint32_t idx= 0;
608
idx < (uint32_t) dirp->number_off_files && !session->killed ;
611
FILEINFO *file=dirp->dir_entry+idx;
614
/* skiping . and .. */
615
if (file->name[0] == '.' && (!file->name[1] ||
616
(file->name[1] == '.' && !file->name[2])))
619
if (!(extension= strrchr(file->name, '.')))
620
extension= strchr(file->name, '\0');
621
if (find_type(extension, &deletable_extentions,1+2) <= 0)
626
strange checking for magic extensions that are then deleted if
627
not reg_ext (i.e. .frm).
629
and (previously) we'd err out on drop database if files not matching
630
engine ha_known_exts() or deletable_extensions were present.
632
presumably this was to avoid deleting other user data... except if that
633
data happened to be in files ending in .BAK, .opt or .TMD. *fun*
637
/* just for safety we use files_charset_info */
638
if (db && !my_strcasecmp(files_charset_info,
641
uint32_t db_len= strlen(db);
643
/* Drop the table nicely */
644
*extension= 0; // Remove extension
645
TableList *table_list=(TableList*)
646
session->calloc(sizeof(*table_list) +
648
strlen(file->name) + 1);
652
table_list->db= (char*) (table_list+1);
653
table_list->table_name= strcpy(table_list->db, db) + db_len + 1;
654
filename_to_tablename(file->name, table_list->table_name,
655
strlen(file->name) + 1);
656
table_list->alias= table_list->table_name; // If lower_case_table_names=2
657
table_list->internal_tmp_table= is_prefix(file->name, TMP_FILE_PREFIX);
659
(*tot_list_next)= table_list;
660
tot_list_next= &table_list->next_local;
665
sprintf(filePath, "%s/%s", org_path, file->name);
666
if (my_delete_with_symlink(filePath,MYF(MY_WME)))
672
if (session->killed ||
673
(tot_list && mysql_rm_table_part2(session, tot_list, 1, 0, 1)))
679
*dropped_tables= tot_list;
681
/* Don't give errors if we can't delete 'RAID' directory */
682
if (rm_dir_w_symlink(org_path))
694
Remove directory with symlink
698
org_path path of derictory
704
static bool rm_dir_w_symlink(const char *org_path)
706
char tmp_path[FN_REFLEN], *pos;
707
char *path= tmp_path;
708
unpack_filename(tmp_path, org_path);
711
char tmp2_path[FN_REFLEN];
713
/* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
714
pos= strchr(path, '\0');
715
if (pos > path && pos[-1] == FN_LIBCHAR)
718
if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)
722
if (my_delete(path, MYF(MY_WME)))
726
/* Delete directory symbolic link pointed at */
730
/* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
731
pos= strchr(path, '\0');
733
if (pos > path && pos[-1] == FN_LIBCHAR)
737
my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
745
@brief Internal implementation: switch current database to a valid one.
747
@param session Thread context.
748
@param new_db_name Name of the database to switch to. The function will
749
take ownership of the name (the caller must not free
750
the allocated memory). If the name is NULL, we're
751
going to switch to NULL db.
752
@param new_db_charset Character set of the new database.
755
static void mysql_change_db_impl(Session *session, LEX_STRING *new_db_name)
757
/* 1. Change current database in Session. */
759
if (new_db_name == NULL)
762
Session::set_db() does all the job -- it frees previous database name and
766
session->set_db(NULL, 0);
768
else if (my_strcasecmp(system_charset_info, new_db_name->str,
769
INFORMATION_SCHEMA_NAME.c_str()) == 0)
772
Here we must use Session::set_db(), because we want to copy
773
INFORMATION_SCHEMA_NAME constant.
776
session->set_db(INFORMATION_SCHEMA_NAME.c_str(),
777
INFORMATION_SCHEMA_NAME.length());
782
Here we already have a copy of database name to be used in Session. So,
783
we just call Session::reset_db(). Since Session::reset_db() does not releases
784
the previous database name, we should do it explicitly.
790
session->reset_db(new_db_name->str, new_db_name->length);
797
Backup the current database name before switch.
799
@param[in] session thread handle
800
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
801
the old database name, "length" contains the
803
OUT: if the current (default) database is
804
not NULL, its name is copied to the
805
buffer pointed at by "str"
806
and "length" is updated accordingly.
807
Otherwise "str" is set to NULL and
808
"length" is set to 0.
811
static void backup_current_db_name(Session *session,
812
LEX_STRING *saved_db_name)
816
/* No current (default) database selected. */
818
saved_db_name->str= NULL;
819
saved_db_name->length= 0;
823
strncpy(saved_db_name->str, session->db, saved_db_name->length - 1);
824
saved_db_name->length= session->db_length;
830
Return true if db1_name is equal to db2_name, false otherwise.
832
The function allows to compare database names according to the MySQL
833
rules. The database names db1 and db2 are equal if:
834
- db1 is NULL and db2 is NULL;
836
- db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
837
db2 in system character set (UTF8).
841
cmp_db_names(const char *db1_name,
842
const char *db2_name)
845
/* db1 is NULL and db2 is NULL */
846
(!db1_name && !db2_name) ||
848
/* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
849
(db1_name && db2_name && my_strcasecmp(system_charset_info, db1_name, db2_name) == 0);
558
854
@brief Change the current database and its attributes unconditionally.
616
912
@retval true Error
619
bool mysql_change_db(Session *session, SchemaIdentifier &schema_identifier)
915
bool mysql_change_db(Session *session, const LEX_STRING *new_db_name, bool force_switch)
622
if (not plugin::Authorization::isAuthorized(session->getSecurityContext(), schema_identifier))
624
/* Error message is set in isAuthorized */
628
if (not check_db_name(session, schema_identifier))
631
schema_identifier.getSQLPath(path);
632
my_error(ER_WRONG_DB_NAME, MYF(0), path.c_str());
637
if (not plugin::StorageEngine::doesSchemaExist(schema_identifier))
639
/* Report an error and free new_db_file_name. */
641
schema_identifier.getSQLPath(path);
643
my_error(ER_BAD_DB_ERROR, MYF(0), path.c_str());
645
/* The operation failed. */
650
mysql_change_db_impl(session, schema_identifier);
917
LEX_STRING new_db_file_name;
918
const CHARSET_INFO *db_default_cl;
920
if (new_db_name == NULL ||
921
new_db_name->length == 0)
926
This can happen only if we're switching the current database back
927
after loading stored program. The thing is that loading of stored
928
program can happen when there is no current database.
930
TODO: actually, new_db_name and new_db_name->str seem to be always
931
non-NULL. In case of stored program, new_db_name->str == "" and
932
new_db_name->length == 0.
935
mysql_change_db_impl(session, NULL);
941
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
947
if (my_strcasecmp(system_charset_info, new_db_name->str,
948
INFORMATION_SCHEMA_NAME.c_str()) == 0)
950
/* Switch the current database to INFORMATION_SCHEMA. */
951
/* const_cast<> is safe here: mysql_change_db_impl does a copy */
952
LEX_STRING is_name= { const_cast<char *>(INFORMATION_SCHEMA_NAME.c_str()),
953
INFORMATION_SCHEMA_NAME.length() };
954
mysql_change_db_impl(session, &is_name);
960
Now we need to make a copy because check_db_name requires a
961
non-constant argument. Actually, it takes database file name.
963
TODO: fix check_db_name().
966
new_db_file_name.length= new_db_name->length;
967
new_db_file_name.str= (char *)malloc(new_db_name->length + 1);
968
if (new_db_file_name.str == NULL)
969
return true; /* the error is set */
970
memcpy(new_db_file_name.str, new_db_name->str, new_db_name->length);
971
new_db_file_name.str[new_db_name->length]= 0;
975
NOTE: if check_db_name() fails, we should throw an error in any case,
976
even if we are called from sp_head::execute().
978
It's next to impossible however to get this error when we are called
979
from sp_head::execute(). But let's switch the current database to NULL
980
in this case to be sure.
983
if (check_db_name(&new_db_file_name))
985
my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
986
free(new_db_file_name.str);
989
mysql_change_db_impl(session, NULL);
994
if (check_db_dir_existence(new_db_file_name.str))
998
/* Throw a warning and free new_db_file_name. */
1000
push_warning_printf(session, DRIZZLE_ERROR::WARN_LEVEL_NOTE,
1001
ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
1002
new_db_file_name.str);
1004
free(new_db_file_name.str);
1006
/* Change db to NULL. */
1008
mysql_change_db_impl(session, NULL);
1010
/* The operation succeed. */
1016
/* Report an error and free new_db_file_name. */
1018
my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
1019
free(new_db_file_name.str);
1021
/* The operation failed. */
1028
NOTE: in mysql_change_db_impl() new_db_file_name is assigned to Session
1029
attributes and will be freed in Session::~Session().
1032
db_default_cl= get_default_db_collation(new_db_file_name.str);
1034
mysql_change_db_impl(session, &new_db_file_name);
656
@brief Internal implementation: switch current database to a valid one.
658
@param session Thread context.
659
@param new_db_name Name of the database to switch to. The function will
660
take ownership of the name (the caller must not free
661
the allocated memory). If the name is NULL, we're
662
going to switch to NULL db.
663
@param new_db_charset Character set of the new database.
666
static void mysql_change_db_impl(Session *session, SchemaIdentifier &schema_identifier)
668
/* 1. Change current database in Session. */
671
if (new_db_name == NULL)
674
Session::set_db() does all the job -- it frees previous database name and
678
session->set_db(NULL, 0);
684
Here we already have a copy of database name to be used in Session. So,
685
we just call Session::reset_db(). Since Session::reset_db() does not releases
686
the previous database name, we should do it explicitly.
689
session->set_db(schema_identifier.getSchemaName());
693
static void mysql_change_db_impl(Session *session)
695
session->set_db(string());
698
} /* namespace drizzled */
1041
Change the current database and its attributes if needed.
1043
@param session thread handle
1044
@param new_db_name database name
1045
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
1046
the old database name, "length" contains the
1048
OUT: if the current (default) database is
1049
not NULL, its name is copied to the
1050
buffer pointed at by "str"
1051
and "length" is updated accordingly.
1052
Otherwise "str" is set to NULL and
1053
"length" is set to 0.
1054
@param force_switch @see mysql_change_db()
1055
@param[out] cur_db_changed out-flag to indicate whether the current
1056
database has been changed (valid only if
1057
the function suceeded)
1060
bool mysql_opt_change_db(Session *session,
1061
const LEX_STRING *new_db_name,
1062
LEX_STRING *saved_db_name,
1064
bool *cur_db_changed)
1066
*cur_db_changed= !cmp_db_names(session->db, new_db_name->str);
1068
if (!*cur_db_changed)
1071
backup_current_db_name(session, saved_db_name);
1073
return mysql_change_db(session, new_db_name, force_switch);
1078
Check if there is directory for the database name.
1081
check_db_dir_existence()
1082
db_name database name
1085
false There is directory for the specified database name.
1086
true The directory does not exist.
1089
bool check_db_dir_existence(const char *db_name)
1091
char db_dir_path[FN_REFLEN];
1092
uint32_t db_dir_path_len;
1094
db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
1095
db_name, "", "", 0);
1097
if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
1098
db_dir_path[db_dir_path_len - 1]= 0;
1102
return my_access(db_dir_path, F_OK);