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.cc285
1 files changed, 280 insertions, 5 deletions
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 0e2cfba1b30..dee26aae4be 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -25,20 +25,114 @@
#include <direct.h>
#endif
+#define MY_DB_OPT_FILE ".db.opt"
+
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
const char *db, const char *path,
uint level);
+/*
+ Create database options file:
+ Currently databse default charset is only stored there.
+*/
+
+static int write_db_opt(THD *thd,const char *db,HA_CREATE_INFO *create,char *fn)
+{
+ register File file;
+ char buf[256]; // Should be enough
+ int error=0;
+
+ if ((file=my_create(fn,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+ {
+ sprintf(buf,"default-character-set=%s\n",
+ (create && create->table_charset) ?
+ create->table_charset->name : "DEFAULT");
+
+ if (my_write(file,(byte*)buf,strlen(buf),MYF(MY_NABP+MY_WME)))
+ {
+ // QQ : should we send more suitable error message?
+ my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno);
+ error = -1;
+ goto exit;
+ }
+ my_close(file,MYF(0));
+ }
+ else
+ {
+ // QQ : should we send more suitable error message?
+ my_error(ER_CANT_CREATE_DB,MYF(0),db,my_errno);
+ error = -1;
+ goto exit;
+ }
+exit:
+ return error;
+}
+
+
+ /*
+ Load database options file:
+ */
+static int load_db_opt(THD *thd,const char *db,HA_CREATE_INFO *create,char *fn)
+{
+ register File file;
+ char buf[256]="";
+
+ if ((file=my_open(fn,O_RDWR|O_BINARY,MYF(MY_WME))) >= 0)
+ {
+ int nbytes=my_read(file,(byte*)buf,sizeof(buf)-1,MYF(0));
+ if ( nbytes >= 0 )
+ {
+ char *ln=buf;
+ char *pe=buf+nbytes;
+
+ buf[nbytes]='\0';
+
+ for ( ln=buf; ln<pe; )
+ {
+ char *le,*val;
+ for ( le=ln, val=0 ; le<pe ; le++ )
+ {
+ switch(le[0])
+ {
+ case '=':
+ le[0]='\0';
+ val=le+1;
+ le++;
+ break;
+ case '\r':
+ case '\n':
+ le[0]='\0';
+ le++;
+ for( ; (le[0]=='\r' || le[0]=='\n') ; le++);
+ if (!strcmp(ln,"default-character-set") && val && val[0])
+ {
+ create->table_charset=get_charset_by_name(val, MYF(0));
+ }
+ goto cnt;
+ break;
+ }
+ }
+cnt:
+ ln=le;
+ }
+ }
+ my_close(file,MYF(0));
+ }
+ return 0;
+}
+
/* db-name is already validated when we come here */
-int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
+int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent)
{
char path[FN_REFLEN+16];
MY_DIR *dirp;
long result=1;
int error = 0;
+ uint create_options = create_info ? create_info->options : 0;
+
DBUG_ENTER("mysql_create_db");
-
+
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
// do not create database if another thread is holding read lock
@@ -73,6 +167,12 @@ int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
}
}
+ strcat(path,"/");
+ unpack_dirname(path,path);
+ strcat(path,MY_DB_OPT_FILE);
+ if ((error=write_db_opt(thd,db,create_info,path)))
+ goto exit;
+
if (!silent)
{
if (!thd->query)
@@ -85,6 +185,76 @@ int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
+ Query_log_event qinfo(thd, thd->query);
+ mysql_bin_log.write(&qinfo);
+ }
+ }
+ if (thd->query == path)
+ {
+ thd->query = 0; // just in case
+ thd->query_length = 0;
+ }
+ send_ok(&thd->net, result);
+ }
+
+exit:
+ start_waiting_global_read_lock(thd);
+exit2:
+ VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
+ DBUG_RETURN(error);
+}
+
+
+/* db-name is already validated when we come here */
+
+int mysql_alter_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent)
+{
+ char path[FN_REFLEN+16];
+ MY_DIR *dirp;
+ long result=1;
+ int error = 0;
+ DBUG_ENTER("mysql_create_db");
+ register File file;
+ uint create_options = create_info ? create_info->options : 0;
+
+ VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
+ // do not alter database if another thread is holding read lock
+ if (wait_if_global_read_lock(thd,0))
+ {
+ error= -1;
+ goto exit2;
+ }
+
+ /* Check directory */
+ (void)sprintf(path,"%s/%s", mysql_data_home, db);
+ strcat(path,"/");
+ unpack_dirname(path,path); // Convert if not unix
+ strcat(path,MY_DB_OPT_FILE);
+ if ((error=write_db_opt(thd,db,create_info,path)))
+ goto exit;
+
+ /*
+ Change options if current
+ database is being altered
+ */
+ if (thd->db && !strcmp(thd->db,db))
+ {
+ thd->db_charset= create_info ? create_info->table_charset : NULL;
+ }
+
+ if (!silent)
+ {
+ if (!thd->query)
+ {
+ thd->query = path;
+ thd->query_length = (uint) (strxmov(path,"alter database ", db, NullS)-
+ path);
+ }
+ {
+ mysql_update_log.write(thd,thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
Query_log_event qinfo(thd, thd->query, thd->query_length);
mysql_bin_log.write(&qinfo);
}
@@ -104,7 +274,11 @@ exit2:
DBUG_RETURN(error);
}
-const char *del_exts[]= {".frm", ".BAK", ".TMD", NullS};
+
+
+
+
+const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
static TYPELIB deletable_extentions=
{array_elements(del_exts)-1,"del_exts", del_exts};
@@ -220,7 +394,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
DBUG_PRINT("info",("Examining: %s", file->name));
/* Check if file is a raid directory */
- if (isdigit(file->name[0]) && isdigit(file->name[1]) &&
+ if (my_isdigit(system_charset_info,file->name[0]) &&
+ my_isdigit(system_charset_info,file->name[1]) &&
!file->name[2] && !level)
{
char newpath[FN_REFLEN];
@@ -245,7 +420,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
continue;
}
strxmov(filePath,org_path,"/",file->name,NullS);
- if (db && !my_strcasecmp(fn_ext(file->name), reg_ext))
+ if (db && !my_strcasecmp(system_charset_info,
+ fn_ext(file->name), reg_ext))
{
/* Drop the table nicely */
*fn_ext(file->name)=0; // Remove extension
@@ -333,6 +509,8 @@ bool mysql_change_db(THD *thd,const char *name)
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
uint db_access;
+ HA_CREATE_INFO create;
+
DBUG_ENTER("mysql_change_db");
if (!dbname || !(db_length=strip_sp(dbname)))
@@ -385,5 +563,102 @@ bool mysql_change_db(THD *thd,const char *name)
thd->db=dbname;
thd->db_length=db_length;
thd->db_access=db_access;
+
+ strcat(path,"/");
+ unpack_dirname(path,path);
+ strcat(path,MY_DB_OPT_FILE);
+ bzero(&create,sizeof(create));
+ load_db_opt(thd,name,&create,path);
+ thd->db_charset=create.table_charset;
+
+ DBUG_RETURN(0);
+}
+
+
+int mysqld_show_create_db(THD *thd,const char *name)
+{
+ int length, db_length;
+ char *dbname=my_strdup((char*) name,MYF(MY_WME));
+ char path[FN_REFLEN];
+ uint db_access;
+ HA_CREATE_INFO create;
+ CONVERT *convert=thd->convert_set;
+
+ DBUG_ENTER("mysql_show_create_db");
+
+ if (!dbname || !(db_length=strip_sp(dbname)))
+ {
+ x_free(dbname); /* purecov: inspected */
+ send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+ }
+
+ if ((db_length > NAME_LEN) || check_db_name(dbname))
+ {
+ net_printf(&thd->net,ER_WRONG_DB_NAME, dbname);
+ x_free(dbname);
+ DBUG_RETURN(1);
+ }
+
+ if (test_all_bits(thd->master_access,DB_ACLS))
+ db_access=DB_ACLS;
+ else
+ db_access= (acl_get(thd->host,thd->ip,(char*) &thd->remote.sin_addr,
+ thd->priv_user,dbname) |
+ thd->master_access);
+ if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
+ {
+ net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ dbname);
+ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
+ thd->priv_user,
+ thd->host_or_ip,
+ dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
+ length=unpack_dirname(path,path); // Convert if not unix
+ if (length && path[length-1] == FN_LIBCHAR)
+ path[length-1]=0; // remove ending '\'
+ if (access(path,F_OK))
+ {
+ net_printf(&thd->net,ER_BAD_DB_ERROR,dbname);
+ my_free(dbname,MYF(0));
+ DBUG_RETURN(1);
+ }
+
+ strcat(path,"/");
+ unpack_dirname(path,path);
+ strcat(path,MY_DB_OPT_FILE);
+ bzero(&create,sizeof(create));
+ load_db_opt(thd,name,&create,path);
+
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("Database",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Create Database",1024));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ String *packet = &thd->packet;
+ packet->length(0);
+ net_store_data(packet, convert, name);
+ sprintf(path, "CREATE DATABASE %s", name);
+ if (create.table_charset)
+ {
+ strcat(path," DEFAULT CHARACTER SET ");
+ strcat(path,create.table_charset->name);
+ }
+ net_store_data(packet, convert, path);
+
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_RETURN(1);
+
+ send_eof(&thd->net);
+
DBUG_RETURN(0);
}