summaryrefslogtreecommitdiff
path: root/sql/sql_db.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_db.cc')
-rw-r--r--sql/sql_db.cc266
1 files changed, 242 insertions, 24 deletions
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 9db2198268a..d3804b972c8 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -39,6 +39,197 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
const char *db, const char *path,
uint level);
+/* Database options hash */
+static HASH dboptions;
+static my_bool dboptions_init= 0;
+static rw_lock_t LOCK_dboptions;
+
+/* Structure for database options */
+typedef struct my_dbopt_st
+{
+ char *name; /* Database name */
+ uint name_length; /* Database length name */
+ CHARSET_INFO *charset; /* Database default character set */
+} my_dbopt_t;
+
+
+/*
+ Function we use in the creation of our hash to get key.
+*/
+static byte* dboptions_get_key(my_dbopt_t *opt, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ *length= opt->name_length;
+ return (byte*) opt->name;
+}
+
+
+/*
+ Function to free dboptions hash element
+*/
+
+static void free_dbopt(void *dbopt)
+{
+ my_free((gptr) dbopt, MYF(0));
+}
+
+
+/*
+ Initialize database option hash
+
+ SYNOPSIS
+ my_dbopt_init()
+
+ NOTES
+ Must be called before any other database function is called.
+
+ RETURN
+ 0 ok
+ 1 Fatal error
+*/
+
+bool my_dbopt_init(void)
+{
+ bool error= 0;
+ (void) my_rwlock_init(&LOCK_dboptions, NULL);
+ if (!dboptions_init)
+ {
+ dboptions_init= 1;
+ error= hash_init(&dboptions, lower_case_table_names ?
+ &my_charset_bin : system_charset_info,
+ 32, 0, 0, (hash_get_key) dboptions_get_key,
+ free_dbopt,0);
+ }
+ return error;
+}
+
+
+/*
+ Free database option hash.
+*/
+
+void my_dbopt_free(void)
+{
+ if (dboptions_init)
+ {
+ dboptions_init= 0;
+ hash_free(&dboptions);
+ (void) rwlock_destroy(&LOCK_dboptions);
+ }
+}
+
+
+void my_dbopt_cleanup(void)
+{
+ rw_wrlock(&LOCK_dboptions);
+ hash_free(&dboptions);
+ hash_init(&dboptions, lower_case_table_names ?
+ &my_charset_bin : system_charset_info,
+ 32, 0, 0, (hash_get_key) dboptions_get_key,
+ free_dbopt,0);
+ rw_unlock(&LOCK_dboptions);
+}
+
+
+/*
+ Find database options in the hash.
+
+ DESCRIPTION
+ Search a database options in the hash, usings its path.
+ Fills "create" on success.
+
+ RETURN VALUES
+ 0 on success.
+ 1 on error.
+*/
+
+static my_bool get_dbopt(const char *dbname, HA_CREATE_INFO *create)
+{
+ my_dbopt_t *opt;
+ uint length;
+ my_bool error= 1;
+
+ length= (uint) strlen(dbname);
+
+ rw_rdlock(&LOCK_dboptions);
+ if ((opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length)))
+ {
+ create->default_table_charset= opt->charset;
+ error= 0;
+ }
+ rw_unlock(&LOCK_dboptions);
+ return error;
+}
+
+
+/*
+ Writes database options into the hash.
+
+ DESCRIPTION
+ Inserts database options into the hash, or updates
+ options if they are already in the hash.
+
+ RETURN VALUES
+ 0 on success.
+ 1 on error.
+*/
+
+static my_bool put_dbopt(const char *dbname, HA_CREATE_INFO *create)
+{
+ my_dbopt_t *opt;
+ uint length;
+ my_bool error= 0;
+ DBUG_ENTER("put_dbopt");
+
+ length= (uint) strlen(dbname);
+
+ rw_wrlock(&LOCK_dboptions);
+ if (!(opt= (my_dbopt_t*) hash_search(&dboptions, (byte*) dbname, length)))
+ {
+ /* Options are not in the hash, insert them */
+ char *tmp_name;
+ if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &opt, (uint) sizeof(*opt), &tmp_name, length+1,
+ NullS))
+ {
+ error= 1;
+ goto end;
+ }
+
+ opt->name= tmp_name;
+ strmov(opt->name, dbname);
+ opt->name_length= length;
+
+ if ((error= my_hash_insert(&dboptions, (byte*) opt)))
+ {
+ my_free((gptr) opt, MYF(0));
+ goto end;
+ }
+ }
+
+ /* Update / write options in hash */
+ opt->charset= create->default_table_charset;
+
+end:
+ rw_unlock(&LOCK_dboptions);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Deletes database options from the hash.
+*/
+
+void del_dbopt(const char *path)
+{
+ my_dbopt_t *opt;
+ rw_wrlock(&LOCK_dboptions);
+ if ((opt= (my_dbopt_t *)hash_search(&dboptions, path, strlen(path))))
+ hash_delete(&dboptions, (byte*) opt);
+ rw_unlock(&LOCK_dboptions);
+}
+
+
/*
Create database options file:
@@ -56,15 +247,20 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
char buf[256]; // Should be enough for one option
bool error=1;
+ if (!create->default_table_charset)
+ create->default_table_charset= thd->variables.collation_server;
+
+ if (put_dbopt(path, create))
+ return 1;
+
if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
{
ulong length;
- CHARSET_INFO *cs= ((create && create->default_table_charset) ?
- create->default_table_charset :
- thd->variables.collation_server);
- length= my_sprintf(buf,(buf,
- "default-character-set=%s\ndefault-collation=%s\n",
- cs->csname,cs->name));
+ length= (ulong) (strxnmov(buf, sizeof(buf), "default-character-set=",
+ create->default_table_charset->csname,
+ "\ndefault-collation=",
+ create->default_table_charset->name,
+ "\n", NullS) - buf);
/* Error is written by my_write */
if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME)))
@@ -101,6 +297,12 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
bzero((char*) create,sizeof(*create));
create->default_table_charset= thd->variables.collation_server;
+
+ /* Check if options for this database are already in the hash */
+ if (!get_dbopt(path, create))
+ DBUG_RETURN(0);
+
+ /* Otherwise, load options from the .opt file */
if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0)
{
IO_CACHE cache;
@@ -137,9 +339,16 @@ bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
}
}
}
- error=0;
end_io_cache(&cache);
my_close(file,MYF(0));
+ /*
+ Put the loaded value into the hash.
+ Note that another thread could've added the same
+ entry to the hash after we called get_dbopt(),
+ but it's not an error, as put_dbopt() takes this
+ possibility into account.
+ */
+ error= put_dbopt(path, create);
}
DBUG_RETURN(error);
}
@@ -167,10 +376,11 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
bool silent)
{
char path[FN_REFLEN+16];
- long result=1;
- int error = 0;
+ long result= 1;
+ int error= 0;
MY_STAT stat_info;
- uint create_options = create_info ? create_info->options : 0;
+ uint create_options= create_info ? create_info->options : 0;
+ uint path_len;
DBUG_ENTER("mysql_create_db");
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
@@ -184,17 +394,18 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
/* Check directory */
strxmov(path, mysql_data_home, "/", db, NullS);
- unpack_dirname(path,path); // Convert if not unix
+ path_len= unpack_dirname(path,path); // Convert if not unix
+ path[path_len-1]= 0; // Remove last '/' from path
if (my_stat(path,&stat_info,MYF(0)))
{
if (!(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
{
my_error(ER_DB_CREATE_EXISTS,MYF(0),db);
- error = -1;
+ error= -1;
goto exit;
}
- result = 0;
+ result= 0;
}
else
{
@@ -203,23 +414,23 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
my_error(EE_STAT, MYF(0),path,my_errno);
goto exit;
}
- strend(path)[-1]=0; // Remove last '/' from path
if (my_mkdir(path,0777,MYF(0)) < 0)
{
my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno);
- error = -1;
+ error= -1;
goto exit;
}
}
- unpack_dirname(path, path);
- strcat(path,MY_DB_OPT_FILE);
+ path[path_len-1]= FN_LIBCHAR;
+ strmake(path+path_len, MY_DB_OPT_FILE, sizeof(path)-path_len-1);
if (write_db_opt(thd, path, create_info))
{
/*
Could not create options file.
Restore things to beginning.
*/
+ path[path_len]= 0;
if (rmdir(path) >= 0)
{
error= -1;
@@ -271,7 +482,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
{
char path[FN_REFLEN+16];
long result=1;
- int error = 0;
+ int error= 0;
DBUG_ENTER("mysql_alter_db");
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
@@ -281,7 +492,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
goto exit2;
/* Check directory */
- (void)sprintf(path,"%s/%s/%s", mysql_data_home, db, MY_DB_OPT_FILE);
+ strxmov(path, mysql_data_home, "/", db, "/", MY_DB_OPT_FILE, NullS);
fn_format(path, path, "", "", MYF(MY_UNPACK_FILENAME));
if ((error=write_db_opt(thd, path, create_info)))
goto exit;
@@ -335,9 +546,11 @@ exit2:
int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
{
long deleted=0;
- int error = 0;
+ int error= 0;
char path[FN_REFLEN+16], tmp_db[NAME_LEN+1];
MY_DIR *dirp;
+ uint length;
+ my_dbopt_t *dbopt;
DBUG_ENTER("mysql_rm_db");
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
@@ -350,9 +563,13 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
(void) sprintf(path,"%s/%s",mysql_data_home,db);
- unpack_dirname(path,path); // Convert if not unix
+ length= unpack_dirname(path,path); // Convert if not unix
+ strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
+ del_dbopt(path); // Remove dboption hash entry
+ path[length]= '\0'; // Remove file name
+
/* See if the directory exists */
- if (!(dirp = my_dir(path,MYF(MY_DONT_SORT))))
+ if (!(dirp= my_dir(path,MYF(MY_DONT_SORT))))
{
if (!if_exists)
{
@@ -636,8 +853,10 @@ bool mysql_change_db(THD *thd, const char *name)
int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
- ulong db_access;
HA_CREATE_INFO create;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ ulong db_access;
+#endif
DBUG_ENTER("mysql_change_db");
if (!dbname || !(db_length= strlen(dbname)))
@@ -698,4 +917,3 @@ bool mysql_change_db(THD *thd, const char *name)
thd->variables.collation_database= thd->db_charset;
DBUG_RETURN(0);
}
-