From 09944efd71a7b11de5b06e76b8019aae53d9ca36 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 Jun 2005 13:31:59 +0200 Subject: [PATCH 1/5] BUG#10365 Cluster handler uses non-standard error codes - Added better error messages when trying to open a table that can't be discovered or unpacked. The most likely cause of this is that it does not have any frm data, probably since it has been created from NdbApi or is a NDB system table. - Separated functionality that was in ha_create_table_from_engine into two functions. One that checks if the table exists and another one that tries to create the table from the engine. mysql-test/r/ndb_autodiscover.result: Add tests for reading from a table that can't be discovered(SYSTAB_0) Discovery is not performed during create table anymore. mysql-test/t/ndb_autodiscover.test: Add tests for reading from a table that can't be discovered(SYSTAB_0) Discovery is not performed during create table anymore. ndb/test/ndbapi/create_tab.cpp: Set connectstring before creating Ndb object. sql/ha_ndbcluster.cc: Rename and use the function ndbcluster_table_exists_in_engine. Correct return valu from ndbcluster_discover Remove old code "ndb_discover_tables" sql/ha_ndbcluster.h: Rename function ndbcluster_table_exists to ndb ndbcluster_table_exists_in_engine sql/handler.cc: Update comment of ha_create_table_from_engine Remove parameter create_if_found from ha_create_table_from_engine, the function ha_table_exists_in_engine is now used toi check if table is found in engine. Cleanup return codes from ha_create_table_from_engine. Change name of ha_table_exists to ha_table_exists_in_engine, update comment and returne codes. sql/handler.h: Remove paramter create_if_cound from ha_create_table_from_engine Rename ha_table_exists to ha_table_exists_in_engine sql/sql_base.cc: Use the function ha_table_exists_in_engine to detect if table exists in enegine. If it exists, call function ha_create_table_from_engine to try and create it. If create of table fails, set correct error message. sql/sql_table.cc: Add comments, remove parameter create_if_found to ha_create_table_from_engine. When dropping a table, try to discover it from engine. If discover fails, use same error message as if the table didn't exists. Maybe another message should be displayed here, ex: "Table could not be dropped, unpack failed" When creating a new table, use ha_table_exists_in_engine to check if a table with the given name already exists. --- mysql-test/r/ndb_autodiscover.result | 20 +++++- mysql-test/t/ndb_autodiscover.test | 21 ++++++ ndb/test/ndbapi/create_tab.cpp | 2 +- sql/ha_ndbcluster.cc | 23 +++--- sql/ha_ndbcluster.h | 3 +- sql/handler.cc | 101 +++++++++++++-------------- sql/handler.h | 5 +- sql/sql_base.cc | 17 ++++- sql/sql_table.cc | 18 ++--- 9 files changed, 126 insertions(+), 84 deletions(-) diff --git a/mysql-test/r/ndb_autodiscover.result b/mysql-test/r/ndb_autodiscover.result index b7afb5918a4..b278d6eb048 100644 --- a/mysql-test/r/ndb_autodiscover.result +++ b/mysql-test/r/ndb_autodiscover.result @@ -93,7 +93,7 @@ name char(20), a int, b float, c char(24) ERROR 42S01: Table 't3' already exists show status like 'handler_discover%'; Variable_name Value -Handler_discover 1 +Handler_discover 0 create table IF NOT EXISTS t3( id int not null primary key, id2 int not null, @@ -101,7 +101,7 @@ name char(20) ) engine=ndb; show status like 'handler_discover%'; Variable_name Value -Handler_discover 2 +Handler_discover 0 SHOW CREATE TABLE t3; Table Create Table t3 CREATE TABLE `t3` ( @@ -114,7 +114,7 @@ id name 1 Explorer show status like 'handler_discover%'; Variable_name Value -Handler_discover 2 +Handler_discover 1 drop table t3; flush status; create table t7( @@ -358,6 +358,20 @@ Database mysql test use test; +CREATE TABLE sys.SYSTAB_0 (a int); +ERROR 42S01: Table 'SYSTAB_0' already exists +select * from sys.SYSTAB_0; +ERROR HY000: Failed to open 'SYSTAB_0', error while unpacking from engine +CREATE TABLE IF NOT EXISTS sys.SYSTAB_0 (a int); +show warnings; +Level Code Message +select * from sys.SYSTAB_0; +ERROR HY000: Failed to open 'SYSTAB_0', error while unpacking from engine +drop table sys.SYSTAB_0; +ERROR 42S02: Unknown table 'SYSTAB_0' +drop table IF EXISTS sys.SYSTAB_0; +Warnings: +Note 1051 Unknown table 'SYSTAB_0' CREATE TABLE t9 ( a int NOT NULL PRIMARY KEY, b int diff --git a/mysql-test/t/ndb_autodiscover.test b/mysql-test/t/ndb_autodiscover.test index bd73a36fcab..49ed8c894fe 100644 --- a/mysql-test/t/ndb_autodiscover.test +++ b/mysql-test/t/ndb_autodiscover.test @@ -453,6 +453,27 @@ drop database test2; show databases; use test; +##################################################### +# Test that it's not possible to create tables +# with same name as NDB internal tables +# This will also test that it's not possible to create +# a table with tha same name as a table that can't be +# discovered( for example a table created via NDBAPI) + +--error 1050 +CREATE TABLE sys.SYSTAB_0 (a int); +--error 1105 +select * from sys.SYSTAB_0; + +CREATE TABLE IF NOT EXISTS sys.SYSTAB_0 (a int); +show warnings; +--error 1105 +select * from sys.SYSTAB_0; + +--error 1051 +drop table sys.SYSTAB_0; +drop table IF EXISTS sys.SYSTAB_0; + ###################################################### # Note! This should always be the last step in this # file, the table t9 will be used and dropped diff --git a/ndb/test/ndbapi/create_tab.cpp b/ndb/test/ndbapi/create_tab.cpp index f3f18982ed0..283c83d30e0 100644 --- a/ndb/test/ndbapi/create_tab.cpp +++ b/ndb/test/ndbapi/create_tab.cpp @@ -77,8 +77,8 @@ int main(int argc, const char** argv){ */ // Connect to Ndb + Ndb::setConnectString(_connectstr); Ndb MyNdb( "TEST_DB" ); - MyNdb.setConnectString(_connectstr); if(MyNdb.init() != 0){ ERR(MyNdb.getNdbError()); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index eaa0473df1b..85b7ddc4892 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4308,13 +4308,15 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, len= tab->getFrmLength(); if (len == 0 || tab->getFrmData() == NULL) { - DBUG_PRINT("No frm data found", - ("Table is probably created via NdbApi")); - DBUG_RETURN(2); + DBUG_PRINT("error", ("No frm data found.")); + DBUG_RETURN(1); } if (unpackfrm(&data, &len, tab->getFrmData())) - DBUG_RETURN(3); + { + DBUG_PRINT("error", ("Could not unpack table")); + DBUG_RETURN(1); + } *frmlen= len; *frmblob= data; @@ -4327,13 +4329,13 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, */ -int ndbcluster_table_exists(THD* thd, const char *db, const char *name) +int ndbcluster_table_exists_in_engine(THD* thd, const char *db, const char *name) { uint len; const void* data; const NDBTAB* tab; Ndb* ndb; - DBUG_ENTER("ndbcluster_table_exists"); + DBUG_ENTER("ndbcluster_table_exists_in_engine"); DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); if (!(ndb= check_ndb_in_thd(thd))) @@ -4512,7 +4514,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, DBUG_PRINT("info", ("%s existed on disk", name)); // The .ndb file exists on disk, but it's not in list of tables in ndb // Verify that handler agrees table is gone. - if (ndbcluster_table_exists(thd, db, file_name) == 0) + if (ndbcluster_table_exists_in_engine(thd, db, file_name) == 0) { DBUG_PRINT("info", ("NDB says %s does not exists", file_name)); it.remove(); @@ -4563,7 +4565,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, while ((file_name=it2++)) { DBUG_PRINT("info", ("Table %s need discovery", name)); - if (ha_create_table_from_engine(thd, db, file_name, TRUE) == 0) + if (ha_create_table_from_engine(thd, db, file_name) == 0) files->push_back(thd->strdup(file_name)); } @@ -4639,11 +4641,8 @@ bool ndbcluster_init() pthread_mutex_init(&ndbcluster_mutex,MY_MUTEX_INIT_FAST); ndbcluster_inited= 1; -#ifdef USE_DISCOVER_ON_STARTUP - if (ndb_discover_tables() != 0) - goto ndbcluster_init_error; -#endif DBUG_RETURN(FALSE); + ndbcluster_init_error: ndbcluster_end(); DBUG_RETURN(TRUE); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 439b4855147..5c1d121a157 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -275,7 +275,8 @@ int ndbcluster_discover(THD* thd, const char* dbname, const char* name, const void** frmblob, uint* frmlen); int ndbcluster_find_files(THD *thd,const char *db,const char *path, const char *wild, bool dir, List *files); -int ndbcluster_table_exists(THD* thd, const char *db, const char *name); +int ndbcluster_table_exists_in_engine(THD* thd, + const char *db, const char *name); int ndbcluster_drop_database(const char* path); void ndbcluster_print_error(int error, const NdbOperation *error_op); diff --git a/sql/handler.cc b/sql/handler.cc index f14564b6629..ad5cd28d932 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1336,21 +1336,18 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, } /* - Try to discover table from engine and + Try to discover table from engine and if found, write the frm file to disk. - + RETURN VALUES: - 0 : Table existed in engine and created - on disk if so requested - 1 : Table does not exist - >1 : error + 0 : Table created ok + 1 : Table could not be created */ -int ha_create_table_from_engine(THD* thd, - const char *db, - const char *name, - bool create_if_found) +int ha_create_table_from_engine(THD* thd, + const char *db, + const char *name) { int error; const void *frmblob; @@ -1359,45 +1356,47 @@ int ha_create_table_from_engine(THD* thd, HA_CREATE_INFO create_info; TABLE table; DBUG_ENTER("ha_create_table_from_engine"); - DBUG_PRINT("enter", ("name '%s'.'%s' create_if_found: %d", - db, name, create_if_found)); + DBUG_PRINT("enter", ("name '%s'.'%s'", + db, name)); bzero((char*) &create_info,sizeof(create_info)); - if ((error= ha_discover(thd, db, name, &frmblob, &frmlen))) - DBUG_RETURN(error); - /* - Table exists in handler - frmblob and frmlen are set - */ - - if (create_if_found) + if(ha_discover(thd, db, name, &frmblob, &frmlen)) { - (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); - // Save the frm file - if ((error = writefrm(path, frmblob, frmlen))) - goto err_end; - - if (openfrm(path,"",0,(uint) READ_ALL, 0, &table)) - DBUG_RETURN(1); - - update_create_info_from_table(&create_info, &table); - create_info.table_options|= HA_CREATE_FROM_ENGINE; - - if (lower_case_table_names == 2 && - !(table.file->table_flags() & HA_FILE_BASED)) - { - /* Ensure that handler gets name in lower case */ - my_casedn_str(files_charset_info, path); - } - - error=table.file->create(path,&table,&create_info); - VOID(closefrm(&table)); + // Table could not be discovered and thus not created + DBUG_RETURN(1); } -err_end: + /* + Table exists in handler and could be discovered + frmblob and frmlen are set, write the frm to disk + */ + + (void)strxnmov(path,FN_REFLEN,mysql_data_home,"/",db,"/",name,NullS); + // Save the frm file + if (writefrm(path, frmblob, frmlen)) + { + my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); + DBUG_RETURN(1); + } + + if (openfrm(path,"",0,(uint) READ_ALL, 0, &table)) + DBUG_RETURN(1); + + update_create_info_from_table(&create_info, &table); + create_info.table_options|= HA_CREATE_FROM_ENGINE; + + if (lower_case_table_names == 2 && + !(table.file->table_flags() & HA_FILE_BASED)) + { + /* Ensure that handler gets name in lower case */ + my_casedn_str(files_charset_info, path); + } + error=table.file->create(path,&table,&create_info); + VOID(closefrm(&table)); my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); - DBUG_RETURN(error); + + DBUG_RETURN(error != 0); } static int NEAR_F delete_file(const char *name,const char *ext,int extflag) @@ -1507,8 +1506,8 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, Try to discover one table from handler(s) RETURN - 0 ok. In this case *frmblob and *frmlen are set - 1 error. frmblob and frmlen may not be set + 0 ok. In this case *frmblob and *frmlen are set + >=1 error. frmblob and frmlen may not be set */ int ha_discover(THD *thd, const char *db, const char *name, @@ -1546,11 +1545,8 @@ ha_find_files(THD *thd,const char *db,const char *path, error= ndbcluster_find_files(thd, db, path, wild, dir, files); #endif DBUG_RETURN(error); - - } -#ifdef NOT_YET_USED /* Ask handler if the table exists in engine @@ -1561,20 +1557,19 @@ ha_find_files(THD *thd,const char *db,const char *path, # Error code */ -int ha_table_exists(THD* thd, const char* db, const char* name) +int ha_table_exists_in_engine(THD* thd, const char* db, const char* name) { - int error= 2; - DBUG_ENTER("ha_table_exists"); + int error= 0; + DBUG_ENTER("ha_table_exists_in_engine"); DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); #ifdef HAVE_NDBCLUSTER_DB if (have_ndbcluster == SHOW_OPTION_YES) - error= ndbcluster_table_exists(thd, db, name); + error= ndbcluster_table_exists_in_engine(thd, db, name); #endif + DBUG_PRINT("exit", ("error: %d", error)); DBUG_RETURN(error); } -#endif - /* Read first row between two ranges. diff --git a/sql/handler.h b/sql/handler.h index 75e83082d10..efcdee8f56c 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -547,8 +547,7 @@ enum db_type ha_checktype(enum db_type database_type); my_bool ha_storage_engine_is_enabled(enum db_type database_type); int ha_create_table(const char *name, HA_CREATE_INFO *create_info, bool update_create_info); -int ha_create_table_from_engine(THD* thd, const char *db, const char *name, - bool create_if_found); +int ha_create_table_from_engine(THD* thd, const char *db, const char *name); int ha_delete_table(enum db_type db_type, const char *path); void ha_drop_database(char* path); int ha_init_key_cache(const char *name, KEY_CACHE *key_cache); @@ -574,6 +573,6 @@ int ha_discover(THD* thd, const char* dbname, const char* name, const void** frmblob, uint* frmlen); int ha_find_files(THD *thd,const char *db,const char *path, const char *wild, bool dir,List* files); -int ha_table_exists(THD* thd, const char* db, const char* name); +int ha_table_exists_in_engine(THD* thd, const char* db, const char* name); TYPELIB *ha_known_exts(void); int ha_start_consistent_snapshot(THD *thd); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c580842ce06..0aa2f1ce4b8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1375,9 +1375,20 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, trying to discover the table at the same time. */ if (discover_retry_count++ != 0) - goto err; - if (ha_create_table_from_engine(thd, db, name, TRUE) != 0) - goto err; + goto err; + if (ha_table_exists_in_engine(thd, db, name) && + ha_create_table_from_engine(thd, db, name)) + { + /* Give right error message */ + thd->clear_error(); + DBUG_PRINT("error", ("Dicovery of %s/%s failed", db, name)); + my_printf_error(ER_UNKNOWN_ERROR, + "Failed to open '%-.64s', error while " + "unpacking from engine", + MYF(0), name); + + goto err; + } thd->clear_error(); // Clear error message continue; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 67aade519f5..70dd17cc8bc 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -217,15 +217,18 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, strxmov(path, mysql_data_home, "/", db, "/", alias, reg_ext, NullS); (void) unpack_filename(path,path); } - if (drop_temporary || - (access(path,F_OK) && ha_create_table_from_engine(thd,db,alias,TRUE))) + if (drop_temporary || + (access(path,F_OK) && + ha_create_table_from_engine(thd, db, alias))) { + // Table was not found on disk and table can't be created from engine if (if_exists) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), table->real_name); else - error= 1; + error= 1; + } else { @@ -1371,15 +1374,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { bool create_if_not_exists = create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS; - if (!ha_create_table_from_engine(thd, db, table_name, - create_if_not_exists)) + if (ha_table_exists_in_engine(thd, db, table_name)) { - DBUG_PRINT("info", ("Table already existed in handler")); + DBUG_PRINT("info", ("Table with same name already existed in handler")); if (create_if_not_exists) { - create_info->table_existed= 1; // Mark that table existed - error= 0; + create_info->table_existed= 1; // Mark that table existed + error= 0; } else my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); From 5a98e2a0d05fb9c2b626350d80ffe9161e2726c2 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 10 Jun 2005 16:26:23 +0200 Subject: [PATCH 2/5] Bug #9558 mysqldump --no-data db t1 t2 format still dumps data - Added testcases according to spec in bug report. mysql-test/r/mysqldump.result: Update results mysql-test/t/mysqldump.test: Add tests for --no-data --- mysql-test/r/mysqldump.result | 60 +++++++++++++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 15 +++++++++ 2 files changed, 75 insertions(+) diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 845b0d1da45..f66647bdbf8 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1349,3 +1349,63 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; DROP TABLE t1; +CREATE DATABASE mysqldump_test_db; +USE mysqldump_test_db; +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +DROP TABLE t1, t2; +DROP DATABASE mysqldump_test_db; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 9f3b412b814..5a35c328314 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -543,3 +543,18 @@ CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (1),(2),(3); --exec $MYSQL_DUMP --add-drop-database --skip-comments --databases test DROP TABLE t1; + +# +# Bug #9558 mysqldump --no-data db t1 t2 format still dumps data +# + +CREATE DATABASE mysqldump_test_db; +USE mysqldump_test_db; +CREATE TABLE t1 ( a INT ); +CREATE TABLE t2 ( a INT ); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES (1), (2); +--exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db +--exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db t1 t2 +DROP TABLE t1, t2; +DROP DATABASE mysqldump_test_db; From d18e5622ebacbb386b6cc8508dbdaae4216f4fa8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Jun 2005 15:17:47 +0200 Subject: [PATCH 3/5] BUG10365 Cluster handler uses non-standard error code - Updated after review sql/ha_ndbcluster.cc: Return -1 if table does not exists sql/handler.cc: Return -1 if table does not exists Return 0 if table exists and it could be created Return >0 if table existed but it could not be created. sql/sql_base.cc: Only need to call ha_create_table_from_engine and check if result is > 0. If that is the case, print error message --- sql/ha_ndbcluster.cc | 2 +- sql/handler.cc | 18 ++++++++++-------- sql/sql_base.cc | 3 +-- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 85b7ddc4892..a7d82396eb5 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4300,7 +4300,7 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, { const NdbError err= dict->getNdbError(); if (err.code == 709) - DBUG_RETURN(1); + DBUG_RETURN(-1); ERR_RETURN(err); } DBUG_PRINT("info", ("Found table %s", tab->getName())); diff --git a/sql/handler.cc b/sql/handler.cc index ad5cd28d932..dacfc7d9ac5 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1340,8 +1340,9 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info, if found, write the frm file to disk. RETURN VALUES: + -1 : Table did not exists 0 : Table created ok - 1 : Table could not be created + > 0 : Error, table existed but could not be created */ @@ -1361,10 +1362,10 @@ int ha_create_table_from_engine(THD* thd, bzero((char*) &create_info,sizeof(create_info)); - if(ha_discover(thd, db, name, &frmblob, &frmlen)) + if(error= ha_discover(thd, db, name, &frmblob, &frmlen)) { // Table could not be discovered and thus not created - DBUG_RETURN(1); + DBUG_RETURN(error); } /* @@ -1377,11 +1378,11 @@ int ha_create_table_from_engine(THD* thd, if (writefrm(path, frmblob, frmlen)) { my_free((char*) frmblob, MYF(MY_ALLOW_ZERO_PTR)); - DBUG_RETURN(1); + DBUG_RETURN(2); } if (openfrm(path,"",0,(uint) READ_ALL, 0, &table)) - DBUG_RETURN(1); + DBUG_RETURN(3); update_create_info_from_table(&create_info, &table); create_info.table_options|= HA_CREATE_FROM_ENGINE; @@ -1506,14 +1507,15 @@ int ha_change_key_cache(KEY_CACHE *old_key_cache, Try to discover one table from handler(s) RETURN - 0 ok. In this case *frmblob and *frmlen are set - >=1 error. frmblob and frmlen may not be set + -1 : Table did not exists + 0 : OK. In this case *frmblob and *frmlen are set + >0 : error. frmblob and frmlen may not be set */ int ha_discover(THD *thd, const char *db, const char *name, const void **frmblob, uint *frmlen) { - int error= 1; // Table does not exist in any handler + int error= -1; // Table does not exist in any handler DBUG_ENTER("ha_discover"); DBUG_PRINT("enter", ("db: %s, name: %s", db, name)); #ifdef HAVE_NDBCLUSTER_DB diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0aa2f1ce4b8..d6ef08b8a7c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1376,8 +1376,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, */ if (discover_retry_count++ != 0) goto err; - if (ha_table_exists_in_engine(thd, db, name) && - ha_create_table_from_engine(thd, db, name)) + if (ha_create_table_from_engine(thd, db, name) > 0) { /* Give right error message */ thd->clear_error(); From 2e0ac6d642a0fb328ad80c21c2c310166cab9452 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 17 Jun 2005 18:07:46 +0200 Subject: [PATCH 4/5] BUG#10589: des_encrypt functionality always return NULL - Push warnings if des_encrypt or des_descrypt function fails because of out of resources or wrong params. - Push warning if des_encrypt or des_decrypt function is used when server is missing support for openssl. - Add test func_encrypt_nossl that is tun when the server is missing support for openssl. mysql-test/r/func_encrypt.result: Add tests for use of des_* function with invalid parameters mysql-test/t/func_encrypt.test: Add tests for use of des_* function with invalid parameters sql/item_strfunc.cc: Push warning if invalid paremeters are used Push warning if out of resources Push warning if user tries to use des_* function when the server has been compiled without support for openssl. --- mysql-test/include/not_openssl.inc | 4 ++ mysql-test/r/func_encrypt.result | 56 ++++++++++++++++ mysql-test/r/func_encrypt_nossl.result | 93 ++++++++++++++++++++++++++ mysql-test/r/not_openssl.require | 2 + mysql-test/t/func_encrypt.test | 16 +++++ mysql-test/t/func_encrypt_nossl.test | 36 ++++++++++ sql/item_strfunc.cc | 25 ++++++- 7 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 mysql-test/include/not_openssl.inc create mode 100644 mysql-test/r/func_encrypt_nossl.result create mode 100644 mysql-test/r/not_openssl.require create mode 100644 mysql-test/t/func_encrypt_nossl.test diff --git a/mysql-test/include/not_openssl.inc b/mysql-test/include/not_openssl.inc new file mode 100644 index 00000000000..afe2ed37c28 --- /dev/null +++ b/mysql-test/include/not_openssl.inc @@ -0,0 +1,4 @@ +-- require r/not_openssl.require +disable_query_log; +show variables like "have_openssl"; +enable_query_log; diff --git a/mysql-test/r/func_encrypt.result b/mysql-test/r/func_encrypt.result index d32e67fe7d5..992d01c66cd 100644 --- a/mysql-test/r/func_encrypt.result +++ b/mysql-test/r/func_encrypt.result @@ -120,6 +120,60 @@ hello select des_decrypt(des_encrypt("hello",4),'password4'); des_decrypt(des_encrypt("hello",4),'password4') hello +select des_encrypt("hello",10); +des_encrypt("hello",10) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_encrypt(NULL); +des_encrypt(NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_encrypt(NULL, 10); +des_encrypt(NULL, 10) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_encrypt(NULL, NULL); +des_encrypt(NULL, NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_encrypt(10, NULL); +des_encrypt(10, NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_encrypt("hello", NULL); +des_encrypt("hello", NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_encrypt' +select des_decrypt("hello",10); +des_decrypt("hello",10) +hello +select des_decrypt(NULL); +des_decrypt(NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_decrypt' +select des_decrypt(NULL, 10); +des_decrypt(NULL, 10) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_decrypt' +select des_decrypt(NULL, NULL); +des_decrypt(NULL, NULL) +NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_decrypt' +select des_decrypt(10, NULL); +des_decrypt(10, NULL) +10 +select des_decrypt("hello", NULL); +des_decrypt("hello", NULL) +hello SET @a=des_decrypt(des_encrypt("hello")); flush des_key_file; select @a = des_decrypt(des_encrypt("hello")); @@ -134,6 +188,8 @@ NULL select hex(des_decrypt(des_encrypt("hello","hidden"))); hex(des_decrypt(des_encrypt("hello","hidden"))) NULL +Warnings: +Error 1108 Incorrect parameters to procedure 'des_decrypt' explain extended select des_decrypt(des_encrypt("hello",4),'password2'), des_decrypt(des_encrypt("hello","hidden")); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used diff --git a/mysql-test/r/func_encrypt_nossl.result b/mysql-test/r/func_encrypt_nossl.result new file mode 100644 index 00000000000..fea752f4a4a --- /dev/null +++ b/mysql-test/r/func_encrypt_nossl.result @@ -0,0 +1,93 @@ +select des_encrypt("test", 'akeystr'); +des_encrypt("test", 'akeystr') +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", 1); +des_encrypt("test", 1) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", 9); +des_encrypt("test", 9) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", 100); +des_encrypt("test", 100) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_encrypt("test", NULL); +des_encrypt("test", NULL) +NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt("test", 'anotherkeystr'); +des_decrypt("test", 'anotherkeystr') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(1, 1); +des_decrypt(1, 1) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("test", 'thekey')); +des_decrypt(des_encrypt("test", 'thekey')) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello")); +hex(des_encrypt("hello")) des_decrypt(des_encrypt("hello")) +NULL NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello",4)); +des_decrypt(des_encrypt("hello",4)) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello",'test'),'test'); +des_decrypt(des_encrypt("hello",'test'),'test') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password')); +hex(des_encrypt("hello")) hex(des_encrypt("hello",5)) hex(des_encrypt("hello",'default_password')) +NULL NULL NULL +Warnings: +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +Error 1289 The 'des_encrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello"),'default_password'); +des_decrypt(des_encrypt("hello"),'default_password') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select des_decrypt(des_encrypt("hello",4),'password4'); +des_decrypt(des_encrypt("hello",4),'password4') +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +SET @a=des_decrypt(des_encrypt("hello")); +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +flush des_key_file; +select @a = des_decrypt(des_encrypt("hello")); +@a = des_decrypt(des_encrypt("hello")) +NULL +select hex("hello"); +hex("hello") +68656C6C6F +select hex(des_decrypt(des_encrypt("hello",4),'password2')); +hex(des_decrypt(des_encrypt("hello",4),'password2')) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working +select hex(des_decrypt(des_encrypt("hello","hidden"))); +hex(des_decrypt(des_encrypt("hello","hidden"))) +NULL +Warnings: +Error 1289 The 'des_decrypt' feature is disabled; you need MySQL built with '--with-openssl' to have it working diff --git a/mysql-test/r/not_openssl.require b/mysql-test/r/not_openssl.require new file mode 100644 index 00000000000..2b5e423999c --- /dev/null +++ b/mysql-test/r/not_openssl.require @@ -0,0 +1,2 @@ +Variable_name Value +have_openssl NO diff --git a/mysql-test/t/func_encrypt.test b/mysql-test/t/func_encrypt.test index fe81a814dda..52aca7f9dcb 100644 --- a/mysql-test/t/func_encrypt.test +++ b/mysql-test/t/func_encrypt.test @@ -59,6 +59,22 @@ select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("he select des_decrypt(des_encrypt("hello"),'default_password'); select des_decrypt(des_encrypt("hello",4),'password4'); +# Test use of invalid parameters +select des_encrypt("hello",10); +select des_encrypt(NULL); +select des_encrypt(NULL, 10); +select des_encrypt(NULL, NULL); +select des_encrypt(10, NULL); +select des_encrypt("hello", NULL); + +select des_decrypt("hello",10); +select des_decrypt(NULL); +select des_decrypt(NULL, 10); +select des_decrypt(NULL, NULL); +select des_decrypt(10, NULL); +select des_decrypt("hello", NULL); + + # Test flush SET @a=des_decrypt(des_encrypt("hello")); flush des_key_file; diff --git a/mysql-test/t/func_encrypt_nossl.test b/mysql-test/t/func_encrypt_nossl.test new file mode 100644 index 00000000000..0e9d93f5968 --- /dev/null +++ b/mysql-test/t/func_encrypt_nossl.test @@ -0,0 +1,36 @@ +-- source include/not_openssl.inc + +# +# Test output from des_encrypt and des_decrypt when server is +# compiled without openssl suuport +# +select des_encrypt("test", 'akeystr'); +select des_encrypt("test", 1); +select des_encrypt("test", 9); +select des_encrypt("test", 100); +select des_encrypt("test", NULL); +select des_decrypt("test", 'anotherkeystr'); +select des_decrypt(1, 1); +select des_decrypt(des_encrypt("test", 'thekey')); + + +# +# Test default keys +# +select hex(des_encrypt("hello")),des_decrypt(des_encrypt("hello")); +select des_decrypt(des_encrypt("hello",4)); +select des_decrypt(des_encrypt("hello",'test'),'test'); +select hex(des_encrypt("hello")),hex(des_encrypt("hello",5)),hex(des_encrypt("hello",'default_password')); +select des_decrypt(des_encrypt("hello"),'default_password'); +select des_decrypt(des_encrypt("hello",4),'password4'); + +# Test flush +SET @a=des_decrypt(des_encrypt("hello")); +flush des_key_file; +select @a = des_decrypt(des_encrypt("hello")); + +# Test usage of wrong password +select hex("hello"); +select hex(des_decrypt(des_encrypt("hello",4),'password2')); +select hex(des_decrypt(des_encrypt("hello","hidden"))); + diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 5ca5caf6bdf..ceb925be4d2 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -373,6 +373,7 @@ String *Item_func_des_encrypt::val_str(String *str) { DBUG_ASSERT(fixed == 1); #ifdef HAVE_OPENSSL + uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE; DES_cblock ivec; struct st_des_keyblock keyblock; struct st_des_keyschedule keyschedule; @@ -381,7 +382,7 @@ String *Item_func_des_encrypt::val_str(String *str) String *res= args[0]->val_str(str); if ((null_value=args[0]->null_value)) - return 0; + goto error; if ((res_length=res->length()) == 0) return &my_empty_string; @@ -429,6 +430,7 @@ String *Item_func_des_encrypt::val_str(String *str) tail= (8-(res_length) % 8); // 1..8 marking extra length res_length+=tail; + code= ER_OUT_OF_RESOURCES; if (tail && res->append(append_str, tail) || tmp_value.alloc(res_length+1)) goto error; (*res)[res_length-1]=tail; // save extra length @@ -446,6 +448,13 @@ String *Item_func_des_encrypt::val_str(String *str) return &tmp_value; error: + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + code, ER(code), + "des_encrypt"); +#else + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), + "des_encrypt","--with-openssl"); #endif /* HAVE_OPENSSL */ null_value=1; return 0; @@ -456,6 +465,7 @@ String *Item_func_des_decrypt::val_str(String *str) { DBUG_ASSERT(fixed == 1); #ifdef HAVE_OPENSSL + uint code= ER_WRONG_PARAMETERS_TO_PROCEDURE; DES_key_schedule ks1, ks2, ks3; DES_cblock ivec; struct st_des_keyblock keyblock; @@ -464,7 +474,7 @@ String *Item_func_des_decrypt::val_str(String *str) uint length=res->length(),tail; if ((null_value=args[0]->null_value)) - return 0; + goto error; length=res->length(); if (length < 9 || (length % 8) != 1 || !((*res)[0] & 128)) return res; // Skip decryption if not encrypted @@ -495,6 +505,7 @@ String *Item_func_des_decrypt::val_str(String *str) DES_set_key_unchecked(&keyblock.key2,&keyschedule.ks2); DES_set_key_unchecked(&keyblock.key3,&keyschedule.ks3); } + code= ER_OUT_OF_RESOURCES; if (tmp_value.alloc(length-1)) goto error; @@ -508,11 +519,19 @@ String *Item_func_des_decrypt::val_str(String *str) &ivec, FALSE); /* Restore old length of key */ if ((tail=(uint) (uchar) tmp_value[length-2]) > 8) - goto error; // Wrong key + goto wrong_key; // Wrong key tmp_value.length(length-1-tail); return &tmp_value; error: + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + code, ER(code), + "des_decrypt"); +wrong_key: +#else + push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_FEATURE_DISABLED, ER(ER_FEATURE_DISABLED), + "des_decrypt","--with-openssl"); #endif /* HAVE_OPENSSL */ null_value=1; return 0; From c2a84d5fd2e3d86ab5dd75b13d6dac7a8a06256f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jun 2005 14:19:56 +0200 Subject: [PATCH 5/5] patch client/mysqldump.c: Add description of quote_for_like Add quoting of \ to \\\\ in quote_for_like Add DBUG_* Rearranged code in dump_selected_tables so the first thing it will do is to check that the tables to dump are available Unless --force is used, program will exit if not all specified tables can be found Add files to dump to HASH table for easy iteration Simpler handling of ignore_table list. Add new error code used when table user selected to dump can not be found in db client/mysqltest.c: Make it possible to exec a command that fails by setting --error before the command to exec. Check that the error returned from executed program matches the expected error. Add DBUG_* printouts mysql-test/mysql-test-run.sh: export MYSQL_DUMP_DIR used in "--replace_result" mysql-test/r/mysqldump.result: Added test for illegal / nonexisting table and database names mysql-test/t/mysqldump.test: Added test for illegal / nonexisting table and database names --- client/mysqldump.c | 160 +++++++++++++++++++++------------- client/mysqltest.c | 35 +++++++- mysql-test/mysql-test-run.sh | 3 + mysql-test/r/mysqldump.result | 27 ++++++ mysql-test/t/mysqldump.test | 78 +++++++++++++++++ 5 files changed, 240 insertions(+), 63 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 7b18b1d92da..207235983da 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -57,6 +57,7 @@ #define EX_CONSCHECK 3 #define EX_EOM 4 #define EX_EOF 5 /* ferror for output file was got */ +#define EX_ILLEGAL_TABLE 6 /* index into 'show fields from table' */ @@ -140,14 +141,6 @@ const char *compatible_mode_names[]= TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, "", compatible_mode_names, NULL}; -#define TABLE_RULE_HASH_SIZE 16 - -typedef struct st_table_rule_ent -{ - char* key; /* dbname.tablename */ - uint key_len; -} TABLE_RULE_ENT; - HASH ignore_table; static struct my_option my_long_options[] = @@ -538,29 +531,21 @@ static void write_footer(FILE *sql_file) } /* write_footer */ -static void free_table_ent(TABLE_RULE_ENT* e) +byte* get_table_key(const char *entry, uint *length, + my_bool not_used __attribute__((unused))) { - my_free((gptr) e, MYF(0)); -} - - -static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, - my_bool not_used __attribute__((unused))) -{ - *len= e->key_len; - return (byte*)e->key; + *length= strlen(entry); + return (byte*) entry; } void init_table_rule_hash(HASH* h) { - if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0, - (hash_get_key) get_table_key, - (hash_free_key) free_table_ent, 0)) + if(hash_init(h, charset_info, 16, 0, 0, + (hash_get_key) get_table_key, 0, 0)) exit(EX_EOM); } - static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -633,25 +618,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case (int) OPT_IGNORE_TABLE: { - uint len= (uint)strlen(argument); - TABLE_RULE_ENT* e; if (!strchr(argument, '.')) { fprintf(stderr, "Illegal use of option --ignore-table=.\n"); exit(1); } - /* len is always > 0 because we know the there exists a '.' */ - e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME)); - if (!e) - exit(EX_EOM); - e->key= (char*)e + sizeof(TABLE_RULE_ENT); - e->key_len= len; - memcpy(e->key, argument, len); - if (!hash_inited(&ignore_table)) init_table_rule_hash(&ignore_table); - if(my_hash_insert(&ignore_table, (byte*)e)) + if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0)))) exit(EX_EOM); break; } @@ -955,7 +930,28 @@ static char *quote_name(const char *name, char *buff, my_bool force) return buff; } /* quote_name */ +/* + Quote a table name so it can be used in "SHOW TABLES LIKE " + SYNOPSIS + quote_for_like + name - name of the table + buff - quoted name of the table + + DESCRIPTION + Quote \, _, ' and % characters + + Note: Because MySQL uses the C escape syntax in strings + (for example, '\n' to represent newline), you must double + any '\' that you use in your LIKE strings. For example, to + search for '\n', specify it as '\\n'. To search for '\', specify + it as '\\\\' (the backslashes are stripped once by the parser + and another time when the pattern match is done, leaving a + single backslash to be matched). + + Example: "t\1" => "t\\\\1" + +*/ static char *quote_for_like(const char *name, char *buff) { @@ -963,7 +959,13 @@ static char *quote_for_like(const char *name, char *buff) *to++= '\''; while (*name) { - if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%') + if (*name == '\\') + { + *to++='\\'; + *to++='\\'; + *to++='\\'; + } + else if (*name == '\'' || *name == '_' || *name == '%') *to++= '\\'; *to++= *name++; } @@ -1114,6 +1116,7 @@ static uint getTableStructure(char *table, char* db) FILE *sql_file = md_result_file; int len; DBUG_ENTER("getTableStructure"); + DBUG_PRINT("enter", ("db: %s, table: %s", db, table)); if (!insert_pat_inited) { @@ -2165,6 +2168,7 @@ static int get_actual_table_name(const char *old_table_name, char query[50 + 2*NAME_LEN]; char show_name_buff[FN_REFLEN]; DBUG_ENTER("get_actual_table_name"); + DBUG_PRINT("enter", ("old_table_name: %s", old_table_name)); /* Check memory for quote_for_like() */ DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); @@ -2186,36 +2190,72 @@ static int get_actual_table_name(const char *old_table_name, row= mysql_fetch_row( tableRes ); strmake(new_table_name, row[0], buf_size-1); retval = 0; + DBUG_PRINT("info", ("new_table_name: %s", new_table_name)); } mysql_free_result(tableRes); } - return retval; + DBUG_PRINT("exit", ("retval: %d", retval)); + DBUG_RETURN(retval); } static int dump_selected_tables(char *db, char **table_names, int tables) { - uint numrows; + uint numrows, i; char table_buff[NAME_LEN*+3]; + char new_table_name[NAME_LEN]; + DYNAMIC_STRING lock_tables_query; + HASH dump_tables; + + DBUG_ENTER("dump_selected_tables"); if (init_dumping(db)) return 1; + + /* Init hash table for storing the actual name of tables to dump */ + if (hash_init(&dump_tables, charset_info, 16, 0, 0, + (hash_get_key) get_table_key, 0, 0)) + exit(EX_EOM); + + init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024); + for (; tables > 0 ; tables-- , table_names++) + { + + /* the table name passed on commandline may be wrong case */ + if (!get_actual_table_name( *table_names, + new_table_name, sizeof(new_table_name) )) + { + /* Add found table name to lock_tables_query */ + if (lock_tables) + { + dynstr_append(&lock_tables_query, + quote_name(new_table_name, table_buff, 1)); + dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,"); + } + + /* Add found table name to dump_tables list */ + if (my_hash_insert(&dump_tables, + (byte*)my_strdup(new_table_name, MYF(0)))) + exit(EX_EOM); + + } + else + { + my_printf_error(0,"Couldn't find table: \"%s\"\n", MYF(0), + *table_names); + safe_exit(EX_ILLEGAL_TABLE); + /* We shall countinue here, if --force was given */ + } + } + if (lock_tables) { - DYNAMIC_STRING query; - int i; - - init_dynamic_string(&query, "LOCK TABLES ", 256, 1024); - for (i=0 ; i < tables ; i++) - { - dynstr_append(&query, quote_name(table_names[i], table_buff, 1)); - dynstr_append(&query, " READ /*!32311 LOCAL */,"); - } - if (mysql_real_query(sock, query.str, query.length-1)) + if (mysql_real_query(sock, lock_tables_query.str, + lock_tables_query.length-1)) DBerror(sock, "when doing LOCK TABLES"); /* We shall countinue here, if --force was given */ - dynstr_free(&query); } + dynstr_free(&lock_tables_query); if (flush_logs) { if (mysql_refresh(sock, REFRESH_LOG)) @@ -2224,20 +2264,20 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } if (opt_xml) print_xml_tag1(md_result_file, "", "database name=", db, "\n"); - for (; tables > 0 ; tables-- , table_names++) - { - char new_table_name[NAME_LEN]; - /* the table name passed on commandline may be wrong case */ - if (!get_actual_table_name( *table_names, new_table_name, sizeof(new_table_name) )) - { - numrows = getTableStructure(new_table_name, db); - if (!dFlag && numrows > 0) - dumpTable(numrows, new_table_name); - } - my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); - order_by= 0; + /* Dump each selected table */ + const char *table_name; + for (i= 0 ; i < dump_tables.records ; i++) + { + table_name= hash_element(&dump_tables, i); + DBUG_PRINT("info",("Dumping table %s", table_name)); + numrows = getTableStructure(table_name, db); + if (!dFlag && numrows > 0) + dumpTable(numrows, table_name); } + hash_free(&dump_tables); + my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); + order_by= 0; if (opt_xml) { fputs("\n", md_result_file); @@ -2245,7 +2285,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } if (lock_tables) mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); - return 0; + DBUG_RETURN(0); } /* dump_selected_tables */ diff --git a/client/mysqltest.c b/client/mysqltest.c index e60d9ecd1c5..3c238b57a07 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -781,7 +781,7 @@ int var_set(const char *var_name, const char *var_name_end, } else v = var_reg + digit; - return eval_expr(v, var_val, (const char**)&var_val_end); + DBUG_RETURN(eval_expr(v, var_val, (const char**)&var_val_end)); } @@ -955,9 +955,38 @@ static void do_exec(struct st_query* q) replace_dynstr_append_mem(ds, buf, strlen(buf)); } error= pclose(res_file); - if (error != 0) - die("command \"%s\" failed", cmd); + { + uint status= WEXITSTATUS(error); + if(q->abort_on_error) + die("At line %u: command \"%s\" failed", start_lineno, cmd); + else + { + DBUG_PRINT("info", + ("error: %d, status: %d", error, status)); + bool ok= 0; + uint i; + for (i=0 ; (uint) i < q->expected_errors ; i++) + { + DBUG_PRINT("info", ("expected error: %d", q->expected_errno[i].code.errnum)); + if ((q->expected_errno[i].type == ERR_ERRNO) && + (q->expected_errno[i].code.errnum == status)) + ok= 1; + verbose_msg("At line %u: command \"%s\" failed with expected error: %d", + start_lineno, cmd, status); + } + if (!ok) + die("At line: %u: command \"%s\" failed with wrong error: %d", + start_lineno, cmd, status); + } + } + else if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + die("At line: %u: command \"%s\" succeeded - should have failed with errno %d...", + start_lineno, cmd, q->expected_errno[0].code.errnum); + } if (!disable_result_log) { diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 3f7e7d22200..6071a753c87 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -688,6 +688,9 @@ MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --soc if [ "x$USE_EMBEDDED_SERVER" = "x1" ]; then MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST -A --language=$LANGUAGE -A --datadir=$SLAVE_MYDDIR -A --character-sets-dir=$CHARSETSDIR" fi +# Save path and name of mysqldump +MYSQL_DUMP_DIR="$MYSQL_DUMP" +export MYSQL_DUMP_DIR MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT" MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR $EXTRA_MYSQLBINLOG_OPT" MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD --basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose" diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index f66647bdbf8..50399c91ec9 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1409,3 +1409,30 @@ CREATE TABLE `t2` ( DROP TABLE t1, t2; DROP DATABASE mysqldump_test_db; +create database mysqldump_test_db; +use mysqldump_test_db; +create table t1(a varchar(30) primary key, b int not null); +create table t2(a varchar(30) primary key, b int not null); +create table t3(a varchar(30) primary key, b int not null); +test_sequence +------ Testing with illegal table names ------ +MYSQL_DUMP_DIR: Couldn't find table: "\d-2-1.sql" + +MYSQL_DUMP_DIR: Couldn't find table: "\t1" + +MYSQL_DUMP_DIR: Couldn't find table: "\t1" + +MYSQL_DUMP_DIR: Couldn't find table: "\\t1" + +MYSQL_DUMP_DIR: Couldn't find table: "t\1" + +MYSQL_DUMP_DIR: Couldn't find table: "t\1" + +MYSQL_DUMP_DIR: Couldn't find table: "t/1" + +test_sequence +------ Testing with illegal database names ------ +MYSQL_DUMP_DIR: Got error: 1049: Unknown database 'mysqldump_test_d' when selecting the database +MYSQL_DUMP_DIR: Got error: 1102: Incorrect database name 'mysqld\ump_test_db' when selecting the database +drop table t1, t2, t3; +drop database mysqldump_test_db; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 5a35c328314..349b1e96239 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -558,3 +558,81 @@ INSERT INTO t2 VALUES (1), (2); --exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db t1 t2 DROP TABLE t1, t2; DROP DATABASE mysqldump_test_db; + +# +# Testing with tables and databases that don't exists +# or contains illegal characters +# (Bug #9358 mysqldump crashes if tablename starts with \) +# +create database mysqldump_test_db; +use mysqldump_test_db; +create table t1(a varchar(30) primary key, b int not null); +create table t2(a varchar(30) primary key, b int not null); +create table t3(a varchar(30) primary key, b int not null); + +--disable_query_log +select '------ Testing with illegal table names ------' as test_sequence ; +--enable_query_log +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\d-2-1.sql" 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\t1" 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\t1" 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\\\t1" 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\1" 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\\1" 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t/1" 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1" + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T%1" + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T'1" + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1" + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 6 +--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_" + +--disable_query_log +select '------ Testing with illegal database names ------' as test_sequence ; +--enable_query_log +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 2 +--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_d 2>&1 + +--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR +--error 2 +--exec $MYSQL_DUMP --compact --skip-comments "mysqld\ump_test_db" 2>&1 + +drop table t1, t2, t3; +drop database mysqldump_test_db; + +