1
/* Copyright (C) 2000-2003 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
/* create and drop of databases */
19
#include "mysql_priv.h"
20
#include <mysys_err.h>
25
#define MAX_DROP_TABLE_Q_LEN 1024
27
const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
28
static TYPELIB deletable_extentions=
29
{array_elements(del_exts)-1,"del_exts", del_exts, NULL};
31
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
32
const char *db, const char *path, uint level,
33
TABLE_LIST **dropped_tables);
35
static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path);
36
static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error);
37
static void mysql_change_db_impl(THD *thd,
38
LEX_STRING *new_db_name,
39
CHARSET_INFO *new_db_charset);
42
/* Database lock hash */
44
pthread_mutex_t LOCK_lock_db;
45
int creating_database= 0; // how many database locks are made
48
/* Structure for database lock */
49
typedef struct my_dblock_st
51
char *name; /* Database name */
52
uint name_length; /* Database length name */
60
extern "C" uchar* lock_db_get_key(my_dblock_t *, size_t *, my_bool not_used);
62
uchar* lock_db_get_key(my_dblock_t *ptr, size_t *length,
63
my_bool not_used __attribute__((unused)))
65
*length= ptr->name_length;
66
return (uchar*) ptr->name;
71
Free lock_db hash element.
74
extern "C" void lock_db_free_element(void *ptr);
76
void lock_db_free_element(void *ptr)
83
Put a database lock entry into the hash.
86
Insert a database lock entry into hash.
87
LOCK_db_lock must be previously locked.
94
static my_bool lock_db_insert(const char *dbname, uint length)
98
DBUG_ENTER("lock_db_insert");
100
safe_mutex_assert_owner(&LOCK_lock_db);
102
if (!(opt= (my_dblock_t*) hash_search(&lock_db_cache,
103
(uchar*) dbname, length)))
105
/* Db is not in the hash, insert it */
107
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
108
&opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
116
strmov(opt->name, dbname);
117
opt->name_length= length;
119
if ((error= my_hash_insert(&lock_db_cache, (uchar*) opt)))
120
my_free(opt, MYF(0));
129
Delete a database lock entry from hash.
132
void lock_db_delete(const char *name, uint length)
135
safe_mutex_assert_owner(&LOCK_lock_db);
136
if ((opt= (my_dblock_t *)hash_search(&lock_db_cache,
137
(const uchar*) name, length)))
138
hash_delete(&lock_db_cache, (uchar*) opt);
142
/* Database options hash */
143
static HASH dboptions;
144
static my_bool dboptions_init= 0;
145
static rw_lock_t LOCK_dboptions;
147
/* Structure for database options */
148
typedef struct my_dbopt_st
150
char *name; /* Database name */
151
uint name_length; /* Database length name */
152
CHARSET_INFO *charset; /* Database default character set */
157
Function we use in the creation of our hash to get key.
160
extern "C" uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
163
uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
164
my_bool not_used __attribute__((unused)))
166
*length= opt->name_length;
167
return (uchar*) opt->name;
172
Helper function to write a query to binlog used by mysql_rm_db()
175
static inline void write_to_binlog(THD *thd, char *query, uint q_len,
176
char *db, uint db_len)
178
Query_log_event qinfo(thd, query, q_len, 0, 0);
181
qinfo.db_len= db_len;
182
mysql_bin_log.write(&qinfo);
187
Function to free dboptions hash element
190
extern "C" void free_dbopt(void *dbopt);
192
void free_dbopt(void *dbopt)
194
my_free((uchar*) dbopt, MYF(0));
199
Initialize database option hash and locked database hash.
205
Must be called before any other database function is called.
212
bool my_database_names_init(void)
215
(void) my_rwlock_init(&LOCK_dboptions, NULL);
219
error= hash_init(&dboptions, lower_case_table_names ?
220
&my_charset_bin : system_charset_info,
221
32, 0, 0, (hash_get_key) dboptions_get_key,
223
hash_init(&lock_db_cache, lower_case_table_names ?
224
&my_charset_bin : system_charset_info,
225
32, 0, 0, (hash_get_key) lock_db_get_key,
226
lock_db_free_element,0);
235
Free database option hash and locked databases hash.
238
void my_database_names_free(void)
243
hash_free(&dboptions);
244
(void) rwlock_destroy(&LOCK_dboptions);
245
hash_free(&lock_db_cache);
251
Cleanup cached options
254
void my_dbopt_cleanup(void)
256
rw_wrlock(&LOCK_dboptions);
257
hash_free(&dboptions);
258
hash_init(&dboptions, lower_case_table_names ?
259
&my_charset_bin : system_charset_info,
260
32, 0, 0, (hash_get_key) dboptions_get_key,
262
rw_unlock(&LOCK_dboptions);
267
Find database options in the hash.
270
Search a database options in the hash, usings its path.
271
Fills "create" on success.
278
static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
284
length= (uint) strlen(dbname);
286
rw_rdlock(&LOCK_dboptions);
287
if ((opt= (my_dbopt_t*) hash_search(&dboptions, (uchar*) dbname, length)))
289
create->default_table_charset= opt->charset;
292
rw_unlock(&LOCK_dboptions);
298
Writes database options into the hash.
301
Inserts database options into the hash, or updates
302
options if they are already in the hash.
309
static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
314
DBUG_ENTER("put_dbopt");
316
length= (uint) strlen(dbname);
318
rw_wrlock(&LOCK_dboptions);
319
if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (uchar*) dbname, length)))
321
/* Options are not in the hash, insert them */
323
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
324
&opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1,
332
strmov(opt->name, dbname);
333
opt->name_length= length;
335
if ((error= my_hash_insert(&dboptions, (uchar*) opt)))
337
my_free(opt, MYF(0));
342
/* Update / write options in hash */
343
opt->charset= create->default_table_charset;
346
rw_unlock(&LOCK_dboptions);
352
Deletes database options from the hash.
355
void del_dbopt(const char *path)
358
rw_wrlock(&LOCK_dboptions);
359
if ((opt= (my_dbopt_t *)hash_search(&dboptions, (const uchar*) path,
361
hash_delete(&dboptions, (uchar*) opt);
362
rw_unlock(&LOCK_dboptions);
367
Create database options file:
370
Currently database default charset is only stored there.
374
1 Could not create file or write to it. Error sent through my_error()
377
static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
380
char buf[256]; // Should be enough for one option
383
if (!create->default_table_charset)
384
create->default_table_charset= thd->variables.collation_server;
386
if (put_dbopt(path, create))
389
if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
392
length= (ulong) (strxnmov(buf, sizeof(buf)-1, "default-character-set=",
393
create->default_table_charset->csname,
394
"\ndefault-collation=",
395
create->default_table_charset->name,
398
/* Error is written by my_write */
399
if (!my_write(file,(uchar*) buf, length, MYF(MY_NABP+MY_WME)))
401
my_close(file,MYF(0));
408
Load database options file
411
path Path for option file
412
create Where to store the read options
418
1 No database file or could not open it
422
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
426
DBUG_ENTER("load_db_opt");
430
bzero((char*) create,sizeof(*create));
431
create->default_table_charset= thd->variables.collation_server;
433
/* Check if options for this database are already in the hash */
434
if (!get_dbopt(path, create))
437
/* Otherwise, load options from the .opt file */
438
if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
442
if (init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)))
445
while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0)
447
char *pos= buf+nbytes-1;
448
/* Remove end space and control characters */
449
while (pos > buf && !my_isgraph(&my_charset_latin1, pos[-1]))
452
if ((pos= strchr(buf, '=')))
454
if (!strncmp(buf,"default-character-set", (pos-buf)))
457
Try character set name, and if it fails
458
try collation name, probably it's an old
459
4.1.0 db.opt file, which didn't have
460
separate default-character-set and
461
default-collation commands.
463
if (!(create->default_table_charset=
464
get_charset_by_csname(pos+1, MY_CS_PRIMARY, MYF(0))) &&
465
!(create->default_table_charset=
466
get_charset_by_name(pos+1, MYF(0))))
468
sql_print_error("Error while loading database options: '%s':",path);
469
sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1);
470
create->default_table_charset= default_charset_info;
473
else if (!strncmp(buf,"default-collation", (pos-buf)))
475
if (!(create->default_table_charset= get_charset_by_name(pos+1,
478
sql_print_error("Error while loading database options: '%s':",path);
479
sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1);
480
create->default_table_charset= default_charset_info;
486
Put the loaded value into the hash.
487
Note that another thread could've added the same
488
entry to the hash after we called get_dbopt(),
489
but it's not an error, as put_dbopt() takes this
490
possibility into account.
492
error= put_dbopt(path, create);
494
end_io_cache(&cache);
496
my_close(file,MYF(0));
503
Retrieve database options by name. Load database options file or fetch from
507
load_db_opt_by_name()
508
db_name Database name
509
db_create_info Where to store the database options
512
load_db_opt_by_name() is a shortcut for load_db_opt().
515
Although load_db_opt_by_name() (and load_db_opt()) returns status of
516
the operation, it is useless usually and should be ignored. The problem
517
is that there are 1) system databases ("mysql") and 2) virtual
518
databases ("information_schema"), which do not contain options file.
519
So, load_db_opt[_by_name]() returns FALSE for these databases, but this
522
load_db_opt[_by_name]() clears db_create_info structure in any case, so
523
even on failure it contains valid data. So, common use case is just
524
call load_db_opt[_by_name]() without checking return value and use
525
db_create_info right after that.
527
RETURN VALUES (read NOTE!)
529
TRUE Failed to retrieve options
532
bool load_db_opt_by_name(THD *thd, const char *db_name,
533
HA_CREATE_INFO *db_create_info)
535
char db_opt_path[FN_REFLEN];
538
Pass an empty file name, and the database options file name as extension
539
to avoid table name to file name encoding.
541
(void) build_table_filename(db_opt_path, sizeof(db_opt_path),
542
db_name, "", MY_DB_OPT_FILE, 0);
544
return load_db_opt(thd, db_opt_path, db_create_info);
549
Return default database collation.
551
@param thd Thread context.
552
@param db_name Database name.
554
@return CHARSET_INFO object. The operation always return valid character
555
set, even if the database does not exist.
558
CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
560
HA_CREATE_INFO db_info;
562
if (thd->db != NULL && strcmp(db_name, thd->db) == 0)
563
return thd->db_charset;
565
load_db_opt_by_name(thd, db_name, &db_info);
568
NOTE: even if load_db_opt_by_name() fails,
569
db_info.default_table_charset contains valid character set
570
(collation_server). We should not fail if load_db_opt_by_name() fails,
571
because it is valid case. If a database has been created just by
572
"mkdir", it does not contain db.opt file, but it is valid database.
575
return db_info.default_table_charset;
585
db Name of database to create
586
Function assumes that this is already validated.
587
create_info Database create options (like character set)
588
silent Used by replication when internally creating a database.
589
In this case the entry should not be logged.
592
1. Report back to client that command succeeded (my_ok)
593
2. Report errors to client
594
3. Log event to binary log
595
(The 'silent' flags turns off 1 and 3.)
603
int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
606
char path[FN_REFLEN+16];
607
char tmp_query[FN_REFLEN+16];
611
uint create_options= create_info ? create_info->options : 0;
613
DBUG_ENTER("mysql_create_db");
615
/* do not create 'information_schema' db */
616
if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str))
618
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
623
Do not create database if another thread is holding read lock.
624
Wait for global read lock before acquiring LOCK_mysql_create_db.
625
After wait_if_global_read_lock() we have protection against another
626
global read lock. If we would acquire LOCK_mysql_create_db first,
627
another thread could step in and get the global read lock before we
628
reach wait_if_global_read_lock(). If this thread tries the same as we
629
(admin a db), it would then go and wait on LOCK_mysql_create_db...
630
Furthermore wait_if_global_read_lock() checks if the current thread
631
has the global read lock and refuses the operation with
632
ER_CANT_UPDATE_WITH_READLOCK if applicable.
634
if (wait_if_global_read_lock(thd, 0, 1))
640
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
642
/* Check directory */
643
path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
644
path[path_len-1]= 0; // Remove last '/' from path
646
if (my_stat(path,&stat_info,MYF(0)))
648
if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
650
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
654
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
655
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
663
if (my_errno != ENOENT)
665
my_error(EE_STAT, MYF(0), path, my_errno);
668
if (my_mkdir(path,0777,MYF(0)) < 0)
670
my_error(ER_CANT_CREATE_DB, MYF(0), db, my_errno);
676
path[path_len-1]= FN_LIBCHAR;
677
strmake(path+path_len, MY_DB_OPT_FILE, sizeof(path)-path_len-1);
678
if (write_db_opt(thd, path, create_info))
681
Could not create options file.
682
Restore things to beginning.
685
if (rmdir(path) >= 0)
691
We come here when we managed to create the database, but not the option
692
file. In this case it's best to just continue as if nothing has
693
happened. (This is a very unlikely senario)
702
if (!thd->query) // Only in replication
705
query_length= (uint) (strxmov(tmp_query,"create database `",
706
db, "`", NullS) - tmp_query);
711
query_length= thd->query_length;
714
ha_binlog_log_query(thd, 0, LOGCOM_CREATE_DB,
718
if (mysql_bin_log.is_open())
720
Query_log_event qinfo(thd, query, query_length, 0,
721
/* suppress_use */ TRUE);
724
Write should use the database being created as the "current
725
database" and not the threads current database, which is the
726
default. If we do not change the "current database" to the
727
database being created, the CREATE statement will not be
728
replicated when using --binlog-do-db to select databases to be
731
An example (--binlog-do-db=sisyfos):
733
CREATE DATABASE bob; # Not replicated
734
USE bob; # 'bob' is the current database
735
CREATE DATABASE sisyfos; # Not replicated since 'bob' is
737
USE sisyfos; # Will give error on slave since
738
# database does not exist.
741
qinfo.db_len = strlen(db);
743
/* These DDL methods and logging protected with LOCK_mysql_create_db */
744
mysql_bin_log.write(&qinfo);
750
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
751
start_waiting_global_read_lock(thd);
757
/* db-name is already validated when we come here */
759
bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
761
char path[FN_REFLEN+16];
764
DBUG_ENTER("mysql_alter_db");
767
Do not alter database if another thread is holding read lock.
768
Wait for global read lock before acquiring LOCK_mysql_create_db.
769
After wait_if_global_read_lock() we have protection against another
770
global read lock. If we would acquire LOCK_mysql_create_db first,
771
another thread could step in and get the global read lock before we
772
reach wait_if_global_read_lock(). If this thread tries the same as we
773
(admin a db), it would then go and wait on LOCK_mysql_create_db...
774
Furthermore wait_if_global_read_lock() checks if the current thread
775
has the global read lock and refuses the operation with
776
ER_CANT_UPDATE_WITH_READLOCK if applicable.
778
if ((error=wait_if_global_read_lock(thd,0,1)))
781
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
784
Recreate db options file: /dbpath/.db.opt
785
We pass MY_DB_OPT_FILE as "extension" to avoid
786
"table name to file name" encoding.
788
build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0);
789
if ((error=write_db_opt(thd, path, create_info)))
792
/* Change options if current database is being altered. */
794
if (thd->db && !strcmp(thd->db,db))
796
thd->db_charset= create_info->default_table_charset ?
797
create_info->default_table_charset :
798
thd->variables.collation_server;
799
thd->variables.collation_database= thd->db_charset;
802
ha_binlog_log_query(thd, 0, LOGCOM_ALTER_DB,
803
thd->query, thd->query_length,
806
if (mysql_bin_log.is_open())
808
Query_log_event qinfo(thd, thd->query, thd->query_length, 0,
809
/* suppress_use */ TRUE);
812
Write should use the database being created as the "current
813
database" and not the threads current database, which is the
817
qinfo.db_len = strlen(db);
820
/* These DDL methods and logging protected with LOCK_mysql_create_db */
821
mysql_bin_log.write(&qinfo);
826
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
827
start_waiting_global_read_lock(thd);
834
Drop all tables in a database and the database itself
839
db Database name in the case given by user
840
It's already validated and set to lower case
841
(if needed) when we come here
842
if_exists Don't give error if database doesn't exists
843
silent Don't generate errors
846
FALSE ok (Database dropped)
850
bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
854
char path[FN_REFLEN+16];
857
TABLE_LIST* dropped_tables= 0;
858
DBUG_ENTER("mysql_rm_db");
860
if (db && (strcmp(db, "information_schema") == 0))
862
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), "", "", INFORMATION_SCHEMA_NAME.str);
867
Do not drop database if another thread is holding read lock.
868
Wait for global read lock before acquiring LOCK_mysql_create_db.
869
After wait_if_global_read_lock() we have protection against another
870
global read lock. If we would acquire LOCK_mysql_create_db first,
871
another thread could step in and get the global read lock before we
872
reach wait_if_global_read_lock(). If this thread tries the same as we
873
(admin a db), it would then go and wait on LOCK_mysql_create_db...
874
Furthermore wait_if_global_read_lock() checks if the current thread
875
has the global read lock and refuses the operation with
876
ER_CANT_UPDATE_WITH_READLOCK if applicable.
878
if (wait_if_global_read_lock(thd, 0, 1))
884
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
887
This statement will be replicated as a statement, even when using
888
row-based replication. The flag will be reset at the end of the
891
thd->clear_current_stmt_binlog_row_based();
893
length= build_table_filename(path, sizeof(path), db, "", "", 0);
894
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
895
del_dbopt(path); // Remove dboption hash entry
896
path[length]= '\0'; // Remove file name
898
/* See if the directory exists */
899
if (!(dirp= my_dir(path,MYF(MY_DONT_SORT))))
904
my_error(ER_DB_DROP_EXISTS, MYF(0), db);
908
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
909
ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
913
pthread_mutex_lock(&LOCK_open);
914
remove_db_from_cache(db);
915
pthread_mutex_unlock(&LOCK_open);
919
if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
920
&dropped_tables)) >= 0)
922
ha_drop_database(path);
926
if (!silent && deleted>=0)
932
/* The client used the old obsolete mysql_drop_db() call */
934
query_length= (uint) (strxmov(path, "drop database `", db, "`",
940
query_length= thd->query_length;
942
if (mysql_bin_log.is_open())
944
Query_log_event qinfo(thd, query, query_length, 0,
945
/* suppress_use */ TRUE);
947
Write should use the database being created as the "current
948
database" and not the threads current database, which is the
952
qinfo.db_len = strlen(db);
955
/* These DDL methods and logging protected with LOCK_mysql_create_db */
956
mysql_bin_log.write(&qinfo);
959
thd->server_status|= SERVER_STATUS_DB_DROPPED;
960
my_ok(thd, (ulong) deleted);
961
thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
963
else if (mysql_bin_log.is_open())
965
char *query, *query_pos, *query_end, *query_data_start;
969
if (!(query= (char*) thd->alloc(MAX_DROP_TABLE_Q_LEN)))
970
goto exit; /* not much else we can do */
971
query_pos= query_data_start= strmov(query,"drop table ");
972
query_end= query + MAX_DROP_TABLE_Q_LEN;
975
for (tbl= dropped_tables; tbl; tbl= tbl->next_local)
979
/* 3 for the quotes and the comma*/
980
tbl_name_len= strlen(tbl->table_name) + 3;
981
if (query_pos + tbl_name_len + 1 >= query_end)
983
/* These DDL methods and logging protected with LOCK_mysql_create_db */
984
write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
985
query_pos= query_data_start;
989
query_pos= strmov(query_pos,tbl->table_name);
994
if (query_pos != query_data_start)
996
/* These DDL methods and logging protected with LOCK_mysql_create_db */
997
write_to_binlog(thd, query, query_pos -1 - query, db, db_len);
1003
If this database was the client's selected database, we silently
1004
change the client's selected database to nothing (to have an empty
1005
SELECT DATABASE() in the future). For this we free() thd->db and set
1008
if (thd->db && !strcmp(thd->db, db))
1009
mysql_change_db_impl(thd, NULL, thd->variables.collation_server);
1010
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
1011
start_waiting_global_read_lock(thd);
1017
Removes files with known extensions plus all found subdirectories that
1018
are 2 hex digits (raid directories).
1019
thd MUST be set when calling this function!
1022
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
1023
const char *org_path, uint level,
1024
TABLE_LIST **dropped_tables)
1027
ulong found_other_files=0;
1028
char filePath[FN_REFLEN];
1029
TABLE_LIST *tot_list=0, **tot_list_next;
1030
List<String> raid_dirs;
1031
DBUG_ENTER("mysql_rm_known_files");
1032
DBUG_PRINT("enter",("path: %s", org_path));
1034
tot_list_next= &tot_list;
1037
idx < (uint) dirp->number_off_files && !thd->killed ;
1040
FILEINFO *file=dirp->dir_entry+idx;
1042
DBUG_PRINT("info",("Examining: %s", file->name));
1044
/* skiping . and .. */
1045
if (file->name[0] == '.' && (!file->name[1] ||
1046
(file->name[1] == '.' && !file->name[2])))
1049
/* Check if file is a raid directory */
1050
if ((my_isdigit(system_charset_info, file->name[0]) ||
1051
(file->name[0] >= 'a' && file->name[0] <= 'f')) &&
1052
(my_isdigit(system_charset_info, file->name[1]) ||
1053
(file->name[1] >= 'a' && file->name[1] <= 'f')) &&
1054
!file->name[2] && !level)
1056
char newpath[FN_REFLEN], *copy_of_path;
1061
strxmov(newpath,org_path,"/",file->name,NullS);
1062
length= unpack_filename(newpath,newpath);
1063
if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT))))
1065
DBUG_PRINT("my",("New subdir found: %s", newpath));
1066
if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0)
1068
if (!(copy_of_path= (char*) thd->memdup(newpath, length+1)) ||
1069
!(dir= new (thd->mem_root) String(copy_of_path, length,
1070
&my_charset_bin)) ||
1071
raid_dirs.push_back(dir))
1075
found_other_files++;
1078
else if (file->name[0] == 'a' && file->name[1] == 'r' &&
1079
file->name[2] == 'c' && file->name[3] == '\0')
1082
char newpath[FN_REFLEN];
1084
strxmov(newpath, org_path, "/", "arc", NullS);
1085
(void) unpack_filename(newpath, newpath);
1086
if ((new_dirp = my_dir(newpath, MYF(MY_DONT_SORT))))
1088
DBUG_PRINT("my",("Archive subdir found: %s", newpath));
1089
if ((mysql_rm_arc_files(thd, new_dirp, newpath)) < 0)
1093
found_other_files++;
1096
if (!(extension= strrchr(file->name, '.')))
1097
extension= strend(file->name);
1098
if (find_type(extension, &deletable_extentions,1+2) <= 0)
1100
if (find_type(extension, ha_known_exts(),1+2) <= 0)
1101
found_other_files++;
1104
/* just for safety we use files_charset_info */
1105
if (db && !my_strcasecmp(files_charset_info,
1106
extension, reg_ext))
1108
/* Drop the table nicely */
1109
*extension= 0; // Remove extension
1110
TABLE_LIST *table_list=(TABLE_LIST*)
1111
thd->calloc(sizeof(*table_list) +
1113
MYSQL50_TABLE_NAME_PREFIX_LENGTH +
1114
strlen(file->name) + 1);
1118
table_list->db= (char*) (table_list+1);
1119
table_list->table_name= strmov(table_list->db, db) + 1;
1120
VOID(filename_to_tablename(file->name, table_list->table_name,
1121
MYSQL50_TABLE_NAME_PREFIX_LENGTH +
1122
strlen(file->name) + 1));
1123
table_list->alias= table_list->table_name; // If lower_case_table_names=2
1124
table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix);
1125
/* Link into list */
1126
(*tot_list_next)= table_list;
1127
tot_list_next= &table_list->next_local;
1132
strxmov(filePath, org_path, "/", file->name, NullS);
1133
if (my_delete_with_symlink(filePath,MYF(MY_WME)))
1140
(tot_list && mysql_rm_table_part2(thd, tot_list, 1, 0, 1, 1)))
1143
/* Remove RAID directories */
1145
List_iterator<String> it(raid_dirs);
1148
if (rmdir(dir->c_ptr()) < 0)
1149
found_other_files++;
1154
*dropped_tables= tot_list;
1157
If the directory is a symbolic link, remove the link first, then
1158
remove the directory the symbolic link pointed at
1160
if (found_other_files)
1162
my_error(ER_DB_DROP_RMDIR, MYF(0), org_path, EEXIST);
1167
/* Don't give errors if we can't delete 'RAID' directory */
1168
if (rm_dir_w_symlink(org_path, level == 0))
1172
DBUG_RETURN(deleted);
1181
Remove directory with symlink
1185
org_path path of derictory
1186
send_error send errors
1192
static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error)
1194
char tmp_path[FN_REFLEN], *pos;
1195
char *path= tmp_path;
1196
DBUG_ENTER("rm_dir_w_symlink");
1197
unpack_filename(tmp_path, org_path);
1198
#ifdef HAVE_READLINK
1200
char tmp2_path[FN_REFLEN];
1202
/* Remove end FN_LIBCHAR as this causes problem on Linux in readlink */
1204
if (pos > path && pos[-1] == FN_LIBCHAR)
1207
if ((error= my_readlink(tmp2_path, path, MYF(MY_WME))) < 0)
1211
if (my_delete(path, MYF(send_error ? MY_WME : 0)))
1213
DBUG_RETURN(send_error);
1215
/* Delete directory symbolic link pointed at */
1219
/* Remove last FN_LIBCHAR to not cause a problem on OS/2 */
1222
if (pos > path && pos[-1] == FN_LIBCHAR)
1224
if (rmdir(path) < 0 && send_error)
1226
my_error(ER_DB_DROP_RMDIR, MYF(0), path, errno);
1234
Remove .frm archives from directory
1238
dirp list of files in archive directory
1240
org_path path of archive directory
1243
> 0 number of removed files
1246
static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp,
1247
const char *org_path)
1250
ulong found_other_files= 0;
1251
char filePath[FN_REFLEN];
1252
DBUG_ENTER("mysql_rm_arc_files");
1253
DBUG_PRINT("enter", ("path: %s", org_path));
1256
idx < (uint) dirp->number_off_files && !thd->killed ;
1259
FILEINFO *file=dirp->dir_entry+idx;
1260
char *extension, *revision;
1261
DBUG_PRINT("info",("Examining: %s", file->name));
1263
/* skiping . and .. */
1264
if (file->name[0] == '.' && (!file->name[1] ||
1265
(file->name[1] == '.' && !file->name[2])))
1268
extension= fn_ext(file->name);
1269
if (extension[0] != '.' ||
1270
extension[1] != 'f' || extension[2] != 'r' ||
1271
extension[3] != 'm' || extension[4] != '-')
1273
found_other_files++;
1276
revision= extension+5;
1277
while (*revision && my_isdigit(system_charset_info, *revision))
1281
found_other_files++;
1284
strxmov(filePath, org_path, "/", file->name, NullS);
1285
if (my_delete_with_symlink(filePath,MYF(MY_WME)))
1296
If the directory is a symbolic link, remove the link first, then
1297
remove the directory the symbolic link pointed at
1299
if (!found_other_files &&
1300
rm_dir_w_symlink(org_path, 0))
1302
DBUG_RETURN(deleted);
1311
@brief Internal implementation: switch current database to a valid one.
1313
@param thd Thread context.
1314
@param new_db_name Name of the database to switch to. The function will
1315
take ownership of the name (the caller must not free
1316
the allocated memory). If the name is NULL, we're
1317
going to switch to NULL db.
1318
@param new_db_charset Character set of the new database.
1321
static void mysql_change_db_impl(THD *thd,
1322
LEX_STRING *new_db_name,
1323
CHARSET_INFO *new_db_charset)
1325
/* 1. Change current database in THD. */
1327
if (new_db_name == NULL)
1330
THD::set_db() does all the job -- it frees previous database name and
1334
thd->set_db(NULL, 0);
1336
else if (new_db_name == &INFORMATION_SCHEMA_NAME)
1339
Here we must use THD::set_db(), because we want to copy
1340
INFORMATION_SCHEMA_NAME constant.
1343
thd->set_db(INFORMATION_SCHEMA_NAME.str, INFORMATION_SCHEMA_NAME.length);
1348
Here we already have a copy of database name to be used in THD. So,
1349
we just call THD::reset_db(). Since THD::reset_db() does not releases
1350
the previous database name, we should do it explicitly.
1355
thd->reset_db(new_db_name->str, new_db_name->length);
1358
/* 3. Update db-charset environment variables. */
1360
thd->db_charset= new_db_charset;
1361
thd->variables.collation_database= new_db_charset;
1367
Backup the current database name before switch.
1369
@param[in] thd thread handle
1370
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
1371
the old database name, "length" contains the
1373
OUT: if the current (default) database is
1374
not NULL, its name is copied to the
1375
buffer pointed at by "str"
1376
and "length" is updated accordingly.
1377
Otherwise "str" is set to NULL and
1378
"length" is set to 0.
1381
static void backup_current_db_name(THD *thd,
1382
LEX_STRING *saved_db_name)
1386
/* No current (default) database selected. */
1388
saved_db_name->str= NULL;
1389
saved_db_name->length= 0;
1393
strmake(saved_db_name->str, thd->db, saved_db_name->length - 1);
1394
saved_db_name->length= thd->db_length;
1400
Return TRUE if db1_name is equal to db2_name, FALSE otherwise.
1402
The function allows to compare database names according to the MySQL
1403
rules. The database names db1 and db2 are equal if:
1404
- db1 is NULL and db2 is NULL;
1406
- db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
1407
db2 in system character set (UTF8).
1411
cmp_db_names(const char *db1_name,
1412
const char *db2_name)
1415
/* db1 is NULL and db2 is NULL */
1416
(!db1_name && !db2_name) ||
1418
/* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
1419
(db1_name && db2_name && my_strcasecmp(system_charset_info, db1_name, db2_name) == 0);
1424
@brief Change the current database and its attributes unconditionally.
1426
@param thd thread handle
1427
@param new_db_name database name
1428
@param force_switch if force_switch is FALSE, then the operation will fail if
1430
- new_db_name is NULL or empty;
1432
- OR new database name is invalid
1433
(check_db_name() failed);
1435
- OR user has no privilege on the new database;
1437
- OR new database does not exist;
1439
if force_switch is TRUE, then
1441
- if new_db_name is NULL or empty, the current
1442
database will be NULL, @@collation_database will
1443
be set to @@collation_server, the operation will
1446
- if new database name is invalid
1447
(check_db_name() failed), the current database
1448
will be NULL, @@collation_database will be set to
1449
@@collation_server, but the operation will fail;
1451
- user privileges will not be checked
1452
(THD::db_access however is updated);
1454
TODO: is this really the intention?
1455
(see sp-security.test).
1457
- if new database does not exist,the current database
1458
will be NULL, @@collation_database will be set to
1459
@@collation_server, a warning will be thrown, the
1460
operation will succeed.
1462
@details The function checks that the database name corresponds to a
1463
valid and existent database, checks access rights and changes the current
1464
database with database attributes (@@collation_database session variable,
1467
This function is not the only way to switch the database that is
1468
currently employed. When the replication slave thread switches the
1469
database before executing a query, it calls thd->set_db directly.
1470
However, if the query, in turn, uses a stored routine, the stored routine
1471
will use this function, even if it's run on the slave.
1473
This function allocates the name of the database on the system heap: this
1474
is necessary to be able to uniformly change the database from any module
1475
of the server. Up to 5.0 different modules were using different memory to
1476
store the name of the database, and this led to memory corruption:
1477
a stack pointer set by Stored Procedures was used by replication after
1478
the stack address was long gone.
1480
@return Operation status
1481
@retval FALSE Success
1485
bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
1487
LEX_STRING new_db_file_name;
1488
CHARSET_INFO *db_default_cl;
1490
DBUG_ENTER("mysql_change_db");
1491
DBUG_PRINT("enter",("name: '%s'", new_db_name->str));
1493
if (new_db_name == NULL ||
1494
new_db_name->length == 0)
1499
This can happen only if we're switching the current database back
1500
after loading stored program. The thing is that loading of stored
1501
program can happen when there is no current database.
1503
TODO: actually, new_db_name and new_db_name->str seem to be always
1504
non-NULL. In case of stored program, new_db_name->str == "" and
1505
new_db_name->length == 0.
1508
mysql_change_db_impl(thd, NULL, thd->variables.collation_server);
1514
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
1520
if (my_strcasecmp(system_charset_info, new_db_name->str,
1521
INFORMATION_SCHEMA_NAME.str) == 0)
1523
/* Switch the current database to INFORMATION_SCHEMA. */
1525
mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, system_charset_info);
1531
Now we need to make a copy because check_db_name requires a
1532
non-constant argument. Actually, it takes database file name.
1534
TODO: fix check_db_name().
1537
new_db_file_name.str= my_strndup(new_db_name->str, new_db_name->length,
1539
new_db_file_name.length= new_db_name->length;
1541
if (new_db_file_name.str == NULL)
1542
DBUG_RETURN(TRUE); /* the error is set */
1545
NOTE: if check_db_name() fails, we should throw an error in any case,
1546
even if we are called from sp_head::execute().
1548
It's next to impossible however to get this error when we are called
1549
from sp_head::execute(). But let's switch the current database to NULL
1550
in this case to be sure.
1553
if (check_db_name(&new_db_file_name))
1555
my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
1556
my_free(new_db_file_name.str, MYF(0));
1559
mysql_change_db_impl(thd, NULL, thd->variables.collation_server);
1564
DBUG_PRINT("info",("Use database: %s", new_db_file_name.str));
1567
if (check_db_dir_existence(new_db_file_name.str))
1571
/* Throw a warning and free new_db_file_name. */
1573
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
1574
ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
1575
new_db_file_name.str);
1577
my_free(new_db_file_name.str, MYF(0));
1579
/* Change db to NULL. */
1581
mysql_change_db_impl(thd, NULL, thd->variables.collation_server);
1583
/* The operation succeed. */
1589
/* Report an error and free new_db_file_name. */
1591
my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
1592
my_free(new_db_file_name.str, MYF(0));
1594
/* The operation failed. */
1601
NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD
1602
attributes and will be freed in THD::~THD().
1605
db_default_cl= get_default_db_collation(thd, new_db_file_name.str);
1607
mysql_change_db_impl(thd, &new_db_file_name, db_default_cl);
1614
Change the current database and its attributes if needed.
1616
@param thd thread handle
1617
@param new_db_name database name
1618
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
1619
the old database name, "length" contains the
1621
OUT: if the current (default) database is
1622
not NULL, its name is copied to the
1623
buffer pointed at by "str"
1624
and "length" is updated accordingly.
1625
Otherwise "str" is set to NULL and
1626
"length" is set to 0.
1627
@param force_switch @see mysql_change_db()
1628
@param[out] cur_db_changed out-flag to indicate whether the current
1629
database has been changed (valid only if
1630
the function suceeded)
1633
bool mysql_opt_change_db(THD *thd,
1634
const LEX_STRING *new_db_name,
1635
LEX_STRING *saved_db_name,
1637
bool *cur_db_changed)
1639
*cur_db_changed= !cmp_db_names(thd->db, new_db_name->str);
1641
if (!*cur_db_changed)
1644
backup_current_db_name(thd, saved_db_name);
1646
return mysql_change_db(thd, new_db_name, force_switch);
1651
lock_databases(THD *thd, const char *db1, uint length1,
1652
const char *db2, uint length2)
1654
pthread_mutex_lock(&LOCK_lock_db);
1655
while (!thd->killed &&
1656
(hash_search(&lock_db_cache,(uchar*) db1, length1) ||
1657
hash_search(&lock_db_cache,(uchar*) db2, length2)))
1659
wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
1660
pthread_mutex_lock(&LOCK_lock_db);
1665
pthread_mutex_unlock(&LOCK_lock_db);
1669
lock_db_insert(db1, length1);
1670
lock_db_insert(db2, length2);
1671
creating_database++;
1674
Wait if a concurent thread is creating a table at the same time.
1675
The assumption here is that it will not take too long until
1676
there is a point in time when a table is not created.
1679
while (!thd->killed && creating_table)
1681
wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
1682
pthread_mutex_lock(&LOCK_lock_db);
1687
lock_db_delete(db1, length1);
1688
lock_db_delete(db2, length2);
1689
creating_database--;
1690
pthread_mutex_unlock(&LOCK_lock_db);
1691
pthread_cond_signal(&COND_refresh);
1696
We can unlock now as the hash will protect against anyone creating a table
1697
in the databases we are using
1699
pthread_mutex_unlock(&LOCK_lock_db);
1705
Upgrade a 5.0 database.
1706
This function is invoked whenever an ALTER DATABASE UPGRADE query is executed:
1707
ALTER DATABASE 'olddb' UPGRADE DATA DIRECTORY NAME.
1709
If we have managed to rename (move) tables to the new database
1710
but something failed on a later step, then we store the
1711
RENAME DATABASE event in the log. mysql_rename_db() is atomic in
1712
the sense that it will rename all or none of the tables.
1714
@param thd Current thread
1715
@param old_db 5.0 database name, in #mysql50#name format
1716
@return 0 on success, 1 on error
1718
bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
1720
int error= 0, change_to_newdb= 0;
1721
char path[FN_REFLEN+16];
1723
HA_CREATE_INFO create_info;
1725
TABLE_LIST *table_list;
1726
SELECT_LEX *sl= thd->lex->current_select;
1728
DBUG_ENTER("mysql_upgrade_db");
1730
if ((old_db->length <= MYSQL50_TABLE_NAME_PREFIX_LENGTH) ||
1731
(strncmp(old_db->str,
1732
MYSQL50_TABLE_NAME_PREFIX,
1733
MYSQL50_TABLE_NAME_PREFIX_LENGTH) != 0))
1735
my_error(ER_WRONG_USAGE, MYF(0),
1736
"ALTER DATABASE UPGRADE DATA DIRECTORY NAME",
1741
/* `#mysql50#<name>` converted to encoded `<name>` */
1742
new_db.str= old_db->str + MYSQL50_TABLE_NAME_PREFIX_LENGTH;
1743
new_db.length= old_db->length - MYSQL50_TABLE_NAME_PREFIX_LENGTH;
1745
if (lock_databases(thd, old_db->str, old_db->length,
1746
new_db.str, new_db.length))
1750
Let's remember if we should do "USE newdb" afterwards.
1751
thd->db will be cleared in mysql_rename_db()
1753
if (thd->db && !strcmp(thd->db, old_db->str))
1756
build_table_filename(path, sizeof(path)-1,
1757
old_db->str, "", MY_DB_OPT_FILE, 0);
1758
if ((load_db_opt(thd, path, &create_info)))
1759
create_info.default_table_charset= thd->variables.collation_server;
1761
length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "", 0);
1762
if (length && path[length-1] == FN_LIBCHAR)
1763
path[length-1]=0; // remove ending '\'
1764
if ((error= my_access(path,F_OK)))
1766
my_error(ER_BAD_DB_ERROR, MYF(0), old_db->str);
1770
/* Step1: Create the new database */
1771
if ((error= mysql_create_db(thd, new_db.str, &create_info, 1)))
1774
/* Step2: Move tables to the new database */
1775
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
1777
uint nfiles= (uint) dirp->number_off_files;
1778
for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++)
1780
FILEINFO *file= dirp->dir_entry + idx;
1781
char *extension, tname[FN_REFLEN];
1782
LEX_STRING table_str;
1783
DBUG_PRINT("info",("Examining: %s", file->name));
1785
/* skiping non-FRM files */
1786
if (my_strcasecmp(files_charset_info,
1787
(extension= fn_rext(file->name)), reg_ext))
1790
/* A frm file found, add the table info rename list */
1793
table_str.length= filename_to_tablename(file->name,
1794
tname, sizeof(tname)-1);
1795
table_str.str= (char*) sql_memdup(tname, table_str.length + 1);
1796
Table_ident *old_ident= new Table_ident(thd, *old_db, table_str, 0);
1797
Table_ident *new_ident= new Table_ident(thd, new_db, table_str, 0);
1798
if (!old_ident || !new_ident ||
1799
!sl->add_table_to_list(thd, old_ident, NULL,
1800
TL_OPTION_UPDATING, TL_IGNORE) ||
1801
!sl->add_table_to_list(thd, new_ident, NULL,
1802
TL_OPTION_UPDATING, TL_IGNORE))
1812
if ((table_list= thd->lex->query_tables) &&
1813
(error= mysql_rename_tables(thd, table_list, 1)))
1816
Failed to move all tables from the old database to the new one.
1817
In the best case mysql_rename_tables() moved all tables back to the old
1818
database. In the worst case mysql_rename_tables() moved some tables
1819
to the new database, then failed, then started to move the tables back,
1820
and then failed again. In this situation we have some tables in the
1821
old database and some tables in the new database.
1822
Let's delete the option file, and then the new database directory.
1823
If some tables were left in the new directory, rmdir() will fail.
1824
It garantees we never loose any tables.
1826
build_table_filename(path, sizeof(path)-1,
1827
new_db.str,"",MY_DB_OPT_FILE, 0);
1828
my_delete(path, MYF(MY_WME));
1829
length= build_table_filename(path, sizeof(path)-1, new_db.str, "", "", 0);
1830
if (length && path[length-1] == FN_LIBCHAR)
1831
path[length-1]=0; // remove ending '\'
1837
if ((dirp = my_dir(path,MYF(MY_DONT_SORT))))
1839
uint nfiles= (uint) dirp->number_off_files;
1840
for (uint idx=0 ; idx < nfiles ; idx++)
1842
FILEINFO *file= dirp->dir_entry + idx;
1843
char oldname[FN_REFLEN], newname[FN_REFLEN];
1844
DBUG_PRINT("info",("Examining: %s", file->name));
1846
/* skiping . and .. and MY_DB_OPT_FILE */
1847
if ((file->name[0] == '.' &&
1848
(!file->name[1] || (file->name[1] == '.' && !file->name[2]))) ||
1849
!my_strcasecmp(files_charset_info, file->name, MY_DB_OPT_FILE))
1852
/* pass empty file name, and file->name as extension to avoid encoding */
1853
build_table_filename(oldname, sizeof(oldname)-1,
1854
old_db->str, "", file->name, 0);
1855
build_table_filename(newname, sizeof(newname)-1,
1856
new_db.str, "", file->name, 0);
1857
my_rename(oldname, newname, MYF(MY_WME));
1863
Step7: drop the old database.
1864
remove_db_from_cache(olddb) and query_cache_invalidate(olddb)
1865
are done inside mysql_rm_db(), no needs to execute them again.
1866
mysql_rm_db() also "unuses" if we drop the current database.
1868
error= mysql_rm_db(thd, old_db->str, 0, 1);
1870
/* Step8: logging */
1871
if (mysql_bin_log.is_open())
1873
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, TRUE);
1875
mysql_bin_log.write(&qinfo);
1878
/* Step9: Let's do "use newdb" if we renamed the current database */
1879
if (change_to_newdb)
1880
error|= mysql_change_db(thd, & new_db, FALSE);
1883
pthread_mutex_lock(&LOCK_lock_db);
1884
/* Remove the databases from db lock cache */
1885
lock_db_delete(old_db->str, old_db->length);
1886
lock_db_delete(new_db.str, new_db.length);
1887
creating_database--;
1888
/* Signal waiting CREATE TABLE's to continue */
1889
pthread_cond_signal(&COND_refresh);
1890
pthread_mutex_unlock(&LOCK_lock_db);
1898
Check if there is directory for the database name.
1901
check_db_dir_existence()
1902
db_name database name
1905
FALSE There is directory for the specified database name.
1906
TRUE The directory does not exist.
1909
bool check_db_dir_existence(const char *db_name)
1911
char db_dir_path[FN_REFLEN];
1912
uint db_dir_path_len;
1914
db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
1915
db_name, "", "", 0);
1917
if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
1918
db_dir_path[db_dir_path_len - 1]= 0;
1922
return my_access(db_dir_path, F_OK);