diff options
author | Michael Widenius <monty@mariadb.org> | 2014-03-23 15:43:57 +0200 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2014-03-23 15:43:57 +0200 |
commit | b18a1b0e6ccc326ced01620edd842d899139feec (patch) | |
tree | 1c2d5fab29f5064c7050861aede99c526cc6dfd2 /sql | |
parent | 797a44a9ec5a601a4745b9520c2dea321f96d155 (diff) | |
download | mariadb-git-b18a1b0e6ccc326ced01620edd842d899139feec.tar.gz |
MDEV-5850: MySQL Bug#21317: SHOW CREATE DATABASE does not obey to lower_case_table_names
Bug #3329 Incomplete lower_case_table_names=2 implementation
The problem was that check_db_name() converted database names to lower case also in case of lower_case_table_names=2.
Fixed by removing the conversion in check_db_name for lower_case_table_names = 2 and instead converting db name to
lower case at same places as table names are converted.
Fixed bug that SHOW CREATE DATABASE FOO showed information for database 'foo'.
I also removed some checks of lower_case_table_names when it was enough to use table_alias_charset.
mysql-test/mysql-test-run.pl:
Added --use-copy argument to force mysql-test-run to copy files instead of doing symlinks. This is needed when you run
with test directory on another file system
mysql-test/r/lowercase_table.result:
Updated results
mysql-test/r/lowercase_table2.result:
Updated results
mysql-test/suite/parts/r/partition_mgm_lc2_innodb.result:
Updated results
mysql-test/suite/parts/r/partition_mgm_lc2_memory.result:
Updated results
mysql-test/suite/parts/r/partition_mgm_lc2_myisam.result:
Updated results
mysql-test/t/lowercase_table.test:
Added tests with mixed case databases
mysql-test/t/lowercase_table2.test:
Added tests with mixed case databases
sql/log.cc:
Don't check lower_case_table_names when we can use table_alias_charset
sql/sql_base.cc:
Don't check lower_case_table_names when we can use table_alias_charset
sql/sql_db.cc:
Use cmp_db_names() for checking if current database changed.
mysql_rm_db() now converts db to lower case if lower_case_table_names was used.
Changed database options cache to use table_alias_charset. This fixed a bug where SHOW CREATE DATABASE showed wrong information.
sql/sql_parse.cc:
Change also db name to lower case when file names are changed.
Don't need to story copy of database name anymore when lower_case_table_names == 2 as check_db_name() don't convert in this case.
Updated arguments to mysqld_show_create_db().
When adding table to TABLE_LIST also convert db name to lower case if needed (same way as we do with table names).
sql/sql_show.cc:
mysqld_show_create_db() now also takes original name as argument for output to user.
sql/sql_show.h:
Updated prototype for mysqld_show_create_db()
sql/sql_table.cc:
In mysql_rename_table(), do same conversions to database name as we do for the file name
Diffstat (limited to 'sql')
-rw-r--r-- | sql/log.cc | 14 | ||||
-rw-r--r-- | sql/sql_base.cc | 4 | ||||
-rw-r--r-- | sql/sql_db.cc | 60 | ||||
-rw-r--r-- | sql/sql_parse.cc | 32 | ||||
-rw-r--r-- | sql/sql_show.cc | 32 | ||||
-rw-r--r-- | sql/sql_show.h | 4 | ||||
-rw-r--r-- | sql/sql_table.cc | 14 | ||||
-rw-r--r-- | sql/table.cc | 12 |
8 files changed, 96 insertions, 76 deletions
diff --git a/sql/log.cc b/sql/log.cc index 1943be2817f..e7a4c82b0b4 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -542,25 +542,19 @@ int check_if_log_table(const TABLE_LIST *table, { int result= 0; if (table->db_length == 5 && - !(lower_case_table_names ? - my_strcasecmp(system_charset_info, table->db, "mysql") : - strcmp(table->db, "mysql"))) + !my_strcasecmp(table_alias_charset, table->db, "mysql")) { const char *table_name= table->table_name; if (table->table_name_length == 11 && - !(lower_case_table_names ? - my_strcasecmp(system_charset_info, - table_name, "general_log") : - strcmp(table_name, "general_log"))) + !my_strcasecmp(table_alias_charset, table_name, "general_log")) { result= QUERY_LOG_GENERAL; goto end; } - if (table->table_name_length == 8 && !(lower_case_table_names ? - my_strcasecmp(system_charset_info, table_name, "slow_log") : - strcmp(table_name, "slow_log"))) + if (table->table_name_length == 8 && + !my_strcasecmp(table_alias_charset, table_name, "slow_log")) { result= QUERY_LOG_SLOW; goto end; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fba5708adfe..47db5762cc8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1372,9 +1372,7 @@ retry: /* Skip if table alias does not match. */ if (check_alias) { - if (lower_case_table_names ? - my_strcasecmp(files_charset_info, t_alias, res->alias) : - strcmp(t_alias, res->alias)) + if (my_strcasecmp(table_alias_charset, t_alias, res->alias)) goto next; } diff --git a/sql/sql_db.cc b/sql/sql_db.cc index bf55a20f2d9..6c823e0480c 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -78,6 +78,29 @@ typedef struct my_dbopt_st } my_dbopt_t; +/** + Return TRUE if db1_name is equal to db2_name, FALSE otherwise. + + The function allows to compare database names according to the MariaDB + rules. The database names db1 and db2 are equal if: + - db1 is NULL and db2 is NULL; + or + - db1 is not-NULL, db2 is not-NULL, db1 is equal to db2 in + table_alias_charset + + This is the same rules as we use for filenames. +*/ + +static inline bool +cmp_db_names(const char *db1_name, + const char *db2_name) +{ + return ((!db1_name && !db2_name) || + (db1_name && db2_name && + my_strcasecmp(table_alias_charset, db1_name, db2_name) == 0)); +} + + /* Function we use in the creation of our hash to get key. */ @@ -159,8 +182,7 @@ bool my_dboptions_cache_init(void) if (!dboptions_init) { dboptions_init= 1; - error= my_hash_init(&dboptions, lower_case_table_names ? - &my_charset_bin : system_charset_info, + error= my_hash_init(&dboptions, table_alias_charset, 32, 0, 0, (my_hash_get_key) dboptions_get_key, free_dbopt,0); } @@ -192,8 +214,7 @@ void my_dbopt_cleanup(void) { mysql_rwlock_wrlock(&LOCK_dboptions); my_hash_free(&dboptions); - my_hash_init(&dboptions, lower_case_table_names ? - &my_charset_bin : system_charset_info, + my_hash_init(&dboptions, table_alias_charset, 32, 0, 0, (my_hash_get_key) dboptions_get_key, free_dbopt,0); mysql_rwlock_unlock(&LOCK_dboptions); @@ -762,7 +783,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) Drop_table_error_handler err_handler; DBUG_ENTER("mysql_rm_db"); - if (lock_schema_name(thd, db)) DBUG_RETURN(true); @@ -966,7 +986,7 @@ exit: SELECT DATABASE() in the future). For this we free() thd->db and set it to 0. */ - if (thd->db && !strcmp(thd->db, db) && !error) + if (thd->db && cmp_db_names(thd->db, db) && !error) mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); my_dirend(dirp); DBUG_RETURN(error); @@ -993,6 +1013,13 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp, /* Now put the tables in the list */ tot_list_next_local= tot_list_next_global= &tot_list; + if (lower_case_table_names) + { + /* Change database name to lower case for comparision */ + db.str= thd->strmake(db.str, db.length); + db.length= my_casedn_str(files_charset_info, db.str); + } + for (size_t idx=0; idx < files.elements(); idx++) { LEX_STRING *table= files.at(idx); @@ -1300,27 +1327,6 @@ static void backup_current_db_name(THD *thd, /** - Return TRUE if db1_name is equal to db2_name, FALSE otherwise. - - The function allows to compare database names according to the MySQL - rules. The database names db1 and db2 are equal if: - - db1 is NULL and db2 is NULL; - or - - db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to - db2 in system character set (UTF8). -*/ - -static inline bool -cmp_db_names(const char *db1_name, - const char *db2_name) -{ - return ((!db1_name && !db2_name) || - (db1_name && db2_name && - my_strcasecmp(system_charset_info, db1_name, db2_name) == 0)); -} - - -/** @brief Change the current database and its attributes unconditionally. @param thd thread handle diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f2bbd7462fd..1891aa6147b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1435,7 +1435,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, lex_start(thd); /* Must be before we init the table list. */ if (lower_case_table_names) + { table_name.length= my_casedn_str(files_charset_info, table_name.str); + db.length= my_casedn_str(files_charset_info, db.str); + } table_list.init_one_table(db.str, db.length, table_name.str, table_name.length, table_name.str, TL_READ); /* @@ -3869,9 +3872,7 @@ end_with_restore_list: prepared statement- safe. */ HA_CREATE_INFO create_info(lex->create_info); - char *alias; - if (!(alias=thd->strmake(lex->name.str, lex->name.length)) || - check_db_name(&lex->name)) + if (check_db_name(&lex->name)) { my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); break; @@ -3894,8 +3895,7 @@ end_with_restore_list: #endif if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0)) break; - res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : - lex->name.str), &create_info, 0); + res= mysql_create_db(thd, lex->name.str, &create_info, 0); break; } case SQLCOM_DROP_DB: @@ -3988,14 +3988,20 @@ end_with_restore_list: } case SQLCOM_SHOW_CREATE_DB: { + char db_name_buff[NAME_LEN+1]; + LEX_STRING db_name; DBUG_EXECUTE_IF("4x_server_emul", my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;); - if (check_db_name(&lex->name)) + + db_name.str= db_name_buff; + db_name.length= lex->name.length; + strmov(db_name.str, lex->name.str); + if (check_db_name(&db_name)) { - my_error(ER_WRONG_DB_NAME, MYF(0), lex->name.str); + my_error(ER_WRONG_DB_NAME, MYF(0), db_name); break; } - res= mysqld_show_create_db(thd, lex->name.str, &lex->create_info); + res= mysqld_show_create_db(thd, &db_name, &lex->name, &lex->create_info); break; } case SQLCOM_CREATE_EVENT: @@ -6748,8 +6754,14 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->alias= alias_str; ptr->is_alias= alias ? TRUE : FALSE; - if (lower_case_table_names && table->table.length) - table->table.length= my_casedn_str(files_charset_info, table->table.str); + if (lower_case_table_names) + { + if (table->table.length) + table->table.length= my_casedn_str(files_charset_info, table->table.str); + if (ptr->db_length) + ptr->db_length= my_casedn_str(files_charset_info, ptr->db); + } + ptr->table_name=table->table.str; ptr->table_name_length=table->table.length; ptr->lock_type= lock_type; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index aa23f01ab7d..43a5d1ffec7 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1009,9 +1009,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) { /* - Use open_tables() directly rather than open_normal_and_derived_tables(). - This ensures that close_thread_tables() is not called if open tables fails - and the error is ignored. This allows us to handle broken views nicely. + Use open_tables() directly rather than + open_normal_and_derived_tables(). This ensures that + close_thread_tables() is not called if open tables fails and the + error is ignored. This allows us to handle broken views nicely. */ uint counter; Show_create_error_handler view_error_suppressor(thd, table_list); @@ -1105,7 +1106,8 @@ exit: DBUG_RETURN(error); } -bool mysqld_show_create_db(THD *thd, char *dbname, +bool mysqld_show_create_db(THD *thd, LEX_STRING *dbname, + LEX_STRING *orig_dbname, HA_CREATE_INFO *create_info) { char buff[2048]; @@ -1123,32 +1125,32 @@ bool mysqld_show_create_db(THD *thd, char *dbname, if (test_all_bits(sctx->master_access, DB_ACLS)) db_access=DB_ACLS; else - db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname, 0) | + db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, dbname->str, 0) | sctx->master_access); - if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname)) + if (!(db_access & DB_ACLS) && check_grant_db(thd,dbname->str)) { status_var_increment(thd->status_var.access_denied_errors); my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), - sctx->priv_user, sctx->host_or_ip, dbname); + sctx->priv_user, sctx->host_or_ip, dbname->str); general_log_print(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), - sctx->priv_user, sctx->host_or_ip, dbname); + sctx->priv_user, sctx->host_or_ip, orig_dbname->str); DBUG_RETURN(TRUE); } #endif - if (is_infoschema_db(dbname)) + if (is_infoschema_db(dbname->str)) { - dbname= INFORMATION_SCHEMA_NAME.str; + *dbname= INFORMATION_SCHEMA_NAME; create.default_table_charset= system_charset_info; } else { - if (check_db_dir_existence(dbname)) + if (check_db_dir_existence(dbname->str)) { - my_error(ER_BAD_DB_ERROR, MYF(0), dbname); + my_error(ER_BAD_DB_ERROR, MYF(0), dbname->str); DBUG_RETURN(TRUE); } - load_db_opt_by_name(thd, dbname, &create); + load_db_opt_by_name(thd, dbname->str, &create); } List<Item> field_list; field_list.push_back(new Item_empty_string("Database",NAME_CHAR_LEN)); @@ -1159,12 +1161,12 @@ bool mysqld_show_create_db(THD *thd, char *dbname, DBUG_RETURN(TRUE); protocol->prepare_for_resend(); - protocol->store(dbname, strlen(dbname), system_charset_info); + protocol->store(orig_dbname->str, orig_dbname->length, system_charset_info); buffer.length(0); buffer.append(STRING_WITH_LEN("CREATE DATABASE ")); if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS) buffer.append(STRING_WITH_LEN("/*!32312 IF NOT EXISTS*/ ")); - append_identifier(thd, &buffer, dbname, strlen(dbname)); + append_identifier(thd, &buffer, dbname->str, dbname->length); if (create.default_table_charset) { diff --git a/sql/sql_show.h b/sql/sql_show.h index 0416f2fdaba..708a77d74cd 100644 --- a/sql/sql_show.h +++ b/sql/sql_show.h @@ -86,7 +86,9 @@ bool append_identifier(THD *thd, String *packet, const char *name, void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild); int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd); bool mysqld_show_create(THD *thd, TABLE_LIST *table_list); -bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create); +bool mysqld_show_create_db(THD *thd, LEX_STRING *db_name, + LEX_STRING *orig_db_name, + HA_CREATE_INFO *create); void mysqld_list_processes(THD *thd,const char *user,bool verbose); int mysqld_show_status(THD *thd); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d30eb3169e3..ee3b954168d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5132,7 +5132,7 @@ mysql_rename_table(handlerton *base, const char *old_db, char from[FN_REFLEN + 1], to[FN_REFLEN + 1], lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1]; char *from_base= from, *to_base= to; - char tmp_name[SAFE_NAME_LEN+1]; + char tmp_name[SAFE_NAME_LEN+1], tmp_db_name[SAFE_NAME_LEN+1]; handler *file; int error=0; ulonglong save_bits= thd->variables.option_bits; @@ -5169,13 +5169,19 @@ mysql_rename_table(handlerton *base, const char *old_db, { strmov(tmp_name, old_name); my_casedn_str(files_charset_info, tmp_name); - build_table_filename(lc_from, sizeof(lc_from) - 1, old_db, tmp_name, "", - flags & FN_FROM_IS_TMP); + strmov(tmp_db_name, old_db); + my_casedn_str(files_charset_info, tmp_db_name); + + build_table_filename(lc_from, sizeof(lc_from) - 1, tmp_db_name, tmp_name, + "", flags & FN_FROM_IS_TMP); from_base= lc_from; strmov(tmp_name, new_name); my_casedn_str(files_charset_info, tmp_name); - build_table_filename(lc_to, sizeof(lc_to) - 1, new_db, tmp_name, "", + strmov(tmp_db_name, new_db); + my_casedn_str(files_charset_info, tmp_db_name); + + build_table_filename(lc_to, sizeof(lc_to) - 1, tmp_db_name, tmp_name, "", flags & FN_TO_IS_TMP); to_base= lc_to; } diff --git a/sql/table.cc b/sql/table.cc index 8daf54920cd..268b35c409e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -3440,10 +3440,11 @@ uint calculate_key_len(TABLE *table, uint key, const uchar *buf, SYNPOSIS check_db_name() - org_name Name of database and length + org_name Name of database NOTES - If lower_case_table_names is set then database is converted to lower case + If lower_case_table_names is set to 1 then database name is converted + to lower case RETURN 0 ok @@ -3465,13 +3466,12 @@ bool check_db_name(LEX_STRING *org_name) if (!name_length || name_length > NAME_LEN) return 1; - if (lower_case_table_names && name != any_db) - my_casedn_str(files_charset_info, name); - + if (lower_case_table_names == 1 && name != any_db) + org_name->length= my_casedn_str(files_charset_info, name); if (db_name_is_in_ignore_db_dirs_list(name)) return 1; - return check_table_name(name, name_length, check_for_path_chars); + return check_table_name(name, org_name->length, check_for_path_chars); } |