diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1d0e3c1a72f..2992f11ef65 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -289,7 +289,8 @@ inline THD *_current_thd(void) #define prepare_execute(A) ((A)->command == COM_EXECUTE) -int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent); +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); +int mysql_alter_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); void mysql_binlog_send(THD* thd, char* log_ident, ulong pos, ushort flags); int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 91f7474bb33..aa8030e5a3e 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -31,6 +31,96 @@ 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, 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,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; lndb_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, HA_CREATE_INFO *create_info, bool silent) @@ -39,10 +129,10 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent 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; - + + DBUG_ENTER("mysql_create_db"); + VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); // do not create database if another thread is holding read lock @@ -77,37 +167,12 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent } } - /* - Create database options file: - Currently databse default charset is only stored there. - */ - strcat(path,"/"); unpack_dirname(path,path); strcat(path,MY_DB_OPT_FILE); - if ((file=my_create(path,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) - { - sprintf(path,"default-character-set=%s\n", - (create_info && create_info->table_charset) ? - create_info->table_charset->name : "DEFAULT"); - - if (my_write(file,(byte*) path,strlen(path),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; + if ((error=write_db_opt(thd,db,create_info,path))) goto exit; - } - + if (!silent) { if (!thd->query) @@ -139,6 +204,73 @@ exit2: 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; + + printf("alter database\n"); + + 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; + + 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); + 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); +} + + + + + const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS}; static TYPELIB deletable_extentions= {array_elements(del_exts)-1,"del_exts", del_exts}; @@ -368,7 +500,6 @@ bool mysql_change_db(THD *thd,const char *name) char path[FN_REFLEN]; uint db_access; DBUG_ENTER("mysql_change_db"); - register File file; if (!dbname || !(db_length=strip_sp(dbname))) { @@ -419,53 +550,11 @@ bool mysql_change_db(THD *thd,const char *name) thd->db_length=db_length; thd->db_access=db_access; - /* - Load database options file: - */ - strcat(path,"/"); unpack_dirname(path,path); strcat(path,MY_DB_OPT_FILE); - if ((file=my_open(path,O_RDWR|O_BINARY,MYF(MY_WME))) >= 0) - { - int nbytes=my_read(file,(byte*) path,sizeof(path),MYF(0)); - if ( nbytes >= 0 ) - { - char *ln=path; - char *pe=path+nbytes; + load_db_opt(thd,path); - path[nbytes]='\0'; - for ( ln=path; lndb_charset=get_charset_by_name(val, MYF(0)); - } - goto cnt; - break; - } - } -cnt: - ln=le; - } - } - my_close(file,MYF(0)); - } DBUG_RETURN(0); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ca824b3eab8..545300b2629 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -44,7 +44,8 @@ enum enum_sql_command { SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, - SQLCOM_GRANT, SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, + SQLCOM_GRANT, + SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1f7e05fbae0..43cb056ffc8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2328,6 +2328,23 @@ mysql_execute_command(void) res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0); break; } + case SQLCOM_ALTER_DB: + { + if (!strip_sp(lex->name) || check_db_name(lex->name)) + { + net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + break; + } + if (check_access(thd,DROP_ACL,lex->name,0,1)) + break; + if (thd->locked_tables || thd->active_transaction()) + { + send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + goto error; + } + res=mysql_alter_db(thd,lex->name,&lex->create_info,0); + break; + } case SQLCOM_CREATE_FUNCTION: if (check_access(thd,INSERT_ACL,"mysql",0,1)) break; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index faa63afa6c7..303a539eb49 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -885,12 +885,7 @@ create_table_option: table_list->next=0; lex->create_info.used_fields|= HA_CREATE_USED_UNION; } - | CHARSET EQ DEFAULT - { - Lex->create_info.table_charset=NULL; - Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET; - } - | CHARSET EQ charset + | CHARSET EQ charset_or_nocharset { Lex->create_info.table_charset=Lex->charset; Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET; @@ -1139,6 +1134,10 @@ charset: } }; +charset_or_nocharset: + charset + | DEFAULT {Lex->charset=NULL; } + opt_binary: /* empty */ { Lex->charset=NULL; } | BINARY { Lex->type|=BINARY_FLAG; Lex->charset=NULL; } @@ -1146,7 +1145,7 @@ opt_binary: default_charset: /* empty */ { Lex->charset=NULL; } - | DEFAULT CHAR_SYM SET charset ; + | DEFAULT CHAR_SYM SET charset_or_nocharset ; references: REFERENCES table_ident @@ -1270,7 +1269,16 @@ alter: lex->simple_alter=1; } alter_list; - + + | ALTER DATABASE ident default_charset + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_ALTER_DB; + lex->name=$3.str; + lex->create_info.table_charset=lex->charset; + } + + alter_list: | alter_list_item | alter_list ',' alter_list_item;