diff options
Diffstat (limited to 'sql/sql_db.cc')
-rw-r--r-- | sql/sql_db.cc | 139 |
1 files changed, 108 insertions, 31 deletions
diff --git a/sql/sql_db.cc b/sql/sql_db.cc index d110ff6f778..5ca3f07f0bd 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -26,13 +26,16 @@ #include <direct.h> #endif +#define MAX_DROP_TABLE_Q_LEN 1024 + const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS}; static TYPELIB deletable_extentions= {array_elements(del_exts)-1,"del_exts", del_exts, NULL}; static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, - const char *db, const char *path, - uint level); + const char *db, const char *path, uint level, + TABLE_LIST **dropped_tables); + static long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path); static my_bool rm_dir_w_symlink(const char *org_path, my_bool send_error); /* Database options hash */ @@ -52,6 +55,7 @@ typedef struct my_dbopt_st /* 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))) { @@ -61,6 +65,21 @@ static byte* dboptions_get_key(my_dbopt_t *opt, uint *length, /* + Helper function to write a query to binlog used by mysql_rm_db() +*/ + +static inline void write_to_binlog(THD *thd, char *query, uint q_len, + char *db, uint db_len) +{ + Query_log_event qinfo(thd, query, q_len, 0, 0); + qinfo.error_code= 0; + qinfo.db= db; + qinfo.db_len= db_len; + mysql_bin_log.write(&qinfo); +} + + +/* Function to free dboptions hash element */ @@ -593,6 +612,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) char path[FN_REFLEN+16]; MY_DIR *dirp; uint length; + TABLE_LIST* dropped_tables= 0; DBUG_ENTER("mysql_rm_db"); VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); @@ -629,8 +649,10 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) remove_db_from_cache(db); pthread_mutex_unlock(&LOCK_open); + error= -1; - if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0)) >= 0) + if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0, + &dropped_tables)) >= 0) { ha_drop_database(path); query_cache_invalidate1(db); @@ -672,6 +694,43 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) send_ok(thd, (ulong) deleted); thd->server_status&= ~SERVER_STATUS_DB_DROPPED; } + else if (mysql_bin_log.is_open()) + { + char *query, *query_pos, *query_end, *query_data_start; + TABLE_LIST *tbl; + uint db_len; + + if (!(query= thd->alloc(MAX_DROP_TABLE_Q_LEN))) + goto exit; /* not much else we can do */ + query_pos= query_data_start= strmov(query,"drop table "); + query_end= query + MAX_DROP_TABLE_Q_LEN; + db_len= strlen(db); + + for (tbl= dropped_tables; tbl; tbl= tbl->next_local) + { + uint tbl_name_len; + if (!tbl->was_dropped) + continue; + + /* 3 for the quotes and the comma*/ + tbl_name_len= strlen(tbl->table_name) + 3; + if (query_pos + tbl_name_len + 1 >= query_end) + { + write_to_binlog(thd, query, query_pos -1 - query, db, db_len); + query_pos= query_data_start; + } + + *query_pos++ = '`'; + query_pos= strmov(query_pos,tbl->table_name); + *query_pos++ = '`'; + *query_pos++ = ','; + } + + if (query_pos != query_data_start) + { + write_to_binlog(thd, query, query_pos -1 - query, db, db_len); + } + } exit: (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */ @@ -717,7 +776,8 @@ exit2: */ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, - const char *org_path, uint level) + const char *org_path, uint level, + TABLE_LIST **dropped_tables) { long deleted=0; ulong found_other_files=0; @@ -759,7 +819,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) { DBUG_PRINT("my",("New subdir found: %s", newpath)); - if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1)) < 0) + if ((mysql_rm_known_files(thd, new_dirp, NullS, newpath,1,0)) < 0) goto err; if (!(copy_of_path= thd->memdup(newpath, length+1)) || !(dir= new (thd->mem_root) String(copy_of_path, length, @@ -837,6 +897,9 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, } my_dirend(dirp); + if (dropped_tables) + *dropped_tables= tot_list; + /* If the directory is a symbolic link, remove the link first, then remove the directory the symbolic link pointed at @@ -996,8 +1059,9 @@ err: SYNOPSIS mysql_change_db() - thd Thread handler - name Databasename + thd Thread handler + name Databasename + no_access_check True don't do access check. In this case name may be "" DESCRIPTION Becasue the database name may have been given directly from the @@ -1009,28 +1073,37 @@ err: replication slave SQL thread (for that thread, setting of thd->db is done in ::exec_event() methods of log_event.cc). - This function does not send the error message to the client, if that - should be sent to the client, call net_send_error after this function + This function does not send anything, including error messages to the + client, if that should be sent to the client, call net_send_error after + this function. RETURN VALUES 0 ok 1 error */ -bool mysql_change_db(THD *thd, const char *name) +bool mysql_change_db(THD *thd, const char *name, bool no_access_check) { int length, db_length; char *dbname=my_strdup((char*) name,MYF(MY_WME)); char path[FN_REFLEN]; HA_CREATE_INFO create; - bool schema_db= 0; + bool system_db= 0; #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; #endif DBUG_ENTER("mysql_change_db"); + DBUG_PRINT("enter",("name: '%s'",name)); + /* dbname can only be NULL if malloc failed */ if (!dbname || !(db_length= strlen(dbname))) { + if (no_access_check && dbname) + { + /* Called from SP when orignal database was not set */ + system_db= 1; + goto end; + } x_free(dbname); /* purecov: inspected */ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */ @@ -1045,7 +1118,7 @@ bool mysql_change_db(THD *thd, const char *name) DBUG_PRINT("info",("Use database: %s", dbname)); if (!my_strcasecmp(system_charset_info, dbname, information_schema_name.str)) { - schema_db= 1; + system_db= 1; #ifndef NO_EMBEDDED_ACCESS_CHECKS db_access= SELECT_ACL; #endif @@ -1053,23 +1126,27 @@ bool mysql_change_db(THD *thd, const char *name) } #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (test_all_bits(thd->master_access,DB_ACLS)) - db_access=DB_ACLS; - else - db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) | - thd->master_access); - if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) + if (!no_access_check) { - my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - thd->priv_user, - thd->priv_host, - dbname); - mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - thd->priv_user, - thd->priv_host, - dbname); - my_free(dbname,MYF(0)); - 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, thd->priv_user,dbname,0) | + thd->master_access); + if (!(db_access & DB_ACLS) && (!grant_option || + check_grant_db(thd,dbname))) + { + my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), + thd->priv_user, + thd->priv_host, + dbname); + mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), + thd->priv_user, + thd->priv_host, + dbname); + my_free(dbname,MYF(0)); + DBUG_RETURN(1); + } } #endif (void) sprintf(path,"%s/%s",mysql_data_home,dbname); @@ -1083,14 +1160,14 @@ bool mysql_change_db(THD *thd, const char *name) DBUG_RETURN(1); } end: - send_ok(thd); x_free(thd->db); thd->db=dbname; // THD::~THD will free this thd->db_length=db_length; #ifndef NO_EMBEDDED_ACCESS_CHECKS - thd->db_access=db_access; + if (!no_access_check) + thd->db_access=db_access; #endif - if (schema_db) + if (system_db) { thd->db_charset= system_charset_info; thd->variables.collation_database= system_charset_info; |