From bafa5fe8aa6a79ab5f28a9275d71647049709863 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Sep 2007 09:16:41 +0800 Subject: BUG#29851 TRUNCATE causes error 4350 from cluster in INSERT... ON DUPLICATE KEY UPDATE mysql-test/r/ndb_alter_table2.result: Add test case for BUG#29851 mysql-test/t/ndb_alter_table2.test: Add test case for BUG#29851 sql/ha_ndbcluster.cc: Indexes are dropped also when dropping table in GlobalDictCache --- sql/ha_ndbcluster.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 03b6bcf3242..76857900ea2 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -439,7 +439,8 @@ void ha_ndbcluster::no_uncommitted_rows_reset(THD *thd) void ha_ndbcluster::invalidate_dictionary_cache(bool global) { - NDBDICT *dict= get_ndb()->getDictionary(); + Ndb * ndb= get_ndb(); + NDBDICT *dict= ndb->getDictionary(); DBUG_ENTER("invalidate_dictionary_cache"); DBUG_PRINT("info", ("invalidating %s", m_tabname)); @@ -459,6 +460,7 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global) } else dict->removeCachedTable(m_tabname); + build_index_list(ndb, table, ILBP_OPEN); table->s->version=0L; /* Free when thread is ready */ /* Invalidate indexes */ for (uint i= 0; i < table->s->keys; i++) @@ -470,17 +472,23 @@ void ha_ndbcluster::invalidate_dictionary_cache(bool global) switch (idx_type) { case PRIMARY_KEY_ORDERED_INDEX: case ORDERED_INDEX: + if (!index) + break; if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); break; case UNIQUE_ORDERED_INDEX: + if (!index) + break; if (global) dict->invalidateIndex(index->getName(), m_tabname); else dict->removeCachedIndex(index->getName(), m_tabname); case UNIQUE_INDEX: + if (!unique_index) + break; if (global) dict->invalidateIndex(unique_index->getName(), m_tabname); else -- cgit v1.2.1 From 0741a4d1b0fa15865fd7bd1a3e8a785d388dd69b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Oct 2007 15:32:07 +0300 Subject: Removed extra spaces Added extra debug client/mysql_upgrade.c: Removed extra space client/mysqlcheck.c: Removed extra space client/mysqldump.c: Removed extra space client/mysqlimport.c: Removed extra space client/mysqlshow.c: Removed extra space client/mysqlslap.c: Removed extra space client/mysqltest.c: Removed extra space sql/handler.cc: Added extra debug --- sql/handler.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 2cb3c5aa348..d59ef4d037f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2502,8 +2502,9 @@ int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) int ha_enable_transaction(THD *thd, bool on) { int error=0; - DBUG_ENTER("ha_enable_transaction"); + DBUG_PRINT("enter", ("on: %d", (int) on)); + thd->transaction.on= on; if (on) { -- cgit v1.2.1 From 272bb6b5856a7f033e6826ba5a96b1ca52aabb12 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 8 Oct 2007 12:46:38 +0500 Subject: Bug#27580 SPACE() function collation bug? Problem: when character_set_connection=utf8, mixing SPACE() with a non-Unicode column (e.g. for concat) produced "illegal mix of collations" error. Fix: Item_string() corresponding to space character is now created using "ASCII" repertoire. Previously it was incorrectly created using "UNICODE" repertoure, which didn't allow to convert results of SPACE() to a non-Unicode character set. mysql-test/include/ctype_common.inc: - Adding test for bug#27580 - Restoring previous values of character_set_client and character_set_results, because ctype_common.inc now changes them when doing "set names utf8" in the test for bug#27580 mysql-test/r/ctype_big5.result: Adding test mysql-test/r/ctype_cp1250_ch.result: Adding test mysql-test/r/ctype_euckr.result: Adding test mysql-test/r/ctype_gb2312.result: Adding test mysql-test/r/ctype_gbk.result: Adding test mysql-test/r/ctype_uca.result: Adding test mysql-test/r/ctype_ucs.result: Adding test mysql-test/t/ctype_cp1250_ch.test: Adding test mysql-test/t/ctype_ucs.test: Adding test sql/item_create.cc: Item for SQL function SPACE() is now created with ASCII repertoire, to allow automatic conversion from UTF8 to column's character set e.g. for CONCAT(). --- sql/item_create.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_create.cc b/sql/item_create.cc index 561613032bc..60a17c21521 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -361,13 +361,13 @@ Item *create_func_space(Item *a) if (cs->mbminlen > 1) { uint dummy_errors; - sp= new Item_string("",0,cs); + sp= new Item_string("", 0, cs, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); if (sp) sp->str_value.copy(" ", 1, &my_charset_latin1, cs, &dummy_errors); } else { - sp= new Item_string(" ",1,cs); + sp= new Item_string(" ", 1, cs, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII); } return sp ? new Item_func_repeat(sp, a) : 0; } -- cgit v1.2.1 From fb84f573adf00de5e606a3b312bec99d24a0f49c Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Oct 2007 18:07:40 +0300 Subject: Moved a lot of old bug fixes and safe cleanups from Maria 5.1 tree to 5.1 - Reserver namespace and place in frm for TABLE_CHECKSUM and PAGE_CHECKSUM create options - Added syncing of directory when creating .frm files - Portability fixes - Added missing cast that could cause bugs - Code cleanups - Made some bit functions inline - Moved things out of myisam.h to my_handler.h to make them more accessable - Renamed some myisam variables and defines to make them more globaly usable (as they are used outside of MyISAM) - Fixed bugs in error conditions - Use compiler time asserts instead of run time - Fixed indentation HA_EXTRA_PREPARE_FOR_DELETE -> HA_EXTRA_PREPARE_FOR_DROP as the old name was wrong (Added a define for old value to ensure we don't break any old code) Added HA_EXTRA_PREPARE_FOR_RENAME as a signal for rename (before we used a DROP signal which is wrong) - Initialize error messages early to get better errors when mysqld or an engine fails to start - Fix windows bug that query_performance_frequency was not initialized if registry code failed - thread_stack -> my_thread_stack_size BitKeeper/etc/ignore: added libmysqld/scheduler.cc libmysqld/sql_connect.cc libmysqld/sql_tablespace.cc include/Makefile.am: Added my_bit.h include/m_string.h: Added bzero_if_purify() to simplify code include/my_base.h: Reserve options for the future Added HA_OPTION_NULL_FIELDS, HA_OPTION_PAGE_CHECKSUM, HA_CREATE_PAGE_CHECKSUM Added new error message HA_ERR_NEW_FILE Added optional new row type BLOCK_RECORD Renamed HA_EXTRA_PREPARE_FOR_DELETE to HA_EXTRA_PREPARE_FOR_DROP Added HA_EXTRA_PREARE_FOR_RENAME to inform handler we will do a rename (Added define to make things compatible until 6.0) Moved invalidator_by_filename form myisam.h include/my_dbug.h: Poirtablity fix include/my_global.h: Added helper macros STATIC_INLINE and MY_ERRPTR Added NEED_EXPLICIT_SYNC_DIR include/my_handler.h: Added missing casts Moved some constants and macros out from myisam.h to make these generally available Renamed mi_compare_text() to ha_compare_text() as this function is not myisam specific Renamed mi_portable_sizeof_char_ptr to portable_sizeof_char_ptr Added registering of handler messages for better error reporting during startup include/my_sys.h: Added my_sync_dir() and my_sync_dir_by_file() More comments Some indentation fixes Moved bit functions to my_bit.h Added prototype for crc32() include/myisam.h: Moved things from here to my_handler.h to make them more accessable libmysql/Makefile.shared: Added my_sync mysys/array.c: Fixed indentation and spelling errors Split set_dynamic() to two functions Added allocate_dynamic() as a new visiable function (no new code, only refactoring) mysys/mf_iocache.c: More DBUG mysys/mf_keycache.c: More explicite ASSERT Removed some casts Fixed indentation mysys/mf_tempfile.c: Fixed bug with possible dangling file descriptor mysys/my_atomic.c: Use compile time asserts instead of run time mysys/my_bit.c: Make most bit functions inline mysys/my_bitmap.c: Added my_bit.h mysys/my_compress.c: Fixed indentation mysys/my_create.c: Added my_sync_by_dir() mysys/my_delete.c: Added my_sync_by_dir() mysys/my_error.c: init_glob_errs() is now done in my_init() mysys/my_handler.c: mi_compare_text() -> ha_compare_text() as this is not MyISAM specific Added functions to initialize handler error messages Fixed indentation More clear usage of include files mysys/my_init.c: Added my_thread_stack_size to be used by other programs Ensure that global error messages are always initialized Fix windows bug that query_performance_frequency was not initialized if registry code failed mysys/my_open.c: More comments Removed duplicate code mysys/my_pread.c: Ensure that my_errno is set even if errno is 0 mysys/my_realloc.c: Added comment mysys/my_rename.c: Added syncing of directories mysys/my_symlink.c: Added my_sync_by_dir() mysys/my_sync.c: Added my_sync_dir() On recent Mac OS X, fcntl(F_FULLFSYNC) is recommended over fsync() (see "man fsync" on Mac OS X 10.3). my_sync_dir(): to sync a directory after a file creation/deletion/ renaming; can be called directly or via MY_SYNC_DIR in my_create/ my_delete/my_rename(). No-op except on Linux (see "man fsync" on Linux). my_sync_dir_from_file(): same as above, just more practical when the caller has a file name but no directory name ready. Should the #warning even be a #error? I mean do we want to release binaries which don't guarantee any durability? mysys/safemalloc.c: Added sf_malloc_report_allocated() (Debugging aid) sql/gen_lex_hash.cc: Remove inline for big function sql/ha_partition.cc: HA_EXTRA_PREPARE_FOR_DELETE -> HA_EXTRA_PREPARE_FOR_DROP prepare_for_delete -> prepare_for_rename() as this is the the time this function is called sql/ha_partition.h: prepare_for_delete -> prepare_for_rename() as this is the the time this function is called sql/handler.cc: ha_init_errors() is now called at startup before plugins This allows us to get better error messages sql/handler.h: Reserve enum value for Maria Add future proof enum for page checksums sql/item_func.cc: Include my_bit.h sql/lex.h: Added future proof CREATE table options sql/log.cc: Added comment sql/mysql_priv.h: thread_stack moved to mysys sql/mysqld.cc: thread_stack moved to mysys thread_stack -> my_thread_stack_size Initialize myisam key caches before plugins starts Initialize error to allow storage engine to give better error messages if init failes. Fixed indentation Group all MyISAM options together Added new status variable 'Opened_table_definitions' to allow one to monitor if table definition cache is too small Clarified some option help messages sql/opt_range.cc: Removed wrong usage of SAFE_MODE (this disabled key usage for UPDATES, which was never the intention) Removed print if total cost in a place where it didn't have any usable value sql/set_var.cc: thread_stack -> my_thread_stack sql/sql_class.cc: Intialize transaction object properly sql/sql_parse.cc: thread_stack -> my_thread_stack sql/sql_select.cc: Include my_bit.h mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr sql/sql_show.cc: Simplify handling of ha_choice variables Added future safe PAGE_CHECKSUM option Addid missing 'transactional=#' in information schema sql/sql_table.cc: HA_EXTRA_PREPARE_FOR_DELETE -> HA_EXTRA_FORCE_REOPEN when doing reopen HA_EXTRA_PREPARE_FOR_DELETE -> HA_EXTRA_PREPARE_FOR_RENAME when doing rename Removed not needed initialization sql/sql_test.cc: thread_stack -> my_thread_stack sql/sql_yacc.yy: Simplify handling of ha_choice variables Added future proof create table options TABLE_CHECKSUM=# & PAGE_CHECKSUM=# sql/table.cc: Save page_checksum in .frm sql/table.h: Added variable to hold create table option PAGE_CHECKSUM sql/unireg.cc: Added syncing of directories storage/myisam/ft_boolean_search.c: mi_compare_text() -> ha_compare_text() storage/myisam/ft_eval.c: mi_compare_text() -> ha_compare_text() storage/myisam/ft_nlq_search.c: mi_compare_text() -> ha_compare_text() storage/myisam/ft_parser.c: mi_compare_text() -> ha_compare_text() storage/myisam/ft_stopwords.c: mi_compare_text() -> ha_compare_text() storage/myisam/ft_test1.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/ft_update.c: mi_compare_text() -> ha_compare_text() storage/myisam/ha_myisam.cc: Include my_bit.h storage/myisam/mi_check.c: MI_MAX_POSSIBLE_KEY_BUFF -> HA_MAX_POSSIBLE_KEY_BUFF mi_compare_text() -> ha_compare_text() Added BLOCK_RECORD to avoid compiler warnings storage/myisam/mi_checksum.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/mi_create.c: MI_MAX_POSSIBLE_KEY -> HA_MAX_POSSIBLE_KEY MI_MAX_KEY_BLOCK_SIZE -> HA_MAX_KEY_BLOCK_SIZE mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/mi_dynrec.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/mi_extra.c: HA_EXTRA_PREPARE_FOR_DELETE -> HA_EXTRA_PREPARE_FOR_DROP storage/myisam/mi_open.c: MI_MAX_POSSIBLE_KEY -> HA_MAX_POSSIBLE_KEY mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/mi_packrec.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/mi_range.c: mi_compare_text -> ha_compare_text storage/myisam/mi_test1.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/mi_test2.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/mi_unique.c: mi_compare_text() -> ha_compare_text() storage/myisam/mi_write.c: mi_compare_text() -> ha_compare_text() storage/myisam/myisamchk.c: Include my_bit.h storage/myisam/myisamdef.h: Moved store_key_length_inc to handler.h storage/myisam/myisampack.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisam/sp_test.c: mi_portable_sizeof_char_ptr -> portable_sizeof_char_ptr storage/myisammrg/ha_myisammrg.cc: HA_EXTRA_PREPARE_FOR_DELETE -> HA_EXTRA_PREPARE_FOR_DROP include/my_bit.h: New BitKeeper file ``include/my_bit.h'' --- sql/gen_lex_hash.cc | 4 ++-- sql/ha_partition.cc | 20 ++++++++++------- sql/ha_partition.h | 2 +- sql/handler.cc | 9 +++----- sql/handler.h | 5 +++++ sql/item_func.cc | 1 + sql/lex.h | 6 ++++- sql/log.cc | 5 +++++ sql/mysql_priv.h | 2 +- sql/mysqld.cc | 63 +++++++++++++++++++++++++++++------------------------ sql/opt_range.cc | 4 ---- sql/set_var.cc | 2 +- sql/sql_class.cc | 1 + sql/sql_parse.cc | 4 ++-- sql/sql_select.cc | 5 +++-- sql/sql_show.cc | 24 +++++++++++++++++--- sql/sql_table.cc | 10 ++++----- sql/sql_test.cc | 4 ++-- sql/sql_yacc.yy | 28 ++++++++++++++++++++---- sql/table.cc | 10 ++++++--- sql/table.h | 1 + sql/unireg.cc | 6 +++-- 22 files changed, 141 insertions(+), 75 deletions(-) (limited to 'sql') diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 36b7f30dc64..18f80e11a15 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -481,8 +481,8 @@ int main(int argc,char **argv) printf("\nstatic unsigned int symbols_max_len=%d;\n\n", max_len2); printf("\ -static inline SYMBOL *get_hash_symbol(const char *s,\n\ - unsigned int len,bool function)\n\ +static SYMBOL *get_hash_symbol(const char *s,\n\ + unsigned int len,bool function)\n\ {\n\ register uchar *hash_map;\n\ register const char *cur_str= s;\n\ diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 200e8a97c67..a57f1d24758 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4701,11 +4701,14 @@ void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info, about this call). We pass this along to all underlying MyISAM handlers and ignore it for the rest. - HA_EXTRA_PREPARE_FOR_DELETE: + HA_EXTRA_PREPARE_FOR_DROP: Only used by MyISAM, called in preparation for a DROP TABLE. It's used mostly by Windows that cannot handle dropping an open file. On other platforms it has the same effect as HA_EXTRA_FORCE_REOPEN. + HA_EXTRA_PREPARE_FOR_RENAME: + Informs the handler we are about to attempt a rename of the table. + HA_EXTRA_READCHECK: HA_EXTRA_NO_READCHECK: Only one call to HA_EXTRA_NO_READCHECK from ha_open where it says that @@ -4831,14 +4834,15 @@ int ha_partition::extra(enum ha_extra_function operation) } /* Category 3), used by MyISAM handlers */ - case HA_EXTRA_PREPARE_FOR_DELETE: - DBUG_RETURN(prepare_for_delete()); + case HA_EXTRA_PREPARE_FOR_RENAME: + DBUG_RETURN(prepare_for_rename()); break; case HA_EXTRA_NORMAL: case HA_EXTRA_QUICK: case HA_EXTRA_NO_READCHECK: case HA_EXTRA_PREPARE_FOR_UPDATE: case HA_EXTRA_FORCE_REOPEN: + case HA_EXTRA_PREPARE_FOR_DROP: case HA_EXTRA_FLUSH_CACHE: { if (m_myisam) @@ -4990,24 +4994,24 @@ void ha_partition::prepare_extra_cache(uint cachesize) 0 Success */ -int ha_partition::prepare_for_delete() +int ha_partition::prepare_for_rename() { int result= 0, tmp; handler **file; - DBUG_ENTER("ha_partition::prepare_for_delete()"); + DBUG_ENTER("ha_partition::prepare_for_rename()"); if (m_new_file != NULL) { for (file= m_new_file; *file; file++) - if ((tmp= (*file)->extra(HA_EXTRA_PREPARE_FOR_DELETE))) + if ((tmp= (*file)->extra(HA_EXTRA_PREPARE_FOR_RENAME))) result= tmp; for (file= m_reorged_file; *file; file++) - if ((tmp= (*file)->extra(HA_EXTRA_PREPARE_FOR_DELETE))) + if ((tmp= (*file)->extra(HA_EXTRA_PREPARE_FOR_RENAME))) result= tmp; DBUG_RETURN(result); } - DBUG_RETURN(loop_extra(HA_EXTRA_PREPARE_FOR_DELETE)); + DBUG_RETURN(loop_extra(HA_EXTRA_PREPARE_FOR_RENAME)); } /* diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 9d10aea2b6f..ac00581fae0 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -211,7 +211,7 @@ public: } virtual void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share); private: - int prepare_for_delete(); + int prepare_for_rename(); int copy_partitions(ulonglong *copied, ulonglong *deleted); void cleanup_new_partition(uint part_count); int prepare_new_partition(TABLE *table, HA_CREATE_INFO *create_info, diff --git a/sql/handler.cc b/sql/handler.cc index 9e47baadd4a..5b121ac258a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -290,7 +290,8 @@ handler *get_ha_partition(partition_info *part_info) 0 OK != 0 Error */ -static int ha_init_errors(void) + +int ha_init_errors(void) { #define SETMSG(nr, msg) errmsgs[(nr) - HA_ERR_FIRST]= (msg) const char **errmsgs; @@ -505,9 +506,6 @@ int ha_init() int error= 0; DBUG_ENTER("ha_init"); - if (ha_init_errors()) - DBUG_RETURN(1); - DBUG_ASSERT(total_ha < MAX_HA); /* Check if there is a transaction-capable storage engine besides the @@ -2505,8 +2503,7 @@ int ha_enable_transaction(THD *thd, bool on) DBUG_ENTER("ha_enable_transaction"); DBUG_PRINT("enter", ("on: %d", (int) on)); - thd->transaction.on= on; - if (on) + if ((thd->transaction.on= on)) { /* Now all storage engines should have transaction handling enabled. diff --git a/sql/handler.h b/sql/handler.h index b91d8a39b88..6b3975351a1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -20,6 +20,7 @@ #pragma interface /* gcc class implementation */ #endif +#include #include #include @@ -272,6 +273,7 @@ enum legacy_db_type DB_TYPE_TABLE_FUNCTION, DB_TYPE_MEMCACHE, DB_TYPE_FALCON, + DB_TYPE_MARIA, DB_TYPE_FIRST_DYNAMIC=42, DB_TYPE_DEFAULT=127 // Must be last }; @@ -322,6 +324,7 @@ enum enum_binlog_command { #define HA_CREATE_USED_CONNECTION (1L << 18) #define HA_CREATE_USED_KEY_BLOCK_SIZE (1L << 19) #define HA_CREATE_USED_TRANSACTIONAL (1L << 20) +#define HA_CREATE_USED_PAGE_CHECKSUM (1L << 21) typedef ulonglong my_xid; // this line is the same as in log_event.h #define MYSQL_XID_PREFIX "MySQLXid" @@ -818,6 +821,7 @@ typedef struct st_ha_create_information bool frm_only; /* 1 if no ha_create_table() */ bool varchar; /* 1 if table has a VARCHAR */ enum ha_storage_media storage_media; /* DEFAULT, DISK or MEMORY */ + enum ha_choice page_checksum; /* If we have page_checksums */ } HA_CREATE_INFO; @@ -1851,6 +1855,7 @@ static inline bool ha_storage_engine_is_enabled(const handlerton *db_type) } /* basic stuff */ +int ha_init_errors(void); int ha_init(void); int ha_end(void); int ha_initialize_handlerton(st_plugin_int *plugin); diff --git a/sql/item_func.cc b/sql/item_func.cc index efc42c1b73f..8891838bb2a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -27,6 +27,7 @@ #include #include #include +#include #include "sp_head.h" #include "sp_rcontext.h" diff --git a/sql/lex.h b/sql/lex.h index e311379120d..aab2182b097 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -380,6 +380,8 @@ static SYMBOL symbols[] = { { "OWNER", SYM(OWNER_SYM)}, { "PACK_KEYS", SYM(PACK_KEYS_SYM)}, { "PARSER", SYM(PARSER_SYM)}, + { "PAGE", SYM(PAGE_SYM)}, + { "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)}, { "PARTIAL", SYM(PARTIAL)}, { "PARTITION", SYM(PARTITION_SYM)}, { "PARTITIONING", SYM(PARTITIONING_SYM)}, @@ -512,7 +514,8 @@ static SYMBOL symbols[] = { { "SUSPEND", SYM(SUSPEND_SYM)}, { "TABLE", SYM(TABLE_SYM)}, { "TABLES", SYM(TABLES)}, - { "TABLESPACE", SYM(TABLESPACE)}, + { "TABLESPACE", SYM(TABLESPACE)}, + { "TABLE_CHECKSUM", SYM(TABLE_CHECKSUM_SYM)}, { "TEMPORARY", SYM(TEMPORARY)}, { "TEMPTABLE", SYM(TEMPTABLE_SYM)}, { "TERMINATED", SYM(TERMINATED)}, @@ -529,6 +532,7 @@ static SYMBOL symbols[] = { { "TO", SYM(TO_SYM)}, { "TRAILING", SYM(TRAILING)}, { "TRANSACTION", SYM(TRANSACTION_SYM)}, + { "TRANSACTIONAL", SYM(TRANSACTIONAL_SYM)}, { "TRIGGER", SYM(TRIGGER_SYM)}, { "TRIGGERS", SYM(TRIGGERS_SYM)}, { "TRUE", SYM(TRUE_SYM)}, diff --git a/sql/log.cc b/sql/log.cc index 95204e89d0e..f8c78b03228 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2270,6 +2270,11 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg, my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)), 0, MYF(MY_WME | MY_WAIT_IF_FULL))) { + /* + TODO: all operations creating/deleting the index file or a log, should + call my_sync_dir() or my_sync_dir_by_file() to be durable. + TODO: file creation should be done with my_create() not my_open(). + */ if (index_file_nr >= 0) my_close(index_file_nr,MYF(0)); return TRUE; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 47a42354423..4aa574e5d47 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1760,7 +1760,7 @@ extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong slave_net_timeout, slave_trans_retries; extern uint max_user_connections; extern ulong what_to_log,flush_time; -extern ulong query_buff_size, thread_stack; +extern ulong query_buff_size; extern ulong max_prepared_stmt_count, prepared_stmt_count; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, max_relay_log_size; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6ea1cf111bb..c02fdc85d32 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -16,6 +16,7 @@ #include "mysql_priv.h" #include #include +#include #include "slave.h" #include "rpl_mi.h" #include "sql_repl.h" @@ -441,7 +442,7 @@ uint volatile thread_count, thread_running; ulonglong thd_startup_options; ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, table_def_size; -ulong thread_stack, what_to_log; +ulong what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; ulong slave_net_timeout, slave_trans_retries; @@ -2194,7 +2195,7 @@ or misconfigured. This error can also be caused by malfunctioning hardware.\n", We will try our best to scrape up some info that will hopefully help diagnose\n\ the problem, but since we have already crashed, something is definitely wrong\n\ and this may fail.\n\n"); - fprintf(stderr, "key_buffer_size=%lu\n", + fprintf(stderr, "key_buffer_size=%lu\n", (ulong) dflt_key_cache->key_cache_mem_size); fprintf(stderr, "read_buffer_size=%ld\n", (long) global_system_variables.read_buff_size); fprintf(stderr, "max_used_connections=%lu\n", max_used_connections); @@ -2226,7 +2227,7 @@ the thread stack. Please read http://www.mysql.com/doc/en/Linux.html\n\n", { fprintf(stderr,"thd: 0x%lx\n",(long) thd); print_stacktrace(thd ? (uchar*) thd->thread_stack : (uchar*) 0, - thread_stack); + my_thread_stack_size); } if (thd) { @@ -2385,9 +2386,9 @@ static void start_signal_handler(void) Peculiar things with ia64 platforms - it seems we only have half the stack size in reality, so we have to double it here */ - pthread_attr_setstacksize(&thr_attr,thread_stack*2); + pthread_attr_setstacksize(&thr_attr,my_thread_stack_size*2); #else - pthread_attr_setstacksize(&thr_attr,thread_stack); + pthread_attr_setstacksize(&thr_attr,my_thread_stack_size); #endif #endif @@ -3397,6 +3398,13 @@ server."); using_update_log=1; } + /* call ha_init_key_cache() on all key caches to init them */ + process_key_caches(&ha_init_key_cache); + + /* Allow storage engine to give real error messages */ + if (ha_init_errors()) + DBUG_RETURN(1); + if (plugin_init(&defaults_argc, defaults_argv, (opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) | (opt_help ? PLUGIN_INIT_SKIP_INITIALIZATION : 0))) @@ -3563,9 +3571,6 @@ server."); if (opt_myisam_log) (void) mi_log(1); - /* call ha_init_key_cache() on all key caches to init them */ - process_key_caches(&ha_init_key_cache); - #if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && !defined(EMBEDDED_LIBRARY) if (locked_in_memory && !getuid()) { @@ -3755,9 +3760,9 @@ int main(int argc, char **argv) Peculiar things with ia64 platforms - it seems we only have half the stack size in reality, so we have to double it here */ - pthread_attr_setstacksize(&connection_attrib,thread_stack*2); + pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size*2); #else - pthread_attr_setstacksize(&connection_attrib,thread_stack); + pthread_attr_setstacksize(&connection_attrib,my_thread_stack_size); #endif #ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE { @@ -3768,15 +3773,15 @@ int main(int argc, char **argv) stack_size/= 2; #endif /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ - if (stack_size && stack_size < thread_stack) + if (stack_size && stack_size < my_thread_stack_size) { if (global_system_variables.log_warnings) sql_print_warning("Asked for %lu thread stack, but got %ld", - thread_stack, (long) stack_size); + my_thread_stack_size, (long) stack_size); #if defined(__ia64__) || defined(__ia64) - thread_stack= stack_size*2; + my_thread_stack_size= stack_size*2; #else - thread_stack= stack_size; + my_thread_stack_size= stack_size; #endif } } @@ -5022,7 +5027,7 @@ enum options_mysqld OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, - OPT_MYISAM_USE_MMAP, + OPT_MYISAM_USE_MMAP, OPT_MYISAM_REPAIR_THREADS, OPT_MYISAM_STATS_METHOD, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT, @@ -5037,7 +5042,7 @@ enum options_mysqld OPT_SORT_BUFFER, OPT_TABLE_OPEN_CACHE, OPT_TABLE_DEF_CACHE, OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE, OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK, - OPT_WAIT_TIMEOUT, OPT_MYISAM_REPAIR_THREADS, + OPT_WAIT_TIMEOUT, OPT_ERROR_LOG_FILE, OPT_DEFAULT_WEEK_FORMAT, OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS, @@ -6193,10 +6198,10 @@ The minimum value for this variable is 4096.", (uchar**) &opt_plugin_load, (uchar**) &opt_plugin_load, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE, - "The size of the buffer that is allocated when preloading indexes", - (uchar**) &global_system_variables.preload_buff_size, - (uchar**) &max_system_variables.preload_buff_size, 0, GET_ULONG, - REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0}, + "The size of the buffer that is allocated when preloading indexes", + (uchar**) &global_system_variables.preload_buff_size, + (uchar**) &max_system_variables.preload_buff_size, 0, GET_ULONG, + REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0}, {"query_alloc_block_size", OPT_QUERY_ALLOC_BLOCK_SIZE, "Allocation block size for query parsing and execution", (uchar**) &global_system_variables.query_alloc_block_size, @@ -6339,8 +6344,8 @@ The minimum value for this variable is 4096.", REQUIRED_ARG, 20, 1, 16384, 0, 1, 0}, #endif {"thread_stack", OPT_THREAD_STACK, - "The stack size for each thread.", (uchar**) &thread_stack, - (uchar**) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, + "The stack size for each thread.", (uchar**) &my_thread_stack_size, + (uchar**) &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, 1024L*128L, ~0L, 0, 1024, 0}, { "time_format", OPT_TIME_FORMAT, "The TIME format (for future).", @@ -6354,12 +6359,12 @@ The minimum value for this variable is 4096.", (uchar**) &max_system_variables.tmp_table_size, 0, GET_ULL, REQUIRED_ARG, 16*1024*1024L, 1024, MAX_MEM_TABLE_SIZE, 0, 1, 0}, {"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE, - "Allocation block size for various transaction-related structures", + "Allocation block size for transactions to be stored in binary log", (uchar**) &global_system_variables.trans_alloc_block_size, (uchar**) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG, REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, {"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE, - "Persistent buffer for various transaction-related structures", + "Persistent buffer for transactions to be stored in binary log", (uchar**) &global_system_variables.trans_prealloc_size, (uchar**) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, @@ -6889,6 +6894,7 @@ SHOW_VAR status_vars[]= { {"Open_tables", (char*) &show_open_tables, SHOW_FUNC}, {"Opened_files", (char*) &my_file_total_opened, SHOW_LONG_NOFLUSH}, {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables), SHOW_LONG_STATUS}, + {"Opened_table_definitions", (char*) offsetof(STATUS_VAR, opened_shares), SHOW_LONG_STATUS}, {"Prepared_stmt_count", (char*) &show_prepared_stmt_count, SHOW_FUNC}, #ifdef HAVE_QUERY_CACHE {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_NOFLUSH}, @@ -7112,9 +7118,10 @@ static void mysql_init_variables(void) thread_cache.empty(); key_caches.empty(); if (!(dflt_key_cache= get_or_create_key_cache(default_key_cache_base.str, - default_key_cache_base.length))) + default_key_cache_base.length))) exit(1); - multi_keycache_init(); /* set key_cache_hash.default_value = dflt_key_cache */ + /* set key_cache_hash.default_value = dflt_key_cache */ + multi_keycache_init(); /* Set directory paths */ strmake(language, LANGUAGE, sizeof(language)-1); @@ -7129,7 +7136,7 @@ static void mysql_init_variables(void) master_password= master_host= 0; master_info_file= (char*) "master.info", relay_log_info_file= (char*) "relay-log.info"; - master_ssl_key= master_ssl_cert= master_ssl_ca= + master_ssl_key= master_ssl_cert= master_ssl_ca= master_ssl_capath= master_ssl_cipher= 0; report_user= report_password = report_host= 0; /* TO BE DELETED */ opt_relay_logname= opt_relaylog_index_name= 0; @@ -7782,7 +7789,7 @@ mysql_getopt_value(const char *keyname, uint key_length, } } } - return option->value; + return option->value; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 5a772501e48..97d0bcc8707 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2139,9 +2139,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, quick=0; needed_reg.clear_all(); quick_keys.clear_all(); - if ((specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range || - !limit) - DBUG_RETURN(0); /* purecov: inspected */ if (keys_to_use.is_clear_all()) DBUG_RETURN(0); records= head->file->stats.records; @@ -4308,7 +4305,6 @@ static bool ror_intersect_add(ROR_INTERSECT_INFO *info, } info->out_rows *= selectivity_mult; - DBUG_PRINT("info", ("info->total_cost= %g", info->total_cost)); if (is_cpk_scan) { diff --git a/sql/set_var.cc b/sql/set_var.cc index 697de9cda97..f67ccc02dc7 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -706,7 +706,7 @@ static SHOW_VAR fixed_vars[]= { #ifdef HAVE_THR_SETCONCURRENCY {"thread_concurrency", (char*) &concurrency, SHOW_LONG}, #endif - {"thread_stack", (char*) &thread_stack, SHOW_LONG}, + {"thread_stack", (char*) &my_thread_stack_size, SHOW_LONG}, }; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 66a51d5bb00..afe0383658f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -440,6 +440,7 @@ THD::THD() cleanup_done= abort_on_warning= no_warnings_for_error= 0; peer_port= 0; // For SHOW PROCESSLIST transaction.m_pending_rows_event= 0; + transaction.on= 1; #ifdef SIGNAL_WITH_VIO_CLOSE active_vio = 0; #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ae347bebb47..e440aeaa588 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5120,10 +5120,10 @@ bool check_stack_overrun(THD *thd, long margin, long stack_used; DBUG_ASSERT(thd == current_thd); if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >= - (long) (thread_stack - margin)) + (long) (my_thread_stack_size - margin)) { sprintf(errbuff[0],ER(ER_STACK_OVERRUN_NEED_MORE), - stack_used,thread_stack,margin); + stack_used,my_thread_stack_size,margin); my_message(ER_STACK_OVERRUN_NEED_MORE,errbuff[0],MYF(0)); thd->fatal_error(); return 1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b77bb719e1e..1f206e2ec17 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -29,6 +29,7 @@ #include "sql_cursor.h" #include +#include #include #include @@ -9580,7 +9581,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, table->s= share; init_tmp_table_share(share, "", 0, tmpname, tmpname); share->blob_field= blob_field; - share->blob_ptr_size= mi_portable_sizeof_char_ptr; + share->blob_ptr_size= portable_sizeof_char_ptr; share->db_low_byte_first=1; // True for HEAP and MyISAM share->table_charset= param->table_charset; share->primary_key= MAX_KEY; // Indicate no primary key @@ -10145,7 +10146,7 @@ TABLE *create_virtual_tmp_table(THD *thd, List &field_list) table->s= share; share->blob_field= blob_field; share->fields= field_count; - share->blob_ptr_size= mi_portable_sizeof_char_ptr; + share->blob_ptr_size= portable_sizeof_char_ptr; setup_tmp_table_column_bitmaps(table, bitmaps); /* Create all fields and calculate the total length of record */ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f7813b73089..38db2fe85a5 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -70,6 +70,9 @@ static TYPELIB grant_types = { sizeof(grant_names)/sizeof(char **), grant_names, NULL}; #endif +/* Match the values of enum ha_choice */ +static const char *ha_choice_values[] = {"", "0", "1"}; + static void store_key_options(THD *thd, String *packet, TABLE *table, KEY *key_info); @@ -1182,6 +1185,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, key_info= table->key_info; bzero((char*) &create_info, sizeof(create_info)); + /* Allow update_create_info to update row type */ + create_info.row_type= share->row_type; file->update_create_info(&create_info); primary_key= share->primary_key; @@ -1366,19 +1371,25 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(" PACK_KEYS=1")); if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) packet->append(STRING_WITH_LEN(" PACK_KEYS=0")); + /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */ if (share->db_create_options & HA_OPTION_CHECKSUM) packet->append(STRING_WITH_LEN(" CHECKSUM=1")); + if (share->page_checksum != HA_CHOICE_UNDEF) + { + packet->append(STRING_WITH_LEN(" PAGE_CHECKSUM=")); + packet->append(ha_choice_values[(uint) share->page_checksum], 1); + } if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) packet->append(STRING_WITH_LEN(" DELAY_KEY_WRITE=1")); - if (share->row_type != ROW_TYPE_DEFAULT) + if (create_info.row_type != ROW_TYPE_DEFAULT) { packet->append(STRING_WITH_LEN(" ROW_FORMAT=")); - packet->append(ha_row_type[(uint) share->row_type]); + packet->append(ha_row_type[(uint) create_info.row_type]); } if (share->transactional != HA_CHOICE_UNDEF) { packet->append(STRING_WITH_LEN(" TRANSACTIONAL=")); - packet->append(share->transactional == HA_CHOICE_YES ? "1" : "0", 1); + packet->append(ha_choice_values[(uint) share->transactional], 1); } if (table->s->key_block_size) { @@ -3462,8 +3473,12 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, ptr=strmov(ptr," pack_keys=1"); if (share->db_create_options & HA_OPTION_NO_PACK_KEYS) ptr=strmov(ptr," pack_keys=0"); + /* We use CHECKSUM, instead of TABLE_CHECKSUM, for backward compability */ if (share->db_create_options & HA_OPTION_CHECKSUM) ptr=strmov(ptr," checksum=1"); + if (share->page_checksum != HA_CHOICE_UNDEF) + ptr= strxmov(ptr, " page_checksum=", + ha_choice_values[(uint) share->page_checksum], NullS); if (share->db_create_options & HA_OPTION_DELAY_KEY_WRITE) ptr=strmov(ptr," delay_key_write=1"); if (share->row_type != ROW_TYPE_DEFAULT) @@ -3482,6 +3497,9 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, show_table->part_info->no_parts > 0) ptr= strmov(ptr, " partitioned"); #endif + if (share->transactional != HA_CHOICE_UNDEF) + ptr= strxmov(ptr, " transactional=", + ha_choice_values[(uint) share->transactional], NullS); table->field[19]->store(option_buff+1, (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1), cs); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cd39623f2b4..5f1f7f9db0e 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3678,8 +3678,9 @@ mysql_rename_table(handlerton *base, const char *old_db, wait_while_table_is_used() thd Thread handler table Table to remove from cache - function HA_EXTRA_PREPARE_FOR_DELETE if table is to be deleted - HA_EXTRA_FORCE_REOPEN if table is not be used + function HA_EXTRA_PREPARE_FOR_DROP if table is to be deleted + HA_EXTRA_FORCE_REOPEN if table is not be used + HA_EXTRA_PREPARE_FOR_RENAME if table is to be renamed NOTES When returning, the table will be unusable for other threads until the table is closed. @@ -3729,7 +3730,7 @@ void close_cached_table(THD *thd, TABLE *table) { DBUG_ENTER("close_cached_table"); - wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DELETE); + wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); /* Close lock if this is not got with LOCK TABLES */ if (thd->lock) { @@ -6488,7 +6489,7 @@ view_err: if (lower_case_table_names) my_casedn_str(files_charset_info, old_name); - wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DELETE); + wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME); close_data_files_and_morph_locks(thd, db, table_name); error=0; @@ -6946,7 +6947,6 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list) DBUG_ENTER("mysql_recreate_table"); bzero((char*) &create_info, sizeof(create_info)); - create_info.db_type= 0; create_info.row_type=ROW_TYPE_NOT_USED; create_info.default_table_charset=default_charset_info; /* Force alter table to recreate table */ diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 0fe299d4505..f1d7e4a7312 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -459,7 +459,7 @@ void mysql_print_status() VOID(my_getwd(current_dir, sizeof(current_dir),MYF(0))); printf("Current dir: %s\n", current_dir); printf("Running threads: %d Stack size: %ld\n", thread_count, - (long) thread_stack); + (long) my_thread_stack_size); thr_print_locks(); // Write some debug info #ifndef DBUG_OFF print_cached_tables(); @@ -536,7 +536,7 @@ Estimated memory (with thread stack): %ld\n", (int) info.uordblks, (int) info.fordblks, (int) info.keepcost, - (long) (thread_count * thread_stack + info.hblkhd + info.arena)); + (long) (thread_count * my_thread_stack_size + info.hblkhd + info.arena)); #endif Events::dump_internal_status(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 68680addc58..560aebcc456 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -487,6 +487,7 @@ Item* handle_sql2003_note184_exception(THD *thd, Item* left, bool equal, enum enum_tx_isolation tx_isolation; enum Cast_target cast_type; enum Item_udftype udf_type; + enum ha_choice choice; CHARSET_INFO *charset; thr_lock_type lock_type; interval_type interval, interval_time_st; @@ -875,6 +876,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token OWNER_SYM %token PACK_KEYS_SYM %token PAGE_SYM +%token PAGE_CHECKSUM_SYM %token PARAM_MARKER %token PARSER_SYM %token PARTIAL /* SQL-2003-N */ @@ -1010,6 +1012,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %token TABLESPACE %token TABLE_REF_PRIORITY %token TABLE_SYM /* SQL-2003-R */ +%token TABLE_CHECKSUM_SYM %token TEMPORARY /* SQL-2003-N */ %token TEMPTABLE_SYM %token TERMINATED @@ -1145,6 +1148,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type ulonglong_num real_ulonglong_num size_number +%type choice + %type part_bit_expr @@ -4440,6 +4445,16 @@ create_table_option: Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM; } + | TABLE_CHECKSUM_SYM opt_equal ulong_num + { + Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; + Lex->create_info.used_fields|= HA_CREATE_USED_CHECKSUM; + } + | PAGE_CHECKSUM_SYM opt_equal choice + { + Lex->create_info.used_fields|= HA_CREATE_USED_PAGE_CHECKSUM; + Lex->create_info.page_checksum= $3; + } | DELAY_KEY_WRITE_SYM opt_equal ulong_num { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; @@ -4499,13 +4514,11 @@ create_table_option: Lex->create_info.used_fields|= HA_CREATE_USED_KEY_BLOCK_SIZE; Lex->create_info.key_block_size= $3; } - | TRANSACTIONAL_SYM opt_equal ulong_num + | TRANSACTIONAL_SYM opt_equal choice { Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL; - Lex->create_info.transactional= ($3 != 0 ? HA_CHOICE_YES : - HA_CHOICE_NO); + Lex->create_info.transactional= $3; } - ; default_charset: @@ -8379,6 +8392,11 @@ dec_num: | FLOAT_NUM ; +choice: + ulong_num { $$= $1 != 0 ? HA_CHOICE_YES : HA_CHOICE_NO; } + | DEFAULT { $$= HA_CHOICE_UNDEF; } + ; + procedure_clause: /* empty */ | PROCEDURE ident /* Procedure name */ @@ -10575,6 +10593,7 @@ keyword_sp: | ONE_SYM {} | PACK_KEYS_SYM {} | PAGE_SYM {} + | PAGE_CHECKSUM_SYM {} | PARTIAL {} | PARTITIONING_SYM {} | PARTITIONS_SYM {} @@ -10638,6 +10657,7 @@ keyword_sp: | SUPER_SYM {} | SUSPEND_SYM {} | TABLES {} + | TABLE_CHECKSUM_SYM {} | TABLESPACE {} | TEMPORARY {} | TEMPTABLE_SYM {} diff --git a/sql/table.cc b/sql/table.cc index c1d8e3abe94..417cd78fe2e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -705,7 +705,8 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, if (!head[32]) // New frm file in 3.23 { share->avg_row_length= uint4korr(head+34); - share->transactional= (ha_choice) head[39]; + share->transactional= (ha_choice) (head[39] & 3); + share->page_checksum= (ha_choice) ((head[39] >> 2) & 3); share->row_type= (row_type) head[40]; share->table_charset= get_charset((uint) head[38],MYF(0)); share->null_field_first= 1; @@ -2428,7 +2429,9 @@ File create_frm(THD *thd, const char *name, const char *db, int2store(fileinfo+16,reclength); int4store(fileinfo+18,create_info->max_rows); int4store(fileinfo+22,create_info->min_rows); + /* fileinfo[26] is set in mysql_create_frm() */ fileinfo[27]=2; // Use long pack-fields + /* fileinfo[28 & 29] is set to key_info_length in mysql_create_frm() */ create_info->table_options|=HA_OPTION_LONG_BLOB_PTR; // Use portable blob pointers int2store(fileinfo+30,create_info->table_options); fileinfo[32]=0; // No filename anymore @@ -2436,9 +2439,10 @@ File create_frm(THD *thd, const char *name, const char *db, int4store(fileinfo+34,create_info->avg_row_length); fileinfo[38]= (create_info->default_table_charset ? create_info->default_table_charset->number : 0); - fileinfo[39]= (uchar) create_info->transactional; + fileinfo[39]= (uchar) ((uint) create_info->transactional | + ((uint) create_info->page_checksum << 2)); fileinfo[40]= (uchar) create_info->row_type; - /* Next few bytes were for RAID support */ + /* Next few bytes where for RAID support */ fileinfo[41]= 0; fileinfo[42]= 0; fileinfo[43]= 0; diff --git a/sql/table.h b/sql/table.h index 6554b6ed578..b9c15ea2b6d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -311,6 +311,7 @@ typedef struct st_table_share enum row_type row_type; /* How rows are stored */ enum tmp_table_type tmp_table; enum ha_choice transactional; + enum ha_choice page_checksum; uint ref_count; /* How many TABLE objects uses this */ uint open_count; /* Number of tables in open list */ diff --git a/sql/unireg.cc b/sql/unireg.cc index f9e8e54439a..da52889fb2f 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -284,8 +284,10 @@ bool mysql_create_frm(THD *thd, const char *file_name, my_free(keybuff, MYF(0)); if (opt_sync_frm && !(create_info->options & HA_LEX_CREATE_TMP_TABLE) && - my_sync(file, MYF(MY_WME))) - goto err2; + (my_sync(file, MYF(MY_WME)) || + my_sync_dir_by_file(file_name, MYF(MY_WME)))) + goto err2; + if (my_close(file,MYF(MY_WME))) goto err3; -- cgit v1.2.1 From 510bda4bed61e3fc96249e693532874e21b1f274 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Dec 2007 17:40:42 +0400 Subject: BUG#25677 - With --skip-symbolic-links option on, DATA DIRECTORY clause is silently ignored When symbolic links are disabled by command line option or NO_DIR_IN_CREATE sql mode, CREATE TABLE silently ignores DATA/INDEX DIRECTORY options. With this fix a warning is issued when symbolic links are disabled. mysql-test/r/symlink.result: A test case for BUG#25677. mysql-test/t/symlink.test: A test case for BUG#25677. sql/sql_parse.cc: Moved handling of situation when mysqld is compiled without HAVE_READLINK to mysql_create_table_no_lock(). sql/sql_table.cc: Issue a warning in case DATA/INDEX DIRECTORY is specified and: - server is compiled without HAVE_READLINK; - using symbolic links is disabled by command line option; - using symbolic links is disabled by NO_DIR_IN_CREATE sql mode. --- sql/sql_parse.cc | 10 +--------- sql/sql_table.cc | 12 +++++++++++- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8ed658df90d..e5f96a96a00 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2237,15 +2237,7 @@ mysql_execute_command(THD *thd) /* Might have been updated in create_table_precheck */ create_info.alias= create_table->alias; -#ifndef HAVE_READLINK - if (create_info.data_file_name) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, - "DATA DIRECTORY option ignored"); - if (create_info.index_file_name) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, - "INDEX DIRECTORY option ignored"); - create_info.data_file_name= create_info.index_file_name= NULL; -#else +#ifdef HAVE_READLINK /* Fix names if symlinked tables */ if (append_file_to_dir(thd, &create_info.data_file_name, create_table->table_name) || diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 91acd8d20a3..4236028c9d8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3437,8 +3437,18 @@ bool mysql_create_table_no_lock(THD *thd, thd->proc_info="creating table"; create_info->table_existed= 0; // Mark that table is created - if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) +#ifdef HAVE_READLINK + if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) +#endif + { + if (create_info->data_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "DATA DIRECTORY option ignored"); + if (create_info->index_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "INDEX DIRECTORY option ignored"); create_info->data_file_name= create_info->index_file_name= 0; + } create_info->table_options=db_options; path[path_length - reg_ext_length]= '\0'; // Remove .frm extension -- cgit v1.2.1 From 647fe5b3a12324918ebb1e75ff5619eec137efed Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Dec 2007 17:05:27 +0400 Subject: BUG#22708 - Error message doesn't refer to storage engine unsupported When openning a table with unsupported (disabled or not compiled) storage engine, confusing error message is returned. Return better error message when we're attempting to open a table that uses unsupported engine. sql/table.cc: Return better error message when we're attempting to open a table that uses unsupported engine. --- sql/table.cc | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'sql') diff --git a/sql/table.cc b/sql/table.cc index c3ddb809b9e..493a940fd2e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -886,26 +886,31 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, ha_legacy_type(share->db_type()))); } #ifdef WITH_PARTITION_STORAGE_ENGINE - else + else if (str_db_type_length == 9 && + !strncmp((char *) next_chunk + 2, "partition", 9)) { - LEX_STRING pname= { C_STRING_WITH_LEN( "partition" ) }; - if (str_db_type_length == pname.length && - !strncmp((char *) next_chunk + 2, pname.str, pname.length)) - { - /* - Use partition handler - tmp_plugin is locked with a local lock. - we unlock the old value of share->db_plugin before - replacing it with a globally locked version of tmp_plugin - */ - plugin_unlock(NULL, share->db_plugin); - share->db_plugin= ha_lock_engine(NULL, partition_hton); - DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)", - str_db_type_length, next_chunk + 2, - ha_legacy_type(share->db_type()))); - } + /* + Use partition handler + tmp_plugin is locked with a local lock. + we unlock the old value of share->db_plugin before + replacing it with a globally locked version of tmp_plugin + */ + plugin_unlock(NULL, share->db_plugin); + share->db_plugin= ha_lock_engine(NULL, partition_hton); + DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)", + str_db_type_length, next_chunk + 2, + ha_legacy_type(share->db_type()))); } #endif + else if (!tmp_plugin) + { + /* purecov: begin inspected */ + error= 8; + my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str); + my_free(buff, MYF(0)); + goto err; + /* purecov: end */ + } next_chunk+= str_db_type_length + 2; } if (next_chunk + 5 < buff_end) @@ -2188,6 +2193,8 @@ void open_table_error(TABLE_SHARE *share, int error, int db_errno, int errarg) "of MySQL and cannot be read", MYF(0), buff); break; + case 8: + break; default: /* Better wrong error than none */ case 4: strxmov(buff, share->normalized_path.str, reg_ext, NullS); -- cgit v1.2.1 From 763c1132c3a2b6352cd199ad17e1a121672c5740 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Dec 2007 15:21:37 +0200 Subject: Bug #31326: No compile check of order of initializations fixed -Wreorder warnings BUILD/SETUP.sh: Bug #31326: enabled the -Wreorder warnings sql/rpl_mi.cc: Bug #31326: fixed -Wreorder warnings storage/heap/ha_heap.cc: Bug #31326: fixed -Wreorder warnings storage/ndb/src/kernel/blocks/backup/Backup.hpp: Bug #31326: fixed -Wreorder warnings storage/ndb/src/kernel/blocks/pgman.cpp: Bug #31326: fixed -Wreorder warnings --- sql/rpl_mi.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 1165164fd88..5e46837e948 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -29,9 +29,9 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, Master_info::Master_info() :Slave_reporting_capability("I/O"), - ssl(0), fd(-1), io_thd(0), inited(0), + ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0), abort_slave(0),slave_running(0), - ssl_verify_server_cert(0), slave_run_id(0) + slave_run_id(0) { host[0] = 0; user[0] = 0; password[0] = 0; ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0; -- cgit v1.2.1 From 46359f4d3059c96425883f2737a333149070522d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Dec 2007 10:13:13 +0200 Subject: Mutex protection added for loading plugins. (BUG#33345) sql/sql_plugin.cc: Mutex protection added for loading plugins. --- sql/sql_plugin.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index ef4c63381e2..401e544d4e4 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1421,6 +1421,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, #endif case ';': name.str[name.length]= '\0'; + pthread_mutex_lock(&LOCK_plugin); if (str != &dl) // load all plugins in named module { dl= name; @@ -1444,6 +1445,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) goto error; } + pthread_mutex_unlock(&LOCK_plugin); name.length= dl.length= 0; dl.str= NULL; name.str= p= buffer; str= &name; @@ -1463,6 +1465,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, } DBUG_RETURN(FALSE); error: + pthread_mutex_unlock(&LOCK_plugin); sql_print_error("Couldn't load plugin named '%s' with soname '%s'.", name.str, dl.str); DBUG_RETURN(TRUE); -- cgit v1.2.1 From 92e31e96a2c6f2f98e77217534fcc3712e7b4fa5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Dec 2007 13:24:43 +0000 Subject: Add new pkgplugindir handling to seperate plugins from libraries, and allow override for binary distributions. Extend mysql_config to print compiled-in plugin location for third-party plugins to use. Resolves bug#31736. libmysqld/Makefile.am: Use pkgplugindir. plugin/daemon_example/Makefile.am: Use pkgplugindir. plugin/fulltext/Makefile.am: Use pkgplugindir. scripts/Makefile.am: Add pkgplugindir. scripts/make_binary_distribution.sh: Add pkgplugindir. scripts/mysql_config.sh: Add pkgplugindir. sql/Makefile.am: Use pkgplugindir. sql/mysqld.cc: Use PLUGINDIR, derived from pkgplugindir, instead of LIBDIR for plugins. sql/unireg.h: Use PLUGINDIR instead of LIBDIR, and define to be the default setting of pkgplugindir. storage/innobase/Makefile.am: Use pkgplugindir. storage/archive/Makefile.am: Use pkgplugindir. storage/blackhole/Makefile.am: Use pkgplugindir. storage/example/Makefile.am: Use pkgplugindir. storage/federated/Makefile.am: Use pkgplugindir. --- sql/Makefile.am | 3 ++- sql/mysqld.cc | 2 +- sql/unireg.h | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/Makefile.am b/sql/Makefile.am index 0081417d492..02a92dee7a7 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -19,6 +19,7 @@ MYSQLDATAdir = $(localstatedir) MYSQLSHAREdir = $(pkgdatadir) MYSQLBASEdir= $(prefix) MYSQLLIBdir= $(pkglibdir) +pkgplugindir = $(libdir)/@PACKAGE@/plugin INCLUDES = @ZLIB_INCLUDES@ \ -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_srcdir)/regex -I$(srcdir) $(openssl_includes) @@ -136,7 +137,7 @@ DEFS = -DMYSQL_SERVER \ -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \ -DDATADIR="\"$(MYSQLDATAdir)\"" \ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \ - -DLIBDIR="\"$(MYSQLLIBdir)\"" \ + -DPLUGINDIR="\"$(pkgplugindir)\"" \ @DEFS@ BUILT_MAINT_SRC = sql_yacc.cc sql_yacc.h diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2f264482d94..48e486f8d02 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8032,7 +8032,7 @@ static void fix_paths(void) (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home); (void) my_load_path(opt_plugin_dir, opt_plugin_dir_ptr ? opt_plugin_dir_ptr : - get_relative_path(LIBDIR), mysql_home); + get_relative_path(PLUGINDIR), mysql_home); opt_plugin_dir_ptr= opt_plugin_dir; char *sharedir=get_relative_path(SHAREDIR); diff --git a/sql/unireg.h b/sql/unireg.h index f0b4a88c7f8..d6a72e6589f 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -35,8 +35,8 @@ #ifndef SHAREDIR #define SHAREDIR "share/" #endif -#ifndef LIBDIR -#define LIBDIR "lib/" +#ifndef PLUGINDIR +#define PLUGINDIR "lib/plugin" #endif #define ER(X) errmesg[(X) - ER_ERROR_FIRST] -- cgit v1.2.1 From d687f1b45dde8e7d1e8a49836242054e5721e17b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Dec 2007 18:42:49 +0100 Subject: Bug #33375 all_set corrupted on table object - make sure to reset the read and write sets --- sql/handler.cc | 2 ++ sql/log_event.cc | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index a4926071598..3b1667b0d59 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3710,6 +3710,8 @@ int handler::ha_reset() DBUG_ASSERT(inited == NONE); /* Free cache used by filesort */ free_io_cache(table); + /* reset the bitmaps to point to defaults */ + table->default_column_bitmaps(); DBUG_RETURN(reset()); } diff --git a/sql/log_event.cc b/sql/log_event.cc index 00e3dc89f6b..182b270ab4d 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -7837,7 +7837,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) { DBUG_PRINT("info",("ha_index_init returns error %d",error)); table->file->print_error(error, MYF(0)); - DBUG_RETURN(error); + goto err; } /* Fill key data for the row */ @@ -7870,7 +7870,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_PRINT("info",("no record matching the key found in the table")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); - DBUG_RETURN(error); + goto err; } /* @@ -7898,7 +7898,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) if (table->key_info->flags & HA_NOSAME) { table->file->ha_index_end(); - DBUG_RETURN(0); + goto ok; } /* @@ -7930,7 +7930,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_PRINT("info",("no record matching the given row found")); table->file->print_error(error, MYF(0)); table->file->ha_index_end(); - DBUG_RETURN(error); + goto err; } } @@ -7951,7 +7951,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) DBUG_PRINT("info",("error initializing table scan" " (ha_rnd_init returns %d)",error)); table->file->print_error(error, MYF(0)); - DBUG_RETURN(error); + goto err; } /* Continue until we find the right record or have made a full loop */ @@ -7975,7 +7975,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli) " (rnd_next returns %d)",error)); table->file->print_error(error, MYF(0)); table->file->ha_rnd_end(); - DBUG_RETURN(error); + goto err; } } while (restart_count < 2 && record_compare(table)); @@ -7995,10 +7995,14 @@ int Rows_log_event::find_row(const Relay_log_info *rli) table->file->ha_rnd_end(); DBUG_ASSERT(error == HA_ERR_END_OF_FILE || error == HA_ERR_RECORD_DELETED || error == 0); - DBUG_RETURN(error); + goto err; } - +ok: + table->default_column_bitmaps(); DBUG_RETURN(0); +err: + table->default_column_bitmaps(); + DBUG_RETURN(error); } #endif -- cgit v1.2.1 From ad367fe00a28d4d3b652900344597f6517fa8462 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 2 Jan 2008 13:00:46 +0000 Subject: Use pkglibdir to simplify pkgplugindir, and fix the path in a couple of Makefiles. Continuation of the fix for bug#31736. libmysqld/Makefile.am: Use pkglibdir plugin/daemon_example/Makefile.am: Use pkglibdir plugin/fulltext/Makefile.am: Use pkglibdir scripts/Makefile.am: Use pkglibdir scripts/make_binary_distribution.sh: Update comment sql/Makefile.am: Use pkglibdir storage/archive/Makefile.am: Use pkglibdir storage/blackhole/Makefile.am: Use pkglibdir storage/example/Makefile.am: Use pkglibdir, fix pkgplugindir storage/federated/Makefile.am: Use pkglibdir storage/innobase/Makefile.am: Use pkglibdir, fix pkgplugindir --- sql/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/Makefile.am b/sql/Makefile.am index 02a92dee7a7..92ae7a05df7 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -19,7 +19,7 @@ MYSQLDATAdir = $(localstatedir) MYSQLSHAREdir = $(pkgdatadir) MYSQLBASEdir= $(prefix) MYSQLLIBdir= $(pkglibdir) -pkgplugindir = $(libdir)/@PACKAGE@/plugin +pkgplugindir = $(pkglibdir)/plugin INCLUDES = @ZLIB_INCLUDES@ \ -I$(top_builddir)/include -I$(top_srcdir)/include \ -I$(top_srcdir)/regex -I$(srcdir) $(openssl_includes) -- cgit v1.2.1 From fa01e8845b6b75c0d5f1f564ff5705a2c3735468 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 4 Jan 2008 12:06:20 +0100 Subject: Bug#30459 Partitioning across disks failing on Windows Problem was that there are no support for symlinked files on Windows for mysqld. So we fail when trying to create them. Solution: Ignore the DATA/INDEX DIRECTORY clause for partitions and push a warning. (Just like a MyISAM table) mysql-test/r/partition.result: Bug#30459 Partitioning across disks failing on Windows Moved symlink specific tests to partition_symlink result file mysql-test/r/partition_symlink.result: Bug#30459 Partitioning across disks failing on Windows Moved symlink specific tests from partition.test result file mysql-test/r/partition_windows.result: Bug#30459 Partitioning across disks failing on Windows result file mysql-test/t/partition.test: Bug#30459 Partitioning across disks failing on Windows Moved symlink specific tests to partition_symlink test file mysql-test/t/partition_symlink.test: Bug#30459 Partitioning across disks failing on Windows Moved symlink specific tests from partition.test test file mysql-test/t/partition_windows.test: Bug#30459 Partitioning across disks failing on Windows test file --- sql/partition_info.cc | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3b580422da1..16433497efd 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -794,8 +794,18 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, partition_element *part_elem= part_it++; if (part_elem->engine_type == NULL) part_elem->engine_type= default_engine_type; - if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) - part_elem->data_file_name= part_elem->index_file_name= 0; +#ifdef HAVE_READLINK + if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) +#endif + { + if (part_elem->data_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "DATA DIRECTORY option ignored"); + if (part_elem->index_file_name) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, + "INDEX DIRECTORY option ignored"); + part_elem->data_file_name= part_elem->index_file_name= NULL; + } if (!is_sub_partitioned()) { if (check_table_name(part_elem->partition_name, -- cgit v1.2.1 From d84a0e5caa26602b282695b52417cf7d9b667e7e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 9 Jan 2008 13:15:50 +0100 Subject: Bug#31931 Partitions: unjustified 'mix of handlers' error message Problem was that the mix of handlers was not consistent between CREATE and ALTER changed so that it works like: - All partitions must use the same engine AND it must be the same as the table. - if one does NOT specify an engine on the table level then one must either NOT specify any engine on any partition/subpartition OR for ALL partitions/subpartitions Note: that after a table have been created, the storage engine is specified for all parts of the table (table/partition/subpartition) and so when using alter, one does not need to specify it (unless one wants to change the storage engine, then one have to specify it on the table level) mysql-test/r/partition.result: Bug#31931 Partitions: unjustified 'mix of handlers' error message test result updated mysql-test/r/partition_innodb.result: Bug#31931 Partitions: unjustified 'mix of handlers' error message test result updated mysql-test/suite/ndb/r/ndb_partition_key.result: Bug#31931 Partitions: unjustified 'mix of handlers' error message test result updated mysql-test/suite/ndb/t/ndb_partition_key.test: Bug#31931 Partitions: unjustified 'mix of handlers' error message test case update mysql-test/suite/parts/inc/partition_engine.inc: Bug#31931 Partitions: unjustified 'mix of handlers' error message test case updated mysql-test/suite/parts/r/ndb_partition_key.result: Bug#31931 Partitions: unjustified 'mix of handlers' error message test result updated mysql-test/suite/parts/r/partition_engine_innodb.result: Bug#31931 Partitions: unjustified 'mix of handlers' error message test result updated mysql-test/suite/parts/r/partition_engine_myisam.result: Bug#31931 Partitions: unjustified 'mix of handlers' error message test result updated mysql-test/suite/parts/t/ndb_partition_key.test: Bug#31931 Partitions: unjustified 'mix of handlers' error message test case updated mysql-test/t/partition.test: Bug#31931 Partitions: unjustified 'mix of handlers' error message test case updated mysql-test/t/partition_innodb.test: Bug#31931 Partitions: unjustified 'mix of handlers' error message test case updated sql/partition_info.cc: Bug#31931 Partitions: unjustified 'mix of handlers' error message moved the check_engine_condition here from sql_partition.cc created a new check_engine_mix from check_native_partitioned in sql_partition.cc sql/partition_info.h: Bug#31931 Partitions: unjustified 'mix of handlers' error message non static function check_engine_mix (now used in sql_partition.cc) sql/sql_partition.cc: Bug#31931 Partitions: unjustified 'mix of handlers' error message moved check_engine_condition to partition_info.cc and moved out some common code in check_native_partitioned to check_engine_mix in partition_info.cc --- sql/partition_info.cc | 247 +++++++++++++++++++++++++++++++++++++++++++------- sql/partition_info.h | 2 +- sql/sql_partition.cc | 138 ++++++++-------------------- 3 files changed, 253 insertions(+), 134 deletions(-) (limited to 'sql') diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3b580422da1..cc7a7f17577 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -419,41 +419,167 @@ char *partition_info::has_unique_names() /* - Check that all partitions use the same storage engine. - This is currently a limitation in this version. + Check that the partition/subpartition is setup to use the correct + storage engine + SYNOPSIS + check_engine_condition() + p_elem Partition element + table_engine_set Have user specified engine on table level + inout::engine_type Current engine used + inout::first Is it first partition + RETURN VALUE + TRUE Failed check + FALSE Ok + DESCRIPTION + Specified engine for table and partitions p0 and pn + Must be correct both on CREATE and ALTER commands + table p0 pn res (0 - OK, 1 - FAIL) + - - - 0 + - - x 1 + - x - 1 + - x x 0 + x - - 0 + x - x 0 + x x - 0 + x x x 0 + i.e: + - All subpartitions must use the same engine + AND it must be the same as the partition. + - All partitions must use the same engine + AND it must be the same as the table. + - if one does NOT specify an engine on the table level + then one must either NOT specify any engine on any + partition/subpartition OR for ALL partitions/subpartitions + Note: + When ALTER a table, the engines are already set for all levels + (table, all partitions and subpartitions). So if one want to + change the storage engine, one must specify it on the table level + +*/ + +static bool check_engine_condition(partition_element *p_elem, + bool table_engine_set, + handlerton **engine_type, + bool *first) +{ + DBUG_ENTER("check_engine_condition"); + + DBUG_PRINT("enter", ("p_eng %u t_eng %u t_eng_set %u first %u state %u", + ha_legacy_type(p_elem->engine_type), + ha_legacy_type(*engine_type), + table_engine_set, *first, p_elem->part_state)); + if (*first && !table_engine_set) + { + *engine_type= p_elem->engine_type; + DBUG_PRINT("info", ("setting table_engine = %u", + ha_legacy_type(*engine_type))); + } + *first= FALSE; + if ((table_engine_set && + (p_elem->engine_type != (*engine_type) && + p_elem->engine_type)) || + (!table_engine_set && + p_elem->engine_type != (*engine_type))) + { + DBUG_RETURN(TRUE); + } + else + { + DBUG_RETURN(FALSE); + } +} + +/* + Check engine mix that it is correct + Current limitation is that all partitions and subpartitions + must use the same storage engine. SYNOPSIS check_engine_mix() - engine_array An array of engine identifiers - no_parts Total number of partitions - + inout::engine_type Current engine used + table_engine_set Have user specified engine on table level RETURN VALUE - TRUE Error, mixed engines - FALSE Ok, no mixed engines + TRUE Error, mixed engines + FALSE Ok, no mixed engines DESCRIPTION Current check verifies only that all handlers are the same. Later this check will be more sophisticated. + (specified partition handler ) specified table handler + (NDB, NDB) NDB OK + (MYISAM, MYISAM) - OK + (MYISAM, -) - NOT OK + (MYISAM, -) MYISAM OK + (- , MYISAM) - NOT OK + (- , -) MYISAM OK + (-,-) - OK + (NDB, MYISAM) * NOT OK */ -bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts) +bool partition_info::check_engine_mix(handlerton *engine_type, + bool table_engine_set) { - uint i= 0; + handlerton *old_engine_type= engine_type; + bool first= TRUE; + uint no_parts= partitions.elements; DBUG_ENTER("partition_info::check_engine_mix"); - - do + DBUG_PRINT("info", ("in: engine_type = %u, table_engine_set = %u", + ha_legacy_type(engine_type), + table_engine_set)); + if (no_parts) { - if (engine_array[i] != engine_array[0]) + List_iterator part_it(partitions); + uint i= 0; + do { - my_error(ER_MIX_HANDLER_ERROR, MYF(0)); - DBUG_RETURN(TRUE); - } - } while (++i < no_parts); - if (engine_array[0]->flags & HTON_NO_PARTITION) + partition_element *part_elem= part_it++; + DBUG_PRINT("info", ("part = %d engine = %d table_engine_set %u", + i, ha_legacy_type(part_elem->engine_type), + table_engine_set)); + if (is_sub_partitioned() && + part_elem->subpartitions.elements) + { + uint no_subparts= part_elem->subpartitions.elements; + uint j= 0; + List_iterator sub_it(part_elem->subpartitions); + do + { + partition_element *sub_elem= sub_it++; + DBUG_PRINT("info", ("sub = %d engine = %u table_engie_set %u", + j, ha_legacy_type(sub_elem->engine_type), + table_engine_set)); + if (check_engine_condition(sub_elem, table_engine_set, + &engine_type, &first)) + goto error; + } while (++j < no_subparts); + /* ensure that the partition also has correct engine */ + if (check_engine_condition(part_elem, table_engine_set, + &engine_type, &first)) + goto error; + } + else if (check_engine_condition(part_elem, table_engine_set, + &engine_type, &first)) + goto error; + } while (++i < no_parts); + } + DBUG_PRINT("info", ("engine_type = %u", + ha_legacy_type(engine_type))); + if (!engine_type) + engine_type= old_engine_type; + if (engine_type->flags & HTON_NO_PARTITION) { my_error(ER_PARTITION_MERGE_ERROR, MYF(0)); DBUG_RETURN(TRUE); } + DBUG_PRINT("info", ("out: engine_type = %u", + ha_legacy_type(engine_type))); + DBUG_ASSERT(engine_type != partition_hton); DBUG_RETURN(FALSE); +error: + /* + Mixed engines not yet supported but when supported it will need + the partition handler + */ + DBUG_RETURN(TRUE); } @@ -726,12 +852,12 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, handler *file, HA_CREATE_INFO *info, bool check_partition_function) { - handlerton **engine_array= NULL; - uint part_count= 0; + handlerton *table_engine= default_engine_type; uint i, tot_partitions; - bool result= TRUE; + bool result= TRUE, table_engine_set; char *same_name; DBUG_ENTER("partition_info::check_partition_info"); + DBUG_ASSERT(default_engine_type != partition_hton); if (check_partition_function) { @@ -777,23 +903,49 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0)); goto end; } + /* + if NOT specified ENGINE = : + If Create, always use create_info->db_type + else, use previous tables db_type + either ALL or NONE partition should be set to + default_engine_type when not table_engine_set + Note: after a table is created its storage engines for + the table and all partitions/subpartitions are set. + So when ALTER it is already set on table level + */ + if (thd->lex->create_info.used_fields & HA_CREATE_USED_ENGINE) + { + table_engine_set= TRUE; + table_engine= thd->lex->create_info.db_type; + } + else + { + table_engine_set= FALSE; + if (thd->lex->sql_command != SQLCOM_CREATE_TABLE) + { + table_engine_set= TRUE; + DBUG_ASSERT(table_engine && table_engine != partition_hton); + } + } + if ((same_name= has_unique_names())) { my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name); goto end; } - engine_array= (handlerton**)my_malloc(tot_partitions * sizeof(handlerton *), - MYF(MY_WME)); - if (unlikely(!engine_array)) - goto end; i= 0; { List_iterator part_it(partitions); + uint no_parts_not_set= 0; + uint prev_no_subparts_not_set= no_subparts + 1; do { partition_element *part_elem= part_it++; if (part_elem->engine_type == NULL) + { + no_parts_not_set++; part_elem->engine_type= default_engine_type; + } if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) part_elem->data_file_name= part_elem->index_file_name= 0; if (!is_sub_partitioned()) @@ -804,13 +956,13 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, my_error(ER_WRONG_PARTITION_NAME, MYF(0)); goto end; } - DBUG_PRINT("info", ("engine = %d", - ha_legacy_type(part_elem->engine_type))); - engine_array[part_count++]= part_elem->engine_type; + DBUG_PRINT("info", ("part = %d engine = %d", + i, ha_legacy_type(part_elem->engine_type))); } else { uint j= 0; + uint no_subparts_not_set= 0; List_iterator sub_it(part_elem->subpartitions); do { @@ -822,19 +974,49 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, goto end; } if (sub_elem->engine_type == NULL) + { sub_elem->engine_type= default_engine_type; - DBUG_PRINT("info", ("engine = %u", - ha_legacy_type(sub_elem->engine_type))); - engine_array[part_count++]= sub_elem->engine_type; + no_subparts_not_set++; + } + DBUG_PRINT("info", ("part = %d sub = %d engine = %u", + i, j, ha_legacy_type(sub_elem->engine_type))); } while (++j < no_subparts); + if (prev_no_subparts_not_set == (no_subparts + 1)) + prev_no_subparts_not_set= no_subparts_not_set; + if (!table_engine_set && + prev_no_subparts_not_set == no_subparts_not_set && + no_subparts_not_set != 0 && + no_subparts_not_set != no_subparts) + { + DBUG_PRINT("info", ("no_subparts_not_set = %u no_subparts = %u", + no_subparts_not_set, no_subparts)); + my_error(ER_MIX_HANDLER_ERROR, MYF(0)); + goto end; + } } } while (++i < no_parts); + if (!table_engine_set && + no_parts_not_set != 0 && + no_parts_not_set != no_parts) + { + DBUG_PRINT("info", ("no_parts_not_set = %u no_parts = %u", + no_parts_not_set, no_subparts)); + my_error(ER_MIX_HANDLER_ERROR, MYF(0)); + goto end; + } } - if (unlikely(partition_info::check_engine_mix(engine_array, part_count))) + if (unlikely(check_engine_mix(table_engine, table_engine_set))) + { + my_error(ER_MIX_HANDLER_ERROR, MYF(0)); goto end; + } + if (table_engine == partition_hton) + DBUG_PRINT("info", ("Table engine set to partition_hton")); + DBUG_ASSERT(default_engine_type == table_engine); if (eng_type) - *eng_type= (handlerton*)engine_array[0]; + *eng_type= table_engine; + /* We need to check all constant expressions that they are of the correct @@ -850,7 +1032,6 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } result= FALSE; end: - my_free((char*)engine_array,MYF(MY_ALLOW_ZERO_PTR)); DBUG_RETURN(result); } diff --git a/sql/partition_info.h b/sql/partition_info.h index b7d13e188f3..b38e572d3aa 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -269,7 +269,7 @@ public: bool set_up_defaults_for_partitioning(handler *file, HA_CREATE_INFO *info, uint start_no); char *has_unique_names(); - static bool check_engine_mix(handlerton **engine_array, uint no_parts); + bool check_engine_mix(handlerton *engine_type, bool default_engine); bool check_range_constants(); bool check_list_constants(); bool check_partition_info(THD *thd, handlerton **eng_type, diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index ce70e177a85..d10ee3fa408 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3863,6 +3863,8 @@ bool mysql_unpack_partition(THD *thd, if (!part_info->default_engine_type) part_info->default_engine_type= default_db_type; DBUG_ASSERT(part_info->default_engine_type == default_db_type); + DBUG_ASSERT(part_info->default_engine_type->db_type != DB_TYPE_UNKNOWN); + DBUG_ASSERT(part_info->default_engine_type != partition_hton); { /* @@ -3996,56 +3998,6 @@ static int fast_end_partition(THD *thd, ulonglong copied, } -/* - Check engine mix that it is correct - SYNOPSIS - check_engine_condition() - p_elem Partition element - default_engine Have user specified engine on table level - inout::engine_type Current engine used - inout::first Is it first partition - RETURN VALUE - TRUE Failed check - FALSE Ok - DESCRIPTION - (specified partition handler ) specified table handler - (NDB, NDB) NDB OK - (MYISAM, MYISAM) - OK - (MYISAM, -) - NOT OK - (MYISAM, -) MYISAM OK - (- , MYISAM) - NOT OK - (- , -) MYISAM OK - (-,-) - OK - (NDB, MYISAM) * NOT OK -*/ - -static bool check_engine_condition(partition_element *p_elem, - bool default_engine, - handlerton **engine_type, - bool *first) -{ - DBUG_ENTER("check_engine_condition"); - - DBUG_PRINT("enter", ("def_eng = %u, first = %u", default_engine, *first)); - if (*first && default_engine) - { - *engine_type= p_elem->engine_type; - } - *first= FALSE; - if ((!default_engine && - (p_elem->engine_type != (*engine_type) && - p_elem->engine_type)) || - (default_engine && - p_elem->engine_type != (*engine_type))) - { - DBUG_RETURN(TRUE); - } - else - { - DBUG_RETURN(FALSE); - } -} - /* We need to check if engine used by all partitions can handle partitioning natively. @@ -4070,52 +4022,30 @@ static bool check_engine_condition(partition_element *p_elem, static bool check_native_partitioned(HA_CREATE_INFO *create_info,bool *ret_val, partition_info *part_info, THD *thd) { - List_iterator part_it(part_info->partitions); - bool first= TRUE; - bool default_engine; - handlerton *engine_type= create_info->db_type; + bool table_engine_set; + handlerton *engine_type= part_info->default_engine_type; handlerton *old_engine_type= engine_type; - uint i= 0; - uint no_parts= part_info->partitions.elements; DBUG_ENTER("check_native_partitioned"); - default_engine= (create_info->used_fields & HA_CREATE_USED_ENGINE) ? - FALSE : TRUE; - DBUG_PRINT("info", ("engine_type = %u, default = %u", - ha_legacy_type(engine_type), - default_engine)); - if (no_parts) + if (create_info->used_fields & HA_CREATE_USED_ENGINE) { - do + table_engine_set= TRUE; + engine_type= create_info->db_type; + } + else + { + table_engine_set= FALSE; + if (thd->lex->sql_command != SQLCOM_CREATE_TABLE) { - partition_element *part_elem= part_it++; - if (part_info->is_sub_partitioned() && - part_elem->subpartitions.elements) - { - uint no_subparts= part_elem->subpartitions.elements; - uint j= 0; - List_iterator sub_it(part_elem->subpartitions); - do - { - partition_element *sub_elem= sub_it++; - if (check_engine_condition(sub_elem, default_engine, - &engine_type, &first)) - goto error; - } while (++j < no_subparts); - /* - In case of subpartitioning and defaults we allow that only - subparts have specified engines, as long as the parts haven't - specified the wrong engine it's ok. - */ - if (check_engine_condition(part_elem, FALSE, - &engine_type, &first)) - goto error; - } - else if (check_engine_condition(part_elem, default_engine, - &engine_type, &first)) - goto error; - } while (++i < no_parts); + table_engine_set= TRUE; + DBUG_ASSERT(engine_type && engine_type != partition_hton); + } } + DBUG_PRINT("info", ("engine_type = %u, table_engine_set = %u", + ha_legacy_type(engine_type), + table_engine_set)); + if (part_info->check_engine_mix(engine_type, table_engine_set)) + goto error; /* All engines are of the same type. Check if this engine supports @@ -4212,7 +4142,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); DBUG_RETURN(TRUE); } - if (alter_info->flags == ALTER_TABLE_REORG) + if (alter_info->flags & ALTER_TABLE_REORG) { uint new_part_no, curr_part_no; if (tab_part_info->part_type != HASH_PARTITION || @@ -4538,7 +4468,7 @@ that are reorganised. tab_part_info->is_auto_partitioned= FALSE; } } - else if (alter_info->flags == ALTER_DROP_PARTITION) + else if (alter_info->flags & ALTER_DROP_PARTITION) { /* Drop a partition from a range partition and list partitioning is @@ -4742,7 +4672,7 @@ state of p1. tab_part_info->is_auto_partitioned= FALSE; } } - else if (alter_info->flags == ALTER_REORGANIZE_PARTITION) + else if (alter_info->flags & ALTER_REORGANIZE_PARTITION) { /* Reorganise partitions takes a number of partitions that are next @@ -4923,8 +4853,8 @@ the generated partition syntax in a correct manner. } *partition_changed= TRUE; thd->work_part_info= tab_part_info; - if (alter_info->flags == ALTER_ADD_PARTITION || - alter_info->flags == ALTER_REORGANIZE_PARTITION) + if (alter_info->flags & ALTER_ADD_PARTITION || + alter_info->flags & ALTER_REORGANIZE_PARTITION) { if (tab_part_info->use_default_subpartitions && !alt_part_info->use_default_subpartitions) @@ -5051,13 +4981,21 @@ the generated partition syntax in a correct manner. DBUG_PRINT("info", ("partition changed")); *partition_changed= TRUE; } - if (create_info->db_type == partition_hton) + /* + Set up partition default_engine_type either from the create_info + or from the previus table + */ + if (create_info->used_fields & HA_CREATE_USED_ENGINE) + part_info->default_engine_type= create_info->db_type; + else { - if (!part_info->default_engine_type) + if (table->part_info) part_info->default_engine_type= table->part_info->default_engine_type; + else + part_info->default_engine_type= create_info->db_type; } - else - part_info->default_engine_type= create_info->db_type; + DBUG_ASSERT(part_info->default_engine_type && + part_info->default_engine_type != partition_hton); if (check_native_partitioned(create_info, &is_native_partitioned, part_info, thd)) { @@ -6164,7 +6102,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, goto err; } } - else if (alter_info->flags == ALTER_DROP_PARTITION) + else if (alter_info->flags & ALTER_DROP_PARTITION) { /* Now after all checks and setting state on dropped partitions we can -- cgit v1.2.1 From 7e6ab3a006faa58c8ca3b77391536c4a1a242e8c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 23 Jan 2008 11:40:06 +0100 Subject: Ndb.hpp, Ndb.cpp, ha_ndbcluster.cc: Add a check if setting an auto_increment field will change it's next value before retrieving tuple_id_range lock. This avoids hitting locks when updating auto_increment values to a lower value than the current maximum. This is useful in loading a table with auto_increment where one loads the highest numbered pk's first and then proceeds backwards to the first. This can then be achieved with the same performance as a normal insert without auto_increment. ndb_restore.result: Updated result file mysql-test/suite/ndb/r/ndb_restore.result: Updated result file sql/ha_ndbcluster.cc: Add a check if setting an auto_increment field will change it's next value before retrieving tuple_id_range lock. This avoids hitting locks when updating auto_increment values to a lower value than the current maximum. This is useful in loading a table with auto_increment where one loads the highest numbered pk's first and then proceeds backwards to the first. This can then be achieved with the same performance as a normal insert without auto_increment. storage/ndb/include/ndbapi/Ndb.hpp: Add a check if setting an auto_increment field will change it's next value before retrieving tuple_id_range lock. This avoids hitting locks when updating auto_increment values to a lower value than the current maximum. This is useful in loading a table with auto_increment where one loads the highest numbered pk's first and then proceeds backwards to the first. This can then be achieved with the same performance as a normal insert without auto_increment. storage/ndb/src/ndbapi/Ndb.cpp: Add a check if setting an auto_increment field will change it's next value before retrieving tuple_id_range lock. This avoids hitting locks when updating auto_increment values to a lower value than the current maximum. This is useful in loading a table with auto_increment where one loads the highest numbered pk's first and then proceeds backwards to the first. This can then be achieved with the same performance as a normal insert without auto_increment. --- sql/ha_ndbcluster.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b9d7e846d84..6d745140c96 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -2738,10 +2738,13 @@ ha_ndbcluster::set_auto_inc(Field *field) ("Trying to set next auto increment value to %s", llstr(next_val, buff))); #endif - Ndb_tuple_id_range_guard g(m_share); - if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) - == -1) - ERR_RETURN(ndb->getNdbError()); + if (ndb->checkUpdateAutoIncrementValue(m_share->tuple_id_range, next_val)) + { + Ndb_tuple_id_range_guard g(m_share); + if (ndb->setAutoIncrementValue(m_table, g.range, next_val, TRUE) + == -1) + ERR_RETURN(ndb->getNdbError()); + } DBUG_RETURN(0); } -- cgit v1.2.1 From 8bfec4b2626e460429812d9cd7147d6359a9ebea Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 23 Jan 2008 18:20:04 -0700 Subject: Applied innodb-5.0-ss2223 snapshot Fixes: Bug #32083: server crashes on show status when InnoDB is not initialized innodb_export_status(): Check that InnoDB has been initialized before invoking srv_export_innodb_status(). (Bug #32083) This bug does not exist in MySQL/InnoDB 5.1. sql/ha_innodb.cc: Applied innodb-5.0-ss2223 snapshot Revision r2223: branches/5.0: innodb_export_status(): Check that InnoDB has been initialized before invoking srv_export_innodb_status(). (Bug #32083) This bug does not exist in MySQL/InnoDB 5.1. --- sql/ha_innodb.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index fa68da87661..2d2007c8fdd 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -6339,7 +6339,9 @@ void innodb_export_status(void) /*======================*/ { - srv_export_innodb_status(); + if (innodb_inited) { + srv_export_innodb_status(); + } } /**************************************************************************** -- cgit v1.2.1 From f1042103e619330f5b1fdd11faed7d07c79df49f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2008 16:05:15 -0800 Subject: Bug#33358 "Plugin enum variables can't be set from command line" fix crash of LOCK_plugins mutex when loading plug-ins from command line. fix off-by-one bug when loading multiple plug-ins from the command line. initialize command line handling for ENUM and SET plugin variable types. sql/sql_plugin.cc: Bug33358 fix crash of LOCK_plugins mutex when loading plug-ins from command line. fix off-by-one bug when loading multiple plug-ins from the command line. initialize command line handling for ENUM and SET plugin variable types. mysql-test/r/plugin_load.result: New BitKeeper file ``mysql-test/r/plugin_load.result'' mysql-test/t/plugin_load-master.opt: New BitKeeper file ``mysql-test/t/plugin_load-master.opt'' mysql-test/t/plugin_load.test: New BitKeeper file ``mysql-test/t/plugin_load.test'' --- sql/sql_plugin.cc | 66 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 18 deletions(-) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 2a86844c8c6..8e204eb3d51 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1412,7 +1412,11 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, while (list) { if (p == buffer + sizeof(buffer) - 1) - break; + { + sql_print_error("plugin-load parameter too long"); + DBUG_RETURN(TRUE); + } + switch ((*(p++)= *(list++))) { case '\0': list= NULL; /* terminate the loop */ @@ -1421,10 +1425,17 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, case ':': /* can't use this as delimiter as it may be drive letter */ #endif case ';': - name.str[name.length]= '\0'; - if (str != &dl) // load all plugins in named module + str->str[str->length]= '\0'; + if (str == &name) // load all plugins in named module { + if (!name.length) + { + p--; /* reset pointer */ + continue; + } + dl= name; + pthread_mutex_lock(&LOCK_plugin); if ((plugin_dl= plugin_dl_add(&dl, REPORT_TO_LOG))) { for (plugin= plugin_dl->plugins; plugin->info; plugin++) @@ -1434,7 +1445,10 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) + { + pthread_mutex_unlock(&LOCK_plugin); goto error; + } } plugin_dl_del(&dl); // reduce ref count } @@ -1442,9 +1456,14 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, else { free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); + pthread_mutex_lock(&LOCK_plugin); if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) + { + pthread_mutex_unlock(&LOCK_plugin); goto error; + } } + pthread_mutex_unlock(&LOCK_plugin); name.length= dl.length= 0; dl.str= NULL; name.str= p= buffer; str= &name; @@ -1453,6 +1472,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, case '#': if (str == &name) { + name.str[name.length]= '\0'; str= &dl; str->str= p; continue; @@ -2999,7 +3019,8 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, DBUG_RETURN(-1); } - if (opt->flags & PLUGIN_VAR_NOCMDOPT) + if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL)) + == PLUGIN_VAR_NOCMDOPT) continue; if (!opt->name) @@ -3009,7 +3030,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, DBUG_RETURN(-1); } - if (!(v= find_bookmark(name, opt->name, opt->flags))) + if (!(opt->flags & PLUGIN_VAR_THDLOCAL)) { optnamelen= strlen(opt->name); optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2); @@ -3017,7 +3038,23 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, optnamelen= namelen + optnamelen + 1; } else - optname= (char*) memdup_root(mem_root, v->key + 1, (optnamelen= v->name_len) + 1); + { + /* this should not fail because register_var should create entry */ + if (!(v= find_bookmark(name, opt->name, opt->flags))) + { + sql_print_error("Thread local variable '%s' not allocated " + "in plugin '%s'.", opt->name, plugin_name); + DBUG_RETURN(-1); + } + + *(int*)(opt + 1)= offset= v->offset; + + if (opt->flags & PLUGIN_VAR_NOCMDOPT) + continue; + + optname= (char*) memdup_root(mem_root, v->key + 1, + (optnamelen= v->name_len) + 1); + } /* convert '_' to '-' */ for (p= optname; *p; p++) @@ -3029,20 +3066,13 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, options->app_type= opt; options->id= (options-1)->id + 1; - if (opt->flags & PLUGIN_VAR_THDLOCAL) - *(int*)(opt + 1)= offset= v->offset; - plugin_opt_set_limits(options, opt); - if ((opt->flags & PLUGIN_VAR_TYPEMASK) != PLUGIN_VAR_ENUM && - (opt->flags & PLUGIN_VAR_TYPEMASK) != PLUGIN_VAR_SET) - { - if (opt->flags & PLUGIN_VAR_THDLOCAL) - options->value= options->u_max_value= (uchar**) - (global_system_variables.dynamic_variables_ptr + offset); - else - options->value= options->u_max_value= *(uchar***) (opt + 1); - } + if (opt->flags & PLUGIN_VAR_THDLOCAL) + options->value= options->u_max_value= (uchar**) + (global_system_variables.dynamic_variables_ptr + offset); + else + options->value= options->u_max_value= *(uchar***) (opt + 1); options[1]= options[0]; options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8); -- cgit v1.2.1 From 70884e09b8d10088da4598aaf0b8ebe04e6a97b8 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2008 02:13:35 -0800 Subject: fixes to make pushbuild tests green mysql-test/t/plugin_load-master.opt: add '--loose' modifier to allow test to be skipped if plugin is not available. sql/sql_plugin.cc: Failure to load a plugin from command line option made non-fatal as plugin load failures from plugin table is already non-fatal. --- sql/sql_plugin.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 8e204eb3d51..bae4a85fd8a 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1181,9 +1181,8 @@ int plugin_init(int *argc, char **argv, int flags) /* Register all dynamic plugins */ if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING)) { - if (opt_plugin_load && - plugin_load_list(&tmp_root, argc, argv, opt_plugin_load)) - goto err; + if (opt_plugin_load) + plugin_load_list(&tmp_root, argc, argv, opt_plugin_load); if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE)) plugin_load(&tmp_root, argc, argv); } -- cgit v1.2.1 From e30a0dda8f322aa8714caf6d6de6d583e51809f1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 26 Jan 2008 21:45:35 -0800 Subject: Fixed bug #33833. Two disjuncts containing equalities of the form key=const1 and key=const2 can be merged into one if const1 is equal to const2. To check it the common collation of the constants were used rather than the collation of the field key. For example when the default collation of the constants was cases insensitive while the collation of the field was case sensitive, then two or-ed equality predicates key='b' and key='B' incorrectly were merged into one f='b'. As a result ref access was used instead of range access and wrong result sets were returned in many cases. Fixed the problem by comparing constant in the or-ed predicate with collation of the key field. mysql-test/r/range.result: Added a test case for bug #33833. mysql-test/t/range.test: Added a test case for bug #33833. sql/item.cc: Fixed bug #33833. Added the method eq_by_collation that compares two items almost as the method Item::eq, but it rather enforces a given collation for the comparison. sql/item.h: Fixed bug #33833. Added the method eq_by_collation that compares two items almost as the method Item::eq, but it rather enforces a given collation for the comparison. --- sql/item.cc | 43 +++++++++++++++++++++++++++++++++++++++++++ sql/item.h | 1 + sql/sql_select.cc | 4 +++- 3 files changed, 47 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 713e7709bcb..182632bb40f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4302,6 +4302,49 @@ String *Item::check_well_formed_result(String *str, bool send_error) return str; } +/* + Compare two items using a given collation + + SYNOPSIS + eq_by_collation() + item item to compare with + binary_cmp TRUE <-> compare as binaries + cs collation to use when comparing strings + + DESCRIPTION + This method works exactly as Item::eq if the collation cs coincides with + the collation of the compared objects. Otherwise, first the collations that + differ from cs are replaced for cs and then the items are compared by + Item::eq. After the comparison the original collations of items are + restored. + + RETURN + 1 compared items has been detected as equal + 0 otherwise +*/ + +bool Item::eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs) +{ + CHARSET_INFO *save_cs= 0; + CHARSET_INFO *save_item_cs= 0; + if (collation.collation != cs) + { + save_cs= collation.collation; + collation.collation= cs; + } + if (item->collation.collation != cs) + { + save_item_cs= item->collation.collation; + item->collation.collation= cs; + } + bool res= eq(item, binary_cmp); + if (save_cs) + collation.collation= save_cs; + if (save_item_cs) + item->collation.collation= save_item_cs; + return res; +} + /* Create a field to hold a string value from an item diff --git a/sql/item.h b/sql/item.h index 5f511557f47..f87499f23e3 100644 --- a/sql/item.h +++ b/sql/item.h @@ -873,6 +873,7 @@ public: virtual Field::geometry_type get_geometry_type() const { return Field::GEOM_GEOMETRY; }; String *check_well_formed_result(String *str, bool send_error= 0); + bool eq_by_collation(Item *item, bool binary_cmp, CHARSET_INFO *cs); }; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 87935b5548f..bdea25ab99d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2887,7 +2887,9 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, } } else if (old->eq_func && new_fields->eq_func && - old->val->eq(new_fields->val, old->field->binary())) + old->val->eq_by_collation(new_fields->val, + old->field->binary(), + old->field->charset())) { old->level= and_level; -- cgit v1.2.1 From 516f95acea961ed8e7c550ba49acdd884678058c Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2008 15:20:55 +0100 Subject: BUG#32943: Fixed buggy lock handling of ALTER TABLE for partitioning mysql-test/r/partition_range.result: Added new test cases for lock tables and ALTER TABLE for partitions, also added a test case with a trigger. mysql-test/t/partition_range.test: Added new test cases for lock tables and ALTER TABLE for partitions, also added a test case with a trigger. sql/mysql_priv.h: Added WFRM_KEEP_SHARE for use of code not to be used otherwise sql/sql_partition.cc: Removed get_name_lock and release_name_lock, use close_data_files_and_morph_locks which leaves an exclusive name lock after completing. Reopen table after completing if under lock tables Updated comments sql/sql_table.cc: Ensure that code to set partition syntax isn't used other than when specifically asked to do it. --- sql/mysql_priv.h | 1 + sql/sql_partition.cc | 114 ++++++++++++++++++++------------------------------- sql/sql_table.cc | 10 +++-- 3 files changed, 52 insertions(+), 73 deletions(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0adf90dc258..b2e97116828 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1635,6 +1635,7 @@ extern pthread_mutex_t LOCK_gdl; #define WFRM_WRITE_SHADOW 1 #define WFRM_INSTALL_SHADOW 2 #define WFRM_PACK_FRM 4 +#define WFRM_KEEP_SHARE 8 bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags); int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt); void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index eabf4526f7b..677d45dc33d 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5838,32 +5838,32 @@ static void release_log_entries(partition_info *part_info) /* - Get a lock on table name to avoid that anyone can open the table in - a critical part of the ALTER TABLE. - SYNOPSIS - get_name_lock() + Final part of partition changes to handle things when under + LOCK TABLES. + SYNPOSIS + alter_partition_lock_handling() lpt Struct carrying parameters RETURN VALUES - FALSE Success - TRUE Failure + NONE */ - -static int get_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) { - int error= 0; - DBUG_ENTER("get_name_lock"); - - bzero(&lpt->table_list, sizeof(lpt->table_list)); - lpt->table_list.db= (char*)lpt->db; - lpt->table_list.table= lpt->table; - lpt->table_list.table_name= (char*)lpt->table_name; - pthread_mutex_lock(&LOCK_open); - error= lock_table_name(lpt->thd, &lpt->table_list, FALSE); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(error); + int err; + if (lpt->thd->locked_tables) + { + pthread_mutex_lock(&LOCK_open); + lpt->thd->in_lock_tables= 1; + err= reopen_tables(lpt->thd, 1, 1); + lpt->thd->in_lock_tables= 0; + pthread_mutex_unlock(&LOCK_open); + if (err) + { + /* Issue a warning since we weren't able to regain the lock again. */ + sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE"); + } + } } - /* Unlock and close table before renaming and dropping partitions SYNOPSIS @@ -5876,35 +5876,16 @@ static int get_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt) static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt) { THD *thd= lpt->thd; - TABLE *table= lpt->table; + const char *db= lpt->db; + const char *table_name= lpt->table_name; DBUG_ENTER("alter_close_tables"); /* We need to also unlock tables and close all handlers. We set lock to zero to ensure we don't do this twice and we set db_stat to zero to ensure we don't close twice. */ - mysql_unlock_tables(thd, thd->lock); - thd->lock= 0; - table->file->close(); - table->db_stat= 0; - DBUG_RETURN(0); -} - - -/* - Release a lock name - SYNOPSIS - release_name_lock() - lpt - RETURN VALUES - 0 -*/ - -static int release_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt) -{ - DBUG_ENTER("release_name_lock"); pthread_mutex_lock(&LOCK_open); - unlock_table_name(lpt->thd, &lpt->table_list); + close_data_files_and_morph_locks(thd, db, table_name); pthread_mutex_unlock(&LOCK_open); DBUG_RETURN(0); } @@ -6202,7 +6183,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, name lock. 5) Close all tables that have already been opened but didn't stumble on the abort locked previously. This is done as part of the - get_name_lock call. + close_data_files_and_morph_locks call. 6) We are now ready to release all locks we got in this thread. 7) Write the bin log Unfortunately the writing of the binlog is not synchronised with @@ -6219,8 +6200,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 9) Prepare handlers for drop of partitions 10) Drop the partitions 11) Remove entries from ddl log - 12) Release name lock so that all other threads can access the table - again. + 12) Reopen table if under lock tables 13) Complete query We insert Error injections at all places where it could be interesting @@ -6235,23 +6215,21 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ERROR_INJECT_CRASH("crash_drop_partition_4") || - get_name_lock(lpt) || - ERROR_INJECT_CRASH("crash_drop_partition_5") || alter_close_tables(lpt) || - ERROR_INJECT_CRASH("crash_drop_partition_6") || + ERROR_INJECT_CRASH("crash_drop_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH("crash_drop_partition_7") || + ERROR_INJECT_CRASH("crash_drop_partition_6") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ((frm_install= FALSE), FALSE) || - ERROR_INJECT_CRASH("crash_drop_partition_8") || + ERROR_INJECT_CRASH("crash_drop_partition_7") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH("crash_drop_partition_9") || + ERROR_INJECT_CRASH("crash_drop_partition_8") || (write_log_completed(lpt, FALSE), FALSE) || - ERROR_INJECT_CRASH("crash_drop_partition_10") || - (release_name_lock(lpt), FALSE)) + ERROR_INJECT_CRASH("crash_drop_partition_9") || + (alter_partition_lock_handling(lpt), FALSE)) { handle_alter_part_error(lpt, not_completed, TRUE, frm_install); goto err; @@ -6283,7 +6261,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, name lock. 5) Close all tables that have already been opened but didn't stumble on the abort locked previously. This is done as part of the - get_name_lock call. + close_data_files_and_morph_locks call. 6) Close all table handlers and unlock all handlers but retain name lock 7) Write binlog 8) Now the change is completed except for the installation of the @@ -6293,7 +6271,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, added to the table. 10)Wait until all accesses using the old frm file has completed 11)Remove entries from ddl log - 12)Release name lock + 12)Reopen tables if under lock tables 13)Complete query */ if (write_log_add_change_partition(lpt) || @@ -6303,8 +6281,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || abort_and_upgrade_lock(lpt) || /* Always returns 0 */ - ERROR_INJECT_CRASH("crash_add_partition_3") || - get_name_lock(lpt) || ERROR_INJECT_CRASH("crash_add_partition_4") || alter_close_tables(lpt) || ERROR_INJECT_CRASH("crash_add_partition_5") || @@ -6320,7 +6296,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_8") || (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_add_partition_9") || - (release_name_lock(lpt), FALSE)) + (alter_partition_lock_handling(lpt), FALSE)) { handle_alter_part_error(lpt, not_completed, FALSE, frm_install); goto err; @@ -6374,15 +6350,15 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 7) Close all tables opened but not yet locked, after this call we are certain that no other thread is in the lock wait queue or has opened the table. The name lock will ensure that they are blocked - on the open call. This is achieved also by get_name_lock call. + on the open call. + This is achieved also by close_data_files_and_morph_locks call. 8) Close all partitions opened by this thread, but retain name lock. 9) Write bin log 10) Prepare handlers for rename and delete of partitions 11) Rename and drop the reorged partitions such that they are no longer used and rename those added to their real new names. 12) Install the shadow frm file - 13) Release the name lock to enable other threads to start using the - table again. + 13) Reopen the table if under lock tables 14) Complete query */ if (write_log_add_change_partition(lpt) || @@ -6396,24 +6372,22 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || /* Always returns 0 */ ERROR_INJECT_CRASH("crash_change_partition_5") || - get_name_lock(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_6") || alter_close_tables(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_7") || + ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH("crash_change_partition_8") || + ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH("crash_change_partition_9") || + ERROR_INJECT_CRASH("crash_change_partition_8") || mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH("crash_change_partition_10") || + ERROR_INJECT_CRASH("crash_change_partition_9") || mysql_rename_partitions(lpt) || ((frm_install= TRUE), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_11") || + ERROR_INJECT_CRASH("crash_change_partition_10") || (write_log_completed(lpt, FALSE), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_12") || - (release_name_lock(lpt), FALSE)) + ERROR_INJECT_CRASH("crash_change_partition_11") || + (alter_partition_lock_handling(lpt), FALSE)) { handle_alter_part_error(lpt, not_completed, FALSE, frm_install); goto err; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 505bcd1b421..a0464d43372 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1226,8 +1226,12 @@ uint build_table_shadow_filename(char *buff, size_t bufflen, flags Flags as defined below WFRM_INITIAL_WRITE If set we need to prepare table before creating the frm file - WFRM_CREATE_HANDLER_FILES If set we need to create the handler file as - part of the creation of the frm file + WFRM_INSTALL_SHADOW If set we should install the new frm + WFRM_KEEP_SHARE If set we know that the share is to be + retained and thus we should ensure share + object is correct, if not set we don't + set the new partition syntax string since + we know the share object is destroyed. WFRM_PACK_FRM If set we should pack the frm file and delete the frm file @@ -1370,7 +1374,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) goto err; } #ifdef WITH_PARTITION_STORAGE_ENGINE - if (part_info) + if (part_info && (flags & WFRM_KEEP_SHARE)) { TABLE_SHARE *share= lpt->table->s; char *tmp_part_syntax_str; -- cgit v1.2.1 From 21e654a828fb553a05fa59ce1e24a9360e377835 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2008 16:11:43 +0100 Subject: BUG#33429: No check for maxvalue before adding partition mysql-test/r/partition_range.result: Added new test cases mysql-test/t/partition_range.test: Added new test cases sql/sql_partition.cc: Added check that last partition hasn't got maxvalue defined when executing ADD PARTITION --- sql/sql_partition.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index eabf4526f7b..36f1cc771a6 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4313,7 +4313,12 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, { my_error(ER_NO_BINLOG_ERROR, MYF(0)); DBUG_RETURN(TRUE); - } + } + if (tab_part_info->defined_max_value) + { + my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } if (no_new_partitions == 0) { my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0)); -- cgit v1.2.1 From bb091abb145f89e2332a5b49cbc221793bce3452 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 28 Jan 2008 22:05:25 +0100 Subject: BUG#33182: Disallow division due to div_precision_increment problems mysql-test/r/partition.result: New test case to validate that '/' is no longer allowed, only integer division is allowed mysql-test/t/partition.test: New test case to validate that '/' is no longer allowed, only integer division is allowed sql/item_func.h: +,-,*, mod is allowed / is disallowed --- sql/item_func.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_func.h b/sql/item_func.h index e09b584de95..c73b46f21e6 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -296,7 +296,6 @@ class Item_num_op :public Item_func_numhybrid void print(String *str) { print_op(str); } void find_num_type(); String *str_op(String *str) { DBUG_ASSERT(0); return 0; } - bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; @@ -382,6 +381,7 @@ class Item_func_additive_op :public Item_num_op public: Item_func_additive_op(Item *a,Item *b) :Item_num_op(a,b) {} void result_precision(); + bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; @@ -416,6 +416,7 @@ public: double real_op(); my_decimal *decimal_op(my_decimal *); void result_precision(); + bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; @@ -456,6 +457,7 @@ public: const char *func_name() const { return "%"; } void result_precision(); void fix_length_and_dec(); + bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; -- cgit v1.2.1 From e743c791cba5bca00b81f21d7b5e5ea1c19ce9b5 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 29 Jan 2008 14:14:34 +0300 Subject: Fix Bug#27812 "an ampersand is missed in sql/sql_bitmap.h, line 68" --- sql/sql_bitmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index 9a765120895..97accefe8aa 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -65,7 +65,7 @@ public: my_bool is_clear_all() const { return bitmap_is_clear_all(&map); } my_bool is_set_all() const { return bitmap_is_set_all(&map); } my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); } - my_bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, map2.map); } + my_bool is_overlapping(const Bitmap& map2) const { return bitmap_is_overlapping(&map, &map2.map); } my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); } char *print(char *buf) const { -- cgit v1.2.1 From e524e0f146e403f2a8c8c5fe62f39366aa7cb0b9 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 29 Jan 2008 21:58:57 -0500 Subject: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency to storage engines that include mysqld_error.h extra/yassl/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. sql/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/archive/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/blackhole/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/csv/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/example/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/federated/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/heap/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/innobase/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/myisam/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. storage/myisammrg/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. vio/CMakeLists.txt: Bug#31929 Windows build fails with >=4 Parallel build threads. - Add GenError Dependency. --- sql/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 77abc4e6fa5..8a943c269fb 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -167,5 +167,5 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "lex_hash.h;message.rc;message.h;sql_yacc.h;sql_yacc.cc") ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def) -ADD_DEPENDENCIES(udf_example strings) +ADD_DEPENDENCIES(udf_example strings GenError) TARGET_LINK_LIBRARIES(udf_example strings wsock32) -- cgit v1.2.1 From 39509d64c370b5a309f1c905d847ea0f92921327 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 Jan 2008 18:27:41 +0300 Subject: A fix and a test case for Bug#34166 Server crash in SHOW OPEN TABLES and pre-locking. The crash was caused by an implicit assumption in check_table_access() that table_list parameter is always a part of lex->query_tables. When iterating over the passed list of tables, check_table_access() used to stop only when lex->query_tables_last_not_own was reached. In case of pre-locking, lex->query_tables_last_own is not NULL and points to some element of lex->query_tables. When the parameter of check_table_access() was not part of lex->query_tables, loop invariant could never be violated and a crash would happen when the current table pointer would point beyond the end of the provided list. The fix is to change the signature of check_table_access() to also accept a numeric limit of loop iterations, similarly to check_grant(), and supply this limit in all places when we want to check access of tables that are outside lex->query_tables, or just want to check access to one table. mysql-test/r/information_schema.result: Update test results (Bug#34166). mysql-test/t/information_schema.test: Add a test case for Bug#34166. sql/mysql_priv.h: Change signature of check_table_access() to accept a numeric limit of tables to check. sql/sp_head.cc: Update to the new signature of check_table_access(). sql/sql_acl.cc: Improve code clarity: if there is a numeric limit, we should not need to look at first_not_own_table. sql/sql_base.cc: Update to the new signature of check_table_access(). sql/sql_cache.cc: Update to the new signature of check_table_access(). sql/sql_parse.cc: Update to the new signature of check_table_access(). Change check_table_access() to accept an optional numeric limit of tables to check. A crash would happen when check_table_access() was passed a list of tables that is not part of lex->query_tables and lex->query_tables_last_own was not NULL. sql/sql_plugin.cc: Update to the new signature of check_table_access(). sql/sql_prepare.cc: Update to the new signature of check_table_access(). sql/sql_show.cc: Update to the new signature of check_table_access(). Ensure that check_table_access() only checks access to the first table in the table list when called from list_open_tables(). list_open_tables() supplies a table list that is created on stack, whereas check_table_access() used to assume that the supplied list is a part of thd->lex. sql/sql_trigger.cc: Update to the new signature of check_table_access(). sql/sql_view.cc: Update to the new signature of check_table_access(). --- sql/mysql_priv.h | 4 +-- sql/sp_head.cc | 4 +-- sql/sql_acl.cc | 2 +- sql/sql_base.cc | 2 +- sql/sql_cache.cc | 2 +- sql/sql_parse.cc | 74 +++++++++++++++++++++++++++++------------------------- sql/sql_plugin.cc | 2 +- sql/sql_prepare.cc | 6 ++--- sql/sql_show.cc | 6 ++--- sql/sql_trigger.cc | 2 +- sql/sql_view.cc | 6 ++--- 11 files changed, 57 insertions(+), 53 deletions(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index f61267711b0..696e0bce50c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1015,7 +1015,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv, bool no_grant, bool no_errors, bool schema_db); bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, - bool no_errors); + uint number, bool no_errors); bool check_global_access(THD *thd, ulong want_access); #else inline bool check_access(THD *thd, ulong access, const char *db, @@ -1027,7 +1027,7 @@ inline bool check_access(THD *thd, ulong access, const char *db, return false; } inline bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, - bool no_errors) + uint number, bool no_errors) { return false; } inline bool check_global_access(THD *thd, ulong want_access) { return false; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 74f5bf55828..036101021f5 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2265,7 +2265,7 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) bzero((char*) &tables,sizeof(tables)); tables.db= (char*) "mysql"; tables.table_name= tables.alias= (char*) "proc"; - *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1) || + *full_access= (!check_table_access(thd, SELECT_ACL, &tables, 1, TRUE) || (!strcmp(sp->m_definer_user.str, thd->security_ctx->priv_user) && !strcmp(sp->m_definer_host.str, @@ -2712,7 +2712,7 @@ int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables) Check whenever we have access to tables for this statement and open and lock them before executing instructions core function. */ - if (check_table_access(thd, SELECT_ACL, tables, 0) + if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE) || open_and_lock_tables(thd, tables)) result= -1; else diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d2d26da229a..da0b7bb89fc 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3862,7 +3862,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, of other queries). For simple queries first_not_own_table is 0. */ for (i= 0, table= tables; - table != first_not_own_table && i < number; + i < number && table != first_not_own_table; table= table->next_global, i++) { /* Remove SHOW_VIEW_ACL, because it will be checked during making view */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c50c89d6937..b79ce3fe70e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -799,7 +799,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *db, const char *wild) table_list.table_name= share->table_name.str; table_list.grant.privilege=0; - if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list,1)) + if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list, 1, TRUE)) continue; /* need to check if we haven't already listed it */ for (table= open_list ; table ; table=table->next) diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 47301e1d205..be2322360fb 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1378,7 +1378,7 @@ def_week_frmt: %lu", table_list.db = table->db(); table_list.alias= table_list.table_name= table->table(); #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_table_access(thd,SELECT_ACL,&table_list,1)) + if (check_table_access(thd,SELECT_ACL,&table_list, 1, TRUE)) { DBUG_PRINT("qcache", ("probably no SELECT access to %s.%s => return to normal processing", diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b60a72e4c53..3a89b745d4a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -495,7 +495,7 @@ static bool check_merge_table_access(THD *thd, char *db, tlist->db= db; /* purecov: inspected */ } error= check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, - table_list,0); + table_list, UINT_MAX, FALSE); } return error; } @@ -1994,7 +1994,7 @@ mysql_execute_command(THD *thd) res= check_table_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, - all_tables, 0); + all_tables, UINT_MAX, FALSE); } else res= check_access(thd, @@ -2019,7 +2019,7 @@ mysql_execute_command(THD *thd) break; } case SQLCOM_DO: - if (check_table_access(thd, SELECT_ACL, all_tables, 0) || + if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || open_and_lock_tables(thd, all_tables)) goto error; @@ -2116,7 +2116,7 @@ mysql_execute_command(THD *thd) case SQLCOM_BACKUP_TABLE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL, all_tables, 0) || + if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || check_global_access(thd, FILE_ACL)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; @@ -2128,7 +2128,7 @@ mysql_execute_command(THD *thd) case SQLCOM_RESTORE_TABLE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, INSERT_ACL, all_tables, 0) || + if (check_table_access(thd, INSERT_ACL, all_tables, UINT_MAX, FALSE) || check_global_access(thd, FILE_ACL)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; @@ -2677,7 +2677,8 @@ end_with_restore_list: case SQLCOM_CHECKSUM: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, 0)) + if (check_table_access(thd, SELECT_ACL | EXTRA_ACL, all_tables, + UINT_MAX, FALSE)) goto error; /* purecov: inspected */ res = mysql_checksum_table(thd, first_table, &lex->check_opt); break; @@ -2685,7 +2686,8 @@ end_with_restore_list: case SQLCOM_REPAIR: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) + if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, + UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_repair_table(thd, first_table, &lex->check_opt); @@ -2704,7 +2706,8 @@ end_with_restore_list: case SQLCOM_CHECK: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, 0)) + if (check_table_access(thd, SELECT_ACL | EXTRA_ACL , all_tables, + UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res = mysql_check_table(thd, first_table, &lex->check_opt); @@ -2715,7 +2718,8 @@ end_with_restore_list: case SQLCOM_ANALYZE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) + if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, + UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= mysql_analyze_table(thd, first_table, &lex->check_opt); @@ -2735,7 +2739,8 @@ end_with_restore_list: case SQLCOM_OPTIMIZE: { DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, 0)) + if (check_table_access(thd, SELECT_ACL | INSERT_ACL, all_tables, + UINT_MAX, FALSE)) goto error; /* purecov: inspected */ thd->enable_slow_log= opt_log_slow_admin_statements; res= (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC)) ? @@ -3064,7 +3069,7 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (!lex->drop_temporary) { - if (check_table_access(thd, DROP_ACL, all_tables, 0)) + if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE)) goto error; /* purecov: inspected */ if (end_active_trans(thd)) goto error; @@ -3168,7 +3173,7 @@ end_with_restore_list: if (lex->autocommit && end_active_trans(thd)) goto error; - if ((check_table_access(thd, SELECT_ACL, all_tables, 0) || + if ((check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || open_and_lock_tables(thd, all_tables))) goto error; if (lex->one_shot_set && not_all_support_one_shot(lex_var_list)) @@ -3210,7 +3215,8 @@ end_with_restore_list: /* we must end the trasaction first, regardless of anything */ if (end_active_trans(thd)) goto error; - if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0)) + if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, + UINT_MAX, FALSE)) goto error; thd->in_lock_tables=1; thd->options|= OPTION_TABLE_LOCK; @@ -3704,7 +3710,7 @@ end_with_restore_list: #endif case SQLCOM_HA_OPEN: DBUG_ASSERT(first_table == all_tables && first_table != 0); - if (check_table_access(thd, SELECT_ACL, all_tables, 0)) + if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE)) goto error; res= mysql_ha_open(thd, first_table, 0); break; @@ -3952,7 +3958,7 @@ create_sp_error: This will cache all SP and SF and open and lock all tables required for execution. */ - if (check_table_access(thd, SELECT_ACL, all_tables, 0) || + if (check_table_access(thd, SELECT_ACL, all_tables, UINT_MAX, FALSE) || open_and_lock_tables(thd, all_tables)) goto error; @@ -4299,7 +4305,7 @@ create_sp_error: } case SQLCOM_DROP_VIEW: { - if (check_table_access(thd, DROP_ACL, all_tables, 0) || + if (check_table_access(thd, DROP_ACL, all_tables, UINT_MAX, FALSE) || end_active_trans(thd)) goto error; /* Conditionally writes to binlog. */ @@ -4778,7 +4784,7 @@ bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) subselects_tables= subselects_tables->next_global; } if (subselects_tables && - (check_table_access(thd, SELECT_ACL, subselects_tables, 0))) + (check_table_access(thd, SELECT_ACL, subselects_tables, UINT_MAX, FALSE))) return 1; } return 0; @@ -5011,39 +5017,39 @@ static bool check_show_access(THD *thd, TABLE_LIST *table) /* Check the privilege for all used tables. - SYNOPSYS - check_table_access() - thd Thread context - want_access Privileges requested - tables List of tables to be checked - no_errors FALSE/TRUE - report/don't report error to - the client (using my_error() call). + @param thd Thread context + @param want_access Privileges requested + @param tables List of tables to be checked + @param number Check at most this number of tables. + @param no_errors FALSE/TRUE - report/don't report error to + the client (using my_error() call). - NOTES + @note Table privileges are cached in the table list for GRANT checking. This functions assumes that table list used and thd->lex->query_tables_own_last value correspond to each other (the latter should be either 0 or point to next_global member of one of elements of this table list). - RETURN VALUE - FALSE - OK - TRUE - Access denied + @retval FALSE OK + @retval TRUE Access denied */ bool check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, - bool no_errors) + uint number, bool no_errors) { TABLE_LIST *org_tables= tables; TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); + uint i= 0; Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx; /* The check that first_not_own_table is not reached is for the case when the given table list refers to the list for prelocking (contains tables of other queries). For simple queries first_not_own_table is 0. */ - for (; tables != first_not_own_table; tables= tables->next_global) + for (; i < number && tables != first_not_own_table; + tables= tables->next_global, i++) { if (tables->security_ctx) sctx= tables->security_ctx; @@ -5093,7 +5099,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, } thd->security_ctx= backup_ctx; return check_grant(thd,want_access & ~EXTRA_ACL,org_tables, - test(want_access & EXTRA_ACL), UINT_MAX, no_errors); + test(want_access & EXTRA_ACL), number, no_errors); deny: thd->security_ctx= backup_ctx; return TRUE; @@ -6855,7 +6861,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) /* sql_yacc guarantees that tables and aux_tables are not zero */ DBUG_ASSERT(aux_tables != 0); - if (check_table_access(thd, SELECT_ACL, tables, 0)) + if (check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) DBUG_RETURN(TRUE); /* @@ -6864,7 +6870,7 @@ bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) call check_table_access() safely. */ thd->lex->query_tables_own_last= 0; - if (check_table_access(thd, DELETE_ACL, aux_tables, 0)) + if (check_table_access(thd, DELETE_ACL, aux_tables, UINT_MAX, FALSE)) { thd->lex->query_tables_own_last= save_query_tables_own_last; DBUG_RETURN(TRUE); @@ -7108,7 +7114,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, } } #endif - if (tables && check_table_access(thd, SELECT_ACL, tables,0)) + if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) goto err; } else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE) diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 2a86844c8c6..5cd056807a6 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1619,7 +1619,7 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl bzero(&tables, sizeof(tables)); tables.db= (char *)"mysql"; tables.table_name= tables.alias= (char *)"plugin"; - if (check_table_access(thd, INSERT_ACL, &tables, 0)) + if (check_table_access(thd, INSERT_ACL, &tables, 1, FALSE)) DBUG_RETURN(TRUE); /* need to open before acquiring LOCK_plugin or it will deadlock */ diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 52e6fcc5d58..b76ed0852f5 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1272,7 +1272,7 @@ static int mysql_test_select(Prepared_statement *stmt, ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL; if (tables) { - if (check_table_access(thd, privilege, tables,0)) + if (check_table_access(thd, privilege, tables, UINT_MAX, FALSE)) goto error; } else if (check_access(thd, privilege, any_db,0,0,0,0)) @@ -1342,7 +1342,7 @@ static bool mysql_test_do_fields(Prepared_statement *stmt, THD *thd= stmt->thd; DBUG_ENTER("mysql_test_do_fields"); - if (tables && check_table_access(thd, SELECT_ACL, tables, 0)) + if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) DBUG_RETURN(TRUE); if (open_normal_and_derived_tables(thd, tables, 0)) @@ -1374,7 +1374,7 @@ static bool mysql_test_set_fields(Prepared_statement *stmt, THD *thd= stmt->thd; set_var_base *var; - if (tables && check_table_access(thd, SELECT_ACL, tables, 0) || + if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE) || open_normal_and_derived_tables(thd, tables, 0)) goto error; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 20cf12b95c5..644aa3fd4cb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4059,7 +4059,7 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) proc_tables.table_name= proc_tables.alias= (char*) "proc"; proc_tables.table_name_length= 4; proc_tables.lock_type= TL_READ; - full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1); + full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1, TRUE); if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup))) { DBUG_RETURN(1); @@ -4447,10 +4447,8 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, Table_triggers_list *triggers= tables->table->triggers; int event, timing; -#ifndef NO_EMBEDDED_ACCESS_CHECKS - if (check_table_access(thd, TRIGGER_ACL, tables, 1)) + if (check_table_access(thd, TRIGGER_ACL, tables, 1, TRUE)) goto ret; -#endif for (event= 0; event < (int)TRG_EVENT_MAX; event++) { diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index b421f57b7ab..7925eb3e95a 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -418,7 +418,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last; thd->lex->query_tables_own_last= 0; - err_status= check_table_access(thd, TRIGGER_ACL, tables, 0); + err_status= check_table_access(thd, TRIGGER_ACL, tables, 1, FALSE); thd->lex->query_tables_own_last= save_query_tables_own_last; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index f7223cafb5e..ec3f8b5e84c 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1123,8 +1123,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, if (!table->prelocking_placeholder && (old_lex->sql_command == SQLCOM_SELECT && old_lex->describe)) { - if (check_table_access(thd, SELECT_ACL, view_tables, 1) && - check_table_access(thd, SHOW_VIEW_ACL, table, 1)) + if (check_table_access(thd, SELECT_ACL, view_tables, UINT_MAX, TRUE) && + check_table_access(thd, SHOW_VIEW_ACL, table, UINT_MAX, TRUE)) { my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0)); goto err; @@ -1134,7 +1134,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, (old_lex->sql_command == SQLCOM_SHOW_CREATE) && !table->belong_to_view) { - if (check_table_access(thd, SHOW_VIEW_ACL, table, 0)) + if (check_table_access(thd, SHOW_VIEW_ACL, table, UINT_MAX, FALSE)) goto err; } -- cgit v1.2.1 From 96f33937779296da12b9818dd4d4c21371558c0d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 Jan 2008 23:04:55 +0300 Subject: Fix a build failure (embedded server). --- sql/sql_show.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 644aa3fd4cb..bc5628f12c0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4486,9 +4486,7 @@ static int get_schema_triggers_record(THD *thd, TABLE_LIST *tables, } } } -#ifndef NO_EMBEDDED_ACCESS_CHECKS ret: -#endif DBUG_RETURN(0); } -- cgit v1.2.1 From a3f80f54b46aaf64abd5e28c47e423880afc934f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 30 Jan 2008 19:00:20 -0700 Subject: Bug #32149 Long semaphore wait for adaptive hash latch Fix by calling ha_release_temporary_latches() before ::filesort(). sql/filesort.cc: Call ha_release_temporary_latches() before performing a (possibly long) ::filesort(). --- sql/filesort.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sql') diff --git a/sql/filesort.cc b/sql/filesort.cc index 43b079e83d5..132e91363f3 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -112,6 +112,13 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, FILESORT_INFO table_sort; TABLE_LIST *tab= table->pos_in_table_list; Item_subselect *subselect= tab ? tab->containing_subselect() : 0; + + /* + Release InnoDB's adaptive hash index latch (if holding) before + running a sort. + */ + ha_release_temporary_latches(thd); + /* Don't use table->sort in filesort as it is also used by QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end -- cgit v1.2.1 From 53086d89accbd7219a861f8297eaac2575e4acae Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 Jan 2008 15:56:02 +0400 Subject: Bug #25426 Prefix index on DECIMAL column causes warning. Error message modified to be consistent with the manual. mysql-test/r/alter_table.result: Bug #25426 Prefix index on DECIMAL column causes warning. test result fixed sql/share/errmsg.txt: Bug #25426 Prefix index on DECIMAL column causes warning. error messages modified --- sql/share/errmsg.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 02e20ad7c5c..571335d877c 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -2146,14 +2146,14 @@ ER_WRONG_SUB_KEY cze "Chybn-Bá podèást klíèe -- není to øetìzec nebo je del¹í ne¾ délka èásti klíèe" dan "Forkert indeksdel. Den anvendte nøgledel er ikke en streng eller længden er større end nøglelængden" nla "Foutief sub-gedeelte van de zoeksleutel. De gebruikte zoeksleutel is geen onderdeel van een string of of de gebruikte lengte is langer dan de zoeksleutel" - eng "Incorrect sub part key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique sub keys" + eng "Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys" est "Vigane võtme osa. Kasutatud võtmeosa ei ole string tüüpi, määratud pikkus on pikem kui võtmeosa või tabelihandler ei toeta seda tüüpi võtmeid" fre "Mauvaise sous-clef. Ce n'est pas un 'string' ou la longueur dépasse celle définie dans la clef" ger "Falscher Unterteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String, die verwendete Länge ist länger als der Teilschlüssel oder die Speicher-Engine unterstützt keine Unterteilschlüssel" greek "ÅóöáëìÝíï sub part key. Ôï ÷ñçóéìïðïéïýìåíï key part äåí åßíáé string Þ ôï ìÞêïò ôïõ åßíáé ìåãáëýôåñï" hun "Rossz alkulcs. A hasznalt kulcsresz nem karaktersorozat vagy hosszabb, mint a kulcsresz" ita "Sotto-parte della chiave errata. La parte di chiave utilizzata non e` una stringa o la lunghezza e` maggiore della parte di chiave." - jpn "Incorrect sub part key; the used key part isn't a string or the used length is longer than the key part" + jpn "Incorrect prefix key; the used key part isn't a string or the used length is longer than the key part" kor "ºÎÁ¤È®ÇÑ ¼­¹ö ÆÄÆ® Ű. »ç¿ëµÈ Ű ÆÄÆ®°¡ ½ºÆ®¸µÀÌ ¾Æ´Ï°Å³ª Ű ÆÄÆ®ÀÇ ±æÀ̰¡ ³Ê¹« ±é´Ï´Ù." nor "Feil delnøkkel. Den brukte delnøkkelen er ikke en streng eller den oppgitte lengde er lengre enn nøkkel lengden" norwegian-ny "Feil delnykkel. Den brukte delnykkelen er ikkje ein streng eller den oppgitte lengda er lengre enn nykkellengden" @@ -2162,7 +2162,7 @@ ER_WRONG_SUB_KEY rum "Componentul cheii este incorrect. Componentul folosit al cheii nu este un sir sau lungimea folosita este mai lunga decit lungimea cheii" rus "îÅËÏÒÒÅËÔÎÁÑ ÞÁÓÔØ ËÌÀÞÁ. éÓÐÏÌØÚÕÅÍÁÑ ÞÁÓÔØ ËÌÀÞÁ ÎÅ Ñ×ÌÑÅÔÓÑ ÓÔÒÏËÏÊ, ÕËÁÚÁÎÎÁÑ ÄÌÉÎÁ ÂÏÌØÛÅ, ÞÅÍ ÄÌÉÎÁ ÞÁÓÔÉ ËÌÀÞÁ, ÉÌÉ ÏÂÒÁÂÏÔÞÉË ÔÁÂÌÉÃÙ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÕÎÉËÁÌØÎÙÅ ÞÁÓÔÉ ËÌÀÞÁ" serbian "Pogrešan pod-kljuè dela kljuèa. Upotrebljeni deo kljuèa nije string, upotrebljena dužina je veæa od dela kljuèa ili handler tabela ne podržava jedinstvene pod-kljuèeve" - slo "Incorrect sub part key; the used key part isn't a string or the used length is longer than the key part" + slo "Incorrect prefix key; the used key part isn't a string or the used length is longer than the key part" spa "Parte de la clave es erronea. Una parte de la clave no es una cadena o la longitud usada es tan grande como la parte de la clave" swe "Felaktig delnyckel. Nyckeldelen är inte en sträng eller den angivna längden är längre än kolumnlängden" ukr "îÅצÒÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ. ÷ÉËÏÒÉÓÔÁÎÁ ÞÁÓÔÉÎÁ ËÌÀÞÁ ÎÅ ¤ ÓÔÒÏËÏÀ, ÚÁÄÏ×ÇÁ ÁÂÏ ×ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ ÕΦËÁÌØÎÉÈ ÞÁÓÔÉÎ ËÌÀÞÅÊ" -- cgit v1.2.1 From 5177c97ec0e11b65227868d6cf98de3970262340 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 Jan 2008 18:51:20 +0400 Subject: BUG#22989 - START SLAVE causes Error on COM_REGISTER_SLAVE: 1105 'Wrong parameters to functi START SLAVE reports vague error when it fails to register on master: "Wrong parameters to function register_slave". If master failed to register slave because of too long 'report-host'/'report-user'/'report-password', return better error messages: "Failed to register slave: too long 'report-host'" "Failed to register slave: too long 'report-user'" "Failed to register slave; too long 'report-password'" No test case for this fix. sql/repl_failsafe.cc: Report descriptive error when master fails to register slave. --- sql/repl_failsafe.cc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 896315ec82f..f1826678c9f 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -109,11 +109,14 @@ void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status) } -#define get_object(p, obj) \ +#define get_object(p, obj, msg) \ {\ uint len = (uint)*p++; \ if (p + len > p_end || len >= sizeof(obj)) \ + {\ + errmsg= msg;\ goto err; \ + }\ strmake(obj,(char*) p,len); \ p+= len; \ }\ @@ -158,6 +161,7 @@ int register_slave(THD* thd, uchar* packet, uint packet_length) int res; SLAVE_INFO *si; uchar *p= packet, *p_end= packet + packet_length; + const char *errmsg= "Wrong parameters to function register_slave"; if (check_access(thd, REPL_SLAVE_ACL, any_db,0,0,0,0)) return 1; @@ -166,9 +170,9 @@ int register_slave(THD* thd, uchar* packet, uint packet_length) thd->server_id= si->server_id= uint4korr(p); p+= 4; - get_object(p,si->host); - get_object(p,si->user); - get_object(p,si->password); + get_object(p,si->host, "Failed to register slave: too long 'report-host'"); + get_object(p,si->user, "Failed to register slave: too long 'report-user'"); + get_object(p,si->password, "Failed to register slave; too long 'report-password'"); if (p+10 > p_end) goto err; si->port= uint2korr(p); @@ -187,8 +191,7 @@ int register_slave(THD* thd, uchar* packet, uint packet_length) err: my_free((gptr) si, MYF(MY_WME)); - my_message(ER_UNKNOWN_ERROR, "Wrong parameters to function register_slave", - MYF(0)); + my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); err2: return 1; } -- cgit v1.2.1 From 754c3f51ec6e0557b8c4ca2f141ee74075e11b48 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 31 Jan 2008 23:46:26 +0300 Subject: Bug#30787: Stored function ignores user defined alias. Simple subselects are pulled into upper selects. This operation substitutes the pulled subselect for the first item from the select list of the subselect. If an alias is defined for a subselect it is inherited by the replacement item. As this is done after fix_fields phase this alias isn't showed if the replacement item is a stored function. This happens because the Item_func_sp::make_field function makes send field from its result_field and ignores the defined alias. Now when an alias is defined the Item_func_sp::make_field function sets it for the returned field. mysql-test/t/sp.test: Added a test case for the bug#30787: Stored function ignores user defined alias. mysql-test/r/sp.result: Added a test case for the bug#30787: Stored function ignores user defined alias. sql/item_func.cc: Bug#30787: Stored function ignores user defined alias. Now when an alias is defined the Item_func_sp::make_field function sets it for the returned field. --- sql/item_func.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 639e069d24e..dbde4237511 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5515,6 +5515,8 @@ Item_func_sp::make_field(Send_field *tmp_field) DBUG_ENTER("Item_func_sp::make_field"); DBUG_ASSERT(sp_result_field); sp_result_field->make_field(tmp_field); + if (name) + tmp_field->col_name= name; DBUG_VOID_RETURN; } -- cgit v1.2.1 From 4d794c233419658cd79b416a3ce45d0b1efea688 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 1 Feb 2008 13:00:40 +0500 Subject: Fix for bug #25162: Backing up DB from 5.1 adds 'USING BTREE' to KEYs on table creates The problem was in incompatible syntax for key definition in CREATE TABLE. 5.0 supports only the following syntax for key definition (see "CREATE TABLE syntax" in the manual): {INDEX|KEY} [index_name] [index_type] (index_col_name,...) While 5.1 parser supports the above syntax, the "preferred" syntax was changed to: {INDEX|KEY} [index_name] (index_col_name,...) [index_type] The above syntax is used in 5.1 for the SHOW CREATE TABLE output, which led to dumps generated by 5.1 being incompatible with 5.0. Fixed by changing the parser in 5.0 to support both 5.0 and 5.1 syntax for key definition. mysql-test/r/create.result: Added a test case for bug #25162. mysql-test/t/create.test: Added a test case for bug #25162. sql/sql_yacc.yy: Changed the parser to support both 5.0 and 5.1 syntax for index type specification in CREATE TABLE. --- sql/sql_yacc.yy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c4aca1df7ec..af57fbdb108 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2982,15 +2982,15 @@ column_def: ; key_def: - key_type opt_ident key_alg '(' key_list ')' + key_type opt_ident key_alg '(' key_list ')' key_alg { LEX *lex=Lex; - Key *key= new Key($1, $2, $3, 0, lex->col_list); + Key *key= new Key($1, $2, $7 ? $7 : $3, 0, lex->col_list); lex->alter_info.key_list.push_back(key); lex->col_list.empty(); /* Alloced by sql_alloc */ } - | opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')' + | opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')' key_alg { LEX *lex=Lex; const char *key_name= $3 ? $3:$1; -- cgit v1.2.1 From f7d8fb1cdde7a9655b984827547a7f4f85560834 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 1 Feb 2008 14:10:46 +0100 Subject: Bug#33201 Crash occurs when granting update privilege on one column of a view When issuing a column level grant on a table which require pre-locking the server crashed. The reason behind the crash was that data structures used by the lock api wasn't properly reinitialized in the case of a column level grant. mysql-test/r/grant.result: * Added test case mysql-test/t/grant.test: * Added test case sql/sql_acl.cc: * The lock api is dending on the thd->lex object and this variable needs to be re-initialized when opened with a new set of tables than specified in the original statement. --- sql/sql_acl.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 134541368e9..703918329c2 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2878,6 +2878,12 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, } #endif + /* + The lock api is depending on the thd->lex variable which needs to be + re-initialized. + */ + Query_tables_list backup; + thd->lex->reset_n_backup_query_tables_list(&backup); if (simple_open_n_lock_tables(thd,tables)) { // Should never happen close_thread_tables(thd); /* purecov: deadcode */ @@ -3016,6 +3022,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, send_ok(thd); /* Tables are automatically closed */ + thd->lex->restore_backup_query_tables_list(&backup); DBUG_RETURN(result); } -- cgit v1.2.1 From 77b84b12e69e05a891f57cac157506c37dd60d0a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Feb 2008 16:35:41 +0200 Subject: Bug #32790 crash in trigger.test with InnoDB for a table the reason for the failure were incorrect asserts. Removing asserts altogether as there is no the implication does not hold (as explained in the comments for the file). sql/sql_delete.cc: removing two asserts because they can not hold basing on the definition of `normal_tables'. The one does not specify in a non-transactional table, which must be in the list of tables to be deleted, is modified indeed. So, it's possible to have normal_tables == true and deleted == true both but that would be yet a transactional table got modified (and then thd->transaction.stmt.modified_non_trans_table remains false default). --- sql/sql_delete.cc | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a28a39a769d..52e3ab73de0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -730,8 +730,6 @@ void multi_delete::send_error(uint errcode,const char *err) } thd->transaction.all.modified_non_trans_table= true; } - DBUG_ASSERT(!normal_tables || !deleted || - thd->transaction.stmt.modified_non_trans_table); DBUG_VOID_RETURN; } @@ -839,8 +837,6 @@ bool multi_delete::send_eof() { query_cache_invalidate3(thd, delete_tables, 1); } - DBUG_ASSERT(!normal_tables || !deleted || - thd->transaction.stmt.modified_non_trans_table); if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table) { if (mysql_bin_log.is_open()) -- cgit v1.2.1 From 6210278628b834bfd599d461b0f5b515d4f085ee Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Feb 2008 16:37:41 +0200 Subject: Bug#33329 extraneous ROLLBACK in binlog on connection does not use trans tables There had been two issues. Rollback statement was recorded in binlog even though a multi-update had not modified any non-transactional table. The reason for this artifact was a false initial value of multi_update::transactional_tables. Yet another artifact that explained on the bug page is that `ha_autocommit_or_rollback' works differently depending on whether a transaction engine has been compiled in. Fixed: with setting multi_update::transactional_tables to zero at initialization time. Multi-update on non-trans table won't cause ROLLBACK in binlog with either compilation option. The 2nd mentioned artifact comprises a self-standing issue (to be reported separately). mysql-test/r/multi_update.result: results changed - there is no ROLLBACK in binlog anymore as it should be sql/sql_update.cc: A wrong assumption on that there were modified transactional table, which is nonsense at the very beginning of the query execution. --- sql/sql_update.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 84349a40977..e5017058659 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -979,7 +979,7 @@ multi_update::multi_update(TABLE_LIST *table_list, tmp_tables(0), updated(0), found(0), fields(field_list), values(value_list), table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg), do_update(1), trans_safe(1), - transactional_tables(1), ignore(ignore_arg), error_handled(0) + transactional_tables(0), ignore(ignore_arg), error_handled(0) {} -- cgit v1.2.1 From 0fe17ab3c0a941124cce1ccc2bcd16c3d93425aa Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Feb 2008 15:40:04 +0100 Subject: Bug #34275 mysqld leak if doing multiple statements within same transaction (or wo/ trans) - in autocommit do not allocate statistics share, but instead use one directly on the handler --- sql/ha_ndbcluster.cc | 83 ++++++++++++++++++++++++++++------------------------ sql/ha_ndbcluster.h | 8 +---- 2 files changed, 45 insertions(+), 46 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index b4bf8e15902..b8e6ff32d37 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -313,6 +313,10 @@ int execute_no_commit_ie(ha_ndbcluster *h, NdbTransaction *trans, /* Place holder for ha_ndbcluster thread specific data */ +typedef struct st_thd_ndb_share { + const void *key; + struct Ndb_local_table_statistics stat; +} THD_NDB_SHARE; static uchar *thd_ndb_share_get_key(THD_NDB_SHARE *thd_ndb_share, size_t *length, my_bool not_used __attribute__((unused))) @@ -369,41 +373,6 @@ Thd_ndb::init_open_tables() my_hash_reset(&open_tables); } -THD_NDB_SHARE * -Thd_ndb::get_open_table(THD *thd, const void *key) -{ - DBUG_ENTER("Thd_ndb::get_open_table"); - HASH_SEARCH_STATE state; - THD_NDB_SHARE *thd_ndb_share= - (THD_NDB_SHARE*)hash_first(&open_tables, (uchar *)&key, sizeof(key), &state); - while (thd_ndb_share && thd_ndb_share->key != key) - thd_ndb_share= (THD_NDB_SHARE*)hash_next(&open_tables, (uchar *)&key, sizeof(key), &state); - if (thd_ndb_share == 0) - { - thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root, - sizeof(THD_NDB_SHARE)); - if (!thd_ndb_share) - { - mem_alloc_error(sizeof(THD_NDB_SHARE)); - DBUG_RETURN(NULL); - } - thd_ndb_share->key= key; - thd_ndb_share->stat.last_count= count; - thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records= ~(ha_rows)0; - my_hash_insert(&open_tables, (uchar *)thd_ndb_share); - } - else if (thd_ndb_share->stat.last_count != count) - { - thd_ndb_share->stat.last_count= count; - thd_ndb_share->stat.no_uncommitted_rows_count= 0; - thd_ndb_share->stat.records= ~(ha_rows)0; - } - DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx", - (long) thd_ndb_share, (long) key)); - DBUG_RETURN(thd_ndb_share); -} - inline Ndb *ha_ndbcluster::get_ndb() { @@ -4554,12 +4523,48 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb) thd_ndb->trans_options|= TNTO_INJECTED_APPLY_STATUS; } #endif - // TODO remove double pointers... - if (!(m_thd_ndb_share= thd_ndb->get_open_table(thd, m_table))) + + if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) { - DBUG_RETURN(1); + const void *key= m_table; + HASH_SEARCH_STATE state; + THD_NDB_SHARE *thd_ndb_share= + (THD_NDB_SHARE*)hash_first(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state); + while (thd_ndb_share && thd_ndb_share->key != key) + thd_ndb_share= (THD_NDB_SHARE*)hash_next(&thd_ndb->open_tables, (uchar *)&key, sizeof(key), &state); + if (thd_ndb_share == 0) + { + thd_ndb_share= (THD_NDB_SHARE *) alloc_root(&thd->transaction.mem_root, + sizeof(THD_NDB_SHARE)); + if (!thd_ndb_share) + { + mem_alloc_error(sizeof(THD_NDB_SHARE)); + DBUG_RETURN(1); + } + thd_ndb_share->key= key; + thd_ndb_share->stat.last_count= thd_ndb->count; + thd_ndb_share->stat.no_uncommitted_rows_count= 0; + thd_ndb_share->stat.records= ~(ha_rows)0; + my_hash_insert(&thd_ndb->open_tables, (uchar *)thd_ndb_share); + } + else if (thd_ndb_share->stat.last_count != thd_ndb->count) + { + thd_ndb_share->stat.last_count= thd_ndb->count; + thd_ndb_share->stat.no_uncommitted_rows_count= 0; + thd_ndb_share->stat.records= ~(ha_rows)0; + } + DBUG_PRINT("exit", ("thd_ndb_share: 0x%lx key: 0x%lx", + (long) thd_ndb_share, (long) key)); + m_table_info= &thd_ndb_share->stat; + } + else + { + struct Ndb_local_table_statistics &stat= m_table_info_instance; + stat.last_count= thd_ndb->count; + stat.no_uncommitted_rows_count= 0; + stat.records= ~(ha_rows)0; + m_table_info= &stat; } - m_table_info= &m_thd_ndb_share->stat; DBUG_RETURN(0); } diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index cc79402fe92..a17323d3fd6 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -195,11 +195,6 @@ struct Ndb_local_table_statistics { ha_rows records; }; -typedef struct st_thd_ndb_share { - const void *key; - struct Ndb_local_table_statistics stat; -} THD_NDB_SHARE; - class Thd_ndb { public: @@ -207,7 +202,6 @@ class Thd_ndb ~Thd_ndb(); void init_open_tables(); - THD_NDB_SHARE *get_open_table(THD *thd, const void *key); Ndb *ndb; ulong count; @@ -514,6 +508,7 @@ private: NdbScanOperation *m_active_cursor; const NdbDictionary::Table *m_table; struct Ndb_local_table_statistics *m_table_info; + struct Ndb_local_table_statistics m_table_info_instance; char m_dbname[FN_HEADLEN]; //char m_schemaname[FN_HEADLEN]; char m_tabname[FN_HEADLEN]; @@ -522,7 +517,6 @@ private: bool m_lock_tuple; NDB_SHARE *m_share; NDB_INDEX_DATA m_index[MAX_KEY]; - THD_NDB_SHARE *m_thd_ndb_share; // NdbRecAttr has no reference to blob NdbValue m_value[NDB_MAX_ATTRIBUTES_IN_TABLE]; uchar m_ref[NDB_HIDDEN_PRIMARY_KEY_LENGTH]; -- cgit v1.2.1 From ff8651c4ecb33305c84bf545b000241d34a9ed2a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 4 Feb 2008 16:39:55 -0200 Subject: Bug#21801 SQL exception handlers and warnings The problem is that deprecated syntax warnings were not being suppressed when the stored routine is being parsed for the first execution. It's doesn't make sense to print out deprecated syntax warnings when the routine is being executed because this kind of warning only matters when the routine is being created. The solution is to suppress deprecated syntax warnings when parsing the stored routine for loading into the cache (might mean that the routine is being executed for the first time). mysql-test/r/sp-error.result: Add test case result for Bug#21801 mysql-test/t/sp-error.test: Add test case for Bug#21801 sql/sp.cc: Implement a internal error handler to catch deprecated syntax warnings when loading a stored procedure into the cache. --- sql/sp.cc | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sp.cc b/sql/sp.cc index 99ffc18deea..5514cf0ed5f 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -507,6 +507,31 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) } +/** + Silence DEPRECATED SYNTAX warnings when loading a stored procedure + into the cache. +*/ +struct Silence_deprecated_warning : public Internal_error_handler +{ +public: + virtual bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); +}; + +bool +Silence_deprecated_warning::handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) +{ + if (sql_errno == ER_WARN_DEPRECATED_SYNTAX && + level == MYSQL_ERROR::WARN_LEVEL_WARN) + return TRUE; + + return FALSE; +} + + static int db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, ulong sql_mode, const char *params, const char *returns, @@ -523,7 +548,8 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, ulong old_sql_mode= thd->variables.sql_mode; ha_rows old_select_limit= thd->variables.select_limit; sp_rcontext *old_spcont= thd->spcont; - + Silence_deprecated_warning warning_handler; + char definer_user_name_holder[USERNAME_LENGTH + 1]; LEX_STRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH }; @@ -583,7 +609,9 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, lex_start(thd); + thd->push_internal_handler(&warning_handler); ret= parse_sql(thd, &lip, creation_ctx) || newlex.sphead == NULL; + thd->pop_internal_handler(); /* Force switching back to the saved current database (if changed), -- cgit v1.2.1 From 86a454ed36f227773c10389561112244592d7467 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 5 Feb 2008 12:56:49 +0100 Subject: Bug#21567: mysqld doesn't react to Ctrl-C when run under GDB even with the --gdb option Don't block SIGINT (Control-C) when --gdb is passed to mysqld. Was broken at least on OS X. (kudos to Mattias Jonsson) sql/mysqld.cc: Don't block SIGINT when TEST_SIGINT (--gdb) is used, even if thr_kill_signal is some other signal (SIGUSR2) and pthread_sigmask() in signal_hand() isn't good enough. --- sql/mysqld.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08c2b60fa79..2f65597e2b7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2211,10 +2211,6 @@ static void init_signals(void) struct sigaction sa; DBUG_ENTER("init_signals"); - if (test_flags & TEST_SIGINT) - { - my_sigset(thr_kill_signal, end_thread_signal); - } my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) @@ -2251,7 +2247,6 @@ static void init_signals(void) (void) sigemptyset(&set); my_sigset(SIGPIPE,SIG_IGN); sigaddset(&set,SIGPIPE); - sigaddset(&set,SIGINT); #ifndef IGNORE_SIGHUP_SIGQUIT sigaddset(&set,SIGQUIT); sigaddset(&set,SIGHUP); @@ -2273,9 +2268,12 @@ static void init_signals(void) sigaddset(&set,THR_SERVER_ALARM); if (test_flags & TEST_SIGINT) { + my_sigset(thr_kill_signal, end_thread_signal); // May be SIGINT sigdelset(&set, thr_kill_signal); } + else + sigaddset(&set,SIGINT); sigprocmask(SIG_SETMASK,&set,NULL); pthread_sigmask(SIG_SETMASK,&set,NULL); DBUG_VOID_RETURN; -- cgit v1.2.1 From 66fa5cb968feb2ee2518bbaf7f163d1097545098 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Feb 2008 11:44:07 +0100 Subject: Bug#19911 ndb does not work on sol10 x86 sql/ha_ndbcluster_binlog.cc: Change 'assert' to 'DBUG_ASSERT' to avoid that the assert is triggered in the optimized version on solaris 10 for x86 --- sql/ha_ndbcluster_binlog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 07b0d907229..d16cf46b860 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -1002,7 +1002,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share, uint blob_len= field_blob->get_length((*field)->ptr); uchar *blob_ptr= 0; field_blob->get_ptr(&blob_ptr); - assert(blob_len == 0 || blob_ptr != 0); + DBUG_ASSERT(blob_len == 0 || blob_ptr != 0); s->query_length= blob_len; s->query= sql_strmake((char*) blob_ptr, blob_len); } -- cgit v1.2.1 From 3616b9136f2e44a73f49412ffafbe18d4c4688d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 6 Feb 2008 11:20:15 -0200 Subject: Bug#32710: SHOW INNODB STATUS requires SUPER Changed "SHOW ENGINE ... STATUS" and "SHOW ENGINE ... MUTEX" to require the PROCESS privilege, instead of SUPER. Fixed by Damien Katz mysql-test/r/show_check.result: Add test case result for Bug#32710 mysql-test/t/show_check.test: Add test case for Bug#32710 sql/sql_parse.cc: Require PROCESS privilege instead of SUPER. --- sql/sql_parse.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 221c156fe6b..226cd8f9432 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2271,14 +2271,14 @@ mysql_execute_command(THD *thd) #endif /* HAVE_REPLICATION */ case SQLCOM_SHOW_ENGINE_STATUS: { - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PROCESS_ACL)) goto error; res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS); break; } case SQLCOM_SHOW_ENGINE_MUTEX: { - if (check_global_access(thd, SUPER_ACL)) + if (check_global_access(thd, PROCESS_ACL)) goto error; res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX); break; -- cgit v1.2.1 From 3891d43617e82dcb1a1ecdf876fa2094d672cb79 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 02:33:21 +0400 Subject: Fixed bug#30059. Server handles truncation for assignment of too-long values into CHAR/VARCHAR/TEXT columns in a different ways when the truncated characters are spaces: 1. CHAR(N) columns silently ignore end-space truncation; 2. TEXT columns post a truncation warning/error in the non-strict/strict mode. 3. VARCHAR columns always post a truncation note in any mode. Space truncation processing has been synchronised over CHAR/VARCHAR/TEXT columns: current behavior of VARCHAR columns has been propagated as standard. Binary-encoded string/BLOB columns are not affected. mysql-test/r/heap.result: Updated test case for bug#30059. mysql-test/r/innodb.result: Updated test case for bug#30059. mysql-test/r/myisam.result: Updated test case for bug#30059. mysql-test/r/strict.result: Updated test case for bug#30059. mysql-test/r/type_binary.result: Updated test case for bug#30059. mysql-test/r/warnings.result: Added test case for bug#30059. mysql-test/t/warnings.test: Added test case for bug#30059. sql/field.cc: Fixed bug#30059. The report_data_too_long function was replaced with the Field_longstr::report_if_important_data method. The Field_string::store and the Field_blob::store methods was synchronized with the Field_varstring::store method. Changes: 1. to CHAR(N): posting of space truncation note has been added in both (strict and non-strict) modes; 2. to BLOBs: a check for space truncation has been added, a warning in the non-strict mode and an error message in the strict mode have been replaced with a truncation note. Similar parts of Field_string::store, Field_blob::store and Field_varstring::store have been moved to the Field_longstr::report_if_important_data method. sql/field.h: Fixed bug#30059. The Field_longstr::report_if_important_data method has been declared. --- sql/field.cc | 74 +++++++++++++++++++++++++----------------------------------- sql/field.h | 2 ++ 2 files changed, 33 insertions(+), 43 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index f1e2b6a4f27..3753318b8fa 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5861,26 +5861,41 @@ check_string_copy_error(Field_str *field, } - /* - Send a truncation warning or a truncation error - after storing a too long character string info a field. + Check if we lost any important data and send a truncation error/warning SYNOPSIS - report_data_too_long() - field - Field + Field_longstr::report_if_important_data() + ptr - Truncated rest of string + end - End of truncated string - RETURN - N/A + RETURN VALUES + 0 - None was truncated (or we don't count cut fields) + 2 - Some bytes was truncated + + NOTE + Check if we lost any important data (anything in a binary string, + or any non-space in others). If only trailing spaces was lost, + send a truncation note, otherwise send a truncation error. */ -inline void -report_data_too_long(Field_str *field) +int +Field_longstr::report_if_important_data(const char *ptr, const char *end) { - if (field->table->in_use->abort_on_warning) - field->set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); - else - field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + if ((ptr < end) && table->in_use->count_cuted_fields) + { + if (test_if_important_data(field_charset, ptr, end)) + { + if (table->in_use->abort_on_warning) + set_warning(MYSQL_ERROR::WARN_LEVEL_ERROR, ER_DATA_TOO_LONG, 1); + else + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + } + else /* If we lost only spaces then produce a NOTE, not a WARNING */ + set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); + return 2; + } + return 0; } @@ -5914,19 +5929,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length)) return 2; - /* - Check if we lost any important data (anything in a binary string, - or any non-space in others). - */ - if ((from_end_pos < from + length) && table->in_use->count_cuted_fields) - { - if (test_if_important_data(field_charset, from_end_pos, from + length)) - { - report_data_too_long(this); - return 2; - } - } - return 0; + return report_if_important_data(from_end_pos, from + length); } @@ -6385,16 +6388,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length)) return 2; - // Check if we lost something other than just trailing spaces - if ((from_end_pos < from + length) && table->in_use->count_cuted_fields) - { - if (test_if_important_data(field_charset, from_end_pos, from + length)) - report_data_too_long(this); - else /* If we lost only spaces then produce a NOTE, not a WARNING */ - set_warning(MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_DATA_TRUNCATED, 1); - return 2; - } - return 0; + return report_if_important_data(from_end_pos, from + length); } @@ -7030,13 +7024,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) cannot_convert_error_pos, from + length)) return 2; - if (from_end_pos < from + length) - { - report_data_too_long(this); - return 2; - } - - return 0; + return report_if_important_data(from_end_pos, from + length); oom_error: /* Fatal OOM error */ diff --git a/sql/field.h b/sql/field.h index d681229a9fd..c82d65147ac 100644 --- a/sql/field.h +++ b/sql/field.h @@ -454,6 +454,8 @@ public: class Field_longstr :public Field_str { +protected: + int report_if_important_data(const char *ptr, const char *end); public: Field_longstr(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, uchar null_bit_arg, utype unireg_check_arg, -- cgit v1.2.1 From 5cf3f53e420d185b0a3beec83154d514c3b32deb Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 04:14:50 +0400 Subject: Fixed bug#34223: Failure on assignment to my_innodb_autoextend_increment and my_innodb_commit_concurrency global variables. Type of the my_innodb_autoextend_increment and the my_innodb_commit_concurrency variables has been changed to GET_ULONG. mysql-test/r/variables.result: Added test case for bug#34223. mysql-test/t/variables.test: Added test case for bug#34223. sql/mysqld.cc: Fixed bug#34223. Last update of the getopt_ull_limit_value function introduced a sanity check for a variable type (only GET_UINT or GET_ULONG are valid types). However, my_innodb_autoextend_increment and my_innodb_commit_concurrency are declared as GET_LONG. Call stack is: sys_var_long_ptr_global::update() fix_unsigned() getopt_ull_limit_value() Type of the my_innodb_autoextend_increment and the my_innodb_commit_concurrency variables has been changed to GET_ULONG. --- sql/mysqld.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 693b72f5c98..f98b09f4ef6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5798,7 +5798,7 @@ log and this option does nothing anymore.", "Data file autoextend increment in megabytes", (gptr*) &srv_auto_extend_increment, (gptr*) &srv_auto_extend_increment, - 0, GET_LONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0}, + 0, GET_ULONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0}, {"innodb_buffer_pool_awe_mem_mb", OPT_INNODB_BUFFER_POOL_AWE_MEM_MB, "If Windows AWE is used, the size of InnoDB buffer pool allocated from the AWE memory.", (gptr*) &innobase_buffer_pool_awe_mem_mb, (gptr*) &innobase_buffer_pool_awe_mem_mb, 0, @@ -5811,7 +5811,7 @@ log and this option does nothing anymore.", {"innodb_commit_concurrency", OPT_INNODB_COMMIT_CONCURRENCY, "Helps in performance tuning in heavily concurrent environments.", (gptr*) &srv_commit_concurrency, (gptr*) &srv_commit_concurrency, - 0, GET_LONG, REQUIRED_ARG, 0, 0, 1000, 0, 1, 0}, + 0, GET_ULONG, REQUIRED_ARG, 0, 0, 1000, 0, 1, 0}, {"innodb_concurrency_tickets", OPT_INNODB_CONCURRENCY_TICKETS, "Number of times a thread is allowed to enter InnoDB within the same \ SQL query after it has once got the ticket", -- cgit v1.2.1 From a1e839783e3a6f415df1b404a86d86fd1553fb94 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 05:10:04 +0300 Subject: BUG#27732 "Possible memory leak with index_merge" The bug was that handler::clone/handler::ha_open() call caused allocation of cloned_copy->ref on the handler->table->mem_root. The allocated memory could not be reclaimed until the table is flushed, so it was possible to exhaust memory by repeatedly running index_merge queries without doing table flushes. The fix: - make handler::clone() allocate new_handler->ref on the passed mem_root - make handler::ha_open() not allocate this->ref if it has already been allocated There is no testcase as it is not possible to check small leaks from testsuite. sql/handler.cc: BUG#27732 "Possible memory leak with index_merge" - make handler::clone() allocate new_handler->ref on the passed mem_root - make handler::ha_open() not allocate this->ref if it has already been allocated --- sql/handler.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 27204ae725b..bfad10f986f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1381,6 +1381,13 @@ int ha_delete_table(THD *thd, enum db_type table_type, const char *path, handler *handler::clone(MEM_ROOT *mem_root) { handler *new_handler= get_new_handler(table, mem_root, table->s->db_type); + /* + Allocate handler->ref here because otherwise ha_open will allocate it + on this->table->mem_root and we will not be able to reclaim that memory + when the clone handler object is destroyed. + */ + if (!(new_handler->ref= (byte*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2))) + return NULL; if (new_handler && !new_handler->ha_open(table->s->path, table->db_stat, HA_OPEN_IGNORE_IF_LOCKED)) return new_handler; @@ -1420,8 +1427,9 @@ int handler::ha_open(const char *name, int mode, int test_if_locked) (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL DBUG_ASSERT(alloc_root_inited(&table->mem_root)); - - if (!(ref= (byte*) alloc_root(&table->mem_root, ALIGN_SIZE(ref_length)*2))) + /* ref is already allocated for us if we're called from handler::clone() */ + if (!ref && !(ref= (byte*) alloc_root(&table->mem_root, + ALIGN_SIZE(ref_length)*2))) { close(); error=HA_ERR_OUT_OF_MEM; -- cgit v1.2.1 From 1b6b7010a6b1bd6e7f79632c2738d7a1654078e4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 08:47:39 -0200 Subject: Bug#32633 Can not create any routine if SQL_MODE=no_engine_substitution The problem is that one can not create a stored routine if sql_mode contains NO_ENGINE_SUBSTITUTION or PAD_CHAR_TO_FULL_LENGTH. Also when a event is created, the mode is silently lost if sql_mode contains one of the aforementioned. This was happening because the table definitions which stored sql_mode values weren't being updated to accept new values of sql_mode. The solution is to update, in a backwards compatible manner, the various table definitions (columns) that store the sql_mode value to take into account the new possible values. One incompatible change is that if a event that is being created can't be stored to the mysql.event table, an error will be raised. The tests case also ensure that new SQL modes will be added to the mysql.proc and mysql.event tables, otherwise the tests will fail. mysql-test/r/events_bugs.result: Add test case result for Bug#32633 mysql-test/r/information_schema.result: Update the sql_mode column definition. mysql-test/r/sp.result: Add test case result for Bug#32633 mysql-test/r/system_mysql_db.result: Update the sql_mode column definition. mysql-test/t/events_bugs.test: Add test case for Bug#32633 mysql-test/t/sp.test: Add test case for Bug#32633 mysql-test/t/system_mysql_db_fix50117.test: Update the sql_mode column definition. scripts/mysql_system_tables.sql: Update the sql_mode column definition. scripts/mysql_system_tables_fix.sql: Update the sql_mode column definition. sql/event_db_repository.cc: Reset and restore SQL modes when storing and loading a event from the data dictionary. Also throw out a error if a store fails. sql/mysqld.cc: Add warning to avoid this problem in the future. sql-common/my_user.c: Truncate length if user name or host name does not fit in the buffer. sql/sp.cc: SQL mode of the thread must not effect data dictionary operations. --- sql/event_db_repository.cc | 69 ++++++++++++++++++++++++++++++---------------- sql/mysqld.cc | 5 ++++ sql/sp.cc | 13 +++++++-- 3 files changed, 61 insertions(+), 26 deletions(-) (limited to 'sql') diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index 9a33b33d8c9..401f76f5d26 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -111,7 +111,7 @@ const TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES'," "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES'," "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER'," - "'HIGH_NOT_PRECEDENCE')") }, + "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") }, {NULL, 0} }, { @@ -172,11 +172,13 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et, sp_head *sp, + ulong sql_mode, my_bool is_update) { CHARSET_INFO *scs= system_charset_info; enum enum_events_table_field f_num; Field **fields= table->field; + int rs= FALSE; DBUG_ENTER("mysql_event_fill_row"); @@ -205,12 +207,9 @@ mysql_event_fill_row(THD *thd, goto err_truncate; /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/ - fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE); - - fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE); - - fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE); - + rs|= fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE); + rs|= fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE); + rs|= fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE); /* Change the SQL_MODE only if body was present in an ALTER EVENT and of course @@ -220,7 +219,7 @@ mysql_event_fill_row(THD *thd, { DBUG_ASSERT(sp->m_body.str); - fields[ET_FIELD_SQL_MODE]->store((longlong)thd->variables.sql_mode, TRUE); + rs|= fields[ET_FIELD_SQL_MODE]->store((longlong)sql_mode, TRUE); if (fields[f_num= ET_FIELD_BODY]->store(sp->m_body.str, sp->m_body.length, @@ -236,16 +235,16 @@ mysql_event_fill_row(THD *thd, if (!is_update || !et->starts_null) { fields[ET_FIELD_TIME_ZONE]->set_notnull(); - fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), - tz_name->charset()); + rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), + tz_name->charset()); } fields[ET_FIELD_INTERVAL_EXPR]->set_notnull(); - fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE); + rs|= fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE); fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull(); - fields[ET_FIELD_TRANSIENT_INTERVAL]-> + rs|= fields[ET_FIELD_TRANSIENT_INTERVAL]-> store(interval_type_to_name[et->interval].str, interval_type_to_name[et->interval].length, scs); @@ -274,8 +273,8 @@ mysql_event_fill_row(THD *thd, { const String *tz_name= thd->variables.time_zone->get_name(); fields[ET_FIELD_TIME_ZONE]->set_notnull(); - fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), - tz_name->charset()); + rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(), + tz_name->charset()); fields[ET_FIELD_INTERVAL_EXPR]->set_null(); fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null(); @@ -308,13 +307,13 @@ mysql_event_fill_row(THD *thd, } fields[ET_FIELD_CHARACTER_SET_CLIENT]->set_notnull(); - fields[ET_FIELD_CHARACTER_SET_CLIENT]->store( + rs|= fields[ET_FIELD_CHARACTER_SET_CLIENT]->store( thd->variables.character_set_client->csname, strlen(thd->variables.character_set_client->csname), system_charset_info); fields[ET_FIELD_COLLATION_CONNECTION]->set_notnull(); - fields[ET_FIELD_COLLATION_CONNECTION]->store( + rs|= fields[ET_FIELD_COLLATION_CONNECTION]->store( thd->variables.collation_connection->name, strlen(thd->variables.collation_connection->name), system_charset_info); @@ -323,15 +322,23 @@ mysql_event_fill_row(THD *thd, CHARSET_INFO *db_cl= get_default_db_collation(thd, et->dbname.str); fields[ET_FIELD_DB_COLLATION]->set_notnull(); - fields[ET_FIELD_DB_COLLATION]->store( - db_cl->name, strlen(db_cl->name), system_charset_info); + rs|= fields[ET_FIELD_DB_COLLATION]->store(db_cl->name, + strlen(db_cl->name), + system_charset_info); } if (et->body_changed) { fields[ET_FIELD_BODY_UTF8]->set_notnull(); - fields[ET_FIELD_BODY_UTF8]->store( - sp->m_body_utf8.str, sp->m_body_utf8.length, system_charset_info); + rs|= fields[ET_FIELD_BODY_UTF8]->store(sp->m_body_utf8.str, + sp->m_body_utf8.length, + system_charset_info); + } + + if (rs) + { + my_error(ER_EVENT_STORE_FAILED, MYF(0), fields[f_num]->field_name, rs); + DBUG_RETURN(TRUE); } DBUG_RETURN(FALSE); @@ -585,12 +592,16 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, int ret= 1; TABLE *table= NULL; sp_head *sp= thd->lex->sphead; + ulong saved_mode= thd->variables.sql_mode; DBUG_ENTER("Event_db_repository::create_event"); DBUG_PRINT("info", ("open mysql.event for update")); DBUG_ASSERT(sp); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + if (open_event_table(thd, TL_WRITE, &table)) goto end; @@ -646,7 +657,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, mysql_event_fill_row() calls my_error() in case of error so no need to handle it here */ - if (mysql_event_fill_row(thd, table, parse_data, sp, FALSE)) + if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, FALSE)) goto end; table->field[ET_FIELD_STATUS]->store((longlong)parse_data->status, TRUE); @@ -661,6 +672,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, end: if (table) close_thread_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -691,6 +703,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, CHARSET_INFO *scs= system_charset_info; TABLE *table= NULL; sp_head *sp= thd->lex->sphead; + ulong saved_mode= thd->variables.sql_mode; int ret= 1; DBUG_ENTER("Event_db_repository::update_event"); @@ -698,6 +711,9 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, /* None or both must be set */ DBUG_ASSERT(new_dbname && new_name || new_dbname == new_name); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + if (open_event_table(thd, TL_WRITE, &table)) goto end; @@ -736,7 +752,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, mysql_event_fill_row() calls my_error() in case of error so no need to handle it here */ - if (mysql_event_fill_row(thd, table, parse_data, sp, TRUE)) + if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, TRUE)) goto end; if (new_dbname) @@ -755,6 +771,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, end: if (table) close_thread_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -950,13 +967,17 @@ bool Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *etn) { - TABLE *table= NULL; bool ret; + TABLE *table= NULL; + ulong saved_mode= thd->variables.sql_mode; DBUG_ENTER("Event_db_repository::load_named_event"); DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd, (int) name.length, name.str)); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + if (!(ret= open_event_table(thd, TL_READ, &table))) { if ((ret= find_named_event(dbname, name, table))) @@ -967,7 +988,7 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, close_thread_tables(thd); } - + thd->variables.sql_mode= saved_mode; DBUG_RETURN(ret); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7b331d42941..9dc77fb8356 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -221,6 +221,11 @@ extern "C" int gethostname(char *name, int namelen); /* Constants */ const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; +/* + WARNING: When adding new SQL modes don't forget to update the + tables definitions that stores it's value. + (ie: mysql.event, mysql.proc) +*/ static const char *sql_mode_names[]= { "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", diff --git a/sql/sp.cc b/sql/sp.cc index 99ffc18deea..b6813d8948c 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -388,7 +388,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) uint length; char buff[65]; String str(buff, sizeof(buff), &my_charset_bin); - ulong sql_mode; + ulong sql_mode, saved_mode= thd->variables.sql_mode; Open_tables_state open_tables_state_backup; Stored_program_creation_ctx *creation_ctx; @@ -400,6 +400,9 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup))) DBUG_RETURN(SP_OPEN_TABLE_FAILED); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) goto done; @@ -503,6 +506,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) done: if (table) close_system_tables(thd, &open_tables_state_backup); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(ret); } @@ -675,6 +679,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp) int ret; TABLE *table; char definer[USER_HOST_BUFF_SIZE]; + ulong saved_mode= thd->variables.sql_mode; CHARSET_INFO *db_cs= get_default_db_collation(thd, sp->m_db.str); @@ -689,6 +694,9 @@ sp_create_routine(THD *thd, int type, sp_head *sp) DBUG_ASSERT(type == TYPE_ENUM_PROCEDURE || type == TYPE_ENUM_FUNCTION); + /* Reset sql_mode during data dictionary operations. */ + thd->variables.sql_mode= 0; + /* This statement will be replicated as a statement, even when using row-based replication. The flag will be reset at the end of the @@ -790,7 +798,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp) store_failed= store_failed || table->field[MYSQL_PROC_FIELD_SQL_MODE]-> - store((longlong)thd->variables.sql_mode, TRUE); + store((longlong)saved_mode, TRUE); if (sp->m_chistics->comment.str) { @@ -890,6 +898,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp) done: thd->count_cuted_fields= saved_count_cuted_fields; + thd->variables.sql_mode= saved_mode; close_thread_tables(thd); DBUG_RETURN(ret); -- cgit v1.2.1 From b2f0ed637171a1658699e3084c3a68710fefac93 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 12:28:38 +0100 Subject: Bug#33379: valgrind error in parts/partition_bit_myisam Problem was that Field_bit used Field::hash() function that did not know about using null-byte for storing bits. Resulting in wrong length, which was caught by valgrind. Solution: created a Field_bit::hash() that uses Field_bit::val_int() and my_charset_bin-collation function hash_sort. Also use the store function for platform independs mysql-test/r/partition_datatype.result: Bug#33379: valgrind error in parts/partition_bit_myisam result file enabled bit datatype test mysql-test/t/partition_datatype.test: Bug#33379: valgrind error in parts/partition_bit_myisam test file enabled bit datatype test sql/field.cc: Bug#33379: valgrind error in parts/partition_bit_myisam Problem was that Field_bit used Field::hash() function that did not know about using null-byte for storing bits. Resulting in wrong length. Solution: created a Field_bit::hash() that uses Field_bit::val_int() and my_charset_bin-collation function hash_sort. Also use the store function for platform independens. sql/field.h: Bug#33379: valgrind error in parts/partition_bit_myisam Problem was that Field_bit used Field::hash() function that did not know about using null-byte for storing bits. Resulting in wrong length. Solution: created a Field_bit::hash(). --- sql/field.cc | 17 +++++++++++++++++ sql/field.h | 1 + 2 files changed, 18 insertions(+) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 7c4f6c9ff5f..88fac96df89 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -8793,6 +8793,23 @@ Field_bit::Field_bit(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg, } +void Field_bit::hash(ulong *nr, ulong *nr2) +{ + if (is_null()) + { + *nr^= (*nr << 1) | 1; + } + else + { + CHARSET_INFO *cs= &my_charset_bin; + longlong value= Field_bit::val_int(); + uchar tmp[8]; + mi_int8store(tmp,value); + cs->coll->hash_sort(cs, tmp, 8, nr, nr2); + } +} + + size_t Field_bit::do_last_null_byte() const { diff --git a/sql/field.h b/sql/field.h index a6a1d8bfabc..38a0b1d5bbd 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1904,6 +1904,7 @@ public: Field::move_field_offset(ptr_diff); bit_ptr= ADD_TO_PTR(bit_ptr, ptr_diff, uchar*); } + void hash(ulong *nr, ulong *nr2); private: virtual size_t do_last_null_byte() const; -- cgit v1.2.1 From 1c0bd60db4e6810e4ac11f2626ab97063f205477 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 15:09:59 +0100 Subject: Bug#34358: Cannot find specified bit row in partitioned table Problem was incorrect data length in the key_restore function resulting in overwriting the search key. Solution, remove one byte in length if uneven bits are used. mysql-test/r/partition_datatype.result: Bug#34358: Cannot find specified bit row Updated result file mysql-test/t/partition_datatype.test: Bug#34358: Cannot find specified bit row Updated test file (corrected a few errors and added a test case for the bug) sql/key.cc: Bug34358: error in key_restore for bit fields with uneven bits When uneven bits exist, it has special treatment for the uneven bits but does use the same byte again when copying the rest of the key_part. --- sql/key.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/key.cc b/sql/key.cc index 7f075674ab6..47e5c5ebdd7 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -168,6 +168,7 @@ void key_restore(uchar *to_record, uchar *from_key, KEY *key_info, } for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++) { + uchar used_uneven_bits= 0; if (key_part->null_bit) { if (*from_key++) @@ -186,6 +187,8 @@ void key_restore(uchar *to_record, uchar *from_key, KEY *key_info, set_rec_bits(bits, to_record + key_part->null_offset + (key_part->null_bit == 128), field->bit_ofs, field->bit_len); + /* we have now used the byte with 'uneven' bits */ + used_uneven_bits= 1; } } if (key_part->key_part_flag & HA_BLOB_PART) @@ -222,7 +225,9 @@ void key_restore(uchar *to_record, uchar *from_key, KEY *key_info, else { length= min(key_length, key_part->length); - memcpy(to_record + key_part->offset, from_key, (size_t) length); + /* skip the byte with 'uneven' bits, if used */ + memcpy(to_record + key_part->offset, from_key + used_uneven_bits + , (size_t) length - used_uneven_bits); } from_key+= length; key_length-= length; -- cgit v1.2.1 From d9831ae5329d6916667ee9beb885c3e4c35c4018 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 7 Feb 2008 19:58:06 -0200 Subject: Bug#31891 Meaningful stack trace On crashes generate a user-friendly resolved and demangled stack trace when libc provides the necessary functions (newer libc on i386, x86_64, powerpc, ia64, alpha and s390). Otherwise print a numeric stack trace as before, relying on resolve_stack_dump utility. configure.in: Add check for backtrace headers, backtrace functions and if __cxa_demangle (libstdc++) is available at link time. sql/mysqld.cc: Print the value of the THD::killed variable when dumping. In some circumstances knowing if the thread was killed makes debugging easier. sql/stacktrace.c: Use the glibc backtrace function when available and demangle C++ function names if the __cxa_demangle function is available. sql/stacktrace.h: Locally export and wrap in C linkage the C++ function __cxa_demangle if available. --- sql/mysqld.cc | 29 +++++++++++++++++++++++++ sql/stacktrace.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/stacktrace.h | 8 +++++++ 3 files changed, 101 insertions(+) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9dc77fb8356..84f7620962e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2182,6 +2182,16 @@ static void check_data_home(const char *path) #define UNSAFE_DEFAULT_LINUX_THREADS 200 #endif + +#if BACKTRACE_DEMANGLE +#include +extern "C" char *my_demangle(const char *mangled_name, int *status) +{ + return abi::__cxa_demangle(mangled_name, NULL, NULL, status); +} +#endif + + extern "C" sig_handler handle_segfault(int sig) { time_t curr_time; @@ -2253,10 +2263,29 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", } if (thd) { + const char *kreason= "UNKNOWN"; + switch (thd->killed) { + case THD::NOT_KILLED: + kreason= "NOT_KILLED"; + break; + case THD::KILL_BAD_DATA: + kreason= "KILL_BAD_DATA"; + break; + case THD::KILL_CONNECTION: + kreason= "KILL_CONNECTION"; + break; + case THD::KILL_QUERY: + kreason= "KILL_QUERY"; + break; + case THD::KILLED_NO_VALUE: + kreason= "KILLED_NO_VALUE"; + break; + } fprintf(stderr, "Trying to get some variables.\n\ Some pointers may be invalid and cause the dump to abort...\n"); safe_print_str("thd->query", thd->query, 1024); fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id); + fprintf(stderr, "thd->killed=%s\n", kreason); } fprintf(stderr, "\ The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\ diff --git a/sql/stacktrace.c b/sql/stacktrace.c index b1267e20774..3d718dfd9d2 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -17,11 +17,16 @@ #include "stacktrace.h" #include #include +#include #ifdef HAVE_STACKTRACE #include #include +#if HAVE_EXECINFO_H +#include +#endif + #define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) char *heap_start; @@ -93,9 +98,68 @@ inline uint32* find_prev_pc(uint32* pc, uchar** fp) } #endif /* defined(__alpha__) && defined(__GNUC__) */ +#if BACKTRACE_DEMANGLE +static void my_demangle_symbols(char **addrs, int n) +{ + int status, i; + char *begin, *end, *demangled; + + for (i= 0; i < n; i++) + { + demangled= NULL; + begin= strchr(addrs[i], '('); + end= begin ? strchr(begin, '+') : NULL; + + if (begin && end) + { + *begin++= *end++= '\0'; + demangled= my_demangle(begin, &status); + if (!demangled || status) + { + demangled= NULL; + begin[-1]= '('; + end[-1]= '+'; + } + } + + if (demangled) + fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end); + else + fprintf(stderr, "%s\n", addrs[i]); + } +} +#endif + + +#if HAVE_BACKTRACE +static void backtrace_current_thread(void) +{ + void *addrs[128]; + char **strings= NULL; + int n = backtrace(addrs, array_elements(addrs)); +#if BACKTRACE_DEMANGLE + if ((strings= backtrace_symbols(addrs, n))) + { + my_demangle_symbols(strings, n); + free(strings); + } +#endif +#if HAVE_BACKTRACE_SYMBOLS_FD + if (!strings) + { + backtrace_symbols_fd(addrs, n, fileno(stderr)); + } +#endif +} +#endif + void print_stacktrace(uchar* stack_bottom, ulong thread_stack) { +#if HAVE_BACKTRACE + backtrace_current_thread(); + return; +#endif uchar** fp; uint frame_count = 0, sigreturn_frame_count; #if defined(__alpha__) && defined(__GNUC__) diff --git a/sql/stacktrace.h b/sql/stacktrace.h index 1a0b80c88d3..96c09a21ad6 100644 --- a/sql/stacktrace.h +++ b/sql/stacktrace.h @@ -17,6 +17,14 @@ extern "C" { #endif +#if HAVE_BACKTRACE && HAVE_BACKTRACE_SYMBOLS && HAVE_CXXABI_H && HAVE_ABI_CXA_DEMANGLE +#define BACKTRACE_DEMANGLE 1 +#endif + +#if BACKTRACE_DEMANGLE +char *my_demangle(const char *mangled_name, int *status); +#endif + #ifdef TARGET_OS_LINUX #if defined(HAVE_STACKTRACE) || (defined (__x86_64__) || defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) #undef HAVE_STACKTRACE -- cgit v1.2.1 From d8eab9769309b36b96c2239d436fdb93b175a760 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 13:35:00 +0300 Subject: Bug#31590: Wrong error message on sort buffer being too small. The out of memory error was thrown when the sort buffer size were too small. This led to a user confusion. Now filesort throws the error message about sort buffer being too small. mysql-test/t/order_by.test: Added a test case for the bug#31590: Wrong error message on sort buffer being too small. mysql-test/r/order_by.result: Added a test case for the bug#31590: Wrong error message on sort buffer being too small. sql/filesort.cc: Bug#31590: Wrong error message on sort buffer being too small. Now filesort throws the error message about sort buffer being too small instead of out of memory error. --- sql/filesort.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/filesort.cc b/sql/filesort.cc index 43b079e83d5..a85f9caefbe 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -215,8 +215,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, sort_keys= table_sort.sort_keys; if (memavl < min_sort_memory) { - my_error(ER_OUTOFMEMORY,MYF(ME_ERROR+ME_WAITTANG), - thd->variables.sortbuff_size); + my_error(ER_OUT_OF_SORTMEMORY,MYF(ME_ERROR+ME_WAITTANG)); goto err; } if (open_cached_file(&buffpek_pointers,mysql_tmpdir,TEMP_PREFIX, -- cgit v1.2.1 From ed312cb5790c33d91e1160e9a41eb4d9df2675bd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 13:35:11 +0300 Subject: Give a more informative message if we failed to write to mysql.general_log table. --- sql/log.cc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 3a09acd8fca..06f4e2d7b78 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -73,23 +73,28 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all); */ class Silence_log_table_errors : public Internal_error_handler { + char m_message[MYSQL_ERRMSG_SIZE]; public: Silence_log_table_errors() - {} + { + m_message[0]= '\0'; + } virtual ~Silence_log_table_errors() {} virtual bool handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd); + const char *message() const { return m_message; } }; bool Silence_log_table_errors::handle_error(uint /* sql_errno */, - const char * /* message */, + const char *message_arg, MYSQL_ERROR::enum_warning_level /* level */, THD * /* thd */) { + strmake(m_message, message_arg, sizeof(m_message)); return TRUE; } @@ -437,7 +442,8 @@ bool Log_to_csv_event_handler:: err: if (result) - sql_print_error("Failed to write to mysql.general_log"); + sql_print_error("Failed to write to mysql.general_log: %s", + error_handler.message()); if (need_rnd_end) { -- cgit v1.2.1 From 7d98c21cdf4235ebe0d4abc52ae71fa4502e1524 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 08:55:55 -0200 Subject: Bug#33798 prepared statements improperly handle large unsigned ints The unsignedness of large integer user variables was not being properly preserved when feeded to prepared statements. This was happening because the unsigned flags wasn't being updated when converting the user variable is converted to a parameter. The solution is to copy the unsigned flag when converting the user variable to a parameter and take the unsigned flag into account when converting the integer to a string. mysql-test/r/binlog.result: Add test case result for Bug#33798 mysql-test/r/ps.result: Add test case result for Bug#33798 mysql-test/t/binlog.test: Add test case for Bug#33798 mysql-test/t/ps.test: Add test case for Bug#33798 sql/item.cc: Take the unsigned flag into account when converting the user variable. --- sql/item.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 713e7709bcb..ffb18054750 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2580,6 +2580,7 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) if (entry && entry->value) { item_result_type= entry->type; + unsigned_flag= entry->unsigned_flag; if (strict_type && required_result_type != item_result_type) DBUG_RETURN(1); switch (item_result_type) { @@ -2875,7 +2876,10 @@ const String *Item_param::query_val_str(String* str) const { switch (state) { case INT_VALUE: - str->set(value.integer, &my_charset_bin); + if (unsigned_flag) + str->set((ulonglong) value.integer, &my_charset_bin); + else + str->set(value.integer, &my_charset_bin); break; case REAL_VALUE: str->set(value.real, NOT_FIXED_DEC, &my_charset_bin); -- cgit v1.2.1 From 213b4dcd9ede1b1de850d526d6600c5fe4aa5497 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 16:04:01 +0400 Subject: Fixed bug#15409: Columns with 64-element SET may not be updated with integers. SET column storing procedure has been modified to be 64bit-clean. mysql-test/r/type_set.result: Added test case for bug#15409. mysql-test/t/type_set.test: Added test case for bug#15409. sql/field.cc: Fixed bug#15409. The Field_set::store(longlong nr,...) method incompletely calculates a bit mask for the comparison with a given number: if that number is greater than 0x7F00 0000 0000 0000 (LONGLONG_MAX), it uses zero bit mask instead of 0xFFFF FFFF FFFF FFFF (ULONGLONG_MAX). Incomplete expression has been replaced with a set_bits macro call. --- sql/field.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 3753318b8fa..53eafcaf2cc 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7871,10 +7871,10 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) int Field_set::store(longlong nr, bool unsigned_val) { int error= 0; - if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) - - (longlong) 1)) + ulonglong max_nr= set_bits(ulonglong, typelib->count); + if ((ulonglong) nr > max_nr) { - nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1); + nr&= max_nr; set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); error=1; } -- cgit v1.2.1 From 0c551b72ded5140e00c0dbe7eadab172f298742f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 10:47:25 -0200 Subject: Manual merge of Bug 33798 mysql-test/extra/binlog_tests/binlog.test: Manual merge of binlog test case for Bug#33798 mysql-test/suite/binlog/r/binlog_row_binlog.result: Add test case result for Bug#33798 mysql-test/suite/binlog/r/binlog_stm_binlog.result: Add test case result for Bug#33798 sql/item.cc: Use new method which accepts a unsigned flag. --- sql/item.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 390e99fbde5..ab9243fcaf5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2926,10 +2926,7 @@ const String *Item_param::query_val_str(String* str) const { switch (state) { case INT_VALUE: - if (unsigned_flag) - str->set((ulonglong) value.integer, &my_charset_bin); - else - str->set(value.integer, &my_charset_bin); + str->set_int(value.integer, unsigned_flag, &my_charset_bin); break; case REAL_VALUE: str->set_real(value.real, NOT_FIXED_DEC, &my_charset_bin); -- cgit v1.2.1 From ba068d64b414f5e3cb00af291a9a0894c8c70172 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 15:53:57 +0300 Subject: Silence the slow log errors (they won't make it to the client anyway). --- sql/log.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 06f4e2d7b78..1a3c98da60b 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -501,11 +501,13 @@ bool Log_to_csv_event_handler:: bool result= TRUE; bool need_close= FALSE; bool need_rnd_end= FALSE; + Silence_log_table_errors error_handler; Open_tables_state open_tables_backup; CHARSET_INFO *client_cs= thd->variables.character_set_client; bool save_time_zone_used; DBUG_ENTER("Log_to_csv_event_handler::log_slow"); + thd->push_internal_handler(& error_handler); /* CSV uses TIME_to_timestamp() internally if table needs to be repaired which will set thd->time_zone_used @@ -635,8 +637,11 @@ bool Log_to_csv_event_handler:: result= FALSE; err: + thd->pop_internal_handler(); + if (result) - sql_print_error("Failed to write to mysql.slow_log"); + sql_print_error("Failed to write to mysql.slow_log: %s", + error_handler.message()); if (need_rnd_end) { -- cgit v1.2.1 From d157f5fd43949d9927ec4683b5e66e32a945e13d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 17:25:20 +0300 Subject: Don't complain about a failure to write a log message if we were simply killed. sql/log.cc: Don't complain if were simply killed. --- sql/log.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 1a3c98da60b..24dd279cefd 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -441,7 +441,7 @@ bool Log_to_csv_event_handler:: result= FALSE; err: - if (result) + if (result && !thd->killed) sql_print_error("Failed to write to mysql.general_log: %s", error_handler.message()); @@ -639,7 +639,7 @@ bool Log_to_csv_event_handler:: err: thd->pop_internal_handler(); - if (result) + if (result && !thd->killed) sql_print_error("Failed to write to mysql.slow_log: %s", error_handler.message()); -- cgit v1.2.1 From 13e44e30eb4fa588687ae4cc07e675aad08fd2ca Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 19:33:24 +0300 Subject: Fix -ansi -pedantic compilation error --- sql/set_var.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/set_var.cc b/sql/set_var.cc index 410608f154f..4c77cbfff82 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1021,7 +1021,7 @@ bool sys_var_set::update(THD *thd, set_var *var) { *value= var->save_result.ulong_value; return 0; -}; +} uchar *sys_var_set::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base) -- cgit v1.2.1 From a7df0e2dc493c5000e7dc61200a64293866c5d55 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 8 Feb 2008 19:37:57 -0700 Subject: Fixed buffer overflow --- sql/log.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 042eddea5cf..9b5b2ae5a6c 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -94,7 +94,7 @@ Silence_log_table_errors::handle_error(uint /* sql_errno */, MYSQL_ERROR::enum_warning_level /* level */, THD * /* thd */) { - strmake(m_message, message_arg, sizeof(m_message)); + strmake(m_message, message_arg, sizeof(m_message)-1); return TRUE; } -- cgit v1.2.1 From 17af021c36e1ff63705a7cf6f5fe6cbafe1513e6 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Feb 2008 10:31:22 +0300 Subject: Fix a buffer overflow with strmake(). --- sql/sql_class.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 75376c53f68..5180cafc774 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -406,7 +406,7 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg, m_affected_rows= affected_rows_arg; m_last_insert_id= last_insert_id_arg; if (message_arg) - strmake(m_message, message_arg, sizeof(m_message)); + strmake(m_message, message_arg, sizeof(m_message) - 1); else m_message[0]= '\0'; m_status= DA_OK; @@ -456,7 +456,7 @@ Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg, DBUG_ASSERT(! is_set() || can_overwrite_status); m_sql_errno= sql_errno_arg; - strmake(m_message, message_arg, sizeof(m_message)); + strmake(m_message, message_arg, sizeof(m_message) - 1); m_status= DA_ERROR; } -- cgit v1.2.1 From 6a15453640b4d92797817aeb83bcc96957a12c51 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Feb 2008 11:32:46 +0100 Subject: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Problem was that it did not work with corrupted/crashed tables. Solution is to disable these commands until WL#4176 is completed mysql-test/r/partition.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/inc/partition_alter4.inc: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION copy-paste error, changed from REBUILT to REPAIR, as the heading says mysql-test/suite/parts/r/partition_alter1_innodb.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/r/partition_alter1_myisam.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/r/partition_alter2_innodb.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/r/partition_alter2_myisam.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/r/partition_basic_innodb.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/r/partition_basic_myisam.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/r/partition_engine_innodb.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/r/partition_engine_myisam.result: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Test result mysql-test/suite/parts/t/disabled.def: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Disabled test since the tested feature is not longer supported mysql-test/t/partition.test: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION OPTIMIZE PARTITION is not longer supported, waiting for WL#4176 sql/ha_partition.cc: Bug#20129: ALTER TABLE ... ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION Problem was that it did not work with corrupted/crashed tables. Solution is to disable these commands until WL#4176 is completed (returning HA_ADMIN_NOT_IMPLEMENTED and #ifdef'ed the non-reachable code) --- sql/ha_partition.cc | 15 +++++++++++++++ sql/sql_partition.cc | 14 +++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 51070a525c5..d97af771a00 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1035,6 +1035,13 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, DBUG_ENTER("handle_opt_part"); DBUG_PRINT("enter", ("flag = %u", flag)); + /* + TODO: + Rewrite the code for ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION WL4176 + */ + DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); + +#ifdef WL4176_IS_DONE if (flag == OPTIMIZE_PARTS) error= file->ha_optimize(thd, check_opt); else if (flag == ANALYZE_PARTS) @@ -1051,6 +1058,7 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, if (error == HA_ADMIN_ALREADY_DONE) error= 0; DBUG_RETURN(error); +#endif } @@ -1080,6 +1088,12 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, DBUG_ENTER("ha_partition::handle_opt_partitions"); DBUG_PRINT("enter", ("all_parts %u, flag= %u", all_parts, flag)); + /* + TODO: + Rewrite the code for ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION WL4176 + */ + DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); +#ifdef WL4176_IS_DONE do { partition_element *part_elem= part_it++; @@ -1110,6 +1124,7 @@ int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, } } while (++i < no_parts); DBUG_RETURN(FALSE); +#endif } /* diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index eabf4526f7b..c0707360027 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -6113,7 +6113,19 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ((alter_info->flags & ALTER_REPAIR_PARTITION) && (error= table->file->ha_repair_partitions(thd)))) { - table->file->print_error(error, MYF(0)); + if (error == HA_ADMIN_NOT_IMPLEMENTED) { + if (alter_info->flags & ALTER_OPTIMIZE_PARTITION) + my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "optimize partition"); + else if (alter_info->flags & ALTER_ANALYZE_PARTITION) + my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "analyze partition"); + else if (alter_info->flags & ALTER_CHECK_PARTITION) + my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "check partition"); + else if (alter_info->flags & ALTER_REPAIR_PARTITION) + my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "repair partition"); + else + table->file->print_error(error, MYF(0)); + } else + table->file->print_error(error, MYF(0)); goto err; } } -- cgit v1.2.1 From 6f6fabb7f97db7e9b8a5efaa2cd337b34fdf9161 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Feb 2008 14:04:30 +0300 Subject: Patch to eliminate some valgrind warnings in debug printout code. (originally from Mats) sql/rpl_rli.cc: Adding variable to mark an instance of Relay_log_info as fake. sql/rpl_rli.h: Adding variable to mark an instance of Relay_log_info as fake. sql/slave.cc: Not printing debug information if we are working with a fake instance of Relay_log_info. This because the result of calling update is nonsense, and trying to print it generates valgrind warnings. sql/sql_binlog.cc: Marking newly created instance of Relay_log_info as a fake instance. --- sql/rpl_rli.cc | 5 ++++- sql/rpl_rli.h | 4 ++++ sql/slave.cc | 22 ++++++++++++++-------- sql/sql_binlog.cc | 3 +++ 4 files changed, 25 insertions(+), 9 deletions(-) (limited to 'sql') diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 3e9a484126a..03f790b934f 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -33,7 +33,10 @@ Relay_log_info::Relay_log_info() :Slave_reporting_capability("SQL"), no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), - group_relay_log_pos(0), + group_relay_log_pos(0), event_relay_log_pos(0), +#if HAVE_purify + is_fake(FALSE), +#endif cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0), sql_thd(0), diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index a3a57ad4ce9..36daffae1af 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -154,6 +154,10 @@ public: ulonglong event_relay_log_pos; ulonglong future_event_relay_log_pos; +#ifdef HAVE_purify + bool is_fake; /* Mark that this is a fake relay log info structure */ +#endif + /* Original log name and position of the group we're currently executing (whose coordinates are group_relay_log_name/pos in the relay log) diff --git a/sql/slave.cc b/sql/slave.cc index 4ffc2023e85..c76e7c75a56 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1892,14 +1892,19 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, if (exec_res == 0) { int error= ev->update_pos(rli); - char buf[22]; - DBUG_PRINT("info", ("update_pos error = %d", error)); - DBUG_PRINT("info", ("group %s %s", - llstr(rli->group_relay_log_pos, buf), - rli->group_relay_log_name)); - DBUG_PRINT("info", ("event %s %s", - llstr(rli->event_relay_log_pos, buf), - rli->event_relay_log_name)); +#ifdef HAVE_purify + if (!rli->is_fake) +#endif + { + char buf[22]; + DBUG_PRINT("info", ("update_pos error = %d", error)); + DBUG_PRINT("info", ("group %s %s", + llstr(rli->group_relay_log_pos, buf), + rli->group_relay_log_name)); + DBUG_PRINT("info", ("event %s %s", + llstr(rli->event_relay_log_pos, buf), + rli->event_relay_log_name)); + } /* The update should not fail, so print an error message and return an error code. @@ -1909,6 +1914,7 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, */ if (error) { + char buf[22]; rli->report(ERROR_LEVEL, ER_UNKNOWN_ERROR, "It was not possible to update the positions" " of the relay log information: the slave may" diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 04f408453ea..f1fbe6eb4b7 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -56,6 +56,9 @@ void mysql_client_binlog_statement(THD* thd) if (!thd->rli_fake) { thd->rli_fake= new Relay_log_info; +#ifdef HAVE_purify + thd->rli_fake->is_fake= TRUE; +#endif have_fd_event= FALSE; } if (thd->rli_fake && !thd->rli_fake->relay_log.description_event_for_exec) -- cgit v1.2.1 From c9d0934a8f430d1c89d261be0f0f7cac18501b78 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Feb 2008 14:05:27 +0300 Subject: Disabling declaration of debug variable for non-debug builds. (originally from Mats) sql/slave.cc: Disabling declaration in non-debug builds. --- sql/slave.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index c76e7c75a56..9dd52c60dad 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1896,7 +1896,9 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli, if (!rli->is_fake) #endif { +#ifndef DBUG_OFF char buf[22]; +#endif DBUG_PRINT("info", ("update_pos error = %d", error)); DBUG_PRINT("info", ("group %s %s", llstr(rli->group_relay_log_pos, buf), -- cgit v1.2.1 From 88cc6d9736a0108027075b0d12f7cd650cd433ad Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Feb 2008 10:43:38 +0100 Subject: Removed extra symbol during merge. --- sql/lex.h | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/lex.h b/sql/lex.h index d97f0718913..acb81dcf717 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -389,7 +389,6 @@ static SYMBOL symbols[] = { { "PAGE", SYM(PAGE_SYM)}, { "PAGE_CHECKSUM", SYM(PAGE_CHECKSUM_SYM)}, { "PARTIAL", SYM(PARTIAL)}, - { "PAGE", SYM(PAGE_SYM)}, { "PARTITION", SYM(PARTITION_SYM)}, { "PARTITIONING", SYM(PARTITIONING_SYM)}, { "PARTITIONS", SYM(PARTITIONS_SYM)}, -- cgit v1.2.1 From d5092fa9caf06376023c25cd55610b9a033e3904 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Feb 2008 12:43:55 +0300 Subject: Fix for bug #33389: Selecting from a view into a table from within SP or trigger crashes server Under some circumstances a combination of VIEWs, subselects with outer references and PS/SP/triggers could lead to use of uninitialized memory and server crash as a result. Fixed by changing the code in Item_field::fix_fields() so that in cases when the field is a VIEW reference, we first check whether the field is also an outer reference, and mark it appropriately before returning. mysql-test/r/view.result: Added a test case for bug #33389. mysql-test/t/view.test: Added a test case for bug #33389. sql/item.cc: In cases when in Item_field::fix_fields() from_field is a view reference, do not return too early, i.e. before marking the reference as an outer one when needed. --- sql/item.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 713e7709bcb..8283e1a13d3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3903,6 +3903,18 @@ bool Item_field::fix_fields(THD *thd, Item **reference) else if (!from_field) goto error; + if (!outer_fixed && cached_table && cached_table->select_lex && + context->select_lex && + cached_table->select_lex != context->select_lex) + { + int ret; + if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) + goto error; + else if (!ret) + return FALSE; + outer_fixed= 1; + } + /* if it is not expression from merged VIEW we will set this field. @@ -3918,18 +3930,6 @@ bool Item_field::fix_fields(THD *thd, Item **reference) if (from_field == view_ref_found) return FALSE; - if (!outer_fixed && cached_table && cached_table->select_lex && - context->select_lex && - cached_table->select_lex != context->select_lex) - { - int ret; - if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) - goto error; - else if (!ret) - return FALSE; - outer_fixed= 1; - } - set_field(from_field); if (thd->lex->in_sum_func && thd->lex->in_sum_func->nest_level == -- cgit v1.2.1 From 8d51c6ad68e373551fd848204e1301481c051399 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Feb 2008 09:44:27 -0200 Subject: Bug#23771 AFTER UPDATE trigger not invoked when there are no changes of the data The problem is that AFTER UPDATE triggers will fire only if the new data is different from the old data on the row. The trigger should fire regardless of whether there are changes to the data. The solution is to fire the trigger on UPDATE even if there are no changes to the value (because the value is the same). mysql-test/r/trigger.result: Add test case result for Bug#23771 mysql-test/t/trigger.test: Add test case for Bug#23771 sql/sql_update.cc: Move the invocation of the after update trigger so that the trigger will fire even if the records are the same. --- sql/sql_update.cc | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'sql') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4d075e3308d..d895d2ee0f2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -643,14 +643,6 @@ int mysql_update(THD *thd, updated++; else error= 0; - - if (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_AFTER, TRUE)) - { - error= 1; - break; - } } else if (!ignore || table->file->is_fatal_error(error, HA_CHECK_DUP_KEY)) @@ -669,6 +661,14 @@ int mysql_update(THD *thd, } } + if (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, + TRG_ACTION_AFTER, TRUE)) + { + error= 1; + break; + } + if (!--limit && using_limit) { /* @@ -1644,12 +1644,12 @@ bool multi_update::send_data(List ¬_used_values) trans_safe= 0; thd->transaction.stmt.modified_non_trans_table= TRUE; } - if (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_AFTER, TRUE)) - DBUG_RETURN(1); } } + if (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, + TRG_ACTION_AFTER, TRUE)) + DBUG_RETURN(1); } else { @@ -1881,12 +1881,12 @@ int multi_update::do_updates() updated++; else local_error= 0; - - if (table->triggers && - table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, - TRG_ACTION_AFTER, TRUE)) - goto err2; } + + if (table->triggers && + table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, + TRG_ACTION_AFTER, TRUE)) + goto err2; } if (updated != org_updated) -- cgit v1.2.1 From abe4c14ae93f0d8c97bd97b5674a5b00ddfc9b1f Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Feb 2008 18:21:17 +0100 Subject: Various fixes to fix memory leaks after merging replication tree with main. sql/sql_binlog.cc: Adding code to free memory after execution of BINLOG statement. It caused a memory leak in the case that the execution failed for any reason. sql/sql_class.cc: Since rli_fake is checked for NULL at various occations to mean that no rli_fake is assigned, NULL is assigned to rli_fake after deleting the instance. --- sql/sql_binlog.cc | 1 + sql/sql_class.cc | 3 +++ 2 files changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index cff4ceeccf9..462806ab10d 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -234,6 +234,7 @@ void mysql_client_binlog_statement(THD* thd) send_ok(thd); end: + thd->rli_fake->clear_tables_to_lock(); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN; } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 5180cafc774..044ea70e994 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -870,7 +870,10 @@ THD::~THD() #endif #ifndef EMBEDDED_LIBRARY if (rli_fake) + { delete rli_fake; + rli_fake= NULL; + } #endif free_root(&main_mem_root, MYF(0)); -- cgit v1.2.1 From 215625b14300c50c99682c47af25a10eab1bce7e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Feb 2008 20:59:09 +0300 Subject: Fix for Bug#31222: com_% global status counters behave randomly with mysql_change_user. The problem was that global status variables were not updated in THD::check_user(), so thread statistics were lost after COM_CHANGE_USER. The fix is to update global status variables with the thread ones before preparing the thread for new user. mysql-test/r/change_user.result: Update result file. mysql-test/t/change_user.test: Add a test case for Bug#31222: com_% global status counters behave randomly with mysql_change_user. sql/sql_class.cc: Update global status variables when we're handling COM_CHANGE_USER for a thread. --- sql/sql_class.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 5180cafc774..5bdde066575 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -769,6 +769,10 @@ void THD::init_for_queries() void THD::change_user(void) { + pthread_mutex_lock(&LOCK_status); + add_to_status(&global_status_var, &status_var); + pthread_mutex_unlock(&LOCK_status); + cleanup(); killed= NOT_KILLED; cleanup_done= 0; -- cgit v1.2.1 From c1d0dd94bb4734f0a441c589b6fc9fa25d2fa768 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Feb 2008 22:09:16 +0300 Subject: Fix for Bug#32538: View definition picks up character set, but not collation. The problem here was that text literals in a view were always dumped with character set introducer. That lead to loosing collation information. The fix is to dump character set introducer only if it was in the original query. That is now possible because there is no problem any more of loss of character set of string literals in views -- after WL#4052 the view is dumped in the original character set. mysql-test/r/case.result: Update result file. mysql-test/r/compress.result: Update result file. mysql-test/r/ctype_collate.result: Update result file. mysql-test/r/date_formats.result: Update result file. mysql-test/r/ddl_i18n_koi8r.result: Update result file. mysql-test/r/ddl_i18n_utf8.result: Update result file. mysql-test/r/fulltext.result: Update result file. mysql-test/r/func_crypt.result: Update result file. mysql-test/r/func_encrypt.result: Update result file. mysql-test/r/func_if.result: Update result file. mysql-test/r/func_in.result: Update result file. mysql-test/r/func_like.result: Update result file. mysql-test/r/func_regexp.result: Update result file. mysql-test/r/func_set.result: Update result file. mysql-test/r/func_str.result: Update result file. mysql-test/r/func_time.result: Update result file. mysql-test/r/gis.result: Update result file. mysql-test/r/group_min_max.result: Update result file. mysql-test/r/mysqldump.result: Update result file. mysql-test/r/negation_elimination.result: Update result file. mysql-test/r/null.result: Update result file. mysql-test/r/select.result: Update result file. mysql-test/r/show_check.result: Update result file. mysql-test/r/sp-code.result: Update result file. mysql-test/r/ssl.result: Update result file. mysql-test/r/ssl_compress.result: Update result file. mysql-test/r/subselect.result: Update result file. mysql-test/r/temp_table.result: Update result file. mysql-test/r/type_blob.result: Update result file. mysql-test/r/view.result: Update result file. mysql-test/suite/binlog/r/binlog_stm_blackhole.result: Update result file. mysql-test/suite/rpl/r/rpl_get_lock.result: Update result file. mysql-test/suite/rpl/r/rpl_master_pos_wait.result: Update result file. mysql-test/t/view.test: Add a test case for Bug#32538. sql/item.cc: Do not dump character set introducer if it was not specified explicitly in the original query. sql/item.h: Add 'cs_specified' property to Item_string. sql/sql_yacc.yy: Set Item_string::cs_specified property to TRUE when character set introducer is explicitly specified. --- sql/item.cc | 8 ++++++-- sql/item.h | 45 +++++++++++++++++++++++++++++++++++++++++++++ sql/sql_yacc.yy | 43 ++++++++++++++++++++++++++++++------------- 3 files changed, 81 insertions(+), 15 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index ab9243fcaf5..10c1c58aea8 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2312,8 +2312,12 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value) void Item_string::print(String *str) { - str->append('_'); - str->append(collation.collation->csname); + if (is_cs_specified()) + { + str->append('_'); + str->append(collation.collation->csname); + } + str->append('\''); str_value.print(str); str->append('\''); diff --git a/sql/item.h b/sql/item.h index b98389bc8d4..b3cf9aa6e4c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1842,6 +1842,7 @@ public: Item_string(const char *str,uint length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE, uint repertoire= MY_REPERTOIRE_UNICODE30) + : m_cs_specified(FALSE) { str_value.set_or_copy_aligned(str, length, cs); collation.set(cs, dv, repertoire); @@ -1860,6 +1861,7 @@ public: } /* Just create an item and do not fill string representation */ Item_string(CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) + : m_cs_specified(FALSE) { collation.set(cs, dv); max_length= 0; @@ -1870,6 +1872,7 @@ public: Item_string(const char *name_par, const char *str, uint length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE, uint repertoire= MY_REPERTOIRE_UNICODE30) + : m_cs_specified(FALSE) { str_value.set_or_copy_aligned(str, length, cs); collation.set(cs, dv, repertoire); @@ -1923,6 +1926,48 @@ public: // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} bool check_partition_func_processor(uchar *int_arg) {return FALSE;} + + /** + Return TRUE if character-set-introducer was explicitly specified in the + original query for this item (text literal). + + This operation is to be called from Item_string::print(). The idea is + that when a query is generated (re-constructed) from the Item-tree, + character-set-introducers should appear only for those literals, where + they were explicitly specified by the user. Otherwise, that may lead to + loss collation information (character set introducers implies default + collation for the literal). + + Basically, that makes sense only for views and hopefully will be gone + one day when we start using original query as a view definition. + + @return This operation returns the value of m_cs_specified attribute. + @retval TRUE if character set introducer was explicitly specified in + the original query. + @retval FALSE otherwise. + */ + inline bool is_cs_specified() const + { + return m_cs_specified; + } + + /** + Set the value of m_cs_specified attribute. + + m_cs_specified attribute shows whether character-set-introducer was + explicitly specified in the original query for this text literal or + not. The attribute makes sense (is used) only for views. + + This operation is to be called from the parser during parsing an input + query. + */ + inline void set_cs_specified(bool cs_specified) + { + m_cs_specified= cs_specified; + } + +private: + bool m_cs_specified; }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c98228424a5..764e593a1ed 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9823,8 +9823,11 @@ text_literal: } | UNDERSCORE_CHARSET TEXT_STRING { - $$= new Item_string($2.str, $2.length, $1); - ((Item_string*) $$)->set_repertoire_from_value(); + Item_string *str= new Item_string($2.str, $2.length, $1); + str->set_repertoire_from_value(); + str->set_cs_specified(TRUE); + + $$= str; } | text_literal TEXT_STRING_literal { @@ -9927,15 +9930,22 @@ literal: String *str= tmp ? tmp->quick_fix_field(), tmp->val_str((String*) 0) : (String*) 0; - $$= new Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); - if (!$$ || !$$->check_well_formed_result(&$$->str_value, TRUE)) + + Item_string *item_str= + new Item_string(NULL, /* name will be set in select_item */ + str ? str->ptr() : "", + str ? str->length() : 0, + $1); + if (!item_str || + !item_str->check_well_formed_result(&item_str->str_value, TRUE)) { MYSQL_YYABORT; } - ((Item_string *) $$)->set_repertoire_from_value(); + + item_str->set_repertoire_from_value(); + item_str->set_cs_specified(TRUE); + + $$= item_str; } | UNDERSCORE_CHARSET BIN_NUM { @@ -9947,14 +9957,21 @@ literal: String *str= tmp ? tmp->quick_fix_field(), tmp->val_str((String*) 0) : (String*) 0; - $$= new Item_string(NULL, /* name will be set in select_item */ - str ? str->ptr() : "", - str ? str->length() : 0, - $1); - if (!$$ || !$$->check_well_formed_result(&$$->str_value, TRUE)) + + Item_string *item_str= + new Item_string(NULL, /* name will be set in select_item */ + str ? str->ptr() : "", + str ? str->length() : 0, + $1); + if (!item_str || + !item_str->check_well_formed_result(&item_str->str_value, TRUE)) { MYSQL_YYABORT; } + + item_str->set_cs_specified(TRUE); + + $$= item_str; } | DATE_SYM text_literal { $$ = $2; } | TIME_SYM text_literal { $$ = $2; } -- cgit v1.2.1 From 911a85d54844ad75f407359bd86a44c76c7e6dc4 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Feb 2008 11:26:24 +0100 Subject: Added comments on why we do reopen Handle error case of not being able to reopen which requires us to remove table from thread's open list and table_cache. --- sql/sql_partition.cc | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 677d45dc33d..3f65baa71ff 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5846,21 +5846,31 @@ static void release_log_entries(partition_info *part_info) RETURN VALUES NONE */ -void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) +static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) { int err; if (lpt->thd->locked_tables) { + /* + When we have the table locked, it is necessary to reopen the table + since all table objects were closed and removed as part of the + ALTER TABLE of partitioning structure. + */ pthread_mutex_lock(&LOCK_open); lpt->thd->in_lock_tables= 1; err= reopen_tables(lpt->thd, 1, 1); lpt->thd->in_lock_tables= 0; - pthread_mutex_unlock(&LOCK_open); if (err) { - /* Issue a warning since we weren't able to regain the lock again. */ + /* + Issue a warning since we weren't able to regain the lock again. + We also need to unlink table from thread's open list and from + table_cache + */ + unlink_open_table(lpt->thd, lpt->table, FALSE); sql_print_warning("We failed to reacquire LOCKs in ALTER TABLE"); } + pthread_mutex_unlock(&LOCK_open); } } -- cgit v1.2.1 From ded528ca1249f35f55f9d7b52d95c96e94734495 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Feb 2008 14:09:41 +0200 Subject: Bug #33931 assertion at write_ignored_events_info_to_relay_log if init_slave_thread() fails and bug#33932 assertion at handle_slave_sql if init_slave_thread() fails the asserts were caused by bug33931: having thd deleted at time of executing err: code plus a missed initialization; bug33932: initialization of slave_is_running member was missed; fixed with relocating mi members initialization and removing delete thd It is safe to do as deletion happens later explicitly in the caller of init_slave_thread(). Todo: at merging the test is better to be moved into suite/bugs for 5.x (when x>0). sql/slave.cc: adding the bugs simulating code; relocating some assignments to satisfy the asserts; mysql-test/r/rpl_bug33931.result: the new result file mysql-test/t/rpl_bug33931-slave.opt: option to spark the simulation code mysql-test/t/rpl_bug33931.test: tests check that slave does not crash as before. Slave threads must be in NO running state in the end. --- sql/slave.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index 4a65e9aaa85..272d6f117e9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2895,6 +2895,9 @@ void set_slave_thread_default_charset(THD* thd, RELAY_LOG_INFO *rli) static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) { DBUG_ENTER("init_slave_thread"); +#if !defined(DBUG_OFF) + int simulate_error= 0; +#endif thd->system_thread = (thd_type == SLAVE_THD_SQL) ? SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; thd->security_ctx->skip_grants(); @@ -2914,10 +2917,17 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) thd->thread_id = thread_id++; pthread_mutex_unlock(&LOCK_thread_count); + DBUG_EXECUTE_IF("simulate_io_slave_error_on_init", + simulate_error|= (1 << SLAVE_THD_IO);); + DBUG_EXECUTE_IF("simulate_sql_slave_error_on_init", + simulate_error|= (1 << SLAVE_THD_SQL);); +#if !defined(DBUG_OFF) + if (init_thr_lock() || thd->store_globals() || simulate_error & (1<< thd_type)) +#else if (init_thr_lock() || thd->store_globals()) +#endif { thd->cleanup(); - delete thd; DBUG_RETURN(-1); } @@ -3515,6 +3525,7 @@ slave_begin: thd= new THD; // note that contructor of THD uses DBUG_ ! THD_CHECK_SENTRY(thd); + mi->io_thd = thd; pthread_detach_this_thread(); thd->thread_stack= (char*) &thd; // remember where our stack is @@ -3525,7 +3536,6 @@ slave_begin: sql_print_error("Failed during slave I/O thread initialization"); goto err; } - mi->io_thd = thd; pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); pthread_mutex_unlock(&LOCK_thread_count); @@ -3865,9 +3875,11 @@ slave_begin: thd = new THD; // note that contructor of THD uses DBUG_ ! thd->thread_stack = (char*)&thd; // remember where our stack is + rli->sql_thd= thd; /* Inform waiting threads that slave has started */ rli->slave_run_id++; + rli->slave_running = 1; pthread_detach_this_thread(); if (init_slave_thread(thd, SLAVE_THD_SQL)) @@ -3882,7 +3894,6 @@ slave_begin: goto err; } thd->init_for_queries(); - rli->sql_thd= thd; thd->temporary_tables = rli->save_temporary_tables; // restore temp tables pthread_mutex_lock(&LOCK_thread_count); threads.append(thd); @@ -3895,7 +3906,6 @@ slave_begin: start receiving data so we realize we are not caught up and Seconds_Behind_Master grows. No big deal. */ - rli->slave_running = 1; rli->abort_slave = 0; pthread_mutex_unlock(&rli->run_lock); pthread_cond_broadcast(&rli->start_cond); -- cgit v1.2.1 From 247efb9cf060f0cd8d8eb7e4ecd084b9a202a395 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Feb 2008 19:32:19 +0400 Subject: Fixed bug#33764: Wrong result with IN(), CONCAT() and implicit type conversion. Instead of copying of whole character string from a temporary buffer, the server copied a short-living pointer to that string into a long-living structure. That has been fixed. mysql-test/r/select.result: Added test case for bug#33764. mysql-test/t/select.test: Added test case for bug#33764. sql/item_cmpfunc.cc: Fixed bug#33764. Copying of a pointer has been replaced with an optional copying of a whole array to a newly allocated memory space in case of a functional source item. --- sql/item_cmpfunc.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 98bcb256138..17345e76bba 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2995,7 +2995,10 @@ void in_string::set(uint pos,Item *item) { if (res->uses_buffer_owned_by(str)) res->copy(); - *str= *res; + if (item->type() == Item::FUNC_ITEM) + str->copy(*res); + else + *str= *res; } if (!str->charset()) { -- cgit v1.2.1 From 7a290b55f7691b2518cb1d83da252e07376954f6 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 13 Feb 2008 19:34:12 +0400 Subject: Fixed bug#31194: Privilege ordering does not order properly for wildcard values. The server ignored escape character before wildcards during the calculation of priority values for sorting of a privilege list. (Actually the server counted an escape character as an ordinary wildcard like % or _). I.e. the table name template with a wildcard character like 'tbl_1' had higher priority in a privilege list than concrete table name without wildcards like 'tbl\_1', and some privileges of 'tbl\_1' was hidden by privileges for 'tbl_1'. The get_sort function has been modified to ignore escaped wildcards as usual. mysql-test/r/grant3.result: Added test case for bug#31194. mysql-test/t/grant3.test: Added test case for bug#31194. sql/sql_acl.cc: Fixed bug#31194. The server used the wild_prefix escape character (usually \-character) like % and _ wildcards in the get_sort function for sorting weights calculation. The get_sort function has been modified to ignore escaped wildcards and alone escapes like in the wild_case_compare function. --- sql/sql_acl.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 134541368e9..851af35da32 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -668,7 +668,9 @@ static ulong get_sort(uint count,...) { for (; *str ; str++) { - if (*str == wild_many || *str == wild_one || *str == wild_prefix) + if (*str == wild_prefix && str[1]) + str++; + else if (*str == wild_many || *str == wild_one) { wild_pos= (uint) (str - start) + 1; break; -- cgit v1.2.1 From 29169c6b47109852b37dc57ac0603e04af0cdaa4 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Feb 2008 09:53:01 +0100 Subject: Fixes to try to handle valgrind warnings identical to those in BUG#24387, which is closed since long. sql/mysqld.cc: Moving my_thread_end() to before pthread_cond_broadcast() since it might cause other threads to start using resources that are about to be released, or tries to proceed assuming that the resources have already been released. --- sql/mysqld.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 08ecc025332..9c4e6f9e2a2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1869,9 +1869,9 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) /* It's safe to broadcast outside a lock (COND... is not deleted here) */ DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); + my_thread_end(); (void) pthread_cond_broadcast(&COND_thread_count); - my_thread_end(); pthread_exit(0); DBUG_RETURN(0); // Impossible } -- cgit v1.2.1 From 55f6727b708d99562b48ba5391a43ec235375125 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Feb 2008 16:27:01 +0400 Subject: BUG#33946 - Join on Federated tables with Unique index gives error 1430 from storage engine Federated may crash a server, return wrong result set, return "ERROR 1030 (HY000): Got error 1430 from storage engine" message when local (engine=federated) table has a key against nullable column. The problem was wrong implementation of function that creates WHERE clause for remote query from key. mysql-test/r/federated.result: A test case for BUG#33946. mysql-test/t/federated.test: A test case for BUG#33946. sql/ha_federated.cc: Fixed that federated adds " IS NULL " condition to a remote query, whereas "IS NOT NULL" requested by original query. Fixed that federated didn't check for end of key buffer, didn't setup key buffer pointer and remaining lenght of key buffer, didn't add " AND " between conditions in case original query has IS [NOT] NULL condition against nullable column. Fixed that federated wrongly shifts key buffer pointer by extra one byte when key part may be null (was: store_length + 1, now: store_length). --- sql/ha_federated.cc | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index ac1e0962ffb..c0743bd6c9a 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1094,10 +1094,20 @@ bool ha_federated::create_where_from_key(String *to, { if (*ptr++) { + /* + We got "IS [NOT] NULL" condition against nullable column. We + distinguish between "IS NOT NULL" and "IS NULL" by flag. For + "IS NULL", flag is set to HA_READ_KEY_EXACT. + */ if (emit_key_part_name(&tmp, key_part) || - tmp.append(FEDERATED_ISNULL)) + tmp.append(ranges[i]->flag == HA_READ_KEY_EXACT ? + FEDERATED_ISNULL : " IS NOT NULL ")) DBUG_RETURN(1); - continue; + /* + We need to adjust pointer and length to be prepared for next + key part. As well as check if this was last key part. + */ + goto prepare_for_next_key_part; } } @@ -1199,12 +1209,18 @@ bool ha_federated::create_where_from_key(String *to, if (tmp.append(FEDERATED_CLOSEPAREN)) DBUG_RETURN(1); +prepare_for_next_key_part: if (store_length >= length) break; DBUG_PRINT("info", ("remainder %d", remainder)); DBUG_ASSERT(remainder > 1); length-= store_length; - ptr+= store_length; + /* + For nullable columns, null-byte is already skipped before, that is + ptr was incremented by 1. Since store_length still counts null-byte, + we need to subtract 1 from store_length. + */ + ptr+= store_length - test(key_part->null_bit); if (tmp.append(FEDERATED_AND)) DBUG_RETURN(1); -- cgit v1.2.1 From 50bd4a438e72fdf6f46e2d714b2f13999fa460b2 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Feb 2008 16:28:32 +0200 Subject: bug#33329 extraneous ROLLBACK in binlog on connection does not use trans tables changes for an assert and an updated results file. mysql-test/r/mix_innodb_myisam_binlog.result: results file changed as there is no ROLLBACK query in binlog as it must be. sql/sql_update.cc: refining assert as the initial value of transactional_tables has been changed to zero. --- sql/sql_update.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_update.cc b/sql/sql_update.cc index e5017058659..9c82bde9497 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1482,7 +1482,7 @@ void multi_update::send_error(uint errcode,const char *err) if (trans_safe) { - DBUG_ASSERT(transactional_tables); + DBUG_ASSERT(!updated || transactional_tables); (void) ha_autocommit_or_rollback(thd, 1); } else -- cgit v1.2.1 From 5704c7fe2cf52fb8bec0f8e8006f7a4b181e1660 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 14 Feb 2008 18:13:40 +0300 Subject: A patch for Bug#18834: ALTER TABLE ADD INDEX on table with two timestamp fields. The actual problem here was that CREATE TABLE allowed zero date as a default value for a TIMESTAMP column in NO_ZERO_DATE mode. The thing is that for TIMESTAMP date type specific rule is applied: column_name TIMESTAMP == column_name TIMESTAMP DEFAULT 0 whever for any other date data type column_name TYPE == column_name TYPE DEFAULT NULL The fix is to raise an error when we're in NO_ZERO_DATE mode and there is TIMESTAMP column w/o default value. mysql-test/r/create.result: Update result file. mysql-test/t/create.test: Test case for Bug#18834: ALTER TABLE ADD INDEX on table with two timestamp fields. sql/sql_table.cc: Report an error if NO_ZERO_MODE is set and we have zero date as a default. --- sql/sql_table.cc | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 505bcd1b421..05c73044ddd 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3001,6 +3001,37 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, (qsort_cmp) sort_keys); create_info->null_bits= null_fields; + /* Check fields. */ + it.rewind(); + while ((sql_field=it++)) + { + Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check); + + if (thd->variables.sql_mode & MODE_NO_ZERO_DATE && + !sql_field->def && + sql_field->sql_type == MYSQL_TYPE_TIMESTAMP && + (sql_field->flags & NOT_NULL_FLAG) && + (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD)) + { + /* + An error should be reported if: + - NO_ZERO_DATE SQL mode is active; + - there is no explicit DEFAULT clause (default column value); + - this is a TIMESTAMP column; + - the column is not NULL; + - this is not the DEFAULT CURRENT_TIMESTAMP column. + + In other words, an error should be reported if + - NO_ZERO_DATE SQL mode is active; + - the column definition is equivalent to + 'column_name TIMESTAMP DEFAULT 0'. + */ + + my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); } -- cgit v1.2.1 From 40176e196253b8b79156e6e8258f80fc7ea60903 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Feb 2008 12:56:44 +0100 Subject: Bug #34458 Extreneous use of templates in server code Replacing a template function with a normal static function. The template parameter, which previously was the class to find a binlogging function in, is now passed as a pointer to the actual binlogging function instead. The patch requires change of indention, but that is submitted as a separate patch. sql/handler.cc: Replacing template function with a normal static function. --- sql/handler.cc | 62 ++++++++++++++++++++-------------------------------------- 1 file changed, 21 insertions(+), 41 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 95d63740039..5b0a2693865 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3843,11 +3843,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) - table is not mysql.event */ -/* The Sun compiler cannot instantiate the template below if this is - declared static, but it works by putting it into an anonymous - namespace. */ -namespace { - bool check_table_binlog_row_based(THD *thd, TABLE *table) + static bool check_table_binlog_row_based(THD *thd, TABLE *table) { if (table->s->cached_row_logging_check == -1) { @@ -3864,7 +3860,6 @@ namespace { (thd->options & OPTION_BIN_LOG) && mysql_bin_log.is_open()); } -} /** @brief Write table maps for all (manually or automatically) locked tables @@ -3888,9 +3883,8 @@ namespace { THD::lock THD::locked_tables */ -namespace -{ - int write_locked_table_maps(THD *thd) + + static int write_locked_table_maps(THD *thd) { DBUG_ENTER("write_locked_table_maps"); DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx thd->locked_tables: 0x%lx " @@ -3935,10 +3929,14 @@ namespace DBUG_RETURN(0); } - template int - binlog_log_row(TABLE* table, - const uchar *before_record, - const uchar *after_record) + +typedef bool Log_func(THD*, TABLE*, bool, MY_BITMAP*, + uint, const uchar*, const uchar*); + + static int binlog_log_row(TABLE* table, + const uchar *before_record, + const uchar *after_record, + Log_func *log_func) { if (table->no_replicate) return 0; @@ -3965,15 +3963,10 @@ namespace { bitmap_set_all(&cols); if (likely(!(error= write_locked_table_maps(thd)))) - { - error= - RowsEventT::binlog_row_logging_function(thd, table, - table->file-> - has_transactions(), - &cols, table->s->fields, - before_record, - after_record); - } + error= (*log_func)(thd, table, table->file->has_transactions(), + &cols, table->s->fields, + before_record, after_record); + if (!use_bitbuf) bitmap_free(&cols); } @@ -3981,22 +3974,6 @@ namespace return error ? HA_ERR_RBR_LOGGING_FAILED : 0; } - /* - Instantiate the versions we need for the above template function, - because we have -fno-implicit-template as compiling option. - */ - - template int - binlog_log_row(TABLE *, const uchar *, const uchar *); - - template int - binlog_log_row(TABLE *, const uchar *, const uchar *); - - template int - binlog_log_row(TABLE *, const uchar *, const uchar *); -} - - int handler::ha_external_lock(THD *thd, int lock_type) { DBUG_ENTER("handler::ha_external_lock"); @@ -4041,10 +4018,11 @@ int handler::ha_reset() int handler::ha_write_row(uchar *buf) { int error; + Log_func *log_func= Write_rows_log_event::binlog_row_logging_function; DBUG_ENTER("handler::ha_write_row"); if (unlikely(error= write_row(buf))) DBUG_RETURN(error); - if (unlikely(error= binlog_log_row(table, 0, buf))) + if (unlikely(error= binlog_log_row(table, 0, buf, log_func))) DBUG_RETURN(error); /* purecov: inspected */ DBUG_RETURN(0); } @@ -4053,6 +4031,7 @@ int handler::ha_write_row(uchar *buf) int handler::ha_update_row(const uchar *old_data, uchar *new_data) { int error; + Log_func *log_func= Update_rows_log_event::binlog_row_logging_function; /* Some storage engines require that the new record is in record[0] @@ -4062,7 +4041,7 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) if (unlikely(error= update_row(old_data, new_data))) return error; - if (unlikely(error= binlog_log_row(table, old_data, new_data))) + if (unlikely(error= binlog_log_row(table, old_data, new_data, log_func))) return error; return 0; } @@ -4070,9 +4049,10 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) int handler::ha_delete_row(const uchar *buf) { int error; + Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function; if (unlikely(error= delete_row(buf))) return error; - if (unlikely(error= binlog_log_row(table, buf, 0))) + if (unlikely(error= binlog_log_row(table, buf, 0, log_func))) return error; return 0; } -- cgit v1.2.1 From 38354149c87dcb16a97c79de34ab48c80c10c499 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Feb 2008 16:03:54 +0400 Subject: Fix for bug #33304: Test 'func_group' hangs on Mac OS X 10.4 PowerPC 64-bit Problem: SLEEP(0) never returns on 64-bit Mac OS X due to a bug in pthread_cond_timedwait(). Fix: when given a very short timeout just return immediately. sql/item_func.cc: Fix for bug #33304: Test 'func_group' hangs on Mac OS X 10.4 PowerPC 64-bit - if given a very short timeout (< 10 mcs) just return from SLEEP(). --- sql/item_func.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 639e069d24e..e20b0762ea2 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3729,6 +3729,18 @@ longlong Item_func_sleep::val_int() DBUG_ASSERT(fixed == 1); double time= args[0]->val_real(); + /* + On 64-bit OSX pthread_cond_timedwait() waits forever + if passed abstime time has already been exceeded by + the system time. + When given a very short timeout (< 10 mcs) just return + immediately. + We assume that the lines between this test and the call + to pthread_cond_timedwait() will be executed in less than 0.00001 sec. + */ + if (time < 0.00001) + return 0; + set_timespec_nsec(abstime, (ulonglong)(time * ULL(1000000000))); pthread_cond_init(&cond, NULL); -- cgit v1.2.1 From 450ed5aea667515c2b7f076f2c1b0a2ca0e6e01e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Feb 2008 13:06:28 +0100 Subject: Bug #34458 Extreneous use of templates in server code Patch to remove white-space left over after removing anonymous namespace. sql/handler.cc: Removing indentation and whitespace. --- sql/handler.cc | 173 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 87 insertions(+), 86 deletions(-) (limited to 'sql') diff --git a/sql/handler.cc b/sql/handler.cc index 5b0a2693865..a7a3d8ef53f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3843,23 +3843,24 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) - table is not mysql.event */ - static bool check_table_binlog_row_based(THD *thd, TABLE *table) +static bool check_table_binlog_row_based(THD *thd, TABLE *table) +{ + if (table->s->cached_row_logging_check == -1) { - if (table->s->cached_row_logging_check == -1) - { - int const check(table->s->tmp_table == NO_TMP_TABLE && - binlog_filter->db_ok(table->s->db.str)); - table->s->cached_row_logging_check= check; - } + int const check(table->s->tmp_table == NO_TMP_TABLE && + binlog_filter->db_ok(table->s->db.str)); + table->s->cached_row_logging_check= check; + } - DBUG_ASSERT(table->s->cached_row_logging_check == 0 || - table->s->cached_row_logging_check == 1); + DBUG_ASSERT(table->s->cached_row_logging_check == 0 || + table->s->cached_row_logging_check == 1); + + return (thd->current_stmt_binlog_row_based && + table->s->cached_row_logging_check && + (thd->options & OPTION_BIN_LOG) && + mysql_bin_log.is_open()); +} - return (thd->current_stmt_binlog_row_based && - table->s->cached_row_logging_check && - (thd->options & OPTION_BIN_LOG) && - mysql_bin_log.is_open()); - } /** @brief Write table maps for all (manually or automatically) locked tables @@ -3874,7 +3875,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) that are locked by the thread 'thd'. Either manually locked (stored in THD::locked_tables) and automatically locked (stored in THD::lock) are considered. - + RETURN VALUE 0 All OK 1 Failed to write all table maps @@ -3884,95 +3885,95 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) THD::locked_tables */ - static int write_locked_table_maps(THD *thd) - { - DBUG_ENTER("write_locked_table_maps"); - DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx thd->locked_tables: 0x%lx " - "thd->extra_lock: 0x%lx", - (long) thd, (long) thd->lock, - (long) thd->locked_tables, (long) thd->extra_lock)); +static int write_locked_table_maps(THD *thd) +{ + DBUG_ENTER("write_locked_table_maps"); + DBUG_PRINT("enter", ("thd: 0x%lx thd->lock: 0x%lx thd->locked_tables: 0x%lx " + "thd->extra_lock: 0x%lx", + (long) thd, (long) thd->lock, + (long) thd->locked_tables, (long) thd->extra_lock)); - if (thd->get_binlog_table_maps() == 0) + if (thd->get_binlog_table_maps() == 0) + { + MYSQL_LOCK *locks[3]; + locks[0]= thd->extra_lock; + locks[1]= thd->lock; + locks[2]= thd->locked_tables; + for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i ) { - MYSQL_LOCK *locks[3]; - locks[0]= thd->extra_lock; - locks[1]= thd->lock; - locks[2]= thd->locked_tables; - for (uint i= 0 ; i < sizeof(locks)/sizeof(*locks) ; ++i ) + MYSQL_LOCK const *const lock= locks[i]; + if (lock == NULL) + continue; + + TABLE **const end_ptr= lock->table + lock->table_count; + for (TABLE **table_ptr= lock->table ; + table_ptr != end_ptr ; + ++table_ptr) { - MYSQL_LOCK const *const lock= locks[i]; - if (lock == NULL) - continue; - - TABLE **const end_ptr= lock->table + lock->table_count; - for (TABLE **table_ptr= lock->table ; - table_ptr != end_ptr ; - ++table_ptr) + TABLE *const table= *table_ptr; + DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str)); + if (table->current_lock == F_WRLCK && + check_table_binlog_row_based(thd, table)) { - TABLE *const table= *table_ptr; - DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str)); - if (table->current_lock == F_WRLCK && - check_table_binlog_row_based(thd, table)) - { - int const has_trans= table->file->has_transactions(); - int const error= thd->binlog_write_table_map(table, has_trans); - /* - If an error occurs, it is the responsibility of the caller to - roll back the transaction. - */ - if (unlikely(error)) - DBUG_RETURN(1); - } + int const has_trans= table->file->has_transactions(); + int const error= thd->binlog_write_table_map(table, has_trans); + /* + If an error occurs, it is the responsibility of the caller to + roll back the transaction. + */ + if (unlikely(error)) + DBUG_RETURN(1); } } } - DBUG_RETURN(0); } + DBUG_RETURN(0); +} typedef bool Log_func(THD*, TABLE*, bool, MY_BITMAP*, uint, const uchar*, const uchar*); - static int binlog_log_row(TABLE* table, - const uchar *before_record, - const uchar *after_record, - Log_func *log_func) +static int binlog_log_row(TABLE* table, + const uchar *before_record, + const uchar *after_record, + Log_func *log_func) +{ + if (table->no_replicate) + return 0; + bool error= 0; + THD *const thd= table->in_use; + + if (check_table_binlog_row_based(thd, table)) { - if (table->no_replicate) - return 0; - bool error= 0; - THD *const thd= table->in_use; + MY_BITMAP cols; + /* Potential buffer on the stack for the bitmap */ + uint32 bitbuf[BITMAP_STACKBUF_SIZE/sizeof(uint32)]; + uint n_fields= table->s->fields; + my_bool use_bitbuf= n_fields <= sizeof(bitbuf)*8; - if (check_table_binlog_row_based(thd, table)) + /* + If there are no table maps written to the binary log, this is + the first row handled in this statement. In that case, we need + to write table maps for all locked tables to the binary log. + */ + if (likely(!(error= bitmap_init(&cols, + use_bitbuf ? bitbuf : NULL, + (n_fields + 7) & ~7UL, + FALSE)))) { - MY_BITMAP cols; - /* Potential buffer on the stack for the bitmap */ - uint32 bitbuf[BITMAP_STACKBUF_SIZE/sizeof(uint32)]; - uint n_fields= table->s->fields; - my_bool use_bitbuf= n_fields <= sizeof(bitbuf)*8; - - /* - If there are no table maps written to the binary log, this is - the first row handled in this statement. In that case, we need - to write table maps for all locked tables to the binary log. - */ - if (likely(!(error= bitmap_init(&cols, - use_bitbuf ? bitbuf : NULL, - (n_fields + 7) & ~7UL, - FALSE)))) - { - bitmap_set_all(&cols); - if (likely(!(error= write_locked_table_maps(thd)))) - error= (*log_func)(thd, table, table->file->has_transactions(), - &cols, table->s->fields, - before_record, after_record); - - if (!use_bitbuf) - bitmap_free(&cols); - } + bitmap_set_all(&cols); + if (likely(!(error= write_locked_table_maps(thd)))) + error= (*log_func)(thd, table, table->file->has_transactions(), + &cols, table->s->fields, + before_record, after_record); + + if (!use_bitbuf) + bitmap_free(&cols); } - return error ? HA_ERR_RBR_LOGGING_FAILED : 0; } + return error ? HA_ERR_RBR_LOGGING_FAILED : 0; +} int handler::ha_external_lock(THD *thd, int lock_type) { -- cgit v1.2.1 From cc2e929ac4b787220118f6d4dc4a72b796bf4ea0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 15 Feb 2008 15:47:32 +0200 Subject: Bug #31887: DML Select statement not returning same results when executed in version 5 Zero fill is a field attribute only. So we can't always propagate constants for zerofill fields : the values and expression results don't have that flag. Fixed by converting the const value to a string and using that in const propagation when the context allows it. Disable const propagation for fields with ZEROFILL flag in all the other cases. mysql-test/r/compare.result: Bug #31887: test case mysql-test/t/compare.test: Bug #31887: test case sql/item.cc: Bug #31887: If the context allows conversion of an int constant to a zero-filled string constant put the string constant instead of the int constant when doing const propagation sql/mysql_priv.h: Bug #31887: a macro to get all the Field_num descendant fields. --- sql/item.cc | 31 +++++++++++++++++++++++++++++++ sql/mysql_priv.h | 1 + 2 files changed, 32 insertions(+) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 3555df40060..e3e17a3ceea 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -4072,6 +4072,30 @@ bool Item_field::subst_argument_checker(byte **arg) } +/** + Convert a numeric value to a zero-filled string + + @param[in,out] item the item to operate on + @param field The field that this value is equated to + + This function converts a numeric value to a string. In this conversion + the zero-fill flag of the field is taken into account. + This is required so the resulting string value can be used instead of + the field reference when propagating equalities. +*/ + +static void convert_zerofill_number_to_string(Item **item, Field_num *field) +{ + char buff[MAX_FIELD_WIDTH],*pos; + String tmp(buff,sizeof(buff), field->charset()), *res; + + res= (*item)->val_str(&tmp); + field->prepend_zeros(res); + pos= (char *) sql_strmake (res->ptr(), res->length()); + *item= new Item_string(pos, res->length(), field->charset()); +} + + /* Set a pointer to the multiple equality the field reference belongs to (if any) @@ -4120,6 +4144,13 @@ Item *Item_field::equal_fields_propagator(byte *arg) if (!item || (cmp_context != (Item_result)-1 && item->cmp_context != cmp_context)) item= this; + else if (field && (field->flags & ZEROFILL_FLAG) && IS_NUM(field->type())) + { + if (item && cmp_context != INT_RESULT) + convert_zerofill_number_to_string(&item, (Field_num *)field); + else + item= this; + } return item; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 47396748da6..821495ddecb 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -73,6 +73,7 @@ extern const char *primary_key_name; #include "mysql_com.h" #include #include "unireg.h" +#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR || (t) == FIELD_TYPE_NEWDECIMAL) void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size); gptr sql_alloc(unsigned size); -- cgit v1.2.1 From d6be1a9b957b47c2cf67590932629984c1ef5a14 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 17 Feb 2008 15:48:17 +0400 Subject: Bug #32942 now() - interval '7200' second NOT pre-calculated, causing "full table scan" Problem is not about intervals and doesn't actually cause 'full table scan'. We have an optimization for DISTINCT when we have 'DISTINCT field_from_first_join_table' we don't need to read all the rows from the JOIN-ed table if we found one conforming row. It stopped working in 5.0 as we return NESTED_LOOP_OK if we came upon that case in the evaluate_join_record() and that doesn't break the recordreading loop in sub_select(). Fixed by returning NESTED_LOOP_NO_MORE_ROWS in this case. mysql-test/r/select.result: Bug #32942 now() - interval '7200' second is NOT pre-calculated, causing "full table scan". test result mysql-test/t/select.test: Bug #32942 now() - interval '7200' second is NOT pre-calculated, causing "full table scan" test case sql/sql_select.cc: Bug #32942 now() - interval '7200' second NOT pre-calculated, causing "full table scan" return NESTED_LOOP_NO_MORE_ROWS when we don't need to read rows from this table anymore --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d6cb072ce9b..60ce01c9d89 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10791,7 +10791,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, we found a row, as no new rows can be added to the result. */ if (not_used_in_distinct && found_records != join->found_records) - return NESTED_LOOP_OK; + return NESTED_LOOP_NO_MORE_ROWS; } else join_tab->read_record.file->unlock_row(); -- cgit v1.2.1 From 9191052de50cf4859c93e108d484b3887256ec83 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 18 Feb 2008 14:35:44 +0300 Subject: Initialization order cleanups to get rid of warnings from the -Wreorder option added by the patch for bug#31326. --- sql/rpl_rli.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 03f790b934f..52656fe9973 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -33,12 +33,12 @@ Relay_log_info::Relay_log_info() :Slave_reporting_capability("SQL"), no_storage(FALSE), replicate_same_server_id(::replicate_same_server_id), info_fd(-1), cur_log_fd(-1), save_temporary_tables(0), - group_relay_log_pos(0), event_relay_log_pos(0), #if HAVE_purify is_fake(FALSE), #endif - cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0), - ignore_log_space_limit(0), last_master_timestamp(0), slave_skip_counter(0), + cur_log_old_open_count(0), group_relay_log_pos(0), event_relay_log_pos(0), + group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0), + last_master_timestamp(0), slave_skip_counter(0), abort_pos_wait(0), slave_run_id(0), sql_thd(0), inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE), until_log_pos(0), retried_trans(0), -- cgit v1.2.1 From 0ef346047d744225372dbb325ff9f398c64b0c2b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 18 Feb 2008 18:21:14 +0200 Subject: Fixed duplicate defition warning for bug 31887 --- sql/item.cc | 1 + sql/mysql_priv.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 049740f8538..c0d78aa4492 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -18,6 +18,7 @@ #pragma implementation // gcc: Class implementation #endif #include "mysql_priv.h" +#include #include #include "my_dir.h" #include "sp_rcontext.h" diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c0d4d6e2eb..ea552414d9a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -74,7 +74,6 @@ extern const char *primary_key_name; #include "mysql_com.h" #include #include "unireg.h" -#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR || (t) == FIELD_TYPE_NEWDECIMAL) void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size); void *sql_alloc(size_t); -- cgit v1.2.1 From 721d24124fee09a13da32cb49295fdfd45729592 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 12:37:39 +0100 Subject: Bug#31745 - crash handler does not work on Windows - Replace per-thread signal()'s with SetUnhandledExceptionFilter(). The only remaining signal() is for SIGABRT (default abort() handler in VS2005 is broken, i.e removes user exception filter) - remove MessageBox()'es from error handling code - Windows port for print_stacktrace() and write_core() - Cleanup, removed some unused functions sql/CMakeLists.txt: Implement stack tracing on and generating crash dumps on Windows sql/mysqld.cc: Correct signal handling on Windows. - For console events, like CTRL-C use SetConsoleCtrlHandler - For exceptions like access violation, use SetUnhandledExceptionFilter - For SIGABRT generate exception via __debugbreak() intrinsic if built with VS2005 and later , since default SIGABRT handler replaces unhandled exception filter specified by user - make provisions to debug exception filter, as it is not trivial (should be compiled with /DDEBUG_UNHANDLED_EXCEPTION_FILTER) sql/sql_parse.cc: Remove message box from windows signal handler. The only thread specific handler left is for SIGABRT, which is broken on VS2005 and later (user specified unhandled exception filter gets overwritten) sql/stacktrace.c: Stack tracing and generating crash dumps on Windows sql/stacktrace.h: Implement print_stacktrace and write_core on Windows --- sql/CMakeLists.txt | 2 +- sql/mysqld.cc | 225 ++++++++++++++++++++++++++++++++++--------- sql/sql_parse.cc | 19 +--- sql/stacktrace.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++- sql/stacktrace.h | 23 ++++- 5 files changed, 469 insertions(+), 75 deletions(-) (limited to 'sql') diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 84b042a91b1..9ea9874c1b1 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -48,7 +48,7 @@ ENDIF(DISABLE_GRANT_OPTIONS) ADD_EXECUTABLE(mysqld${MYSQLD_EXE_SUFFIX} ../sql-common/client.c derror.cc des_key_file.cc - discover.cc ../libmysql/errmsg.c field.cc field_conv.cc + discover.cc ../libmysql/errmsg.c field.cc stacktrace.c stacktrace.h field_conv.cc filesort.cc gstream.cc ha_blackhole.cc ha_archive.cc ha_heap.cc ha_myisam.cc ha_myisammrg.cc ha_innodb.cc ha_federated.cc ha_berkeley.cc diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 693b72f5c98..c0afd081846 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -138,6 +138,13 @@ extern "C" { // Because of SCO 3.2V4.2 #include #endif +#ifdef __WIN__ +#include +#define SIGNAL_FMT "exception 0x%x" +#else +#define SIGNAL_FMT "signal %d" +#endif + #ifdef __NETWARE__ #define zVOLSTATE_ACTIVE 6 #define zVOLSTATE_DEACTIVE 2 @@ -227,6 +234,7 @@ inline void set_proper_floating_point_mode() extern "C" int gethostname(char *name, int namelen); #endif +extern "C" sig_handler handle_segfault(int sig); /* Constants */ @@ -1031,9 +1039,6 @@ static void __cdecl kill_server(int sig_ptr) #endif close_connections(); if (sig != MYSQL_KILL_SIGNAL && -#ifdef __WIN__ - sig != SIGINT && /* Bug#18235 */ -#endif sig != 0) unireg_abort(1); /* purecov: inspected */ else @@ -1592,8 +1597,7 @@ static void network_init(void) FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); - MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe", - MB_OK|MB_ICONINFORMATION); + sql_perror((char *)lpMsgBuf); LocalFree(lpMsgBuf); unireg_abort(1); } @@ -1796,17 +1800,163 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused))) ******************************************************************************/ -#if defined(__WIN__) || defined(OS2) +#if defined(__WIN__) + + +/* + On Windows, we use native SetConsoleCtrlHandler for handle events like Ctrl-C + with graceful shutdown. + Also, we do not use signal(), but SetUnhandledExceptionFilter instead - as it + provides possibility to pass the exception to just-in-time debugger, collect + dumps and potentially also the exception and thread context used to output + callstack. +*/ + +static BOOL WINAPI console_event_handler( DWORD type ) +{ + DBUG_ENTER("console_event_handler"); + if(type == CTRL_C_EVENT) + { + /* + Do not shutdown before startup is finished and shutdown + thread is initialized. Otherwise there is a race condition + between main thread doing initialization and CTRL-C thread doing + cleanup, which can result into crash. + */ + if(hEventShutdown) + kill_mysql(); + else + sql_print_warning("CTRL-C ignored during startup"); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +/* + In Visual Studio 2005 and later, default SIGABRT handler will overwrite + any unhandled exception filter set by the application and will try to + call JIT debugger. This is not what we want, this we calling __debugbreak + to stop in debugger, if process is being debugged or to generate + EXCEPTION_BREAKPOINT and then handle_segfault will do its magic. +*/ + +#if (_MSC_VER >= 1400) +static void my_sigabrt_handler(int sig) +{ + __debugbreak(); +} +#endif /*_MSC_VER >=1400 */ + +void win_install_sigabrt_handler(void) +{ +#if (_MSC_VER >=1400) + /*abort() should not override our exception filter*/ + _set_abort_behavior(0,_CALL_REPORTFAULT); + signal(SIGABRT,my_sigabrt_handler); +#endif /* _MSC_VER >=1400 */ +} + +#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER +#define DEBUGGER_ATTACH_TIMEOUT 120 +/* + Wait for debugger to attach and break into debugger. If debugger is not attached, + resume after timeout. +*/ +static void wait_for_debugger(int timeout_sec) +{ + if(!IsDebuggerPresent()) + { + int i; + printf("Waiting for debugger to attach, pid=%u\n",GetCurrentProcessId()); + fflush(stdout); + for(i= 0; i < timeout_sec; i++) + { + Sleep(1000); + if(IsDebuggerPresent()) + { + /* Break into debugger */ + __debugbreak(); + return; + } + } + printf("pid=%u, debugger not attached after %d seconds, resuming\n",GetCurrentProcessId(), + timeout_sec); + fflush(stdout); + } +} +#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ + +LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) +{ + static BOOL first_time= TRUE; + if(!first_time) + { + /* + This routine can be called twice, typically + when detaching in JIT debugger. + Return EXCEPTION_EXECUTE_HANDLER to terminate process. + */ + return EXCEPTION_EXECUTE_HANDLER; + } + first_time= FALSE; +#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER + /* + Unfortunately there is no clean way to debug unhandled exception filters, + as debugger does not stop there(also documented in MSDN) + To overcome, one could put a MessageBox, but this will not work in service. + Better solution is to print error message and sleep some minutes + until debugger is attached + */ + wait_for_debugger(DEBUGGER_ATTACH_TIMEOUT); +#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ + __try + { + set_exception_pointers(ex_pointers); + handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DWORD written; + const char msg[] = "Got exception in exception handler!\n"; + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg, sizeof(msg)-1, + &written,NULL); + } + /* + Return EXCEPTION_CONTINUE_SEARCH to give JIT debugger + (drwtsn32 or vsjitdebugger) possibility to attach, + if JIT debugger is configured. + Windows Error reporting might generate a dump here. + */ + return EXCEPTION_CONTINUE_SEARCH; +} + + static void init_signals(void) { - int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ; - for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++) - signal(signals[i], kill_server) ; -#if defined(__WIN__) - signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT -#else - signal(SIGBREAK, kill_server); -#endif + win_install_sigabrt_handler(); + if(opt_console) + SetConsoleCtrlHandler(console_event_handler,TRUE); + else + { + /* Avoid MessageBox()es*/ + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + + /* + Do not use SEM_NOGPFAULTERRORBOX in the following SetErrorMode (), + because it would prevent JIT debugger and Windows error reporting + from working. We need WER or JIT-debugging, since our own unhandled + exception filter is not guaranteed to work in all situation + (like heap corruption or stack overflow) + */ + SetErrorMode(SetErrorMode(0)|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + } + SetUnhandledExceptionFilter(my_unhandler_exception_filter); } static void start_signal_handler(void) @@ -2094,8 +2244,8 @@ static void start_signal_handler(void) static void check_data_home(const char *path) {} +#endif /*__WIN__ || __NETWARE || __EMX__*/ -#else /* if ! __WIN__ && ! __EMX__ */ #ifdef HAVE_LINUXTHREADS #define UNSAFE_DEFAULT_LINUX_THREADS 200 @@ -2115,7 +2265,7 @@ extern "C" sig_handler handle_segfault(int sig) */ if (segfaulted) { - fprintf(stderr, "Fatal signal %d while backtracing\n", sig); + fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig); exit(1); } @@ -2125,7 +2275,7 @@ extern "C" sig_handler handle_segfault(int sig) localtime_r(&curr_time, &tm); fprintf(stderr,"\ -%02d%02d%02d %2d:%02d:%02d - mysqld got signal %d;\n\ +%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\ This could be because you hit a bug. It is also possible that this binary\n\ or one of the libraries it was linked against is corrupt, improperly built,\n\ or misconfigured. This error can also be caused by malfunctioning hardware.\n", @@ -2166,6 +2316,10 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", if (!(test_flags & TEST_NO_STACKTRACE)) { fprintf(stderr,"thd=%p\n",thd); + fprintf(stderr,"\ +Attempting backtrace. You can use the following information to find out\n\ +where mysqld died. If you see no messages after this, something went\n\ +terribly wrong...\n"); print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0, thread_stack); } @@ -2214,15 +2368,22 @@ of those buggy OS calls. You should consider whether you really need the\n\ bugs.\n"); } +#ifdef HAVE_WRITE_CORE if (test_flags & TEST_CORE_ON_SIGNAL) { fprintf(stderr, "Writing a core file\n"); fflush(stderr); write_core(sig); } +#endif + +#ifndef __WIN__ + /* On Windows, do not terminate, but pass control to exception filter */ exit(1); +#endif } +#if !defined(__WIN__) && !defined(__NETWARE__) && !defined(__EMX__) #ifndef SA_RESETHAND #define SA_RESETHAND 0 #endif @@ -2567,19 +2728,6 @@ static void my_str_free_mysqld(void *ptr) #ifdef __WIN__ - -struct utsname -{ - char nodename[FN_REFLEN]; -}; - - -int uname(struct utsname *a) -{ - return -1; -} - - pthread_handler_t handle_shutdown(void *arg) { MSG msg; @@ -2593,18 +2741,6 @@ pthread_handler_t handle_shutdown(void *arg) kill_server(MYSQL_KILL_SIGNAL); return 0; } - - -int STDCALL handle_kill(ulong ctrl_type) -{ - if (ctrl_type == CTRL_CLOSE_EVENT || - ctrl_type == CTRL_SHUTDOWN_EVENT) - { - kill_server(MYSQL_KILL_SIGNAL); - return TRUE; - } - return FALSE; -} #endif @@ -3633,11 +3769,6 @@ we force server id to 2, but this MySQL server will not act as a slave."); freopen(log_error_file,"a+",stderr); FreeConsole(); // Remove window } - else - { - /* Don't show error dialog box when on foreground: it stops the server */ - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); - } #endif /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8af79d77fa1..493cc1a1a7e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -98,22 +98,7 @@ static bool do_command(THD *thd); #endif // EMBEDDED_LIBRARY #ifdef __WIN__ -static void test_signal(int sig_ptr) -{ -#if !defined( DBUG_OFF) - MessageBox(NULL,"Test signal","DBUG",MB_OK); -#endif -#if defined(OS2) - fprintf(stderr, "Test signal %d\n", sig_ptr); - fflush(stderr); -#endif -} -static void init_signals(void) -{ - int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; - for (int i=0 ; i < 7 ; i++) - signal( signals[i], test_signal) ; -} +extern void win_install_sigabrt_handler(void); #endif static void unlock_locked_tables(THD *thd) @@ -1124,7 +1109,7 @@ pthread_handler_t handle_one_connection(void *arg) /* now that we've called my_thread_init(), it is safe to call DBUG_* */ #if defined(__WIN__) - init_signals(); + win_install_sigabrt_handler(); #elif !defined(OS2) && !defined(__NETWARE__) sigset_t set; VOID(sigemptyset(&set)); // Get mask in use diff --git a/sql/stacktrace.c b/sql/stacktrace.c index c947beafac3..ce91d63d3f7 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -13,11 +13,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/ +#define DONT_DEFINE_VOID 1 + #include #include "stacktrace.h" + +#ifndef __WIN__ #include #include - #ifdef HAVE_STACKTRACE #include #include @@ -118,10 +122,7 @@ void print_stacktrace(gptr stack_bottom, ulong thread_stack) #endif LINT_INIT(fp); - fprintf(stderr,"\ -Attempting backtrace. You can use the following information to find out\n\ -where mysqld died. If you see no messages after this, something went\n\ -terribly wrong...\n"); + #ifdef __i386__ __asm __volatile__ ("movl %%ebp,%0" :"=r"(fp) @@ -257,3 +258,267 @@ void write_core(int sig) #endif } #endif +#else /* __WIN__*/ + +#include + +/* + Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll) + We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000) + is missing some important functions like functions StackWalk64 or MinidumpWriteDump. + Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress. +*/ + +typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions); +typedef BOOL (WINAPI *SymGetModuleInfo64_FctType) + (HANDLE,DWORD64,PIMAGEHLP_MODULE64) ; +typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType) + (HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ; +typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType) + (HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64); +typedef BOOL (WINAPI *SymInitialize_FctType) + (HANDLE,PSTR,BOOL); +typedef BOOL (WINAPI *StackWalk64_FctType) + (DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64, + PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 , + PTRANSLATE_ADDRESS_ROUTINE64); +typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)( + IN HANDLE hProcess, + IN DWORD ProcessId, + IN HANDLE hFile, + IN MINIDUMP_TYPE DumpType, + IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL + IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL + IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL + ); + +static SymSetOptions_FctType pSymSetOptions; +static SymGetModuleInfo64_FctType pSymGetModuleInfo64; +static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64; +static SymInitialize_FctType pSymInitialize; +static StackWalk64_FctType pStackWalk64; +static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64; +static MiniDumpWriteDump_FctType pMiniDumpWriteDump; + +static EXCEPTION_POINTERS *exception_ptrs; + +#define MODULE64_SIZE_WINXP 576 +#define STACKWALK_MAX_FRAMES 64 + +/* + Dynamically load dbghelp functions +*/ +BOOL init_dbghelp_functions() +{ + static BOOL first_time= TRUE; + static BOOL rc; + HMODULE hDbghlp; + + if(first_time) + { + first_time= FALSE; + hDbghlp= LoadLibrary("dbghelp"); + if(!hDbghlp) + { + rc= FALSE; + return rc; + } + pSymSetOptions= (SymSetOptions_FctType) + GetProcAddress(hDbghlp,"SymSetOptions"); + pSymInitialize= (SymInitialize_FctType) + GetProcAddress(hDbghlp,"SymInitialize"); + pSymGetModuleInfo64= (SymGetModuleInfo64_FctType) + GetProcAddress(hDbghlp,"SymGetModuleInfo64"); + pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType) + GetProcAddress(hDbghlp,"SymGetLineFromAddr64"); + pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType) + GetProcAddress(hDbghlp,"SymGetSymFromAddr64"); + pStackWalk64= (StackWalk64_FctType) + GetProcAddress(hDbghlp,"StackWalk64"); + pMiniDumpWriteDump = (MiniDumpWriteDump_FctType) + GetProcAddress(hDbghlp,"MiniDumpWriteDump"); + + rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64 + && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64); + } + return rc; +} + +void set_exception_pointers(EXCEPTION_POINTERS *ep) +{ + exception_ptrs = ep; +} + +/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/ +#ifndef SYMOPT_NO_PROMPTS +#define SYMOPT_NO_PROMPTS 0 +#endif + +void print_stacktrace(gptr unused1, ulong unused2) +{ + HANDLE hProcess= GetCurrentProcess(); + HANDLE hThread= GetCurrentThread(); + static IMAGEHLP_MODULE64 module= {sizeof(module)}; + static IMAGEHLP_SYMBOL64_PACKAGE package; + DWORD64 addr; + DWORD machine; + int i; + CONTEXT context; + STACKFRAME64 frame={0}; + + if(!exception_ptrs || !init_dbghelp_functions()) + return; + + /* Copy context, as stackwalking on original will unwind the stack */ + context = *(exception_ptrs->ContextRecord); + /*Initialize symbols.*/ + pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG); + pSymInitialize(hProcess,NULL,TRUE); + + /*Prepare stackframe for the first StackWalk64 call*/ + frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat; +#if (defined _M_IX86) + machine= IMAGE_FILE_MACHINE_I386; + frame.AddrFrame.Offset= context.Ebp; + frame.AddrPC.Offset= context.Eip; + frame.AddrStack.Offset= context.Esp; +#elif (defined _M_X64) + machine = IMAGE_FILE_MACHINE_AMD64; + frame.AddrFrame.Offset= context.Rbp; + frame.AddrPC.Offset= context.Rip; + frame.AddrStack.Offset= context.Rsp; +#else + /*There is currently no need to support IA64*/ +#pragma error ("unsupported architecture") +#endif + + package.sym.SizeOfStruct= sizeof(package.sym); + package.sym.MaxNameLength= sizeof(package.name); + + /*Walk the stack, output useful information*/ + for(i= 0; i< STACKWALK_MAX_FRAMES;i++) + { + DWORD64 function_offset= 0; + DWORD line_offset= 0; + IMAGEHLP_LINE64 line= {sizeof(line)}; + BOOL have_module= FALSE; + BOOL have_symbol= FALSE; + BOOL have_source= FALSE; + + if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0)) + break; + addr= frame.AddrPC.Offset; + + have_module= pSymGetModuleInfo64(hProcess,addr,&module); +#ifdef _M_IX86 + if(!have_module) + { + /* + ModuleInfo structure has been "compatibly" extended in releases after XP, + and its size was increased. To make XP dbghelp.dll function + happy, pretend passing the old structure. + */ + module.SizeOfStruct= MODULE64_SIZE_WINXP; + have_module= pSymGetModuleInfo64(hProcess, addr, &module); + } +#endif + + have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset, + &(package.sym)); + have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line); + + fprintf(stderr, "%p ", addr); + if(have_module) + { + char *base_image_name= strrchr(module.ImageName, '\\'); + if(base_image_name) + base_image_name++; + else + base_image_name= module.ImageName; + fprintf(stderr, "%s!", base_image_name); + } + if(have_symbol) + fprintf(stderr, "%s()", package.sym.Name); + else if(have_module) + fprintf(stderr, "???"); + + if(have_source) + { + char *base_file_name= strrchr(line.FileName, '\\'); + if(base_file_name) + base_file_name++; + else + base_file_name= line.FileName; + fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber); + } + fprintf(stderr, "\n"); + } + fflush(stderr); +} + + +/* + Write dump. The dump is created in current directory, + file name is constructed from executable name plus + ".dmp" extension +*/ +void write_core(int unused) +{ + char path[MAX_PATH]; + char dump_fname[MAX_PATH]= "core.dmp"; + MINIDUMP_EXCEPTION_INFORMATION info; + HANDLE hFile; + + if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump) + return; + + info.ExceptionPointers= exception_ptrs; + info.ClientPointers= FALSE; + info.ThreadId= GetCurrentThreadId(); + + if(GetModuleFileName(NULL, path, sizeof(path))) + { + _splitpath(path, NULL, NULL,dump_fname,NULL); + strncat(dump_fname, ".dmp", sizeof(dump_fname)); + } + + hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, 0); + if(hFile) + { + /* Create minidump */ + if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), + hFile, MiniDumpNormal, &info, 0, 0)) + { + fprintf(stderr, "Minidump written to %s\n", + _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname); + } + else + { + fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n", + GetLastError()); + } + CloseHandle(hFile); + } + else + { + fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname, + GetLastError()); + } + fflush(stderr); +} + + +void safe_print_str(const char *name, const char *val, int len) +{ + fprintf(stderr,"%s at %p", name, val); + __try + { + fprintf(stderr,"=%.*s\n", len, val); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + fprintf(stderr,"is an invalid string pointer\n"); + } +} +#endif /*__WIN__*/ diff --git a/sql/stacktrace.h b/sql/stacktrace.h index f5c92e54e1c..e5e17cc5b9b 100644 --- a/sql/stacktrace.h +++ b/sql/stacktrace.h @@ -29,20 +29,33 @@ extern char* heap_start; heap_start = (char*) &__bss_start; \ check_thread_lib(); \ } while(0); +void check_thread_lib(void); +#endif /* defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ +#elif defined (__WIN__) +#define HAVE_STACKTRACE +extern void set_exception_pointers(EXCEPTION_POINTERS *ep); +#define init_stacktrace() {} +#endif + +#ifdef HAVE_STACKTRACE void print_stacktrace(gptr stack_bottom, ulong thread_stack); void safe_print_str(const char* name, const char* val, int max_len); -void check_thread_lib(void); -#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */ -#endif /* TARGET_OS_LINUX */ - +#else /* Define empty prototypes for functions that are not implemented */ -#ifndef HAVE_STACKTRACE #define init_stacktrace() {} #define print_stacktrace(A,B) {} #define safe_print_str(A,B,C) {} #endif /* HAVE_STACKTRACE */ + +#if !defined(__NETWARE__) +#define HAVE_WRITE_CORE +#endif + +#ifdef HAVE_WRITE_CORE void write_core(int sig); +#endif + #ifdef __cplusplus } -- cgit v1.2.1 From 526798dbb55c79b62e795a1cf40062030e2342bd Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 14:43:01 +0300 Subject: A fix and a test case for Bug#12713 "Error in a stored function called from a SELECT doesn't cause ROLLBACK of statem". The idea of the fix is to ensure that we always commit the current statement at the end of dispatch_command(). In order to not issue redundant disc syncs, an optimization of the two-phase commit protocol is implemented to bypass the two phase commit if the transaction is read-only. mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: Update test results. mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result: Update test results. mysql-test/suite/rpl_ndb/t/disabled.def: Disable the tests, for which this changeset reveals a bug: the injector thread does not always add 'statement commit' to the rows injected in circular replication set up. To be investigated separately. sql/ha_ndbcluster_binlog.cc: Add close_thread_tables() to run_query: this ensures that all tables are closed and there is no pending statement transaction. sql/handler.cc: Implement optimisation of read-only transactions. If a transaction consists only of DML statements that do not change data, we do not perform a two-phase commit for it (run one phase commit only). sql/handler.h: Implement optimisation of read-only transactions. If a transaction consists only of DML statements that do not change data, we do not perform a two-phase commit for it (run one phase commit only). sql/log.cc: Mark the binlog transaction read-write whenever it's started. We never read from binlog, so it's safe and least intrusive to add this mark up here. sql/log_event.cc: Update to the new layout of thd->transaction. sql/rpl_injector.cc: Always commit statement transaction before committing the global one. sql/sp.cc: Ad comments. sql/sp_head.cc: Add comments. sql/sql_base.cc: Commit transaction at the end of the statement. Always. sql/sql_class.cc: Update thd_ha_data to return the right pointer in the new layout. Fix select_dumpvar::send_data to properly return operation status. A test case from commit.inc would lead to an assertion failure in the diagnostics area (double assignment). Not test otherwise by the test suite. sql/sql_class.h: Implement a new layout of storage engine transaction info in which it is easy to access all members related to the handlerton only based on ht->slot. sql/sql_cursor.cc: Update to the new layout of thd->transaction. sql/sql_delete.cc: Remove wrong and now redundant calls to ha_autocommit_or_rollback. The transaction is committed in one place, at the end of the statement. Remove calls to mysql_unlock_tables, since some engines count locks and commit statement transaction in unlock_tables(), which essentially equates mysql_unlock_tables to ha_autocommit_or_rollback. Previously it was necessary to unlock tables soon because we wanted to avoid sending of 'ok' packet to the client under locked tables. This is no longer necessary, since OK packet is also sent from one place at the end of transaction. sql/sql_do.cc: Add DO always clears the error, we must rollback the current statement before this happens. Otherwise the statement will be committed, and not rolled back in the end. sql/sql_insert.cc: Remove wrong and now redundant calls to ha_autocommit_or_rollback. The transaction is committed in one place, at the end of the statement. Remove calls to mysql_unlock_tables, since some engines count locks and commit statement transaction in unlock_tables(), which essentially equates mysql_unlock_tables to ha_autocommit_or_rollback. Previously it was necessary to unlock tables soon because we wanted to avoid sending of 'ok' packet to the client under locked tables. This is no longer necessary, since OK packet is also sent from one place at the end of transaction. sql/sql_load.cc: Remove wrong and now redundant calls to ha_autocommit_or_rollback. The transaction is committed in one place, at the end of the statement. Remove calls to mysql_unlock_tables, since some engines count locks and commit statement transaction in unlock_tables(), which essentially equates mysql_unlock_tables to ha_autocommit_or_rollback. Previously it was necessary to unlock tables soon because we wanted to avoid sending of 'ok' packet to the client under locked tables. This is no longer necessary, since OK packet is also sent from one place at the end of transaction. sql/sql_parse.cc: Implement optimisation of read-only transactions: bypass 2-phase commit for them. Always commit statement transaction before commiting the global one. Fix an unrelated crash in check_table_access, when called from information_schema. sql/sql_partition.cc: Partitions commit at the end of a DDL operation. Make sure that send_ok() is done only if the commit has succeeded. sql/sql_table.cc: Use ha_autocommit_or_rollback and end_active_trans everywhere. Add end_trans to mysql_admin_table, so that it leaves no pending transaction. sql/sql_udf.cc: Remvove a redundant call to close_thread_tables() sql/sql_update.cc: Remove wrong and now redundant calls to ha_autocommit_or_rollback. The transaction is committed in one place, at the end of the statement. Remove calls to mysql_unlock_tables, since some engines count locks and commit statement transaction in unlock_tables(), which essentially equates mysql_unlock_tables to ha_autocommit_or_rollback. Previously it was necessary to unlock tables soon because we wanted to avoid sending of 'ok' packet to the client under locked tables. This is no longer necessary, since OK packet is also sent from one place at the end of transaction. mysql-test/include/commit.inc: New BitKeeper file ``mysql-test/include/commit.inc'' mysql-test/r/commit_1innodb.result: New BitKeeper file ``mysql-test/r/commit_1innodb.result'' mysql-test/t/commit_1innodb.test: New BitKeeper file ``mysql-test/t/commit_1innodb.test'' --- sql/ha_ndbcluster_binlog.cc | 1 + sql/handler.cc | 615 +++++++++++++++++++++++++++++++++++++++----- sql/handler.h | 122 ++++++++- sql/log.cc | 10 + sql/log_event.cc | 2 +- sql/rpl_injector.cc | 20 ++ sql/sp.cc | 20 +- sql/sp_head.cc | 1 + sql/sql_base.cc | 58 ++--- sql/sql_class.cc | 4 +- sql/sql_class.h | 32 ++- sql/sql_cursor.cc | 5 +- sql/sql_delete.cc | 38 ++- sql/sql_do.cc | 12 +- sql/sql_insert.cc | 42 ++- sql/sql_load.cc | 10 - sql/sql_parse.cc | 27 +- sql/sql_partition.cc | 40 +-- sql/sql_table.cc | 21 +- sql/sql_udf.cc | 9 +- sql/sql_update.cc | 29 +-- 21 files changed, 875 insertions(+), 243 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 07b0d907229..f5fda16b391 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -283,6 +283,7 @@ static void run_query(THD *thd, char *buf, char *end, thd_ndb->m_error_code, (int) thd->is_error(), thd->is_slave_error); } + close_thread_tables(thd); /* XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command() can not be called from within a statement, and diff --git a/sql/handler.cc b/sql/handler.cc index 95d63740039..d831a1c53a0 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -575,6 +575,295 @@ void ha_close_connection(THD* thd) /* ======================================================================== ======================= TRANSACTIONS ===================================*/ +/** + Transaction handling in the server + ================================== + + In each client connection, MySQL maintains two transactional + states: + - a statement transaction, + - a standard, also called normal transaction. + + Historical note + --------------- + "Statement transaction" is a non-standard term that comes + from the times when MySQL supported BerkeleyDB storage engine. + + First of all, it should be said that in BerkeleyDB auto-commit + mode auto-commits operations that are atomic to the storage + engine itself, such as a write of a record, and are too + high-granular to be atomic from the application perspective + (MySQL). One SQL statement could involve many BerkeleyDB + auto-committed operations and thus BerkeleyDB auto-commit was of + little use to MySQL. + + Secondly, instead of SQL standard savepoints, BerkeleyDB + provided the concept of "nested transactions". In a nutshell, + transactions could be arbitrarily nested, but when the parent + transaction was committed or aborted, all its child (nested) + transactions were handled committed or aborted as well. + Commit of a nested transaction, in turn, made its changes + visible, but not durable: it destroyed the nested transaction, + all its changes would become available to the parent and + currently active nested transactions of this parent. + + So the mechanism of nested transactions was employed to + provide "all or nothing" guarantee of SQL statements + required by the standard. + A nested transaction would be created at start of each SQL + statement, and destroyed (committed or aborted) at statement + end. Such nested transaction was internally referred to as + a "statement transaction" and gave birth to the term. + + + + Since then a statement transaction is started for each statement + that accesses transactional tables or uses the binary log. If + the statement succeeds, the statement transaction is committed. + If the statement fails, the transaction is rolled back. Commits + of statement transactions are not durable -- each such + transaction is nested in the normal transaction, and if the + normal transaction is rolled back, the effects of all enclosed + statement transactions are undone as well. Technically, + a statement transaction can be viewed as a savepoint which is + maintained automatically in order to make effects of one + statement atomic. + + The normal transaction is started by the user and is ended + usually upon a user request as well. The normal transaction + encloses transactions of all statements issued between + its beginning and its end. + In autocommit mode, the normal transaction is equivalent + to the statement transaction. + + Since MySQL supports PSEA (pluggable storage engine + architecture), more than one transactional engine can be + active at a time. Hence transactions, from the server + point of view, are always distributed. In particular, + transactional state is maintained independently for each + engine. In order to commit a transaction the two phase + commit protocol is employed. + + Not all statements are executed in context of a transaction. + Administrative and status information statements do not modify + engine data, and thus do not start a statement transaction and + also have no effect on the normal transaction. Examples of such + statements are SHOW STATUS and RESET SLAVE. + + Similarly DDL statements are not transactional, + and therefore a transaction is [almost] never started for a DDL + statement. The difference between a DDL statement and a purely + administrative statement though is that a DDL statement always + commits the current transaction before proceeding, if there is + any. + + At last, SQL statements that work with non-transactional + engines also have no effect on the transaction state of the + connection. Even though they are written to the binary log, + and the binary log is, overall, transactional, the writes + are done in "write-through" mode, directly to the binlog + file, followed with a OS cache sync, in other words, + bypassing the binlog undo log (translog). + They do not commit the current normal transaction. + A failure of a statement that uses non-transactional tables + would cause a rollback of the statement transaction, but + in case there no non-transactional tables are used, + no statement transaction is started. + + Data layout + ----------- + + The server stores its transaction-related data in + thd->transaction. This structure has two members of type + THD_TRANS. These members correspond to the statement and + normal transactions respectively: + + - thd->transaction.stmt contains a list of engines + that are participating in the given statement + - thd->transaction.all contains a list of engines that + have participated in any of the statement transactions started + within the context of the normal transaction. + Each element of the list contains a pointer to the storage + engine, engine-specific transactional data, and engine-specific + transaction flags. + + In autocommit mode thd->transaction.all is empty. + Instead, data of thd->transaction.stmt is + used to commit/rollback the normal transaction. + + The list of registered engines has a few important properties: + - no engine is registered in the list twice + - engines are present in the list a reverse temporal order -- + new participants are always added to the beginning of the list. + + Transaction life cycle + ---------------------- + + When a new connection is established, thd->transaction + members are initialized to an empty state. + If a statement uses any tables, all affected engines + are registered in the statement engine list. In + non-autocommit mode, the same engines are registered in + the normal transaction list. + At the end of the statement, the server issues a commit + or a roll back for all engines in the statement list. + At this point transaction flags of an engine, if any, are + propagated from the statement list to the list of the normal + transaction. + When commit/rollback is finished, the statement list is + cleared. It will be filled in again by the next statement, + and emptied again at the next statement's end. + + The normal transaction is committed in a similar way + (by going over all engines in thd->transaction.all list) + but at different times: + - upon COMMIT SQL statement is issued by the user + - implicitly, by the server, at the beginning of a DDL statement + or SET AUTOCOMMIT={0|1} statement. + + The normal transaction can be rolled back as well: + - if the user has requested so, by issuing ROLLBACK SQL + statement + - if one of the storage engines requested a rollback + by setting thd->transaction_rollback_request. This may + happen in case, e.g., when the transaction in the engine was + chosen a victim of the internal deadlock resolution algorithm + and rolled back internally. When such a situation happens, there + is little the server can do and the only option is to rollback + transactions in all other participating engines. In this case + the rollback is accompanied by an error sent to the user. + + As follows from the use cases above, the normal transaction + is never committed when there is an outstanding statement + transaction. In most cases there is no conflict, since + commits of the normal transaction are issued by a stand-alone + administrative or DDL statement, thus no outstanding statement + transaction of the previous statement exists. Besides, + all statements that manipulate with the normal transaction + are prohibited in stored functions and triggers, therefore + no conflicting situation can occur in a sub-statement either. + The remaining rare cases when the server explicitly has + to commit the statement transaction prior to committing the normal + one cover error-handling scenarios (see for example + SQLCOM_LOCK_TABLES). + + When committing a statement or a normal transaction, the server + either uses the two-phase commit protocol, or issues a commit + in each engine independently. The two-phase commit protocol + is used only if: + - all participating engines support two-phase commit (provide + handlerton::prepare PSEA API call) and + - transactions in at least two engines modify data (i.e. are + not read-only). + + Note that the two phase commit is used for + statement transactions, even though they are not durable anyway. + This is done to ensure logical consistency of data in a multiple- + engine transaction. + For example, imagine that some day MySQL supports unique + constraint checks deferred till the end of statement. In such + case a commit in one of the engines may yield ER_DUP_KEY, + and MySQL should be able to gracefully abort statement + transactions of other participants. + + After the normal transaction has been committed, + thd->transaction.all list is cleared. + + When a connection is closed, the current normal transaction, if + any, is rolled back. + + Roles and responsibilities + -------------------------- + + The server has no way to know that an engine participates in + the statement and a transaction has been started + in it unless the engine says so. Thus, in order to be + a part of a transaction, the engine must "register" itself. + This is done by invoking trans_register_ha() server call. + Normally the engine registers itself whenever handler::external_lock() + is called. trans_register_ha() can be invoked many times: if + an engine is already registered, the call does nothing. + In case autocommit is not set, the engine must register itself + twice -- both in the statement list and in the normal transaction + list. + In which list to register is a parameter of trans_register_ha(). + + Note, that although the registration interface in itself is + fairly clear, the current usage practice often leads to undesired + effects. E.g. since a call to trans_register_ha() in most engines + is embedded into implementation of handler::external_lock(), some + DDL statements start a transaction (at least from the server + point of view) even though they are not expected to. E.g. + CREATE TABLE does not start a transaction, since + handler::external_lock() is never called during CREATE TABLE. But + CREATE TABLE ... SELECT does, since handler::external_lock() is + called for the table that is being selected from. This has no + practical effects currently, but must be kept in mind + nevertheless. + + Once an engine is registered, the server will do the rest + of the work. + + During statement execution, whenever any of data-modifying + PSEA API methods is used, e.g. handler::write_row() or + handler::update_row(), the read-write flag is raised in the + statement transaction for the involved engine. + Currently All PSEA calls are "traced", and the data can not be + changed in a way other than issuing a PSEA call. Important: + unless this invariant is preserved the server will not know that + a transaction in a given engine is read-write and will not + involve the two-phase commit protocol! + + At the end of a statement, server call + ha_autocommit_or_rollback() is invoked. This call in turn + invokes handlerton::prepare() for every involved engine. + Prepare is followed by a call to handlerton::commit_one_phase() + If a one-phase commit will suffice, handlerton::prepare() is not + invoked and the server only calls handlerton::commit_one_phase(). + At statement commit, the statement-related read-write engine + flag is propagated to the corresponding flag in the normal + transaction. When the commit is complete, the list of registered + engines is cleared. + + Rollback is handled in a similar fashion. + + Additional notes on DDL and the normal transaction. + --------------------------------------------------- + + DDLs and operations with non-transactional engines + do not "register" in thd->transaction lists, and thus do not + modify the transaction state. Besides, each DDL in + MySQL is prefixed with an implicit normal transaction commit + (a call to end_active_trans()), and thus leaves nothing + to modify. + However, as it has been pointed out with CREATE TABLE .. SELECT, + some DDL statements can start a *new* transaction. + + Behaviour of the server in this case is currently badly + defined. + DDL statements use a form of "semantic" logging + to maintain atomicity: if CREATE TABLE .. SELECT failed, + the newly created table is deleted. + In addition, some DDL statements issue interim transaction + commits: e.g. ALTER TABLE issues a commit after data is copied + from the original table to the internal temporary table. Other + statements, e.g. CREATE TABLE ... SELECT do not always commit + after itself. + And finally there is a group of DDL statements such as + RENAME/DROP TABLE that doesn't start a new transaction + and doesn't commit. + + This diversity makes it hard to say what will happen if + by chance a stored function is invoked during a DDL -- + whether any modifications it makes will be committed or not + is not clear. Fortunately, SQL grammar of few DDLs allows + invocation of a stored function. + + A consistent behaviour is perhaps to always commit the normal + transaction after all DDLs, just like the statement transaction + is always committed at the end of all statements. +*/ + /** Register a storage engine for a transaction. @@ -592,7 +881,7 @@ void ha_close_connection(THD* thd) void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) { THD_TRANS *trans; - handlerton **ht; + Ha_trx_info *ha_info; DBUG_ENTER("trans_register_ha"); DBUG_PRINT("enter",("%s", all ? "all" : "stmt")); @@ -604,12 +893,13 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg) else trans= &thd->transaction.stmt; - for (ht=trans->ht; *ht; ht++) - if (*ht == ht_arg) - DBUG_VOID_RETURN; /* already registered, return */ + ha_info= thd->ha_data[ht_arg->slot].ha_info + static_cast(all); + + if (ha_info->is_started()) + DBUG_VOID_RETURN; /* already registered, return */ + + ha_info->register_ha(trans, ht_arg); - trans->ht[trans->nht++]=ht_arg; - DBUG_ASSERT(*ht == ht_arg); trans->no_2pc|=(ht_arg->prepare==0); if (thd->transaction.xid_state.xid.is_null()) thd->transaction.xid_state.xid.set(thd->query_id); @@ -626,18 +916,19 @@ int ha_prepare(THD *thd) { int error=0, all=1; THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; - handlerton **ht=trans->ht; + Ha_trx_info *ha_info= trans->ha_list; DBUG_ENTER("ha_prepare"); #ifdef USING_TRANSACTIONS - if (trans->nht) + if (ha_info) { - for (; *ht; ht++) + for (; ha_info; ha_info= ha_info->next()) { int err; + handlerton *ht= ha_info->ht(); status_var_increment(thd->status_var.ha_prepare_count); - if ((*ht)->prepare) + if (ht->prepare) { - if ((err= (*(*ht)->prepare)(*ht, thd, all))) + if ((err= ht->prepare(ht, thd, all))) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); ha_rollback_trans(thd, all); @@ -649,7 +940,7 @@ int ha_prepare(THD *thd) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), - ha_resolve_storage_engine_name(*ht)); + ha_resolve_storage_engine_name(ht)); } } } @@ -657,6 +948,62 @@ int ha_prepare(THD *thd) DBUG_RETURN(error); } +/** + Check if we can skip the two-phase commit. + + A helper function to evaluate if two-phase commit is mandatory. + As a side effect, propagates the read-only/read-write flags + of the statement transaction to its enclosing normal transaction. + + @retval TRUE we must run a two-phase commit. Returned + if we have at least two engines with read-write changes. + @retval FALSE Don't need two-phase commit. Even if we have two + transactional engines, we can run two independent + commits if changes in one of the engines are read-only. +*/ + +static +bool +ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list, + bool all) +{ + /* The number of storage engines that have actual changes. */ + unsigned rw_ha_count= 0; + Ha_trx_info *ha_info; + + for (ha_info= ha_list; ha_info; ha_info= ha_info->next()) + { + if (ha_info->is_trx_read_write()) + ++rw_ha_count; + + if (! all) + { + Ha_trx_info *ha_info_all= &thd->ha_data[ha_info->ht()->slot].ha_info[1]; + DBUG_ASSERT(ha_info != ha_info_all); + /* + Merge read-only/read-write information about statement + transaction to its enclosing normal transaction. Do this + only if in a real transaction -- that is, if we know + that ha_info_all is registered in thd->transaction.all. + Since otherwise we only clutter the normal transaction flags. + */ + if (ha_info_all->is_started()) /* FALSE if autocommit. */ + ha_info_all->coalesce_trx_with(ha_info); + } + else if (rw_ha_count > 1) + { + /* + It is a normal transaction, so we don't need to merge read/write + information up, and the need for two-phase commit has been + already established. Break the loop prematurely. + */ + break; + } + } + return rw_ha_count > 1; +} + + /** @retval 0 ok @@ -674,12 +1021,25 @@ int ha_prepare(THD *thd) int ha_commit_trans(THD *thd, bool all) { int error= 0, cookie= 0; + /* + 'all' means that this is either an explicit commit issued by + user, or an implicit commit issued by a DDL. + */ THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt; - bool is_real_trans= all || thd->transaction.all.nht == 0; - handlerton **ht= trans->ht; + bool is_real_trans= all || thd->transaction.all.ha_list == 0; + Ha_trx_info *ha_info= trans->ha_list; my_xid xid= thd->transaction.xid_state.xid.get_my_xid(); DBUG_ENTER("ha_commit_trans"); + /* + We must not commit the normal transaction if a statement + transaction is pending. Otherwise statement transaction + flags will not get propagated to its normal transaction's + counterpart. + */ + DBUG_ASSERT(thd->transaction.stmt.ha_list == NULL || + trans == &thd->transaction.stmt); + if (thd->in_sub_stmt) { /* @@ -701,8 +1061,10 @@ int ha_commit_trans(THD *thd, bool all) DBUG_RETURN(2); } #ifdef USING_TRANSACTIONS - if (trans->nht) + if (ha_info) { + bool must_2pc; + if (is_real_trans && wait_if_global_read_lock(thd, 0, 0)) { ha_rollback_trans(thd, all); @@ -727,12 +1089,26 @@ int ha_commit_trans(THD *thd, bool all) if (is_real_trans) /* not a statement commit */ thd->stmt_map.close_transient_cursors(); - if (!trans->no_2pc && trans->nht > 1) + must_2pc= ha_check_and_coalesce_trx_read_only(thd, ha_info, all); + + if (!trans->no_2pc && must_2pc) { - for (; *ht && !error; ht++) + for (; ha_info && !error; ha_info= ha_info->next()) { int err; - if ((err= (*(*ht)->prepare)(*ht, thd, all))) + handlerton *ht= ha_info->ht(); + /* + Do not call two-phase commit if this particular + transaction is read-only. This allows for simpler + implementation in engines that are always read-only. + */ + if (! ha_info->is_trx_read_write()) + continue; + /* + Sic: we know that prepare() is not NULL since otherwise + trans->no_2pc would have been set. + */ + if ((err= ht->prepare(ht, thd, all))) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); error= 1; @@ -770,24 +1146,26 @@ int ha_commit_one_phase(THD *thd, bool all) { int error=0; THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; - bool is_real_trans=all || thd->transaction.all.nht == 0; - handlerton **ht=trans->ht; + bool is_real_trans=all || thd->transaction.all.ha_list == 0; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; DBUG_ENTER("ha_commit_one_phase"); #ifdef USING_TRANSACTIONS - if (trans->nht) + if (ha_info) { - for (ht=trans->ht; *ht; ht++) + for (; ha_info; ha_info= ha_info_next) { int err; - if ((err= (*(*ht)->commit)(*ht, thd, all))) + handlerton *ht= ha_info->ht(); + if ((err= ht->commit(ht, thd, all))) { my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); error=1; } status_var_increment(thd->status_var.ha_commit_count); - *ht= 0; + ha_info_next= ha_info->next(); + ha_info->reset(); /* keep it conveniently zero-filled */ } - trans->nht=0; + trans->ha_list= 0; trans->no_2pc=0; if (is_real_trans) thd->transaction.xid_state.xid.null(); @@ -810,8 +1188,17 @@ int ha_rollback_trans(THD *thd, bool all) { int error=0; THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt; - bool is_real_trans=all || thd->transaction.all.nht == 0; + Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; + bool is_real_trans=all || thd->transaction.all.ha_list == 0; DBUG_ENTER("ha_rollback_trans"); + + /* + We must not rollback the normal transaction if a statement + transaction is pending. + */ + DBUG_ASSERT(thd->transaction.stmt.ha_list == NULL || + trans == &thd->transaction.stmt); + if (thd->in_sub_stmt) { /* @@ -826,24 +1213,26 @@ int ha_rollback_trans(THD *thd, bool all) DBUG_RETURN(1); } #ifdef USING_TRANSACTIONS - if (trans->nht) + if (ha_info) { /* Close all cursors that can not survive ROLLBACK */ if (is_real_trans) /* not a statement commit */ thd->stmt_map.close_transient_cursors(); - for (handlerton **ht=trans->ht; *ht; ht++) + for (; ha_info; ha_info= ha_info_next) { int err; - if ((err= (*(*ht)->rollback)(*ht, thd, all))) + handlerton *ht= ha_info->ht(); + if ((err= ht->rollback(ht, thd, all))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; } status_var_increment(thd->status_var.ha_rollback_count); - *ht= 0; + ha_info_next= ha_info->next(); + ha_info->reset(); /* keep it conveniently zero-filled */ } - trans->nht=0; + trans->ha_list= 0; trans->no_2pc=0; if (is_real_trans) thd->transaction.xid_state.xid.null(); @@ -889,17 +1278,19 @@ int ha_autocommit_or_rollback(THD *thd, int error) { DBUG_ENTER("ha_autocommit_or_rollback"); #ifdef USING_TRANSACTIONS - if (thd->transaction.stmt.nht) + if (thd->transaction.stmt.ha_list) { if (!error) { - if (ha_commit_stmt(thd)) + if (ha_commit_trans(thd, 0)) error=1; } - else if (thd->transaction_rollback_request && !thd->in_sub_stmt) - (void) ha_rollback(thd); - else - (void) ha_rollback_stmt(thd); + else + { + (void) ha_rollback_trans(thd, 0); + if (thd->transaction_rollback_request && !thd->in_sub_stmt) + (void) ha_rollback(thd); + } thd->variables.tx_isolation=thd->session_tx_isolation; } @@ -1246,43 +1637,49 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) int error=0; THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : &thd->transaction.all); - handlerton **ht=trans->ht, **end_ht; + Ha_trx_info *ha_info, *ha_info_next; + DBUG_ENTER("ha_rollback_to_savepoint"); - trans->nht=sv->nht; trans->no_2pc=0; - end_ht=ht+sv->nht; /* rolling back to savepoint in all storage engines that were part of the transaction when the savepoint was set */ - for (; ht < end_ht; ht++) + for (ha_info= sv->ha_list; ha_info; ha_info= ha_info->next()) { int err; - DBUG_ASSERT((*ht)->savepoint_set != 0); - if ((err= (*(*ht)->savepoint_rollback)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset))) + handlerton *ht= ha_info->ht(); + DBUG_ASSERT(ht); + DBUG_ASSERT(ht->savepoint_set != 0); + if ((err= ht->savepoint_rollback(ht, thd, + (uchar *)(sv+1)+ht->savepoint_offset))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; } status_var_increment(thd->status_var.ha_savepoint_rollback_count); - trans->no_2pc|=(*ht)->prepare == 0; + trans->no_2pc|= ht->prepare == 0; } /* rolling back the transaction in all storage engines that were not part of the transaction when the savepoint was set */ - for (; *ht ; ht++) + for (ha_info= trans->ha_list; ha_info != sv->ha_list; + ha_info= ha_info_next) { int err; - if ((err= (*(*ht)->rollback)(*ht, thd, !thd->in_sub_stmt))) + handlerton *ht= ha_info->ht(); + if ((err= ht->rollback(ht, thd, !thd->in_sub_stmt))) { // cannot happen my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err); error=1; } status_var_increment(thd->status_var.ha_rollback_count); - *ht=0; // keep it conveniently zero-filled + ha_info_next= ha_info->next(); + ha_info->reset(); /* keep it conveniently zero-filled */ } + trans->ha_list= sv->ha_list; DBUG_RETURN(error); } @@ -1297,26 +1694,32 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv) int error=0; THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : &thd->transaction.all); - handlerton **ht=trans->ht; + Ha_trx_info *ha_info= trans->ha_list; DBUG_ENTER("ha_savepoint"); #ifdef USING_TRANSACTIONS - for (; *ht; ht++) + for (; ha_info; ha_info= ha_info->next()) { int err; - if (! (*ht)->savepoint_set) + handlerton *ht= ha_info->ht(); + DBUG_ASSERT(ht); + if (! ht->savepoint_set) { my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT"); error=1; break; } - if ((err= (*(*ht)->savepoint_set)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset))) + if ((err= ht->savepoint_set(ht, thd, (uchar *)(sv+1)+ht->savepoint_offset))) { // cannot happen my_error(ER_GET_ERRNO, MYF(0), err); error=1; } status_var_increment(thd->status_var.ha_savepoint_count); } - sv->nht=trans->nht; + /* + Remember the list of registered storage engines. All new + engines are prepended to the beginning of the list. + */ + sv->ha_list= trans->ha_list; #endif /* USING_TRANSACTIONS */ DBUG_RETURN(error); } @@ -1324,20 +1727,19 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv) int ha_release_savepoint(THD *thd, SAVEPOINT *sv) { int error=0; - THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt : - &thd->transaction.all); - handlerton **ht=trans->ht, **end_ht; + Ha_trx_info *ha_info= sv->ha_list; DBUG_ENTER("ha_release_savepoint"); - end_ht=ht+sv->nht; - for (; ht < end_ht; ht++) + for (; ha_info; ha_info= ha_info->next()) { int err; - if (!(*ht)->savepoint_release) + handlerton *ht= ha_info->ht(); + /* Savepoint life time is enclosed into transaction life time. */ + DBUG_ASSERT(ht); + if (!ht->savepoint_release) continue; - if ((err= (*(*ht)->savepoint_release)(*ht, thd, - (uchar *)(sv+1)+ - (*ht)->savepoint_offset))) + if ((err= ht->savepoint_release(ht, thd, + (uchar *)(sv+1) + ht->savepoint_offset))) { // cannot happen my_error(ER_GET_ERRNO, MYF(0), err); error=1; @@ -2506,6 +2908,36 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) return update_frm_version(table); } +/** + A helper function to mark a transaction read-write, + if it is started. +*/ + +inline +void +handler::mark_trx_read_write() +{ + Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0]; + /* + When a storage engine method is called, the transaction must + have been started, unless it's a DDL call, for which the + storage engine starts the transaction internally, and commits + it internally, without registering in the ha_list. + Unfortunately here we can't know know for sure if the engine + has registered the transaction or not, so we must check. + */ + if (ha_info->is_started()) + { + DBUG_ASSERT(has_transactions()); + /* + table_share can be NULL in ha_delete_table(). See implementation + of standalone function ha_delete_table() in sql_base.cc. + */ + if (table_share == NULL || table_share->tmp_table == NO_TMP_TABLE) + ha_info->set_trx_read_write(); + } +} + /** Repair table: public interface. @@ -2516,6 +2948,9 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt) { int result; + + mark_trx_read_write(); + if ((result= repair(thd, check_opt))) return result; return update_frm_version(table); @@ -2532,6 +2967,8 @@ int handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data, uint *dup_key_found) { + mark_trx_read_write(); + return bulk_update_row(old_data, new_data, dup_key_found); } @@ -2545,6 +2982,8 @@ handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data, int handler::ha_delete_all_rows() { + mark_trx_read_write(); + return delete_all_rows(); } @@ -2558,6 +2997,8 @@ handler::ha_delete_all_rows() int handler::ha_reset_auto_increment(ulonglong value) { + mark_trx_read_write(); + return reset_auto_increment(value); } @@ -2571,6 +3012,8 @@ handler::ha_reset_auto_increment(ulonglong value) int handler::ha_backup(THD* thd, HA_CHECK_OPT* check_opt) { + mark_trx_read_write(); + return backup(thd, check_opt); } @@ -2584,6 +3027,8 @@ handler::ha_backup(THD* thd, HA_CHECK_OPT* check_opt) int handler::ha_restore(THD* thd, HA_CHECK_OPT* check_opt) { + mark_trx_read_write(); + return restore(thd, check_opt); } @@ -2597,6 +3042,8 @@ handler::ha_restore(THD* thd, HA_CHECK_OPT* check_opt) int handler::ha_optimize(THD* thd, HA_CHECK_OPT* check_opt) { + mark_trx_read_write(); + return optimize(thd, check_opt); } @@ -2610,6 +3057,8 @@ handler::ha_optimize(THD* thd, HA_CHECK_OPT* check_opt) int handler::ha_analyze(THD* thd, HA_CHECK_OPT* check_opt) { + mark_trx_read_write(); + return analyze(thd, check_opt); } @@ -2623,6 +3072,8 @@ handler::ha_analyze(THD* thd, HA_CHECK_OPT* check_opt) bool handler::ha_check_and_repair(THD *thd) { + mark_trx_read_write(); + return check_and_repair(thd); } @@ -2636,6 +3087,8 @@ handler::ha_check_and_repair(THD *thd) int handler::ha_disable_indexes(uint mode) { + mark_trx_read_write(); + return disable_indexes(mode); } @@ -2649,6 +3102,8 @@ handler::ha_disable_indexes(uint mode) int handler::ha_enable_indexes(uint mode) { + mark_trx_read_write(); + return enable_indexes(mode); } @@ -2662,6 +3117,8 @@ handler::ha_enable_indexes(uint mode) int handler::ha_discard_or_import_tablespace(my_bool discard) { + mark_trx_read_write(); + return discard_or_import_tablespace(discard); } @@ -2677,6 +3134,8 @@ handler::ha_discard_or_import_tablespace(my_bool discard) void handler::ha_prepare_for_alter() { + mark_trx_read_write(); + prepare_for_alter(); } @@ -2690,6 +3149,8 @@ handler::ha_prepare_for_alter() int handler::ha_rename_table(const char *from, const char *to) { + mark_trx_read_write(); + return rename_table(from, to); } @@ -2703,6 +3164,8 @@ handler::ha_rename_table(const char *from, const char *to) int handler::ha_delete_table(const char *name) { + mark_trx_read_write(); + return delete_table(name); } @@ -2716,6 +3179,8 @@ handler::ha_delete_table(const char *name) void handler::ha_drop_table(const char *name) { + mark_trx_read_write(); + return drop_table(name); } @@ -2729,6 +3194,8 @@ handler::ha_drop_table(const char *name) int handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info) { + mark_trx_read_write(); + return create(name, form, info); } @@ -2743,6 +3210,8 @@ int handler::ha_create_handler_files(const char *name, const char *old_name, int action_flag, HA_CREATE_INFO *info) { + mark_trx_read_write(); + return create_handler_files(name, old_name, action_flag, info); } @@ -2761,6 +3230,8 @@ handler::ha_change_partitions(HA_CREATE_INFO *create_info, const uchar *pack_frm_data, size_t pack_frm_len) { + mark_trx_read_write(); + return change_partitions(create_info, path, copied, deleted, pack_frm_data, pack_frm_len); } @@ -2775,6 +3246,8 @@ handler::ha_change_partitions(HA_CREATE_INFO *create_info, int handler::ha_drop_partitions(const char *path) { + mark_trx_read_write(); + return drop_partitions(path); } @@ -2788,6 +3261,8 @@ handler::ha_drop_partitions(const char *path) int handler::ha_rename_partitions(const char *path) { + mark_trx_read_write(); + return rename_partitions(path); } @@ -2801,6 +3276,8 @@ handler::ha_rename_partitions(const char *path) int handler::ha_optimize_partitions(THD *thd) { + mark_trx_read_write(); + return optimize_partitions(thd); } @@ -2814,6 +3291,8 @@ handler::ha_optimize_partitions(THD *thd) int handler::ha_analyze_partitions(THD *thd) { + mark_trx_read_write(); + return analyze_partitions(thd); } @@ -2827,6 +3306,8 @@ handler::ha_analyze_partitions(THD *thd) int handler::ha_check_partitions(THD *thd) { + mark_trx_read_write(); + return check_partitions(thd); } @@ -2840,6 +3321,8 @@ handler::ha_check_partitions(THD *thd) int handler::ha_repair_partitions(THD *thd) { + mark_trx_read_write(); + return repair_partitions(thd); } @@ -2866,7 +3349,7 @@ int ha_enable_transaction(THD *thd, bool on) is an optimization hint that storage engine is free to ignore. So, let's commit an open transaction (if any) now. */ - if (!(error= ha_commit_stmt(thd))) + if (!(error= ha_commit_trans(thd, 0))) error= end_trans(thd, COMMIT); } DBUG_RETURN(error); @@ -4042,6 +4525,9 @@ int handler::ha_write_row(uchar *buf) { int error; DBUG_ENTER("handler::ha_write_row"); + + mark_trx_read_write(); + if (unlikely(error= write_row(buf))) DBUG_RETURN(error); if (unlikely(error= binlog_log_row(table, 0, buf))) @@ -4060,6 +4546,8 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) */ DBUG_ASSERT(new_data == table->record[0]); + mark_trx_read_write(); + if (unlikely(error= update_row(old_data, new_data))) return error; if (unlikely(error= binlog_log_row(table, old_data, new_data))) @@ -4070,6 +4558,9 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) int handler::ha_delete_row(const uchar *buf) { int error; + + mark_trx_read_write(); + if (unlikely(error= delete_row(buf))) return error; if (unlikely(error= binlog_log_row(table, buf, 0))) diff --git a/sql/handler.h b/sql/handler.h index b3a4b408589..9800f4974c3 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -721,14 +721,14 @@ struct handlerton #define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables #define HTON_NO_PARTITION (1 << 8) //You can not partition these tables -typedef struct st_thd_trans +class Ha_trx_info; + +struct THD_TRANS { - /* number of entries in the ht[] */ - uint nht; /* true is not all entries in the ht[] support 2pc */ bool no_2pc; - /* storage engines that registered themselves for this transaction */ - handlerton *ht[MAX_HA]; + /* storage engines that registered in this transaction */ + Ha_trx_info *ha_list; /* The purpose of this flag is to keep track of non-transactional tables that were modified in scope of: @@ -758,7 +758,106 @@ typedef struct st_thd_trans saved value. */ bool modified_non_trans_table; -} THD_TRANS; + + void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; } +}; + + +/** + Either statement transaction or normal transaction - related + thread-specific storage engine data. + + If a storage engine participates in a statement/transaction, + an instance of this class is present in + thd->transaction.{stmt|all}.ha_list. The addition to + {stmt|all}.ha_list is made by trans_register_ha(). + + When it's time to commit or rollback, each element of ha_list + is used to access storage engine's prepare()/commit()/rollback() + methods, and also to evaluate if a full two phase commit is + necessary. + + @sa General description of transaction handling in handler.cc. +*/ + +class Ha_trx_info +{ +public: + /** Register this storage engine in the given transaction context. */ + void register_ha(THD_TRANS *trans, handlerton *ht_arg) + { + DBUG_ASSERT(m_flags == 0); + DBUG_ASSERT(m_ht == NULL); + DBUG_ASSERT(m_next == NULL); + + m_ht= ht_arg; + m_flags= (int) TRX_READ_ONLY; /* Assume read-only at start. */ + + m_next= trans->ha_list; + trans->ha_list= this; + } + + /** Clear, prepare for reuse. */ + void reset() + { + m_next= NULL; + m_ht= NULL; + m_flags= 0; + } + + Ha_trx_info() { reset(); } + + void set_trx_read_write() + { + DBUG_ASSERT(is_started()); + m_flags|= (int) TRX_READ_WRITE; + } + bool is_trx_read_write() const + { + DBUG_ASSERT(is_started()); + return m_flags & (int) TRX_READ_WRITE; + } + bool is_started() const { return m_ht != NULL; } + /** Mark this transaction read-write if the argument is read-write. */ + void coalesce_trx_with(const Ha_trx_info *stmt_trx) + { + /* + Must be called only after the transaction has been started. + Can be called many times, e.g. when we have many + read-write statements in a transaction. + */ + DBUG_ASSERT(is_started()); + if (stmt_trx->is_trx_read_write()) + set_trx_read_write(); + } + Ha_trx_info *next() const + { + DBUG_ASSERT(is_started()); + return m_next; + } + handlerton *ht() const + { + DBUG_ASSERT(is_started()); + return m_ht; + } +private: + enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1 }; + /** Auxiliary, used for ha_list management */ + Ha_trx_info *m_next; + /** + Although a given Ha_trx_info instance is currently always used + for the same storage engine, 'ht' is not-NULL only when the + corresponding storage is a part of a transaction. + */ + handlerton *m_ht; + /** + Transaction flags related to this engine. + Not-null only if this instance is a part of transaction. + May assume a combination of enum values above. + */ + uchar m_flags; +}; + enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED, ISO_REPEATABLE_READ, ISO_SERIALIZABLE}; @@ -1640,7 +1739,14 @@ protected: provide useful functionality. */ virtual int rename_table(const char *from, const char *to); + /** + Delete a table in the engine. Called for base as well as temporary + tables. + */ virtual int delete_table(const char *name); +private: + /* Private helpers */ + inline void mark_trx_read_write(); private: /* Low-level primitives for storage engines. These should be @@ -1821,9 +1927,7 @@ extern TYPELIB tx_isolation_typelib; extern TYPELIB myisam_stats_method_typelib; extern ulong total_ha, total_ha_2pc; - /* Wrapper functions */ -#define ha_commit_stmt(thd) (ha_commit_trans((thd), FALSE)) -#define ha_rollback_stmt(thd) (ha_rollback_trans((thd), FALSE)) + /* Wrapper functions */ #define ha_commit(thd) (ha_commit_trans((thd), TRUE)) #define ha_rollback(thd) (ha_rollback_trans((thd), TRUE)) diff --git a/sql/log.cc b/sql/log.cc index 3a09acd8fca..af9359ed6cc 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3332,6 +3332,16 @@ THD::binlog_start_trans_and_stmt() if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); + /* + Mark statement transaction as read/write. We never start + a binary log transaction and keep it read-only, + therefore it's best to mark the transaction read/write just + at the same time we start it. + Not necessary to mark the normal transaction read/write + since the statement-level flag will be propagated automatically + inside ha_commit_trans. + */ + ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write(); } DBUG_VOID_RETURN; } diff --git a/sql/log_event.cc b/sql/log_event.cc index cf03dd5bf44..0d5aefd4422 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2898,7 +2898,7 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli) original place when it comes to us; we'll know this by checking log_pos ("artificial" events have log_pos == 0). */ - if (!artificial_event && created && thd->transaction.all.nht) + if (!artificial_event && created && thd->transaction.all.ha_list) { /* This is not an error (XA is safe), just an information */ rli->report(INFORMATION_LEVEL, 0, diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index aa3020c42be..684655d1c3b 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -62,6 +62,26 @@ int injector::transaction::commit() { DBUG_ENTER("injector::transaction::commit()"); m_thd->binlog_flush_pending_rows_event(true); + /* + Cluster replication does not preserve statement or + transaction boundaries of the master. Instead, a new + transaction on replication slave is started when a new GCI + (global checkpoint identifier) is issued, and is committed + when the last event of the check point has been received and + processed. This ensures consistency of each cluster in + cluster replication, and there is no requirement for stronger + consistency: MySQL replication is asynchronous with other + engines as well. + + A practical consequence of that is that row level replication + stream passed through the injector thread never contains + COMMIT events. + Here we should preserve the server invariant that there is no + outstanding statement transaction when the normal transaction + is committed by committing the statement transaction + explicitly. + */ + ha_autocommit_or_rollback(m_thd, 0); end_trans(m_thd, COMMIT); DBUG_RETURN(0); } diff --git a/sql/sp.cc b/sql/sp.cc index 99ffc18deea..ae738cd0a71 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -665,8 +665,16 @@ sp_returns_type(THD *thd, String &result, sp_head *sp) (TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION). @param sp Stored routine object to store. - @return Error code. SP_OK is returned on success. Other SP_ constants are - used to indicate about errors. + @note Opens and closes the thread tables. Therefore assumes + that there are no locked tables in this thread at the time of + invocation. + Unlike some other DDL statements, *does* close the tables + in the end, since the call to this function is normally + followed by an implicit grant (sp_grant_privileges()) + and this subsequent call opens and closes mysql.procs_priv. + + @return Error code. SP_OK is returned on success. Other + SP_ constants are used to indicate about errors. */ int @@ -1223,7 +1231,13 @@ done: } -/* Drop all routines in database 'db' */ +/** + Drop all routines in database 'db' + + @note Close the thread tables, the calling code might want to + delete from other system tables afterwards. +*/ + int sp_drop_db_routines(THD *thd, char *db) { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8e6f5a96640..1d443b70737 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2700,6 +2700,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, m_lex->unit.cleanup(); thd_proc_info(thd, "closing tables"); + /* Here we also commit or rollback the current statement. */ close_thread_tables(thd); thd_proc_info(thd, 0); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e5a5b51fcf6..4a417dc05b1 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1324,29 +1324,45 @@ void close_thread_tables(THD *thd) Mark all temporary tables used by this statement as free for reuse. */ mark_temp_tables_as_free_for_reuse(thd); - - if (thd->locked_tables || prelocked_mode) + /* + Let us commit transaction for statement. Since in 5.0 we only have + one statement transaction and don't allow several nested statement + transactions this call will do nothing if we are inside of stored + function or trigger (i.e. statement transaction is already active and + does not belong to statement for which we do close_thread_tables()). + TODO: This should be fixed in later releases. + */ + if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) { + thd->main_da.can_overwrite_status= TRUE; + ha_autocommit_or_rollback(thd, thd->is_error()); + thd->main_da.can_overwrite_status= FALSE; + /* - Let us commit transaction for statement. Since in 5.0 we only have - one statement transaction and don't allow several nested statement - transactions this call will do nothing if we are inside of stored - function or trigger (i.e. statement transaction is already active and - does not belong to statement for which we do close_thread_tables()). - TODO: This should be fixed in later releases. + Reset transaction state, but only if we're not inside a + sub-statement of a prelocked statement. */ - ha_commit_stmt(thd); + if (! prelocked_mode || thd->lex->requires_prelocking()) + thd->transaction.stmt.reset(); + } + + if (thd->locked_tables || prelocked_mode) + { /* Ensure we are calling ha_reset() for all used tables */ mark_used_tables_as_free_for_reuse(thd, thd->open_tables); - /* We are under simple LOCK TABLES so should not do anything else. */ + /* + We are under simple LOCK TABLES or we're inside a sub-statement + of a prelocked statement, so should not do anything else. + */ if (!prelocked_mode || !thd->lex->requires_prelocking()) DBUG_VOID_RETURN; /* - We are in prelocked mode, so we have to leave it now with doing - implicit UNLOCK TABLES if need. + We are in the top-level statement of a prelocked statement, + so we have to leave the prelocked mode now with doing implicit + UNLOCK TABLES if needed. */ DBUG_PRINT("info",("thd->prelocked_mode= NON_PRELOCKED")); thd->prelocked_mode= NON_PRELOCKED; @@ -1374,19 +1390,6 @@ void close_thread_tables(THD *thd) mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - /* - assume handlers auto-commit (if some doesn't - transaction handling - in MySQL should be redesigned to support it; it's a big change, - and it's not worth it - better to commit explicitly only writing - transactions, read-only ones should better take care of themselves. - saves some work in 2pc too) - see also sql_parse.cc - dispatch_command() - */ - if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) - bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt)); - if (!thd->active_transaction()) - thd->transaction.xid_state.xid.null(); - /* Note that we need to hold LOCK_open while changing the open_tables list. Another thread may work on it. @@ -5059,10 +5062,7 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables) DBUG_PRINT("info", ("error: %d", error)); if (error) - { - ha_rollback_stmt(thd); return -1; - } /* We switch to row-based format if we are in mixed mode and one of @@ -5216,7 +5216,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) table->table->query_id= thd->query_id; if (check_lock_and_start_stmt(thd, table->table, table->lock_type)) { - ha_rollback_stmt(thd); mysql_unlock_tables(thd, thd->locked_tables); thd->locked_tables= 0; thd->options&= ~(OPTION_TABLE_LOCK); @@ -5251,7 +5250,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen) if (!table->placeholder() && check_lock_and_start_stmt(thd, table->table, table->lock_type)) { - ha_rollback_stmt(thd); DBUG_RETURN(-1); } } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 75376c53f68..2781eec4eaf 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -264,7 +264,7 @@ const char *set_thd_proc_info(THD *thd, const char *info, extern "C" void **thd_ha_data(const THD *thd, const struct handlerton *hton) { - return (void **) thd->ha_data + hton->slot; + return (void **) &thd->ha_data[hton->slot].ha_ptr; } extern "C" @@ -2513,7 +2513,7 @@ bool select_dumpvar::send_data(List &items) suv->update(); } } - DBUG_RETURN(0); + DBUG_RETURN(thd->is_error()); } bool select_dumpvar::send_eof() diff --git a/sql/sql_class.h b/sql/sql_class.h index e8f28b19213..2a9941f78d0 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -686,7 +686,8 @@ private: struct st_savepoint { struct st_savepoint *prev; char *name; - uint length, nht; + uint length; + Ha_trx_info *ha_list; }; enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED}; @@ -1092,6 +1093,33 @@ private: }; +/** + Storage engine specific thread local data. +*/ + +struct Ha_data +{ + /** + Storage engine specific thread local data. + Lifetime: one user connection. + */ + void *ha_ptr; + /** + 0: Life time: one statement within a transaction. If @@autocommit is + on, also represents the entire transaction. + @sa trans_register_ha() + + 1: Life time: one transaction within a connection. + If the storage engine does not participate in a transaction, + this should not be used. + @sa trans_register_ha() + */ + Ha_trx_info ha_info[2]; + + Ha_data() :ha_ptr(NULL) {} +}; + + /** @class THD For each client connection we create a separate thread with THD serving as @@ -1231,7 +1259,7 @@ public: uint in_sub_stmt; /* container for handler's private per-connection data */ - void *ha_data[MAX_HA]; + Ha_data ha_data[MAX_HA]; #ifndef MYSQL_CLIENT int binlog_setup_trx_data(); diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 2301b561797..6f2bac73dc4 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -322,9 +322,10 @@ Sensitive_cursor::post_open(THD *thd) close_at_commit= FALSE; /* reset in case we're reusing the cursor */ info= &ht_info[0]; - for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++) + for (Ha_trx_info *ha_trx_info= thd->transaction.stmt.ha_list; + ha_trx_info; ha_trx_info= ha_trx_info->next()) { - handlerton *ht= *pht; + handlerton *ht= ha_trx_info->ht(); close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); if (ht->create_cursor_read_view) { diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index c6435387f44..234ee35ecca 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -24,6 +24,14 @@ #include "sp_head.h" #include "sql_trigger.h" +/** + Implement DELETE SQL word. + + @note Like implementations of other DDL/DML in MySQL, this function + relies on the caller to close the thread tables. This is done in the + end of dispatch_command(). +*/ + bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, ha_rows limit, ulonglong options, bool reset_auto_increment) @@ -380,17 +388,6 @@ cleanup: } DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table); free_underlaid_joins(thd, select_lex); - if (transactional_table) - { - if (ha_autocommit_or_rollback(thd,error >= 0)) - error=1; - } - - if (thd->lock) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; - } if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error)) { thd->row_count_func= deleted; @@ -751,11 +748,9 @@ void multi_delete::abort() The same if all tables are transactional, regardless of where we are. In all other cases do attempt deletes ... */ - if ((table_being_deleted == delete_tables && - table_being_deleted->table->file->has_transactions()) || - !normal_tables) - ha_rollback_stmt(thd); - else if (do_delete) + if (do_delete && normal_tables && + (table_being_deleted != delete_tables || + !table_being_deleted->table->file->has_transactions())) { /* We have to execute the recorded do_deletes() and write info into the @@ -921,11 +916,6 @@ bool multi_delete::send_eof() if (local_error != 0) error_handled= TRUE; // to force early leave from ::send_error() - /* Commit or rollback the current SQL statement */ - if (transactional_tables) - if (ha_autocommit_or_rollback(thd,local_error > 0)) - local_error=1; - if (!local_error) { thd->row_count_func= deleted; @@ -1055,6 +1045,12 @@ trunc_by_del: error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, HA_POS_ERROR, LL(0), TRUE); ha_enable_transaction(thd, TRUE); + /* + Safety, in case the engine ignored ha_enable_transaction(FALSE) + above. Also clears thd->transaction.*. + */ + error= ha_autocommit_or_rollback(thd, error); + ha_commit(thd); thd->options= save_options; thd->current_stmt_binlog_row_based= save_binlog_row_based; DBUG_RETURN(error); diff --git a/sql/sql_do.cc b/sql/sql_do.cc index a3eb93f87da..af9fa9444e8 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -28,7 +28,17 @@ bool mysql_do(THD *thd, List &values) while ((value = li++)) value->val_int(); free_underlaid_joins(thd, &thd->lex->select_lex); - thd->clear_error(); // DO always is OK + + if (thd->is_error()) + { + /* + Rollback the effect of the statement, since next instruction + will clear the error and the rollback in the end of + dispatch_command() won't work. + */ + ha_autocommit_or_rollback(thd, thd->is_error()); + thd->clear_error(); // DO always is OK + } send_ok(thd); DBUG_RETURN(FALSE); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index c2b1990f6c7..b03e786d1a1 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -541,6 +541,10 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list) /** INSERT statement implementation + + @note Like implementations of other DDL/DML in MySQL, this function + relies on the caller to close the thread tables. This is done in the + end of dispatch_command(). */ bool mysql_insert(THD *thd,TABLE_LIST *table_list, @@ -893,12 +897,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, } DBUG_ASSERT(transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table); - if (transactional_table) - error=ha_autocommit_or_rollback(thd,error); - + if (thd->lock) { - mysql_unlock_tables(thd, thd->lock); /* Invalidate the table in the query cache if something changed after unlocking when changes become fisible. @@ -909,7 +910,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, { query_cache_invalidate3(thd, table_list, 1); } - thd->lock=0; } } thd_proc_info(thd, "end"); @@ -2445,7 +2445,7 @@ err: first call to ha_*_row() instead. Remove code that are used to cover for the case outlined above. */ - ha_rollback_stmt(thd); + ha_autocommit_or_rollback(thd, 1); #ifndef __WIN__ end: @@ -3139,18 +3139,6 @@ bool select_insert::send_eof() thd->query, thd->query_length, trans_table, FALSE, killed_status); } - /* - We will call ha_autocommit_or_rollback() also for - non-transactional tables under row-based replication: there might - be events in the binary logs transaction, and we need to write - them to the binary log. - */ - if (trans_table || thd->current_stmt_binlog_row_based) - { - int error2= ha_autocommit_or_rollback(thd, error); - if (error2 && !error) - error= error2; - } table->file->ha_release_auto_increment(); if (error) @@ -3228,7 +3216,6 @@ void select_insert::abort() { table->file->ha_release_auto_increment(); } - ha_rollback_stmt(thd); DBUG_VOID_RETURN; } @@ -3667,7 +3654,10 @@ bool select_create::send_eof() nevertheless. */ if (!table->s->tmp_table) - ha_commit(thd); // Can fail, but we proceed anyway + { + ha_autocommit_or_rollback(thd, 0); + end_active_trans(thd); + } table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE); @@ -3691,12 +3681,9 @@ void select_create::abort() by removing the table, even for non-transactional tables. */ tmp_disable_binlog(thd); - select_insert::abort(); - reenable_binlog(thd); - /* - We roll back the statement, including truncating the transaction - cache of the binary log, if the statement failed. + In select_insert::abort() we roll back the statement, including + truncating the transaction cache of the binary log. We roll back the statement prior to deleting the table and prior to releasing the lock on the table, since there might be potential @@ -3707,8 +3694,9 @@ void select_create::abort() of the table succeeded or not, since we need to reset the binary log state. */ - if (thd->current_stmt_binlog_row_based) - ha_rollback_stmt(thd); + select_insert::abort(); + reenable_binlog(thd); + if (m_plock) { diff --git a/sql/sql_load.cc b/sql/sql_load.cc index c96fbb80b0c..d50f6c19a33 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -470,9 +470,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } } #endif /*!EMBEDDED_LIBRARY*/ - if (transactional_table) - ha_autocommit_or_rollback(thd,error); - error= -1; // Error on read goto err; } @@ -510,8 +507,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } } #endif /*!EMBEDDED_LIBRARY*/ - if (transactional_table) - error=ha_autocommit_or_rollback(thd,error); /* ok to client sent only after binlog write and engine commit */ send_ok(thd, info.copied + info.deleted, 0L, name); @@ -519,11 +514,6 @@ err: DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) || thd->transaction.stmt.modified_non_trans_table); table->file->ha_release_auto_increment(); - if (thd->lock) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; - } table->auto_increment_field_not_null= FALSE; thd->abort_on_warning= 0; DBUG_RETURN(error); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 221c156fe6b..9b69dd60c45 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1465,21 +1465,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; } - thd_proc_info(thd, "closing tables"); - /* Free tables */ - close_thread_tables(thd); + /* If commit fails, we should be able to reset the OK status. */ + thd->main_da.can_overwrite_status= TRUE; + ha_autocommit_or_rollback(thd, thd->is_error()); + thd->main_da.can_overwrite_status= FALSE; + + thd->transaction.stmt.reset(); - /* - assume handlers auto-commit (if some doesn't - transaction handling - in MySQL should be redesigned to support it; it's a big change, - and it's not worth it - better to commit explicitly only writing - transactions, read-only ones should better take care of themselves. - saves some work in 2pc too) - see also sql_base.cc - close_thread_tables() - */ - bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt)); - if (!thd->active_transaction()) - thd->transaction.xid_state.xid.null(); /* report error issued during command execution */ if (thd->killed_errno()) @@ -1496,6 +1488,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd, net_end_statement(thd); query_cache_end_of_result(thd); + thd->proc_info= "closing tables"; + /* Free tables */ + close_thread_tables(thd); + log_slow_statement(thd); thd_proc_info(thd, "cleaning up"); @@ -3011,10 +3007,8 @@ end_with_restore_list: /* INSERT ... SELECT should invalidate only the very first table */ TABLE_LIST *save_table= first_table->next_local; first_table->next_local= 0; - mysql_unlock_tables(thd, thd->lock); query_cache_invalidate3(thd, first_table, 1); first_table->next_local= save_table; - thd->lock=0; } delete sel_result; } @@ -3985,7 +3979,6 @@ end_with_restore_list: push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_PROC_AUTO_GRANT_FAIL, ER(ER_PROC_AUTO_GRANT_FAIL)); - close_thread_tables(thd); } #endif break; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index eabf4526f7b..cf0aeee938b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3968,31 +3968,35 @@ static int fast_end_partition(THD *thd, ulonglong copied, bool written_bin_log) { int error; + char tmp_name[80]; DBUG_ENTER("fast_end_partition"); thd->proc_info="end"; + if (!is_empty) query_cache_invalidate3(thd, table_list, 0); - error= ha_commit_stmt(thd); - if (ha_commit(thd)) + + error= ha_autocommit_or_rollback(thd, 0); + if (end_active_trans(thd)) error= 1; - if (!error || is_empty) - { - char tmp_name[80]; - if ((!is_empty) && (!written_bin_log) && - (!thd->lex->no_write_to_binlog)) - write_bin_log(thd, FALSE, thd->query, thd->query_length); - close_thread_tables(thd); - my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), - (ulong) (copied + deleted), - (ulong) deleted, - (ulong) 0); - send_ok(thd, (ha_rows) (copied+deleted),0L,tmp_name); - DBUG_RETURN(FALSE); + + if (error) + { + /* If error during commit, no need to rollback, it's done. */ + table->file->print_error(error, MYF(0)); + DBUG_RETURN(TRUE); } - table->file->print_error(error, MYF(0)); - close_thread_tables(thd); - DBUG_RETURN(TRUE); + + if ((!is_empty) && (!written_bin_log) && + (!thd->lex->no_write_to_binlog)) + write_bin_log(thd, FALSE, thd->query, thd->query_length); + + my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), + (ulong) (copied + deleted), + (ulong) deleted, + (ulong) 0); + send_ok(thd, (ha_rows) (copied+deleted),0L, tmp_name); + DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 505bcd1b421..61f8ff342b1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4131,6 +4131,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, switch ((*prepare_func)(thd, table, check_opt)) { case 1: // error, message written to net ha_autocommit_or_rollback(thd, 1); + end_trans(thd, ROLLBACK); close_thread_tables(thd); DBUG_PRINT("admin", ("simple error, admin next table")); continue; @@ -4189,6 +4190,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, table_name); protocol->store(buff, length, system_charset_info); ha_autocommit_or_rollback(thd, 0); + end_trans(thd, COMMIT); close_thread_tables(thd); lex->reset_query_tables_list(FALSE); table->table=0; // For query cache @@ -4461,6 +4463,7 @@ send_result_message: } } ha_autocommit_or_rollback(thd, 0); + end_trans(thd, COMMIT); close_thread_tables(thd); table->table=0; // For query cache if (protocol->write()) @@ -4470,8 +4473,9 @@ send_result_message: send_eof(thd); DBUG_RETURN(FALSE); - err: +err: ha_autocommit_or_rollback(thd, 1); + end_trans(thd, ROLLBACK); close_thread_tables(thd); // Shouldn't be needed if (table) table->table=0; @@ -4994,8 +4998,8 @@ mysql_discard_or_import_tablespace(THD *thd, query_cache_invalidate3(thd, table_list, 0); /* The ALTER TABLE is always in its own transaction */ - error = ha_commit_stmt(thd); - if (ha_commit(thd)) + error = ha_autocommit_or_rollback(thd, 0); + if (end_active_trans(thd)) error=1; if (error) goto err; @@ -5003,7 +5007,6 @@ mysql_discard_or_import_tablespace(THD *thd, err: ha_autocommit_or_rollback(thd, error); - close_thread_tables(thd); thd->tablespace_op=FALSE; if (error == 0) @@ -6526,8 +6529,8 @@ view_err: VOID(pthread_mutex_unlock(&LOCK_open)); alter_table_manage_keys(table, table->file->indexes_are_disabled(), alter_info->keys_onoff); - error= ha_commit_stmt(thd); - if (ha_commit(thd)) + error= ha_autocommit_or_rollback(thd, 0); + if (end_active_trans(thd)) error= 1; } thd->count_cuted_fields= CHECK_FIELD_IGNORE; @@ -6615,7 +6618,7 @@ view_err: /* Need to commit before a table is unlocked (NDB requirement). */ DBUG_PRINT("info", ("Committing before unlocking table")); - if (ha_commit_stmt(thd) || ha_commit(thd)) + if (ha_autocommit_or_rollback(thd, 0) || end_active_trans(thd)) goto err1; committed= 1; } @@ -7116,9 +7119,9 @@ copy_data_between_tables(TABLE *from,TABLE *to, Ensure that the new table is saved properly to disk so that we can do a rename */ - if (ha_commit_stmt(thd)) + if (ha_autocommit_or_rollback(thd, 0)) error=1; - if (ha_commit(thd)) + if (end_active_trans(thd)) error=1; err: diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 30e8829d764..ae3f43eba5b 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -382,6 +382,14 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl, } +/** + Create a user defined function. + + @note Like implementations of other DDL/DML in MySQL, this function + relies on the caller to close the thread tables. This is done in the + end of dispatch_command(). +*/ + int mysql_create_function(THD *thd,udf_func *udf) { int error; @@ -489,7 +497,6 @@ int mysql_create_function(THD *thd,udf_func *udf) table->field[3]->store((longlong) u_d->type, TRUE); error = table->file->ha_write_row(table->record[0]); - close_thread_tables(thd); if (error) { my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4d075e3308d..b1485389db3 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -803,17 +803,6 @@ int mysql_update(THD *thd, } DBUG_ASSERT(transactional_table || !updated || thd->transaction.stmt.modified_non_trans_table); free_underlaid_joins(thd, select_lex); - if (transactional_table) - { - if (ha_autocommit_or_rollback(thd, error >= 0)) - error=1; - } - - if (thd->lock) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; - } /* If LAST_INSERT_ID(X) was used, report X */ id= thd->arg_of_last_insert_id_function ? @@ -1716,13 +1705,8 @@ void multi_update::abort() If not attempt to do remaining updates. */ - if (trans_safe) + if (! trans_safe) { - DBUG_ASSERT(transactional_tables); - (void) ha_autocommit_or_rollback(thd, 1); - } - else - { DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table); if (do_update && table_count > 1) { @@ -1754,11 +1738,6 @@ void multi_update::abort() thd->transaction.all.modified_non_trans_table= TRUE; } DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table); - - if (transactional_tables) - { - (void) ha_autocommit_or_rollback(thd, 1); - } } @@ -1996,12 +1975,6 @@ bool multi_update::send_eof() if (local_error != 0) error_handled= TRUE; // to force early leave from ::send_error() - if (transactional_tables) - { - if (ha_autocommit_or_rollback(thd, local_error != 0)) - local_error=1; - } - if (local_error > 0) // if the above log write did not fail ... { /* Safety: If we haven't got an error before (can happen in do_updates) */ -- cgit v1.2.1 From 14021c96c464406812f84bec45c5f73ac0b96e1a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 15:45:21 +0300 Subject: Rename send_ok to my_ok. Similarly to my_error, it only records the status, does not send it to the client. --- sql/protocol.cc | 8 ++-- sql/repl_failsafe.cc | 2 +- sql/sql_acl.cc | 6 +-- sql/sql_binlog.cc | 2 +- sql/sql_class.cc | 4 +- sql/sql_class.h | 4 +- sql/sql_connect.cc | 4 +- sql/sql_db.cc | 10 ++--- sql/sql_delete.cc | 12 +++--- sql/sql_do.cc | 2 +- sql/sql_handler.cc | 4 +- sql/sql_insert.cc | 6 +-- sql/sql_load.cc | 2 +- sql/sql_parse.cc | 108 +++++++++++++++++++++++++-------------------------- sql/sql_partition.cc | 2 +- sql/sql_prepare.cc | 6 +-- sql/sql_rename.cc | 2 +- sql/sql_repl.cc | 12 +++--- sql/sql_table.cc | 10 ++--- sql/sql_trigger.cc | 2 +- sql/sql_update.cc | 8 ++-- sql/sql_view.cc | 4 +- 22 files changed, 109 insertions(+), 111 deletions(-) (limited to 'sql') diff --git a/sql/protocol.cc b/sql/protocol.cc index 9e1b3c65538..5fe56724d08 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -112,8 +112,6 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) - message : Stored as packed length (1-9 bytes) + message. Is not stored if no message. - If net->no_send_ok return without sending packet. - @param thd Thread handler @param affected_rows Number of rows changed by statement @param id Auto_increment id for first row (if used) @@ -128,7 +126,7 @@ net_send_ok(THD *thd, { NET *net= &thd->net; uchar buff[MYSQL_ERRMSG_SIZE+10],*pos; - DBUG_ENTER("send_ok"); + DBUG_ENTER("my_ok"); if (! net->vio) // hack for re-parsing queries { @@ -425,8 +423,8 @@ void net_end_statement(THD *thd) /**************************************************************************** - Functions used by the protocol functions (like send_ok) to store strings - and numbers in the header result packet. + Functions used by the protocol functions (like net_send_ok) to store + strings and numbers in the header result packet. ****************************************************************************/ /* The following will only be used for short strings < 65K */ diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 589ee8b2605..6f4b4b2571d 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -1011,7 +1011,7 @@ err: mysql_close(&mysql); // safe to call since we always do mysql_init() if (!error) - send_ok(thd); + my_ok(thd); return error; } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b04f624f746..040a7822d9d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3176,7 +3176,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, rw_unlock(&LOCK_grant); if (!result) /* success */ - send_ok(thd); + my_ok(thd); /* Tables are automatically closed */ thd->lex->restore_backup_query_tables_list(&backup); @@ -3344,7 +3344,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, rw_unlock(&LOCK_grant); if (!result && !no_error) - send_ok(thd); + my_ok(thd); /* Tables are automatically closed */ DBUG_RETURN(result); @@ -3460,7 +3460,7 @@ bool mysql_grant(THD *thd, const char *db, List &list, close_thread_tables(thd); if (!result) - send_ok(thd); + my_ok(thd); DBUG_RETURN(result); } diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index 462806ab10d..a6d0c8c9e9b 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -231,7 +231,7 @@ void mysql_client_binlog_statement(THD* thd) DBUG_PRINT("info",("binlog base64 execution finished successfully")); - send_ok(thd); + my_ok(thd); end: thd->rli_fake->clear_tables_to_lock(); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a24266c775c..1fb3fc74151 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1583,7 +1583,7 @@ bool select_to_file::send_eof() function, SELECT INTO has to have an own SQLCOM. TODO: split from SQLCOM_SELECT */ - ::send_ok(thd,row_count); + ::my_ok(thd,row_count); } file= -1; return error; @@ -2533,7 +2533,7 @@ bool select_dumpvar::send_eof() function, SELECT INTO has to have an own SQLCOM. TODO: split from SQLCOM_SELECT */ - ::send_ok(thd,row_count); + ::my_ok(thd,row_count); return 0; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 6e22ddd972b..565375fef95 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -993,7 +993,7 @@ public: { /** The area is cleared at start of a statement. */ DA_EMPTY= 0, - /** Set whenever one calls send_ok(). */ + /** Set whenever one calls my_ok(). */ DA_OK, /** Set whenever one calls send_eof(). */ DA_EOF, @@ -2141,7 +2141,7 @@ private: /** A short cut for thd->main_da.set_ok_status(). */ inline void -send_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0, +my_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0, const char *message= NULL) { thd->main_da.set_ok_status(thd, affected_rows, id, message); diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 309a1c7ab5d..ac9c745bb44 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -334,7 +334,7 @@ check_user(THD *thd, enum enum_server_command command, if (mysql_change_db(thd, &db_str, FALSE)) DBUG_RETURN(1); } - send_ok(thd); + my_ok(thd); DBUG_RETURN(0); #else @@ -483,7 +483,7 @@ check_user(THD *thd, enum enum_server_command command, DBUG_RETURN(1); } } - send_ok(thd); + my_ok(thd); thd->password= test(passwd_len); // remember for error messages /* Ready to handle queries */ DBUG_RETURN(0); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index b5f49b97ec9..d03ac7921ac 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -595,7 +595,7 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name) In this case the entry should not be logged. SIDE-EFFECTS - 1. Report back to client that command succeeded (send_ok) + 1. Report back to client that command succeeded (my_ok) 2. Report errors to client 3. Log event to binary log (The 'silent' flags turns off 1 and 3.) @@ -660,7 +660,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db); if (!silent) - send_ok(thd); + my_ok(thd); error= 0; goto exit; } @@ -749,7 +749,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } - send_ok(thd, result); + my_ok(thd, result); } exit: @@ -826,7 +826,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) /* These DDL methods and logging protected with LOCK_mysql_create_db */ mysql_bin_log.write(&qinfo); } - send_ok(thd, result); + my_ok(thd, result); exit: VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); @@ -960,7 +960,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } thd->clear_error(); thd->server_status|= SERVER_STATUS_DB_DROPPED; - send_ok(thd, (ulong) deleted); + my_ok(thd, (ulong) deleted); thd->server_status&= ~SERVER_STATUS_DB_DROPPED; } else if (mysql_bin_log.is_open()) diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 234ee35ecca..990f7713561 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -158,7 +158,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, { free_underlaid_joins(thd, select_lex); thd->row_count_func= 0; - send_ok(thd, (ha_rows) thd->row_count_func); // No matching records + my_ok(thd, (ha_rows) thd->row_count_func); // No matching records DBUG_RETURN(0); } #endif @@ -175,7 +175,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, delete select; free_underlaid_joins(thd, select_lex); thd->row_count_func= 0; - send_ok(thd, (ha_rows) thd->row_count_func); + my_ok(thd, (ha_rows) thd->row_count_func); /* We don't need to call reset_auto_increment in this case, because mysql_truncate always gives a NULL conds argument, hence we never @@ -391,7 +391,7 @@ cleanup: if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error)) { thd->row_count_func= deleted; - send_ok(thd, (ha_rows) thd->row_count_func); + my_ok(thd, (ha_rows) thd->row_count_func); DBUG_PRINT("info",("%ld records deleted",(long) deleted)); } DBUG_RETURN(error >= 0 || thd->is_error()); @@ -919,7 +919,7 @@ bool multi_delete::send_eof() if (!local_error) { thd->row_count_func= deleted; - ::send_ok(thd, (ha_rows) thd->row_count_func); + ::my_ok(thd, (ha_rows) thd->row_count_func); } return 0; } @@ -973,7 +973,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) my_free((char*) table,MYF(0)); /* If we return here we will not have logged the truncation to the bin log - and we will not send_ok() to the client. + and we will not my_ok() to the client. */ goto end; } @@ -1019,7 +1019,7 @@ end: we don't test current_stmt_binlog_row_based. */ write_bin_log(thd, TRUE, thd->query, thd->query_length); - send_ok(thd); // This should return record count + my_ok(thd); // This should return record count } VOID(pthread_mutex_lock(&LOCK_open)); unlock_table_name(thd, table_list); diff --git a/sql/sql_do.cc b/sql/sql_do.cc index af9fa9444e8..8406a9eaf45 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -39,6 +39,6 @@ bool mysql_do(THD *thd, List &values) ha_autocommit_or_rollback(thd, thd->is_error()); thd->clear_error(); // DO always is OK } - send_ok(thd); + my_ok(thd); DBUG_RETURN(FALSE); } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index a4ba6f1140b..3d47d16ea56 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -298,7 +298,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) tables->table->open_by_handler= 1; if (! reopen) - send_ok(thd); + my_ok(thd); DBUG_PRINT("exit",("OK")); DBUG_RETURN(FALSE); @@ -350,7 +350,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables) DBUG_RETURN(TRUE); } - send_ok(thd); + my_ok(thd); DBUG_PRINT("exit", ("OK")); DBUG_RETURN(FALSE); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b03e786d1a1..2be932a6040 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -946,7 +946,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, thd->row_count_func= info.copied + info.deleted + ((thd->client_capabilities & CLIENT_FOUND_ROWS) ? info.touched : info.updated); - send_ok(thd, (ulong) thd->row_count_func, id); + my_ok(thd, (ulong) thd->row_count_func, id); } else { @@ -961,7 +961,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, (ulong) (info.deleted + updated), (ulong) thd->cuted_fields); thd->row_count_func= info.copied + info.deleted + updated; - ::send_ok(thd, (ulong) thd->row_count_func, id, buff); + ::my_ok(thd, (ulong) thd->row_count_func, id, buff); } thd->abort_on_warning= 0; DBUG_RETURN(FALSE); @@ -3162,7 +3162,7 @@ bool select_insert::send_eof() (thd->arg_of_last_insert_id_function ? thd->first_successful_insert_id_in_prev_stmt : (info.copied ? autoinc_value_of_last_inserted_row : 0)); - ::send_ok(thd, (ulong) thd->row_count_func, id, buff); + ::my_ok(thd, (ulong) thd->row_count_func, id, buff); DBUG_RETURN(0); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index d50f6c19a33..4d5dc8e6f06 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -509,7 +509,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, #endif /*!EMBEDDED_LIBRARY*/ /* ok to client sent only after binlog write and engine commit */ - send_ok(thd, info.copied + info.deleted, 0L, name); + my_ok(thd, info.copied + info.deleted, 0L, name); err: DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) || thd->transaction.stmt.modified_non_trans_table); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 94306132027..11fa77ca2fc 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -913,7 +913,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (!mysql_change_db(thd, &tmp, FALSE)) { general_log_write(thd, command, thd->db, thd->db_length); - send_ok(thd); + my_ok(thd); } break; } @@ -921,7 +921,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_REGISTER_SLAVE: { if (!register_slave(thd, (uchar*)packet, packet_length)) - send_ok(thd); + my_ok(thd); break; } #endif @@ -1322,7 +1322,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; general_log_print(thd, command, NullS); if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) - send_ok(thd); + my_ok(thd); break; } #ifndef EMBEDDED_LIBRARY @@ -1386,7 +1386,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, (uint) (queries_per_second1000 % 1000)); #ifdef EMBEDDED_LIBRARY /* Store the buffer in permanent memory */ - send_ok(thd, 0, 0, buff); + my_ok(thd, 0, 0, buff); #endif #ifdef SAFEMALLOC if (sf_malloc_cur_memory) // Using SAFEMALLOC @@ -1407,7 +1407,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_PING: status_var_increment(thd->status_var.com_other); - send_ok(thd); // Tell client we are alive + my_ok(thd); // Tell client we are alive break; case COM_PROCESS_INFO: status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]); @@ -2075,7 +2075,7 @@ mysql_execute_command(THD *thd) break; case SQLCOM_EMPTY_QUERY: - send_ok(thd); + my_ok(thd); break; case SQLCOM_HELP: @@ -2242,7 +2242,7 @@ mysql_execute_command(THD *thd) { push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, "the master info structure does not exist"); - send_ok(thd); + my_ok(thd); } pthread_mutex_unlock(&LOCK_active_mi); break; @@ -2300,7 +2300,7 @@ mysql_execute_command(THD *thd) if (!fetch_master_table(thd, first_table->db, first_table->table_name, active_mi, 0, 0)) { - send_ok(thd); + my_ok(thd); } pthread_mutex_unlock(&LOCK_active_mi); break; @@ -2511,7 +2511,7 @@ mysql_execute_command(THD *thd) &alter_info, 0, 0); } if (!res) - send_ok(thd); + my_ok(thd); } /* put tables back for PS rexecuting */ @@ -3194,7 +3194,7 @@ end_with_restore_list: LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) }; if (!mysql_change_db(thd, &db_str, FALSE)) - send_ok(thd); + my_ok(thd); break; } @@ -3247,7 +3247,7 @@ end_with_restore_list: about the ONE_SHOT property of that SET. So we use a |= instead of = . */ thd->one_shot_set|= lex->one_shot_set; - send_ok(thd); + my_ok(thd); } break; } @@ -3267,7 +3267,7 @@ end_with_restore_list: } if (thd->global_read_lock) unlock_global_read_lock(thd); - send_ok(thd); + my_ok(thd); break; case SQLCOM_LOCK_TABLES: unlock_locked_tables(thd); @@ -3288,7 +3288,7 @@ end_with_restore_list: #endif /*HAVE_QUERY_CACHE*/ thd->locked_tables=thd->lock; thd->lock=0; - send_ok(thd); + my_ok(thd); } else { @@ -3425,7 +3425,7 @@ end_with_restore_list: res= mysql_upgrade_db(thd, db); if (!res) - send_ok(thd); + my_ok(thd); break; } case SQLCOM_ALTER_DB: @@ -3510,7 +3510,7 @@ end_with_restore_list: } DBUG_PRINT("info",("DDL error code=%d", res)); if (!res) - send_ok(thd); + my_ok(thd); } while (0); /* Don't do it, if we are inside a SP */ @@ -3529,7 +3529,7 @@ end_with_restore_list: if (!(res= Events::drop_event(thd, lex->spname->m_db, lex->spname->m_name, lex->drop_if_exists))) - send_ok(thd); + my_ok(thd); break; case SQLCOM_CREATE_FUNCTION: // UDF function { @@ -3537,7 +3537,7 @@ end_with_restore_list: break; #ifdef HAVE_DLOPEN if (!(res = mysql_create_function(thd, &lex->udf))) - send_ok(thd); + my_ok(thd); #else my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled"); res= TRUE; @@ -3554,7 +3554,7 @@ end_with_restore_list: goto error; /* Conditionally writes to binlog */ if (!(res= mysql_create_user(thd, lex->users_list))) - send_ok(thd); + my_ok(thd); break; } case SQLCOM_DROP_USER: @@ -3566,7 +3566,7 @@ end_with_restore_list: goto error; /* Conditionally writes to binlog */ if (!(res= mysql_drop_user(thd, lex->users_list))) - send_ok(thd); + my_ok(thd); break; } case SQLCOM_RENAME_USER: @@ -3578,7 +3578,7 @@ end_with_restore_list: goto error; /* Conditionally writes to binlog */ if (!(res= mysql_rename_user(thd, lex->users_list))) - send_ok(thd); + my_ok(thd); break; } case SQLCOM_REVOKE_ALL: @@ -3590,7 +3590,7 @@ end_with_restore_list: break; /* Conditionally writes to binlog */ if (!(res = mysql_revoke_all(thd, lex->users_list))) - send_ok(thd); + my_ok(thd); break; } case SQLCOM_REVOKE: @@ -3727,7 +3727,7 @@ end_with_restore_list: { write_bin_log(thd, FALSE, thd->query, thd->query_length); } - send_ok(thd); + my_ok(thd); } break; @@ -3799,19 +3799,19 @@ end_with_restore_list: } if (begin_trans(thd)) goto error; - send_ok(thd); + my_ok(thd); break; case SQLCOM_COMMIT: if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE : lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT)) goto error; - send_ok(thd); + my_ok(thd); break; case SQLCOM_ROLLBACK: if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE : lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK)) goto error; - send_ok(thd); + my_ok(thd); break; case SQLCOM_RELEASE_SAVEPOINT: { @@ -3828,7 +3828,7 @@ end_with_restore_list: if (ha_release_savepoint(thd, sv)) res= TRUE; // cannot happen else - send_ok(thd); + my_ok(thd); thd->transaction.savepoints=sv->prev; } else @@ -3857,7 +3857,7 @@ end_with_restore_list: push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); - send_ok(thd); + my_ok(thd); } thd->transaction.savepoints=sv; } @@ -3868,7 +3868,7 @@ end_with_restore_list: case SQLCOM_SAVEPOINT: if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) || thd->in_sub_stmt) || !opt_using_transactions) - send_ok(thd); + my_ok(thd); else { SAVEPOINT **sv, *newsv; @@ -3905,7 +3905,7 @@ end_with_restore_list: { newsv->prev=thd->transaction.savepoints; thd->transaction.savepoints=newsv; - send_ok(thd); + my_ok(thd); } } break; @@ -4005,7 +4005,7 @@ end_with_restore_list: create_sp_error: if (sp_result != SP_OK ) goto error; - send_ok(thd); + my_ok(thd); break; /* break super switch */ } /* end case group bracket */ case SQLCOM_CALL: @@ -4098,8 +4098,8 @@ create_sp_error: thd->server_status&= ~bits_to_be_cleared; if (!res) - send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 : - thd->row_count_func)); + my_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 : + thd->row_count_func)); else { DBUG_ASSERT(thd->is_error() || thd->killed); @@ -4176,7 +4176,7 @@ create_sp_error: switch (sp_result) { case SP_OK: - send_ok(thd); + my_ok(thd); break; case SP_KEY_NOT_FOUND: my_error(ER_SP_DOES_NOT_EXIST, MYF(0), @@ -4241,7 +4241,7 @@ create_sp_error: if (!(res = mysql_drop_function(thd, &lex->spname->m_name))) { - send_ok(thd); + my_ok(thd); break; } } @@ -4258,7 +4258,7 @@ create_sp_error: res= sp_result; switch (sp_result) { case SP_OK: - send_ok(thd); + my_ok(thd); break; case SP_KEY_NOT_FOUND: if (lex->drop_if_exists) @@ -4267,7 +4267,7 @@ create_sp_error: ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), SP_COM_STRING(lex), lex->spname->m_name.str); res= FALSE; - send_ok(thd); + my_ok(thd); break; } my_error(ER_SP_DOES_NOT_EXIST, MYF(0), @@ -4399,7 +4399,7 @@ create_sp_error: break; } thd->transaction.xid_state.xa_state=XA_ACTIVE; - send_ok(thd); + my_ok(thd); break; } if (thd->lex->xa_opt != XA_NONE) @@ -4430,7 +4430,7 @@ create_sp_error: thd->transaction.all.modified_non_trans_table= FALSE; thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; - send_ok(thd); + my_ok(thd); break; case SQLCOM_XA_END: /* fake it */ @@ -4451,7 +4451,7 @@ create_sp_error: break; } thd->transaction.xid_state.xa_state=XA_IDLE; - send_ok(thd); + my_ok(thd); break; case SQLCOM_XA_PREPARE: if (thd->transaction.xid_state.xa_state != XA_IDLE) @@ -4473,7 +4473,7 @@ create_sp_error: break; } thd->transaction.xid_state.xa_state=XA_PREPARED; - send_ok(thd); + my_ok(thd); break; case SQLCOM_XA_COMMIT: if (!thd->transaction.xid_state.xid.eq(thd->lex->xid)) @@ -4485,7 +4485,7 @@ create_sp_error: { ha_commit_or_rollback_by_xid(thd->lex->xid, 1); xid_cache_delete(xs); - send_ok(thd); + my_ok(thd); } break; } @@ -4496,7 +4496,7 @@ create_sp_error: if ((r= ha_commit(thd))) my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0)); else - send_ok(thd); + my_ok(thd); } else if (thd->transaction.xid_state.xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE) @@ -4511,7 +4511,7 @@ create_sp_error: if (ha_commit_one_phase(thd, 1)) my_error(ER_XAER_RMERR, MYF(0)); else - send_ok(thd); + my_ok(thd); start_waiting_global_read_lock(thd); } } @@ -4537,7 +4537,7 @@ create_sp_error: { ha_commit_or_rollback_by_xid(thd->lex->xid, 0); xid_cache_delete(xs); - send_ok(thd); + my_ok(thd); } break; } @@ -4551,7 +4551,7 @@ create_sp_error: if (ha_rollback(thd)) my_error(ER_XAER_RMERR, MYF(0)); else - send_ok(thd); + my_ok(thd); thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG); thd->transaction.all.modified_non_trans_table= FALSE; thd->server_status&= ~SERVER_STATUS_IN_TRANS; @@ -4565,16 +4565,16 @@ create_sp_error: if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0, thd->db ? is_schema_db(thd->db) : 0)) break; if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info))) - send_ok(thd); + my_ok(thd); break; case SQLCOM_INSTALL_PLUGIN: if (! (res= mysql_install_plugin(thd, &thd->lex->comment, &thd->lex->ident))) - send_ok(thd); + my_ok(thd); break; case SQLCOM_UNINSTALL_PLUGIN: if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment))) - send_ok(thd); + my_ok(thd); break; case SQLCOM_BINLOG_BASE64_EVENT: { @@ -4601,7 +4601,7 @@ create_sp_error: my_error(error, MYF(0), lex->server_options.server_name); break; } - send_ok(thd, 1); + my_ok(thd, 1); break; } case SQLCOM_ALTER_SERVER: @@ -4620,7 +4620,7 @@ create_sp_error: my_error(error, MYF(0), lex->server_options.server_name); break; } - send_ok(thd, 1); + my_ok(thd, 1); break; } case SQLCOM_DROP_SERVER: @@ -4642,18 +4642,18 @@ create_sp_error: } else { - send_ok(thd, 0); + my_ok(thd, 0); } break; } - send_ok(thd, 1); + my_ok(thd, 1); break; } default: #ifndef EMBEDDED_LIBRARY DBUG_ASSERT(0); /* Impossible */ #endif - send_ok(thd); + my_ok(thd); break; } thd_proc_info(thd, "query end"); @@ -6660,7 +6660,7 @@ void sql_kill(THD *thd, ulong id, bool only_kill_query) { uint error; if (!(error= kill_one_thread(thd, id, only_kill_query))) - send_ok(thd); + my_ok(thd); else my_error(error, MYF(0), id); } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index cf0aeee938b..45a82782de0 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3995,7 +3995,7 @@ static int fast_end_partition(THD *thd, ulonglong copied, (ulong) (copied + deleted), (ulong) deleted, (ulong) 0); - send_ok(thd, (ha_rows) (copied+deleted),0L, tmp_name); + my_ok(thd, (ha_rows) (copied+deleted),0L, tmp_name); DBUG_RETURN(FALSE); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 5a903a4fe1c..e03f7cfb6a0 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2111,7 +2111,7 @@ void mysql_sql_stmt_prepare(THD *thd) thd->stmt_map.erase(stmt); } else - send_ok(thd, 0L, 0L, "Statement prepared"); + my_ok(thd, 0L, 0L, "Statement prepared"); DBUG_VOID_RETURN; } @@ -2494,7 +2494,7 @@ void mysql_stmt_reset(THD *thd, char *packet) stmt->state= Query_arena::PREPARED; - send_ok(thd); + my_ok(thd); DBUG_VOID_RETURN; } @@ -2557,7 +2557,7 @@ void mysql_sql_stmt_close(THD *thd) } if (stmt->deallocate() == 0) - send_ok(thd); + my_ok(thd); } /** diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 9dd8e1b70d4..fc87356e452 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -178,7 +178,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) if (!silent && !error) { write_bin_log(thd, TRUE, thd->query, thd->query_length); - send_ok(thd); + my_ok(thd); } if (!error) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index cdce2fa695b..573a257cd3d 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -252,7 +252,7 @@ bool purge_error_message(THD* thd, int res) my_message(errmsg, ER(errmsg), MYF(0)); return TRUE; } - send_ok(thd); + my_ok(thd); return FALSE; } @@ -262,7 +262,7 @@ bool purge_master_logs(THD* thd, const char* to_log) char search_file_name[FN_REFLEN]; if (!mysql_bin_log.is_open()) { - send_ok(thd); + my_ok(thd); return FALSE; } @@ -277,7 +277,7 @@ bool purge_master_logs_before_date(THD* thd, time_t purge_time) { if (!mysql_bin_log.is_open()) { - send_ok(thd); + my_ok(thd); return 0; } return purge_error_message(thd, @@ -884,7 +884,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report) DBUG_RETURN(1); } else if (net_report) - send_ok(thd); + my_ok(thd); DBUG_RETURN(0); } @@ -936,7 +936,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report ) DBUG_RETURN(1); } else if (net_report) - send_ok(thd); + my_ok(thd); DBUG_RETURN(0); } @@ -1279,7 +1279,7 @@ bool change_master(THD* thd, Master_info* mi) unlock_slave_threads(mi); thd_proc_info(thd, 0); - send_ok(thd); + my_ok(thd); DBUG_RETURN(FALSE); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d4f4cfdedab..07ba9d0ec56 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1497,7 +1497,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, if (error) DBUG_RETURN(TRUE); - send_ok(thd); + my_ok(thd); DBUG_RETURN(FALSE); } @@ -5042,7 +5042,7 @@ err: if (error == 0) { - send_ok(thd); + my_ok(thd); DBUG_RETURN(0); } @@ -6006,7 +6006,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE); mysql_bin_log.write(&qinfo); } - send_ok(thd); + my_ok(thd); } unlock_table_names(thd, table_list, (TABLE_LIST*) 0); @@ -6244,7 +6244,7 @@ view_err: if (!error) { write_bin_log(thd, TRUE, thd->query, thd->query_length); - send_ok(thd); + my_ok(thd); } else if (error > 0) { @@ -6880,7 +6880,7 @@ end_temporary: my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), (ulong) (copied + deleted), (ulong) deleted, (ulong) thd->cuted_fields); - send_ok(thd, copied + deleted, 0L, tmp_name); + my_ok(thd, copied + deleted, 0L, tmp_name); thd->some_tables_deleted=0; DBUG_RETURN(FALSE); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 4cd1d542375..d426904e4b2 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -516,7 +516,7 @@ end: start_waiting_global_read_lock(thd); if (!result) - send_ok(thd); + my_ok(thd); DBUG_RETURN(result); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b1485389db3..61df6b0b871 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -319,7 +319,7 @@ int mysql_update(THD *thd, if (prune_partitions(thd, table, conds)) { free_underlaid_joins(thd, select_lex); - send_ok(thd); // No matching records + my_ok(thd); // No matching records DBUG_RETURN(0); } #endif @@ -336,7 +336,7 @@ int mysql_update(THD *thd, { DBUG_RETURN(1); // Error in where } - send_ok(thd); // No matching records + my_ok(thd); // No matching records DBUG_RETURN(0); } if (!select && limit != HA_POS_ERROR) @@ -815,7 +815,7 @@ int mysql_update(THD *thd, (ulong) thd->cuted_fields); thd->row_count_func= (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; - send_ok(thd, (ulong) thd->row_count_func, id, buff); + my_ok(thd, (ulong) thd->row_count_func, id, buff); DBUG_PRINT("info",("%ld records updated", (long) updated)); } thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ @@ -1989,6 +1989,6 @@ bool multi_update::send_eof() (ulong) thd->cuted_fields); thd->row_count_func= (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; - ::send_ok(thd, (ulong) thd->row_count_func, id, buff); + ::my_ok(thd, (ulong) thd->row_count_func, id, buff); DBUG_RETURN(FALSE); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1a4d7d515a8..0b0763afb84 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -599,7 +599,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, if (res) goto err; - send_ok(thd); + my_ok(thd); lex->link_first_table_back(view, link_to_local); DBUG_RETURN(0); @@ -1552,7 +1552,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) { DBUG_RETURN(TRUE); } - send_ok(thd); + my_ok(thd); DBUG_RETURN(FALSE); } -- cgit v1.2.1 From 9060b50f144a6172742ff0089f9cfe36b433c11e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 15:58:08 +0300 Subject: Rename send_eof() to my_eof() for consistency with my_ok() and my_error() --- sql/events.cc | 2 +- sql/handler.cc | 4 ++-- sql/repl_failsafe.cc | 4 ++-- sql/slave.cc | 2 +- sql/sp.cc | 2 +- sql/sp_head.cc | 4 ++-- sql/sql_acl.cc | 2 +- sql/sql_class.cc | 2 +- sql/sql_class.h | 6 +++--- sql/sql_error.cc | 2 +- sql/sql_handler.cc | 2 +- sql/sql_help.cc | 2 +- sql/sql_parse.cc | 8 ++++---- sql/sql_prepare.cc | 2 +- sql/sql_repl.cc | 8 ++++---- sql/sql_show.cc | 18 +++++++++--------- sql/sql_table.cc | 4 ++-- 17 files changed, 37 insertions(+), 37 deletions(-) (limited to 'sql') diff --git a/sql/events.cc b/sql/events.cc index 87385082a82..fc736a5379b 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -737,7 +737,7 @@ send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol) if (protocol->write()) DBUG_RETURN(TRUE); - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } diff --git a/sql/handler.cc b/sql/handler.cc index d831a1c53a0..4cf73874f22 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1590,7 +1590,7 @@ bool mysql_xa_recover(THD *thd) } pthread_mutex_unlock(&LOCK_xid_cache); - send_eof(thd); + my_eof(thd); DBUG_RETURN(0); } @@ -4309,7 +4309,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) } if (!result) - send_eof(thd); + my_eof(thd); return result; } diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 6f4b4b2571d..f8f01d2cad1 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -475,7 +475,7 @@ bool show_new_master(THD* thd) protocol->store((ulonglong) lex_mi->pos); if (protocol->write()) DBUG_RETURN(TRUE); - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } } @@ -688,7 +688,7 @@ bool show_slave_hosts(THD* thd) } } pthread_mutex_unlock(&LOCK_slave_list); - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } diff --git a/sql/slave.cc b/sql/slave.cc index ea0dde942da..d9dc014b025 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1451,7 +1451,7 @@ bool show_master_info(THD* thd, Master_info* mi) if (my_net_write(&thd->net, (uchar*) thd->packet.ptr(), packet->length())) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } diff --git a/sql/sp.cc b/sql/sp.cc index e69bf83d552..b486e58883a 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1259,7 +1259,7 @@ sp_show_status_routine(THD *thd, int type, const char *name_pattern) } err_case1: - send_eof(thd); + my_eof(thd); err_case: table->file->ha_index_end(); close_thread_tables(thd); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1d443b70737..f42a5dde8ed 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2419,7 +2419,7 @@ sp_head::show_create_routine(THD *thd, int type) err_status= protocol->write(); if (!err_status) - send_eof(thd); + my_eof(thd); DBUG_RETURN(err_status); } @@ -2611,7 +2611,7 @@ sp_head::show_routine_code(THD *thd) } if (!res) - send_eof(thd); + my_eof(thd); DBUG_RETURN(res); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 040a7822d9d..3805d9fa8b6 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -4815,7 +4815,7 @@ end: VOID(pthread_mutex_unlock(&acl_cache->lock)); rw_unlock(&LOCK_grant); - send_eof(thd); + my_eof(thd); DBUG_RETURN(error); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1fb3fc74151..3ce1b350027 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1548,7 +1548,7 @@ bool select_send::send_eof() mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - ::send_eof(thd); + ::my_eof(thd); is_result_set_started= 0; return FALSE; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 565375fef95..2f225834545 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,7 +995,7 @@ public: DA_EMPTY= 0, /** Set whenever one calls my_ok(). */ DA_OK, - /** Set whenever one calls send_eof(). */ + /** Set whenever one calls my_eof(). */ DA_EOF, /** Set whenever one calls my_error() or my_message(). */ DA_ERROR, @@ -1063,7 +1063,7 @@ private: Copied from thd->server_status when the diagnostics area is assigned. We need this member as some places in the code use the following pattern: thd->server_status|= ... - send_eof(thd); + my_eof(thd); thd->server_status&= ~... Assigned by OK, EOF or ERROR. */ @@ -2151,7 +2151,7 @@ my_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0, /** A short cut for thd->main_da.set_eof_status(). */ inline void -send_eof(THD *thd) +my_eof(THD *thd) { thd->main_da.set_eof_status(thd); } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 89cff73d153..0b74e3455eb 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -249,6 +249,6 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show) if (protocol->write()) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 3d47d16ea56..28a9fb5c78e 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -658,7 +658,7 @@ retry: } ok: mysql_unlock_tables(thd,lock); - send_eof(thd); + my_eof(thd); DBUG_PRINT("exit",("OK")); DBUG_RETURN(FALSE); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 0d633ce86ac..e424425272e 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -779,7 +779,7 @@ bool mysqld_help(THD *thd, const char *mask) if (send_variant_2_list(mem_root,protocol, &categories_list, "Y", 0)) goto error; } - send_eof(thd); + my_eof(thd); close_system_tables(thd, &open_tables_state_backup); DBUG_RETURN(FALSE); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 11fa77ca2fc..a78ac978a4a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1348,7 +1348,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } DBUG_PRINT("quit",("Got shutdown command for level %u", level)); general_log_print(thd, command, NullS); - send_eof(thd); + my_eof(thd); close_thread_tables(thd); // Free before kill kill_mysql(); error=TRUE; @@ -1434,11 +1434,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, switch (opt_command) { case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON: thd->client_capabilities|= CLIENT_MULTI_STATEMENTS; - send_eof(thd); + my_eof(thd); break; case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF: thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS; - send_eof(thd); + my_eof(thd); break; default: my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); @@ -1452,7 +1452,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; /* purecov: inspected */ mysql_print_status(); general_log_print(thd, command, NullS); - send_eof(thd); + my_eof(thd); break; case COM_SLEEP: case COM_CONNECT: // Impossible here diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index e03f7cfb6a0..02d8ed00c32 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2662,7 +2662,7 @@ bool Select_fetch_protocol_binary::send_fields(List &list, uint flags) bool Select_fetch_protocol_binary::send_eof() { - ::send_eof(thd); + ::my_eof(thd); return FALSE; } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 573a257cd3d..932b7a67b4d 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -738,7 +738,7 @@ end: end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); - send_eof(thd); + my_eof(thd); thd_proc_info(thd, "Waiting to finalize termination"); pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; @@ -1453,7 +1453,7 @@ err: my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0), "SHOW BINLOG EVENTS", errmsg); else - send_eof(thd); + my_eof(thd); pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; @@ -1490,7 +1490,7 @@ bool show_binlog_info(THD* thd) if (protocol->write()) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } @@ -1572,7 +1572,7 @@ bool show_binlogs(THD* thd) goto err; } mysql_bin_log.unlock_index(); - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); err: diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6d817cb0620..9f56933a114 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -224,7 +224,7 @@ bool mysqld_show_authors(THD *thd) if (protocol->write()) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } @@ -258,7 +258,7 @@ bool mysqld_show_contributors(THD *thd) if (protocol->write()) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } @@ -331,7 +331,7 @@ bool mysqld_show_privileges(THD *thd) if (protocol->write()) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } @@ -419,7 +419,7 @@ bool mysqld_show_column_types(THD *thd) if (protocol->write()) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } @@ -666,7 +666,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (protocol->write()) DBUG_RETURN(TRUE); - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } @@ -747,7 +747,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname, if (protocol->write()) DBUG_RETURN(TRUE); - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } @@ -789,7 +789,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) table->use_all_columns(); if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS)) DBUG_VOID_RETURN; - send_eof(thd); + my_eof(thd); DBUG_VOID_RETURN; } @@ -1738,7 +1738,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (protocol->write()) break; /* purecov: inspected */ } - send_eof(thd); + my_eof(thd); DBUG_VOID_RETURN; } @@ -6760,7 +6760,7 @@ static bool show_create_trigger_impl(THD *thd, ret_code= p->write(); if (!ret_code) - send_eof(thd); + my_eof(thd); return ret_code != 0; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 07ba9d0ec56..c62d0545fda 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4501,7 +4501,7 @@ send_result_message: goto err; } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); err: @@ -7311,7 +7311,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, goto err; } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); err: -- cgit v1.2.1 From 8b91756be1b32102a37f492d97a2be8eb731377e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 14:25:26 +0100 Subject: Post-merge fix --- sql/sql_connect.cc | 19 ++----------------- sql/stacktrace.c | 2 +- 2 files changed, 3 insertions(+), 18 deletions(-) (limited to 'sql') diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index 309a1c7ab5d..c3541cb4eb4 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -39,22 +39,7 @@ #endif /* HAVE_OPENSSL */ #ifdef __WIN__ -static void test_signal(int sig_ptr) -{ -#if !defined( DBUG_OFF) - MessageBox(NULL,"Test signal","DBUG",MB_OK); -#endif -#if defined(OS2) - fprintf(stderr, "Test signal %d\n", sig_ptr); - fflush(stderr); -#endif -} -static void init_signals(void) -{ - int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ; - for (int i=0 ; i < 7 ; i++) - signal( signals[i], test_signal) ; -} +extern void win_install_sigabrt_handler(); #endif /* @@ -626,7 +611,7 @@ bool init_new_connection_handler_thread() { pthread_detach_this_thread(); #if defined(__WIN__) - init_signals(); + win_install_sigabrt_handler(); #else /* Win32 calls this in pthread_create */ if (my_thread_init()) diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 0186212900e..49e31fabd23 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -341,7 +341,7 @@ void set_exception_pointers(EXCEPTION_POINTERS *ep) #define SYMOPT_NO_PROMPTS 0 #endif -void print_stacktrace(gptr unused1, ulong unused2) +void print_stacktrace(uchar* unused1, ulong unused2) { HANDLE hProcess= GetCurrentProcess(); HANDLE hThread= GetCurrentThread(); -- cgit v1.2.1 From f802cd51238c7842b789e49ba27d3c119ebb8ce3 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 18:16:17 +0400 Subject: BUG#34289 - Incorrect NAME_CONST substitution in stored procedures breaks replication NAME_CONST() didn't replicate constant character set and collation correctly. With this fix NAME_CONST() inherits collation from the value argument. mysql-test/r/func_misc.result: A test case for BUG#34289. mysql-test/t/func_misc.test: A test case for BUG#34289. sql/item.cc: Inherit collation from value argument. --- sql/item.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index ffb18054750..d0dc8201577 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1240,6 +1240,7 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) return TRUE; } set_name(item_name->ptr(), (uint) item_name->length(), system_charset_info); + collation.set(value_item->collation.collation, DERIVATION_IMPLICIT); max_length= value_item->max_length; decimals= value_item->decimals; fixed= 1; -- cgit v1.2.1 From 1ac319248f6d9ed920c402cb90ed52690161750c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 17:27:18 +0200 Subject: Bug #30604: different flagging of time_zone_used in normal and ps-protocol Finding a routine should be a transparent operation as far as the binary log is concerned. But it was influencing the binary log because of the TIMESTAMP column in the proc table. Fixed by preserving and restoring the time_zone usage flag when searching for a stored routine in the proc table. mysql-test/r/binlog_innodb.result: Bug #30604: test case mysql-test/r/ctype_cp932_binlog.result: Bug #30604: updated test results (a procedure call before that) mysql-test/t/binlog_innodb.test: Bug #30604: test case sql/sp.cc: Bug #30604: finding a routine should be a transparent operation as far as the binary log is concerned. Fixed by preserving and restoring the time_zone usage flag. --- sql/sp.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sp.cc b/sql/sp.cc index f8b039626f9..7224d3c4f0e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -261,6 +261,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) char buff[65]; String str(buff, sizeof(buff), &my_charset_bin); ulong sql_mode; + bool saved_time_zone_used= thd->time_zone_used; Open_tables_state open_tables_state_backup; DBUG_ENTER("db_find_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s", @@ -370,6 +371,11 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp) definer, created, modified); done: + /* + Restore the time zone flag as the timezone usage in proc table + does not affect replication. + */ + thd->time_zone_used= saved_time_zone_used; if (table) close_proc_table(thd, &open_tables_state_backup); DBUG_RETURN(ret); -- cgit v1.2.1 From 4b25d5b10cfc47b4ab54f7bcc8dfb4d91c1f4e6d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 09:44:09 -0700 Subject: Applied InnoDB snapshot innodb-5.1-ss2298 Fixes the following bugs: - Bug #33349: possible race condition revolving around data dictionary and repartitioning Introduce retry/sleep logic as a workaround for a transient bug where ::open fails for partitioned tables randomly if we are using one file per table. - Bug #34053: normal users can enable innodb_monitor logging In CREATE TABLE and DROP TABLE check whether the table in question is one of the magic innodb_monitor tables and whether the user has enough rights to mess with it before doing anything else. - Bug #22868: 'Thread thrashing' with > 50 concurrent conns under an upd-intensive workloadw - Bug #29560: InnoDB >= 5.0.30 hangs on adaptive hash rw-lock 'waiting for an X-lock' This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. - Bug #30930: Add auxiliary function to retrieve THD::thread_id Add thd_get_thread_id() function. Also make check_global_access() function visible to InnoDB under INNODB_COMPATIBILITY_HOOKS #define. include/mysql/plugin.h: Add thd_get_thread_id() accessor function mysql-test/r/innodb.result: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2261: branches/5.1: Merge a change from MySQL AB: ChangeSet@2007-10-13 15:49:42+03:00, aelkin@koti.dsl.inet.fi Bug #29136 erred multi-delete on trans table does not rollback the statement innodb.test, innodb.result: trans table specific test added mysql-test/t/innodb.test: Applied InnoDB snapshot innodb-5.1-ss2298 sql/mysql_priv.h: Make check_global_access() declaration available if when INNODB_COMPATIBILITY_HOOKS is defined. sql/sql_class.cc: Add thd_get_thread_id() accessor function. Add 'extern "C"' to definition for thd_get_xid(). Not strictly needed, but in keeping with our coding style. storage/innobase/btr/btr0cur.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2295: branches/5.1: Merge r2294 from branches/5.0: Fix typo and add comma in comment. storage/innobase/handler/ha_innodb.cc: Applied InnoDB snapshot innodb-5.1-ss2298 - But remove the declaration of check_global_access() from ha_innodb.cc, because it is now visible in mysql_priv.h under INNODB_COMPATIBILITY_HOOKS Revision r2270: branches/5.1: Rename the user visible parameter innodb-use-adaptive-hash-indexes to innodb-adaptive-hash-index so that it is in sync with MySQL 5.0. Suggested by: Heikki Approved by: Heikki Revision r2236: branches/5.1: bug#33349 Introduce retry/sleep logic as a workaround for a transient bug where ::open fails for partitioned tables randomly if we are using one file per table. Reviewed by: Heikki Revision r2282: branches/5.1: Fix Bug#34053: * In CREATE TABLE and DROP TABLE check whether the table in question is one of the magic innodb_monitor tables and whether the user has enough rights to mess with it before doing anything else. * Implement a mysql-test testcase. Approved by: Heikki Revision r2246: branches/5.1: Fix formatting of the autoinc-lock-mode command line parameter. Old view (./mysqld --help --verbose): --innodb-autoinc-lock-mode=# The AUTOINC lock modes supported by InnoDB: 0 => Old style AUTOINC locking (for backward compatibility) 1 => New style AUTOINC locking 2 => No AUTOINC locking (unsafe for SBR) New view: --innodb-autoinc-lock-mode=# The AUTOINC lock modes supported by InnoDB: 0 => Old style AUTOINC locking (for backward compatibility) 1 => New style AUTOINC locking 2 => No AUTOINC locking (unsafe for SBR) Looks like these strings are "automatically" wrapped by MySQL in the following way: * newlines (\n) in the string are ignored * newline separator (\n) is inserted every 57 or so characters. * lots of white space is appended to each inserted new line. Approved by: Heikki storage/innobase/include/os0sync.h: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/include/read0read.h: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2188: branches/5.1: Remove unused field can_be_too_old from read_view_struct. storage/innobase/include/row0mysql.h: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2282: branches/5.1: Fix Bug#34053: * In CREATE TABLE and DROP TABLE check whether the table in question is one of the magic innodb_monitor tables and whether the user has enough rights to mess with it before doing anything else. * Implement a mysql-test testcase. Approved by: Heikki Revision r2272: branches/5.1: Fix typo in comment. storage/innobase/include/sync0arr.h: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/include/sync0rw.h: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/include/sync0rw.ic: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/include/sync0sync.h: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/include/sync0sync.ic: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/os/os0sync.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/read/read0read.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2188: branches/5.1: Remove unused field can_be_too_old from read_view_struct. storage/innobase/row/row0mysql.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2282: branches/5.1: Fix Bug#34053: * In CREATE TABLE and DROP TABLE check whether the table in question is one of the magic innodb_monitor tables and whether the user has enough rights to mess with it before doing anything else. * Implement a mysql-test testcase. Approved by: Heikki Revision r2272: branches/5.1: Fix typo in comment. storage/innobase/srv/srv0srv.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/sync/sync0arr.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/sync/sync0rw.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki storage/innobase/sync/sync0sync.c: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2268: branches/5.1: Port of r2267 This is a combination of changes that forward port the scalability fix applied to 5.0 through r1001. It reverts changes r149 and r122 (these were 5.1 specific changes made in lieu of scalability fix of 5.0) Then it applies r1001 to 5.0 which is the original scalability fix. Finally it applies r2082 which fixes an issue with the original fix. Reviewed by: Heikki mysql-test/r/innodb_bug34053.result: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2282: branches/5.1: Fix Bug#34053: * In CREATE TABLE and DROP TABLE check whether the table in question is one of the magic innodb_monitor tables and whether the user has enough rights to mess with it before doing anything else. * Implement a mysql-test testcase. Approved by: Heikki mysql-test/t/innodb_bug34053.test: Applied InnoDB snapshot innodb-5.1-ss2298 Revision r2282: branches/5.1: Fix Bug#34053: * In CREATE TABLE and DROP TABLE check whether the table in question is one of the magic innodb_monitor tables and whether the user has enough rights to mess with it before doing anything else. * Implement a mysql-test testcase. Approved by: Heikki --- sql/mysql_priv.h | 10 +++++++++- sql/sql_class.cc | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ea552414d9a..5ed670c32ed 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1035,7 +1035,6 @@ bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv, bool no_grant, bool no_errors, bool schema_db); bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, uint number, bool no_errors); -bool check_global_access(THD *thd, ulong want_access); #else inline bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv, bool no_grant, bool no_errors, @@ -1048,9 +1047,18 @@ inline bool check_access(THD *thd, ulong access, const char *db, inline bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, uint number, bool no_errors) { return false; } +#endif /*NO_EMBEDDED_ACCESS_CHECKS*/ + +#endif /* MYSQL_SERVER */ +#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS +#ifndef NO_EMBEDDED_ACCESS_CHECKS +bool check_global_access(THD *thd, ulong want_access); +#else inline bool check_global_access(THD *thd, ulong want_access) { return false; } #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ +#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */ +#ifdef MYSQL_SERVER /* Support routine for SQL parser on partitioning syntax diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 5180cafc774..351e5e8aae8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -682,6 +682,7 @@ void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size) return thd->memdup(str, size); } +extern "C" void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid) { *xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid; @@ -2760,6 +2761,17 @@ extern "C" int thd_killed(const MYSQL_THD thd) return(thd->killed); } +/** + Return the thread id of a user thread + @param thd user thread + @return thread id +*/ +extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd) +{ + return((unsigned long)thd->thread_id); +} + + #ifdef INNODB_COMPATIBILITY_HOOKS extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd) { -- cgit v1.2.1 From 533d4354635163a5430d77d85a131909d991731c Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 19 Feb 2008 23:47:15 +0300 Subject: Fix a compilation failure of the community tree. --- sql/sql_profile.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 1922fa3bc2b..c62cf6401ba 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -456,7 +456,7 @@ bool PROFILING::show_profiles() if (protocol->write()) DBUG_RETURN(TRUE); } - send_eof(thd); + my_eof(thd); DBUG_RETURN(FALSE); } -- cgit v1.2.1 From 61c31af45d075e1aa1135b502209c04ca890425f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 00:33:43 +0300 Subject: Fix for bug #31236: Inconsistent division by zero behavior for floating point numbers Some math functions did not check if the result is a valid number (i.e. neither of +-inf or nan). Fixed by validating the result where necessary and returning NULL in case of invalid result. BitKeeper/deleted/.del-matherr.c: Rename: sql/matherr.c -> BitKeeper/deleted/.del-matherr.c configure.in: Removed DONT_USE_FINITE, it is not used anywhere. include/my_global.h: isfinite() is a C99 macro which absoletes finite(). First try to use it, then fall back to finite() if the target platform has it, otherwise use our own implementation. mysql-test/r/func_math.result: Added a test case for bug #31236. mysql-test/r/strict.result: Fixed a test case which relied on old behavior. mysql-test/t/func_math.test: Added a test case for bug #31236. mysql-test/t/strict.test: Fixed a test case which relied on old behavior. sql/field.cc: No need to check if the finite() or its equivalent is available. sql/item_func.cc: Use fix_result() wherever the result can be one of +-inf or nan, assuming the function arguments are valid numbers. Removed fix_result() from functions that are defined for all possible input numbers. sql/item_func.h: Moved fix_result() from Item_dec_func to Item_func which is a common ancestor for Item_dec_func and Item_num_op. sql/unireg.h: Removed POSTFIX_ERROR because no code returns it. --- sql/field.cc | 4 +--- sql/item_func.cc | 22 +++++++++++----------- sql/item_func.h | 19 +++++++------------ sql/matherr.c | 42 ------------------------------------------ sql/unireg.h | 1 - 5 files changed, 19 insertions(+), 69 deletions(-) delete mode 100644 sql/matherr.c (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 668ced4a229..19eb43862d5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2263,13 +2263,11 @@ int Field_decimal::store(double nr) return 1; } -#ifdef HAVE_FINITE - if (!finite(nr)) // Handle infinity as special case + if (!isfinite(nr)) // Handle infinity as special case { overflow(nr < 0.0); return 1; } -#endif reg4 uint i; size_t length; diff --git a/sql/item_func.cc b/sql/item_func.cc index 8fd6f0966ad..3d6ed590f81 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1104,7 +1104,7 @@ double Item_func_plus::real_op() double value= args[0]->val_real() + args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; - return value; + return fix_result(value); } @@ -1186,7 +1186,7 @@ double Item_func_minus::real_op() double value= args[0]->val_real() - args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; - return value; + return fix_result(value); } @@ -1224,7 +1224,7 @@ double Item_func_mul::real_op() double value= args[0]->val_real() * args[1]->val_real(); if ((null_value=args[0]->null_value || args[1]->null_value)) return 0.0; - return value; + return fix_result(value); } @@ -1282,7 +1282,7 @@ double Item_func_div::real_op() signal_divide_by_null(); return 0.0; } - return value/val2; + return fix_result(value/val2); } @@ -1655,7 +1655,7 @@ double Item_func_exp::val_real() double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; /* purecov: inspected */ - return exp(value); + return fix_result(exp(value)); } double Item_func_sqrt::val_real() @@ -1674,7 +1674,7 @@ double Item_func_pow::val_real() double val2= args[1]->val_real(); if ((null_value=(args[0]->null_value || args[1]->null_value))) return 0.0; /* purecov: inspected */ - return pow(value,val2); + return fix_result(pow(value,val2)); } // Trigonometric functions @@ -1686,7 +1686,7 @@ double Item_func_acos::val_real() volatile double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0)))) return 0.0; - return fix_result(acos(value)); + return acos(value); } double Item_func_asin::val_real() @@ -1696,7 +1696,7 @@ double Item_func_asin::val_real() volatile double value= args[0]->val_real(); if ((null_value=(args[0]->null_value || (value < -1.0 || value > 1.0)))) return 0.0; - return fix_result(asin(value)); + return asin(value); } double Item_func_atan::val_real() @@ -1712,7 +1712,7 @@ double Item_func_atan::val_real() return 0.0; return fix_result(atan2(value,val2)); } - return fix_result(atan(value)); + return atan(value); } double Item_func_cos::val_real() @@ -1721,7 +1721,7 @@ double Item_func_cos::val_real() double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; - return fix_result(cos(value)); + return cos(value); } double Item_func_sin::val_real() @@ -1730,7 +1730,7 @@ double Item_func_sin::val_real() double value= args[0]->val_real(); if ((null_value=args[0]->null_value)) return 0.0; - return fix_result(sin(value)); + return sin(value); } double Item_func_tan::val_real() diff --git a/sql/item_func.h b/sql/item_func.h index e09b584de95..cdcbbdab150 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -192,6 +192,13 @@ public: void * arg, traverse_order order); bool is_expensive_processor(uchar *arg); virtual bool is_expensive() { return 0; } + inline double fix_result(double value) + { + if (isfinite(value)) + return value; + null_value=1; + return 0.0; + } }; @@ -499,18 +506,6 @@ class Item_dec_func :public Item_real_func decimals=NOT_FIXED_DEC; max_length=float_length(decimals); maybe_null=1; } - inline double fix_result(double value) - { -#ifndef HAVE_FINITE - return value; -#else - /* The following should be safe, even if we compare doubles */ - if (finite(value) && value != POSTFIX_ERROR) - return value; - null_value=1; - return 0.0; -#endif - } }; class Item_func_exp :public Item_dec_func diff --git a/sql/matherr.c b/sql/matherr.c deleted file mode 100644 index 4998d8b4961..00000000000 --- a/sql/matherr.c +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright (C) 2000-2001 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Fix that we got POSTFIX_ERROR when doing unreasonable math (not core) */ - -#include -#include - - /* Fix that we gets POSTFIX_ERROR when error in math */ - -#if defined(HAVE_MATHERR) -int matherr(struct exception *x) -{ - if (x->type != PLOSS) - x->retval=POSTFIX_ERROR; - switch (x->type) { - case DOMAIN: - case SING: - my_errno=EDOM; - break; - case OVERFLOW: - case UNDERFLOW: - my_errno=ERANGE; - break; - default: - break; - } - return(1); /* Take no other action */ -} -#endif diff --git a/sql/unireg.h b/sql/unireg.h index f0b4a88c7f8..a18d42baeaa 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -108,7 +108,6 @@ #define READ_RECORD_BUFFER (uint) (IO_SIZE*8) /* Pointer_buffer_size */ #define DISK_BUFFER_SIZE (uint) (IO_SIZE*16) /* Size of diskbuffer */ -#define POSTFIX_ERROR DBL_MAX #define ME_INFO (ME_HOLDTANG+ME_OLDWIN+ME_NOREFRESH) #define ME_ERROR (ME_BELL+ME_OLDWIN+ME_NOREFRESH) -- cgit v1.2.1 From 9dfc925db0db97f20a561d976bd9c2c40917600a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 12:52:04 +0100 Subject: Upon the sql command flush logs, we need to ensure that all outstanding ndb data to be logged has made it to the binary log to get a deterministic behavior on the rotation of the log. --- sql/ha_ndbcluster_binlog.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sql') diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 841dce2d832..af185e97360 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -683,6 +683,18 @@ static void ndbcluster_reset_slave(THD *thd) /* Initialize the binlog part of the ndb handlerton */ + +/** + Upon the sql command flush logs, we need to ensure that all outstanding + ndb data to be logged has made it to the binary log to get a deterministic + behavior on the rotation of the log. + */ +static bool ndbcluster_flush_logs(handlerton *hton) +{ + ndbcluster_binlog_wait(current_thd); + return FALSE; +} + static int ndbcluster_binlog_func(handlerton *hton, THD *thd, enum_binlog_func fn, void *arg) @@ -711,6 +723,7 @@ static int ndbcluster_binlog_func(handlerton *hton, THD *thd, void ndbcluster_binlog_init_handlerton() { handlerton *h= ndbcluster_hton; + h->flush_logs= ndbcluster_flush_logs; h->binlog_func= ndbcluster_binlog_func; h->binlog_log_query= ndbcluster_binlog_log_query; } -- cgit v1.2.1 From 6988f45e6b9fc6546133cfe1e48607bf787bf0de Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 14:52:21 +0100 Subject: WL#4078: Document binary format of binlog entries Minor update with corrections and notes on the binlog format. This only affects comments, not code. sql/log_event.h: Fixes in documentation of binlog format. --- sql/log_event.h | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) (limited to 'sql') diff --git a/sql/log_event.h b/sql/log_event.h index 4e151d6cde9..c46827253a3 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -670,18 +670,18 @@ typedef struct st_print_event_info Any @c Log_event saved on disk consists of the following three components. - * Common-Header - * Post-Header - * Body + - Common-Header + - Post-Header + - Body The Common-Header, documented in the table @ref Table_common_header "below", always has the same form and length within one version of - MySQL. Each event type specifies a form and length of the - Post-Header common to all events of the type. The Body may be of - different form and length even for different events of the same - type. The binary formats of Post-Header and Body are documented - separately in each subclass. The binary format of Common-Header is - as follows. + MySQL. Each event type specifies a format and length of the + Post-Header. The length of the Common-Header is the same for all + events of the same type. The Body may be of different format and + length even for different events of the same type. The binary + formats of Post-Header and Body are documented separately in each + subclass. The binary format of Common-Header is as follows. @@ -750,8 +750,8 @@ typedef struct st_print_event_info - Some events use a special format for efficient representation of unsigned integers, called Packed Integer. A Packed Integer has the capacity of storing up to 8-byte integers, while small integers - still can use 1, 3, or 4 bytes. The first byte indicates how many - bytes are used by the integer, according to the following table: + still can use 1, 3, or 4 bytes. The value of the first byte + determines how to read the number, according to the following table:
Common-Header
@@ -763,7 +763,7 @@ typedef struct st_print_event_info - @@ -1174,6 +1174,10 @@ protected: @section Query_log_event_binary_format Binary format + See @ref Log_event_binary_format "Binary format for log events" for + a general discussion and introduction to the binary format of binlog + events. + The Post-Header has five components:
Format of Packed Integer
0-250The first byte is the number (in range 0-250), and no more + The first byte is the number (in the range 0-250), and no more bytes are used.
@@ -1407,7 +1411,7 @@ protected: query "SELECT id, character_set_name, collation_name FROM COLLATIONS". - Cf. Q_CHARSET_DATABASE_NUMBER below. + Cf. Q_CHARSET_DATABASE_CODE below. This field is always written. @@ -1442,7 +1446,7 @@ protected: - + @@ -1480,7 +1484,7 @@ protected: Q_CATALOG_CODE will never be written by a new master, but can still be understood by a new slave. - * See Q_CHARSET_DATABASE_NUMBER in the table above. + * See Q_CHARSET_DATABASE_CODE in the table above. */ class Query_log_event: public Log_event @@ -1919,6 +1923,8 @@ private: @subsection Load_log_event_notes_on_previous_versions Notes on Previous Versions + This event type is understood by current versions, but only + generated by MySQL 3.23 and earlier. */ class Load_log_event: public Log_event { -- cgit v1.2.1 From 46db2da52fa4b6305006ebc42a291b48deea2a10 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 15:22:14 +0100 Subject: Removed the unused function int THD::binlog_flush_transaction_cache() --- sql/log.cc | 29 ----------------------------- sql/sql_class.h | 1 - 2 files changed, 30 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 9b5b2ae5a6c..f12cedfbf05 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3403,35 +3403,6 @@ void THD::binlog_set_stmt_begin() { trx_data->before_stmt_pos= pos; } -int THD::binlog_flush_transaction_cache() -{ - DBUG_ENTER("binlog_flush_transaction_cache"); - binlog_trx_data *trx_data= (binlog_trx_data*) - thd_get_ha_data(this, binlog_hton); - DBUG_PRINT("enter", ("trx_data=0x%lu", (ulong) trx_data)); - if (trx_data) - DBUG_PRINT("enter", ("trx_data->before_stmt_pos=%lu", - (ulong) trx_data->before_stmt_pos)); - - /* - Write the transaction cache to the binary log. We don't flush and - sync the log file since we don't know if more will be written to - it. If the caller want the log file sync:ed, the caller has to do - it. - - The transaction data is only reset upon a successful write of the - cache to the binary log. - */ - - if (trx_data && likely(mysql_bin_log.is_open())) { - if (int error= mysql_bin_log.write_cache(&trx_data->trans_log, true, true)) - DBUG_RETURN(error); - trx_data->reset(); - } - - DBUG_RETURN(0); -} - /* Write a table map to the binary log. diff --git a/sql/sql_class.h b/sql/sql_class.h index 5f2b50f48b8..b660c615920 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1243,7 +1243,6 @@ public: Public interface to write RBR events to the binlog */ void binlog_start_trans_and_stmt(); - int binlog_flush_transaction_cache(); void binlog_set_stmt_begin(); int binlog_write_table_map(TABLE *table, bool is_transactional); int binlog_write_row(TABLE* table, bool is_transactional, -- cgit v1.2.1 From 27498bbaba9f40f875d62fe0bb676c8218ee2880 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 16:59:03 +0200 Subject: Fixed a test. mysql-test/r/change_user.result: Replaced value in result file, it was dependend on architecture. mysql-test/t/change_user.test: Replaced an architecture dependend value in test sql/mysqld.cc: Can be made shorter and without ifdefs. --- sql/mysqld.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9ca2ab5db0e..455698d4ff4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -308,11 +308,7 @@ TYPELIB thread_handling_typelib= const char *first_keyword= "first", *binary_keyword= "BINARY"; const char *my_localhost= "localhost", *delayed_user= "DELAYED"; -#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) -#define GET_HA_ROWS GET_ULL -#else -#define GET_HA_ROWS GET_ULONG -#endif +#define GET_HA_ROWS (~ (ha_rows) 0) bool opt_large_files= sizeof(my_off_t) > 4; -- cgit v1.2.1 From 985e9523479fb1143ac60e1644613d34e126ef58 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 22:23:39 +0300 Subject: Fix for Bug#34337: Server crash when Altering a view using a table name. The problem was that fill_defined_view_parts() did not return an error if a table is going to be altered. That happened if the table was already in the table cache. In that case, open_table() returned non-NULL value (valid TABLE-instance from the cache). The fix is to ensure that an error is thrown even if the table is in the cache. mysql-test/r/view.result: Fix result file. mysql-test/t/view.test: Add a test case for Bug#34337: Server crash when Altering a view using a table name. sql/sql_view.cc: Report an error if we're going to work with a table. --- sql/sql_view.cc | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 0b0763afb84..0642a2d2e17 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -182,10 +182,33 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) TABLE_LIST decoy; memcpy (&decoy, view, sizeof (TABLE_LIST)); - if (!open_table(thd, &decoy, thd->mem_root, ¬_used, OPEN_VIEW_NO_PARSE) && - !decoy.view) + + /* + Let's reset decoy.view before calling open_table(): when we start + supporting ALTER VIEW in PS/SP that may save us from a crash. + */ + + decoy.view= NULL; + + /* + open_table() will return NULL if 'decoy' is idenitifying a view *and* + there is no TABLE object for that view in the table cache. However, + decoy.view will be set to 1. + + If there is a TABLE-instance for the oject identified by 'decoy', + open_table() will return that instance no matter if it is a table or + a view. + + Thus, there is no need to check for the return value of open_table(), + since the return value itself does not mean anything. + */ + + open_table(thd, &decoy, thd->mem_root, ¬_used, OPEN_VIEW_NO_PARSE); + + if (!decoy.view) { - /* It's a table */ + /* It's a table. */ + my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW"); return TRUE; } -- cgit v1.2.1 From a399fefd565b333078301f4d7406a2bf632bfb19 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 16:45:24 -0300 Subject: Bug#32265 Server returns different metadata if prepared statement is used Executing a prepared statement associated with a materialized cursor yields to the client a metadata packet with wrong table and database names. The problem was occurring because the server was sending the the name of the temporary table used by the cursor instead of the table name of the original table. The same problem occurs when selecting from views, in which case the table name was being sent and not the name of the view. The solution is to fill the list item from the temporary table but preserving the table and database names of the original fields. This is achieved by tweaking the Select_materialize to accept a pointer to the Materialized_cursor class which contains the item list to be filled. sql/sql_cursor.cc: Fill the item list in the send_fields method and preserve the table and database name of the fields. tests/mysql_client_test.c: Add test case for Bug#32265 --- sql/sql_cursor.cc | 98 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 22 deletions(-) (limited to 'sql') diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 2e98da42be1..c2345f1f2cd 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -88,6 +88,7 @@ class Materialized_cursor: public Server_side_cursor public: Materialized_cursor(select_result *result, TABLE *table); + int fill_item_list(THD *thd, List &send_fields); virtual bool is_open() const { return table != 0; } virtual int open(JOIN *join __attribute__((unused))); virtual void fetch(ulong num_rows); @@ -109,6 +110,7 @@ class Select_materialize: public select_union { select_result *result; /* the result object of the caller (PS or SP) */ public: + Materialized_cursor *materialized_cursor; Select_materialize(select_result *result_arg) :result(result_arg) {} virtual bool send_fields(List &list, uint flags); }; @@ -152,7 +154,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result))) { - delete result; + delete result_materialize; return 1; } @@ -174,13 +176,13 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, /* Possible options here: - a sensitive cursor is open. In this case rc is 0 and - result_materialize->table is NULL, or + result_materialize->materialized_cursor is NULL, or - a materialized cursor is open. In this case rc is 0 and - result_materialize->table is not NULL - - an error occured during materializaton. - result_materialize->table is not NULL, but rc != 0 + result_materialize->materialized is not NULL + - an error occurred during materialization. + result_materialize->materialized_cursor is not NULL, but rc != 0 - successful completion of mysql_execute_command without - a cursor: rc is 0, result_materialize->table is NULL, + a cursor: rc is 0, result_materialize->materialized_cursor is NULL, sensitive_cursor is not open. This is possible if some command writes directly to the network, bypassing select_result mechanism. An example of @@ -191,7 +193,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, if (sensitive_cursor->is_open()) { - DBUG_ASSERT(!result_materialize->table); + DBUG_ASSERT(!result_materialize->materialized_cursor); /* It's safer if we grab THD state after mysql_execute_command is finished and not in Sensitive_cursor::open(), because @@ -202,18 +204,10 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, *pcursor= sensitive_cursor; goto end; } - else if (result_materialize->table) + else if (result_materialize->materialized_cursor) { - Materialized_cursor *materialized_cursor; - TABLE *table= result_materialize->table; - MEM_ROOT *mem_root= &table->mem_root; - - if (!(materialized_cursor= new (mem_root) - Materialized_cursor(result, table))) - { - rc= 1; - goto err_open; - } + Materialized_cursor *materialized_cursor= + result_materialize->materialized_cursor; if ((rc= materialized_cursor->open(0))) { @@ -229,8 +223,6 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, err_open: DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open())); delete sensitive_cursor; - if (result_materialize->table) - free_tmp_table(thd, result_materialize->table); end: delete result_materialize; return rc; @@ -544,6 +536,51 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg, } +/** + Preserve the original metadata that would be sent to the client. + + @param thd Thread identifier. + @param send_fields List of fields that would be sent. +*/ + +int Materialized_cursor::fill_item_list(THD *thd, List &send_fields) +{ + Query_arena backup_arena; + int rc; + List_iterator_fast it_org(send_fields); + List_iterator_fast it_dst(item_list); + Item *item_org; + Item *item_dst; + + thd->set_n_backup_active_arena(this, &backup_arena); + + if ((rc= table->fill_item_list(&item_list))) + goto end; + + DBUG_ASSERT(send_fields.elements == item_list.elements); + + /* + Unless we preserve the original metadata, it will be lost, + since new fields describe columns of the temporary table. + Allocate a copy of the name for safety only. Currently + items with original names are always kept in memory, + but in case this changes a memory leak may be hard to notice. + */ + while ((item_dst= it_dst++, item_org= it_org++)) + { + Send_field send_field; + Item_ident *ident= static_cast(item_dst); + item_org->make_field(&send_field); + + ident->db_name= thd->strdup(send_field.db_name); + ident->table_name= thd->strdup(send_field.table_name); + } +end: + thd->restore_active_arena(this, &backup_arena); + /* Check for thd->is_error() in case of OOM */ + return rc || thd->net.report_error; +} + int Materialized_cursor::open(JOIN *join __attribute__((unused))) { THD *thd= fake_unit.thd; @@ -552,8 +589,7 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused))) thd->set_n_backup_active_arena(this, &backup_arena); /* Create a list of fields and start sequential scan */ - rc= (table->fill_item_list(&item_list) || - result->prepare(item_list, &fake_unit) || + rc= (result->prepare(item_list, &fake_unit) || table->file->ha_rnd_init(TRUE)); thd->restore_active_arena(this, &backup_arena); if (rc == 0) @@ -664,6 +700,24 @@ bool Select_materialize::send_fields(List &list, uint flags) if (create_result_table(unit->thd, unit->get_unit_column_types(), FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, "")) return TRUE; + + materialized_cursor= new (&table->mem_root) + Materialized_cursor(result, table); + + if (! materialized_cursor) + { + free_tmp_table(table->in_use, table); + table= 0; + return TRUE; + } + if (materialized_cursor->fill_item_list(unit->thd, list)) + { + delete materialized_cursor; + table= 0; + materialized_cursor= 0; + return TRUE; + } + return FALSE; } -- cgit v1.2.1 From 7114fbb943514e030c7554273b266adb923b035a Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 17:26:50 -0300 Subject: Bug#34587 Creating a view inside a stored procedure leads to a server crash The problem is that when a stored procedure is being parsed for the first execution, the body is copied to a temporary buffer which is disregarded sometime after the statement is parsed. And during this parsing phase, the rule for CREATE VIEW was holding a reference to the string being parsed for use during the execution of the CREATE VIEW statement, leading to invalid memory access later. The solution is to allocate and copy the SELECT of a CREATE VIEW statement using the thread memory root, which is set to the permanent arena of the stored procedure. mysql-test/r/view.result: Add test case result for Bug#34587 mysql-test/t/view.test: Add test case for Bug#34587 sql/sql_lex.h: Remove start and end position variables. The SELECT of a CREATE VIEW is now allocated at parse time. sql/sql_view.cc: Remove assertion that is not true when the statement is being re-executed. Use string that was trimmed of leading and trailing whitespace at parse time. sql/sql_yacc.yy: Allocate the SELECT of a CREATE VIEW using the current thread memory root and remove any leading and trailing whitespace. --- sql/sql_lex.h | 6 ++---- sql/sql_view.cc | 8 ++------ sql/sql_yacc.yy | 8 ++++++-- 3 files changed, 10 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ef0a9bb11ef..744019c8ae9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1513,10 +1513,8 @@ typedef struct st_lex : public Query_tables_list /* store original leaf_tables for INSERT SELECT and PS/SP */ TABLE_LIST *leaf_tables_insert; - /** Start of SELECT of CREATE VIEW statement */ - const char* create_view_select_start; - /** End of SELECT of CREATE VIEW statement */ - const char* create_view_select_end; + /** SELECT of CREATE VIEW statement */ + LEX_STRING create_view_select; /** Start of 'ON table', in trigger statements. */ const char* raw_trg_on_table_name_begin; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1a4d7d515a8..2230b3de8ad 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -237,7 +237,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, /* This is ensured in the parser. */ DBUG_ASSERT(!lex->proc_list.first && !lex->result && - !lex->param_list.elements && !lex->derived_tables); + !lex->param_list.elements); if (mode != VIEW_CREATE_NEW) { @@ -718,11 +718,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, /* fill structure */ view->select_stmt.str= view_query.c_ptr_safe(); view->select_stmt.length= view_query.length(); - - view->source.str= (char*) thd->lex->create_view_select_start; - view->source.length= (thd->lex->create_view_select_end - - thd->lex->create_view_select_start); - trim_whitespace(thd->charset(), & view->source); + view->source= thd->lex->create_view_select; view->file_version= 1; view->calc_md5(md5); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 764e593a1ed..f1689b28719 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12056,18 +12056,22 @@ view_select: lex->parsing_options.allows_select_into= FALSE; lex->parsing_options.allows_select_procedure= FALSE; lex->parsing_options.allows_derived= FALSE; - lex->create_view_select_start= lip->get_cpp_ptr(); + lex->create_view_select.str= (char *) lip->get_cpp_ptr(); } view_select_aux view_check_option { THD *thd= YYTHD; LEX *lex= Lex; Lex_input_stream *lip= thd->m_lip; + uint len= lip->get_cpp_ptr() - lex->create_view_select.str; + void *create_view_select= thd->memdup(lex->create_view_select.str, len); + lex->create_view_select.length= len; + lex->create_view_select.str= (char *) create_view_select; + trim_whitespace(thd->charset(), &lex->create_view_select); lex->parsing_options.allows_variable= TRUE; lex->parsing_options.allows_select_into= TRUE; lex->parsing_options.allows_select_procedure= TRUE; lex->parsing_options.allows_derived= TRUE; - lex->create_view_select_end= lip->get_cpp_ptr(); } ; -- cgit v1.2.1 From e19c8e2ebfdb5c2a50e71d4192681b8b4bd4efad Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 23:18:01 +0200 Subject: Bug #31316 Report server id clashes in SHOW SLAVE STATUS "Server_IO_State" field Critical error messages from get_master_version_and_clock() were written only to the slave errorlog while Show slave status did not display any incident happened. Although the artifact was reported for a particular --replicate-same-server-id related issue the fix refines all critical error reporting with deploying rli->report(). The test for the bug covers only --replicate-same-server-id error reporting. mysql-test/suite/rpl/r/rpl_server_id1.result: new results reflecting changes mysql-test/suite/rpl/t/rpl_server_id1.test: Preserving the idea of the test unnecessary queries and the sleep are eliminated. In the end the slave must stop with the error displayable via $$$. sql/slave.cc: improving get_master_version_and_clock() code to report a critical incident via rli->report() that takes care of bothe the error log and the slave's status info placeholders. A critical error that force the IO slave thread to terminate is handled immediately (goto err). --- sql/slave.cc | 47 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index ea0dde942da..1880dcf0d43 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -747,7 +747,11 @@ int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) { + char err_buff[MAX_SLAVE_ERRMSG]; const char* errmsg= 0; + int err_code= 0; + MYSQL_RES *master_res= 0; + MYSQL_ROW master_row; DBUG_ENTER("get_master_version_and_clock"); /* @@ -758,7 +762,11 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) mi->rli.relay_log.description_event_for_queue= 0; if (!my_isdigit(&my_charset_bin,*mysql->server_version)) + { errmsg = "Master reported unrecognized MySQL version"; + err_code= ER_SLAVE_FATAL_ERROR; + sprintf(err_buff, ER(err_code), errmsg); + } else { /* @@ -770,6 +778,8 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) case '1': case '2': errmsg = "Master reported unrecognized MySQL version"; + err_code= ER_SLAVE_FATAL_ERROR; + sprintf(err_buff, ER(err_code), errmsg); break; case '3': mi->rli.relay_log.description_event_for_queue= new @@ -802,26 +812,21 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) */ if (errmsg) - { - sql_print_error(errmsg); - DBUG_RETURN(1); - } + goto err; /* as we are here, we tried to allocate the event */ if (!mi->rli.relay_log.description_event_for_queue) { - mi->report(ERROR_LEVEL, ER_SLAVE_CREATE_EVENT_FAILURE, - ER(ER_SLAVE_CREATE_EVENT_FAILURE), - "default Format_description_log_event"); - DBUG_RETURN(1); + errmsg= "default Format_description_log_event"; + err_code= ER_SLAVE_CREATE_EVENT_FAILURE; + sprintf(err_buff, ER(err_code), errmsg); + goto err; } /* Compare the master and slave's clock. Do not die if master's clock is unavailable (very old master not supporting UNIX_TIMESTAMP()?). */ - MYSQL_RES *master_res= 0; - MYSQL_ROW master_row; if (!mysql_real_query(mysql, STRING_WITH_LEN("SELECT UNIX_TIMESTAMP()")) && (master_res= mysql_store_result(mysql)) && @@ -858,11 +863,17 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi) if ((master_row= mysql_fetch_row(master_res)) && (::server_id == strtoul(master_row[1], 0, 10)) && !mi->rli.replicate_same_server_id) + { errmsg= "The slave I/O thread stops because master and slave have equal \ MySQL server ids; these ids must be different for replication to work (or \ the --replicate-same-server-id option must be used on slave but this does \ not always make sense; please check the manual before using it)."; + err_code= ER_SLAVE_FATAL_ERROR; + sprintf(err_buff, ER(err_code), errmsg); + } mysql_free_result(master_res); + if (errmsg) + goto err; } /* @@ -893,10 +904,16 @@ not always make sense; please check the manual before using it)."; { if ((master_row= mysql_fetch_row(master_res)) && strcmp(master_row[0], global_system_variables.collation_server->name)) + { errmsg= "The slave I/O thread stops because master and slave have \ different values for the COLLATION_SERVER global variable. The values must \ be equal for replication to work"; + err_code= ER_SLAVE_FATAL_ERROR; + sprintf(err_buff, ER(err_code), errmsg); + } mysql_free_result(master_res); + if (errmsg) + goto err; } /* @@ -921,16 +938,24 @@ be equal for replication to work"; if ((master_row= mysql_fetch_row(master_res)) && strcmp(master_row[0], global_system_variables.time_zone->get_name()->ptr())) + { errmsg= "The slave I/O thread stops because master and slave have \ different values for the TIME_ZONE global variable. The values must \ be equal for replication to work"; + err_code= ER_SLAVE_FATAL_ERROR; + sprintf(err_buff, ER(err_code), errmsg); + } mysql_free_result(master_res); + + if (errmsg) + goto err; } err: if (errmsg) { - sql_print_error(errmsg); + DBUG_ASSERT(err_code != 0); + mi->report(ERROR_LEVEL, err_code, err_buff); DBUG_RETURN(1); } -- cgit v1.2.1 From 88421ee5038ebe83d448110c3386086c2bc71a1f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 20 Feb 2008 23:30:29 -0200 Subject: Post-merge fixes for bugs 34587 and 32265. mysql-test/r/view.result: Drop created view. mysql-test/t/view.test: Update test result. sql/sql_cursor.cc: Fix compilation failure. tests/mysql_client_test.c: Manual merge. --- sql/sql_cursor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index 138116c9283..5c4e93d4c74 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -588,7 +588,7 @@ int Materialized_cursor::fill_item_list(THD *thd, List &send_fields) end: thd->restore_active_arena(this, &backup_arena); /* Check for thd->is_error() in case of OOM */ - return rc || thd->net.report_error; + return rc || thd->is_error(); } int Materialized_cursor::open(JOIN *join __attribute__((unused))) -- cgit v1.2.1 From fa08b280857fde69a70c68bd07797624a52ef262 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Feb 2008 12:17:32 +0300 Subject: Fix for Bug#34337: Server crash when Altering a view using a table name. The problem was that fill_defined_view_parts() did not return an error if a table is going to be altered. That happened if the table was already in the table cache. In that case, open_table() returned non-NULL value (valid TABLE-instance from the cache). The fix is to ensure that an error is thrown even if the table is in the cache. (This is a backport of the original patch for 5.1) mysql-test/r/view.result: Fix result file. mysql-test/r/view_grant.result: Fix result file. mysql-test/t/view.test: Add a test case for Bug#34337: Server crash when Altering a view using a table name. mysql-test/t/view_grant.test: Fix order-dependency. sql/sql_view.cc: Report an error if we're going to work with a table. --- sql/sql_view.cc | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_view.cc b/sql/sql_view.cc index dd0b92a06f8..48ab5b3af9e 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -182,10 +182,33 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) TABLE_LIST decoy; memcpy (&decoy, view, sizeof (TABLE_LIST)); - if (!open_table(thd, &decoy, thd->mem_root, ¬_used, OPEN_VIEW_NO_PARSE) && - !decoy.view) + + /* + Let's reset decoy.view before calling open_table(): when we start + supporting ALTER VIEW in PS/SP that may save us from a crash. + */ + + decoy.view= NULL; + + /* + open_table() will return NULL if 'decoy' is idenitifying a view *and* + there is no TABLE object for that view in the table cache. However, + decoy.view will be set to 1. + + If there is a TABLE-instance for the oject identified by 'decoy', + open_table() will return that instance no matter if it is a table or + a view. + + Thus, there is no need to check for the return value of open_table(), + since the return value itself does not mean anything. + */ + + open_table(thd, &decoy, thd->mem_root, ¬_used, OPEN_VIEW_NO_PARSE); + + if (!decoy.view) { - /* It's a table */ + /* It's a table. */ + my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW"); return TRUE; } -- cgit v1.2.1 From d8c8fd5b4feff08ab3d0480d9b2df78c43b8bf3a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Feb 2008 14:49:27 +0300 Subject: Fix for Bug#33065: Mysql not writing general query logs after sending SIGHUP. There were two problems: - after some recent fix, the server started to crash after receiving SIGHUP. That happened because LEX of new THD-object was not properly initialized. - user-specified log options were ignored when logs were reopened. The fix is to 1) initialize LEX and 2) take user-specified options into account. There is no test case in this CS, because our test suite does not support sending SIGHUP to the server. sql/mysqld.cc: Use proper logging after SIGHUP. sql/sql_parse.cc: Initialize LEX of new THD -- it is required to avoid crash in SIGHUP handling. --- sql/mysqld.cc | 14 ++++++++++++-- sql/sql_parse.cc | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 9c4e6f9e2a2..a982a8f4809 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2573,8 +2573,18 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) (TABLE_LIST*) 0, ¬_used); // Flush logs } /* reenable logs after the options were reloaded */ - logger.set_handlers(LOG_FILE, opt_slow_log ? LOG_TABLE:LOG_NONE, - opt_log ? LOG_TABLE:LOG_NONE); + if (log_output_options & LOG_NONE) + { + logger.set_handlers(LOG_FILE, + opt_slow_log ? LOG_TABLE : LOG_NONE, + opt_log ? LOG_TABLE : LOG_NONE); + } + else + { + logger.set_handlers(LOG_FILE, + opt_slow_log ? log_output_options : LOG_NONE, + opt_log ? log_output_options : LOG_NONE); + } break; #ifdef USE_ONE_SIGNAL_HAND case THR_SERVER_ALARM: diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a78ac978a4a..ccc8b80ffc8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6448,6 +6448,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, { thd->thread_stack= (char*) &tmp_thd; thd->store_globals(); + lex_start(thd); } if (thd) { -- cgit v1.2.1 From 315665cf67dd4e56922955b051eff2c384f2298e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Feb 2008 14:58:29 -0300 Subject: Bug#32890 Crash after repeated create and drop of tables and views The problem is that CREATE VIEW statements inside prepared statements weren't being expanded during the prepare phase, which leads to objects not being allocated in the appropriate memory arenas. The solution is to perform the validation of CREATE VIEW statements during the prepare phase of a prepared statement. The validation during the prepare phase assures that transformations of the parsed tree will use the permanent arena of the prepared statement. mysql-test/r/ps.result: Add test case result for Bug#32890 mysql-test/t/ps.test: Add test case for Bug#32890 sql/item.h: Restore original field name if name is auto generated. sql/sql_prepare.cc: Validate and prepare a CREATE VIEW statement for execution. sql/sql_view.cc: Move privileges check to it's own function. sql/sql_view.h: Export function which check privileges of a CREATE VIEW statement. --- sql/item.h | 43 ++++++----- sql/sql_prepare.cc | 40 ++++++++++ sql/sql_view.cc | 213 +++++++++++++++++++++++++++++++---------------------- sql/sql_view.h | 3 + 4 files changed, 192 insertions(+), 107 deletions(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index 5f511557f47..ae3e240778a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -879,6 +879,23 @@ public: class sp_head; +class Item_basic_constant :public Item +{ +public: + /* to prevent drop fixed flag (no need parent cleanup call) */ + void cleanup() + { + /* + Restore the original field name as it might not have been allocated + in the statement memory. If the name is auto generated, it must be + done again between subsequent executions of a prepared statement. + */ + if (orig_name) + name= orig_name; + } +}; + + /***************************************************************************** The class is a base class for representation of stored routine variables in the Item-hierarchy. There are the following kinds of SP-vars: @@ -1161,7 +1178,7 @@ bool agg_item_charsets(DTCollation &c, const char *name, Item **items, uint nitems, uint flags, int item_sep); -class Item_num: public Item +class Item_num: public Item_basic_constant { public: Item_num() {} /* Remove gcc warning */ @@ -1352,7 +1369,7 @@ public: friend class st_select_lex_unit; }; -class Item_null :public Item +class Item_null :public Item_basic_constant { public: Item_null(char *name_par=0) @@ -1374,8 +1391,6 @@ public: bool send(Protocol *protocol, String *str); enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; } - /* to prevent drop fixed flag (no need parent cleanup call) */ - void cleanup() {} bool basic_const_item() const { return 1; } Item *clone_item() { return new Item_null(name); } bool is_null() { return 1; } @@ -1567,8 +1582,6 @@ public: int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } Item *clone_item() { return new Item_int(name,value,max_length); } - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} void print(String *str); Item_num *neg() { value= -value; return this; } uint decimal_precision() const @@ -1621,8 +1634,6 @@ public: { return new Item_decimal(name, &decimal_value, decimals, max_length); } - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} void print(String *str); Item_num *neg() { @@ -1673,8 +1684,6 @@ public: String *val_str(String*); my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} Item *clone_item() { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } @@ -1696,7 +1705,7 @@ public: }; -class Item_string :public Item +class Item_string :public Item_basic_constant { public: Item_string(const char *str,uint length, @@ -1780,8 +1789,6 @@ public: max_length= str_value.numchars() * collation.collation->mbmaxlen; } void print(String *str); - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} }; @@ -1839,10 +1846,10 @@ public: }; -class Item_hex_string: public Item +class Item_hex_string: public Item_basic_constant { public: - Item_hex_string(): Item() {} + Item_hex_string() {} Item_hex_string(const char *str,uint str_length); enum Type type() const { return VARBIN_ITEM; } double val_real() @@ -1858,8 +1865,6 @@ public: enum Item_result result_type () const { return STRING_RESULT; } enum Item_result cast_to_int_type() const { return INT_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} void print(String *str); bool eq(const Item *item, bool binary_cmp) const; virtual Item *safe_charset_converter(CHARSET_INFO *tocs); @@ -2449,7 +2454,7 @@ private: }; -class Item_cache: public Item +class Item_cache: public Item_basic_constant { protected: Item *example; @@ -2486,8 +2491,6 @@ public: static Item_cache* get_cache(const Item *item); table_map used_tables() const { return used_table_map; } virtual void keep_array() {} - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} void print(String *str); bool eq_def(Field *field) { diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 74cbd2c5505..4972b259693 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1512,6 +1512,45 @@ static bool mysql_test_create_table(Prepared_statement *stmt) } +/** + @brief Validate and prepare for execution CREATE VIEW statement + + @param stmt prepared statement + + @note This function handles create view commands. + + @retval FALSE Operation was a success. + @retval TRUE An error occured. +*/ + +static bool mysql_test_create_view(Prepared_statement *stmt) +{ + DBUG_ENTER("mysql_test_create_view"); + THD *thd= stmt->thd; + LEX *lex= stmt->lex; + SELECT_LEX *select_lex= &lex->select_lex; + bool res= TRUE; + /* Skip first table, which is the view we are creating */ + bool link_to_local; + TABLE_LIST *view= lex->unlink_first_table(&link_to_local); + TABLE_LIST *tables= lex->query_tables; + + if (create_view_precheck(thd, tables, view, lex->create_view_mode)) + goto err; + + if (open_normal_and_derived_tables(thd, tables, 0)) + goto err; + + lex->view_prepare_mode= 1; + res= select_like_stmt_test(stmt, 0, 0); + +err: + /* put view back for PS rexecuting */ + lex->link_first_table_back(view, link_to_local); + DBUG_RETURN(res); +} + + /* Validate and prepare for execution a multi update statement. @@ -1730,6 +1769,7 @@ static bool check_prepared_statement(Prepared_statement *stmt, my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0)); goto error; } + res= mysql_test_create_view(stmt); break; case SQLCOM_DO: res= mysql_test_do_fields(stmt, tables, lex->insert_list); diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 48ab5b3af9e..4c8e6e80c41 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -227,104 +227,31 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view) return FALSE; } +#ifndef NO_EMBEDDED_ACCESS_CHECKS /** - @brief Creating/altering VIEW procedure + @brief CREATE VIEW privileges pre-check. @param thd thread handler + @param tables tables used in the view @param views views to create @param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE - @note This function handles both create and alter view commands. - @retval FALSE Operation was a success. @retval TRUE An error occured. */ -bool mysql_create_view(THD *thd, TABLE_LIST *views, - enum_view_create_mode mode) +bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, + enum_view_create_mode mode) { LEX *lex= thd->lex; - bool link_to_local; /* first table in list is target VIEW name => cut off it */ - TABLE_LIST *view= lex->unlink_first_table(&link_to_local); - TABLE_LIST *tables= lex->query_tables; TABLE_LIST *tbl; SELECT_LEX *select_lex= &lex->select_lex; -#ifndef NO_EMBEDDED_ACCESS_CHECKS SELECT_LEX *sl; -#endif - SELECT_LEX_UNIT *unit= &lex->unit; - bool res= FALSE; - DBUG_ENTER("mysql_create_view"); - - /* This is ensured in the parser. */ - DBUG_ASSERT(!lex->proc_list.first && !lex->result && - !lex->param_list.elements && !lex->derived_tables); - - if (mode != VIEW_CREATE_NEW) - { - if (mode == VIEW_ALTER && - fill_defined_view_parts(thd, view)) - { - res= TRUE; - goto err; - } - sp_cache_invalidate(); - } + bool res= TRUE; + DBUG_ENTER("create_view_precheck"); - if (!lex->definer) - { - /* - DEFINER-clause is missing; we have to create default definer in - persistent arena to be PS/SP friendly. - If this is an ALTER VIEW then the current user should be set as - the definer. - */ - Query_arena original_arena; - Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena); - - if (!(lex->definer= create_default_definer(thd))) - res= TRUE; - - if (ps_arena) - thd->restore_active_arena(ps_arena, &original_arena); - - if (res) - goto err; - } - -#ifndef NO_EMBEDDED_ACCESS_CHECKS - /* - check definer of view: - - same as current user - - current user has SUPER_ACL - */ - if (lex->definer && - (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 || - my_strcasecmp(system_charset_info, - lex->definer->host.str, - thd->security_ctx->priv_host) != 0)) - { - if (!(thd->security_ctx->master_access & SUPER_ACL)) - { - my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); - res= TRUE; - goto err; - } - else - { - if (!is_acl_user(lex->definer->host.str, - lex->definer->user.str)) - { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_NO_SUCH_USER, - ER(ER_NO_SUCH_USER), - lex->definer->user.str, - lex->definer->host.str); - } - } - } /* Privilege check for view creation: - user has CREATE VIEW privilege on view table @@ -346,10 +273,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, (check_access(thd, DROP_ACL, view->db, &view->grant.privilege, 0, 0, is_schema_db(view->db)) || grant_option && check_grant(thd, DROP_ACL, view, 0, 1, 0)))) - { - res= TRUE; goto err; - } + for (sl= select_lex; sl; sl= sl->next_select()) { for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local) @@ -363,7 +288,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY", thd->security_ctx->priv_user, thd->security_ctx->priv_host, tbl->table_name); - res= TRUE; goto err; } /* @@ -399,10 +323,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, if (check_access(thd, SELECT_ACL, tbl->db, &tbl->grant.privilege, 0, 0, test(tbl->schema_table)) || grant_option && check_grant(thd, SELECT_ACL, tbl, 0, 1, 0)) - { - res= TRUE; goto err; - } } } } @@ -426,8 +347,126 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } } } + + res= FALSE; + +err: + DBUG_RETURN(res || thd->net.report_error); +} + +#else + +bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, + enum_view_create_mode mode) +{ + return FALSE; +} + +#endif + + +/** + @brief Creating/altering VIEW procedure + + @param thd thread handler + @param views views to create + @param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE + + @note This function handles both create and alter view commands. + + @retval FALSE Operation was a success. + @retval TRUE An error occured. +*/ + +bool mysql_create_view(THD *thd, TABLE_LIST *views, + enum_view_create_mode mode) +{ + LEX *lex= thd->lex; + bool link_to_local; + /* first table in list is target VIEW name => cut off it */ + TABLE_LIST *view= lex->unlink_first_table(&link_to_local); + TABLE_LIST *tables= lex->query_tables; + TABLE_LIST *tbl; + SELECT_LEX *select_lex= &lex->select_lex; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + SELECT_LEX *sl; +#endif + SELECT_LEX_UNIT *unit= &lex->unit; + bool res= FALSE; + DBUG_ENTER("mysql_create_view"); + + /* This is ensured in the parser. */ + DBUG_ASSERT(!lex->proc_list.first && !lex->result && + !lex->param_list.elements && !lex->derived_tables); + + if (mode != VIEW_CREATE_NEW) + { + if (mode == VIEW_ALTER && + fill_defined_view_parts(thd, view)) + { + res= TRUE; + goto err; + } + sp_cache_invalidate(); + } + + if (!lex->definer) + { + /* + DEFINER-clause is missing; we have to create default definer in + persistent arena to be PS/SP friendly. + If this is an ALTER VIEW then the current user should be set as + the definer. + */ + Query_arena original_arena; + Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena); + + if (!(lex->definer= create_default_definer(thd))) + res= TRUE; + + if (ps_arena) + thd->restore_active_arena(ps_arena, &original_arena); + + if (res) + goto err; + } + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* + check definer of view: + - same as current user + - current user has SUPER_ACL + */ + if (lex->definer && + (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 || + my_strcasecmp(system_charset_info, + lex->definer->host.str, + thd->security_ctx->priv_host) != 0)) + { + if (!(thd->security_ctx->master_access & SUPER_ACL)) + { + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); + res= TRUE; + goto err; + } + else + { + if (!is_acl_user(lex->definer->host.str, + lex->definer->user.str)) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_NO_SUCH_USER, + ER(ER_NO_SUCH_USER), + lex->definer->user.str, + lex->definer->host.str); + } + } + } #endif + if ((res= create_view_precheck(thd, tables, view, mode))) + goto err; + if (open_and_lock_tables(thd, tables)) { res= TRUE; diff --git a/sql/sql_view.h b/sql/sql_view.h index ab0920e0bf2..1d45283352b 100644 --- a/sql/sql_view.h +++ b/sql/sql_view.h @@ -15,6 +15,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, + enum_view_create_mode mode); + bool mysql_create_view(THD *thd, TABLE_LIST *view, enum_view_create_mode mode); -- cgit v1.2.1 From 9f245df8530a560844aca138d103dd2f78301005 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Feb 2008 19:28:25 -0200 Subject: Post-merge fix to silence compiler warning. sql/sql_prepare.cc: Removed unused variable. --- sql/sql_prepare.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 4972b259693..18cfd8d7dfc 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1528,7 +1528,6 @@ static bool mysql_test_create_view(Prepared_statement *stmt) DBUG_ENTER("mysql_test_create_view"); THD *thd= stmt->thd; LEX *lex= stmt->lex; - SELECT_LEX *select_lex= &lex->select_lex; bool res= TRUE; /* Skip first table, which is the view we are creating */ bool link_to_local; -- cgit v1.2.1 From 3676f5188e93a824956dc43c9122904498522ffa Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 21 Feb 2008 23:58:45 -0200 Subject: Post-merge fixes for bug 32890 mysql-test/r/ps.result: Update test case results sql/item.h: Manual merge sql/sql_view.cc: Manual merge --- sql/item.h | 2 -- sql/sql_view.cc | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index f7a4ead9a50..f9a944cc582 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1975,8 +1975,6 @@ public: private: bool m_cs_specified; - // to prevent drop fixed flag (no need parent cleanup call) - void cleanup() {} }; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 92cf3529d2f..608c7a9eaa8 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -351,7 +351,7 @@ bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view, res= FALSE; err: - DBUG_RETURN(res || thd->net.report_error); + DBUG_RETURN(res || thd->is_error()); } #else @@ -397,7 +397,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, /* This is ensured in the parser. */ DBUG_ASSERT(!lex->proc_list.first && !lex->result && - !lex->param_list.elements && !lex->derived_tables); + !lex->param_list.elements); if (mode != VIEW_CREATE_NEW) { -- cgit v1.2.1 From 1a8be8bccb198959c35794bc9055da093b0a4fc9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Feb 2008 12:30:17 +0400 Subject: Bug#23588 SHOW COLUMNS on a temporary table causes locking issues skip lock_type update for temporary tables mysql-test/r/tablelock.result: test result mysql-test/t/tablelock.test: test case sql/sql_base.cc: skip lock_type update for temporary tables --- sql/sql_base.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8190b3eeacd..c9f20b3d71b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2852,8 +2852,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) } if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables) - tables->table->reginfo.lock_type= tables->lock_type == TL_WRITE_DEFAULT ? - thd->update_lock_default : tables->lock_type; + { + if (tables->lock_type == TL_WRITE_DEFAULT) + tables->table->reginfo.lock_type= thd->update_lock_default; + else if (tables->table->s->tmp_table == NO_TMP_TABLE) + tables->table->reginfo.lock_type= tables->lock_type; + } tables->table->grant= tables->grant; process_view_routines: -- cgit v1.2.1 From 012aab7d8bf7ae9c30751a6d5f666c7731ecfdf3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Feb 2008 11:34:18 +0300 Subject: Fix for bug #33049: Assert while running test-as3ap test(mysql-bench suite) Under some circumstances a combination of aggregate functions and GROUP BY in a SELECT query over a VIEW could lead to incorrect calculation of the result type of the aggregate function. This in turn could result in incorrect results, or assertion failures on debug builds. Fixed by changing the logic in Item_sum_hybrid::fix_fields() so that the argument's item is dereferenced before calling its type() method. mysql-test/r/view.result: Added a test case for bug #33049. mysql-test/t/view.test: Added a test case for bug #33049. sql/item_sum.cc: When calculating the result type of an aggregate function, dereference the argument's item before calling its type() method. --- sql/item_sum.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3d261dc2c36..47a7073c2e7 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -597,6 +597,7 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) result_field=0; null_value=1; fix_length_and_dec(); + item= item->real_item(); if (item->type() == Item::FIELD_ITEM) hybrid_field_type= ((Item_field*) item)->field->type(); else -- cgit v1.2.1 From a3e83048a36b20481155315d1026c6d91da8ecef Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Feb 2008 13:30:33 +0300 Subject: Fix for Bug#30217: Views: changes in metadata behaviour between 5.0 and 5.1. The problem was that in the patch for Bug#11986 it was decided to store original query in UTF8 encoding for the INFORMATION_SCHEMA. This approach however turned out to be quite difficult to implement properly. The main problem is to preserve the same IS-output after dump/restore. So, the fix is to rollback to the previous functionality, but also to fix it to support multi-character-set-queries properly. The idea is to generate INFORMATION_SCHEMA-query from the item-tree after parsing view declaration. The IS-query should: - be completely in UTF8; - not contain character set introducers. For more information, see WL4052. mysql-test/include/ddl_i18n.check_views.inc: Add a test case for Bug#30217. mysql-test/r/ddl_i18n_koi8r.result: Update result file. mysql-test/r/ddl_i18n_utf8.result: Update result file. mysql-test/r/information_schema.result: Update result file. mysql-test/r/information_schema_db.result: Update result file. mysql-test/r/mysqldump.result: Update result file. mysql-test/r/show_check.result: Update result file. mysql-test/t/ddl_i18n_koi8r.test: Add a test case for Bug#30217. mysql-test/t/ddl_i18n_utf8.test: Add a test case for Bug#30217. mysql-test/t/mysqldump.test: Add a test case for Bug#30217. sql/ha_ndbcluster.cc: Add a parameter to print(). sql/item.cc: 1. Add a parameter to print(). 2. Item_string::print(): - Do not append character set introducer to the text literal if we're building a query for INFORMATION_SCHEMA; - Convert text literal to UTF8 if we're building a query for INFORMATION_SCHEMA. sql/item.h: Add a parameter to print(). sql/item_cmpfunc.cc: Add a parameter to print(). sql/item_cmpfunc.h: Add a parameter to print(). sql/item_func.cc: Add a parameter to print(). sql/item_func.h: Add a parameter to print(). sql/item_geofunc.h: Add a parameter to print(). sql/item_row.cc: Add a parameter to print(). sql/item_row.h: Add a parameter to print(). sql/item_strfunc.cc: Add a parameter to print(). sql/item_strfunc.h: Add a parameter to print(). sql/item_subselect.cc: Add a parameter to print(). sql/item_subselect.h: Add a parameter to print(). sql/item_sum.cc: Add a parameter to print(). sql/item_sum.h: Add a parameter to print(). sql/item_timefunc.cc: Add a parameter to print(). sql/item_timefunc.h: Add a parameter to print(). sql/mysql_priv.h: Add a parameter to print(). sql/sp_head.cc: Add a parameter to print(). sql/sql_lex.cc: Add a parameter to print(). sql/sql_lex.h: Add a parameter to print(). sql/sql_parse.cc: Add a parameter to print(). sql/sql_select.cc: Add a parameter to print(). sql/sql_show.cc: Add a parameter to print(). sql/sql_test.cc: Add a parameter to print(). sql/sql_view.cc: Build INFORMATION_SCHEMA query from Item-tree. sql/sql_yacc.yy: Build INFORMATION_SCHEMA query from Item-tree. sql/table.h: Add a parameter to print(). --- sql/ha_ndbcluster.cc | 2 +- sql/item.cc | 98 ++++++++++++++++++++++++++++++++------------------- sql/item.h | 90 +++++++++++++++++++++++++++------------------- sql/item_cmpfunc.cc | 56 ++++++++++++++--------------- sql/item_cmpfunc.h | 51 +++++++++++++++++++-------- sql/item_func.cc | 65 +++++++++++++++++----------------- sql/item_func.h | 54 ++++++++++++++++++---------- sql/item_geofunc.h | 9 +++-- sql/item_row.cc | 4 +-- sql/item_row.h | 2 +- sql/item_strfunc.cc | 32 ++++++++--------- sql/item_strfunc.h | 12 +++---- sql/item_subselect.cc | 49 ++++++++++++++------------ sql/item_subselect.h | 20 +++++------ sql/item_sum.cc | 14 ++++---- sql/item_sum.h | 6 ++-- sql/item_timefunc.cc | 32 ++++++++--------- sql/item_timefunc.h | 14 ++++---- sql/mysql_priv.h | 15 +++++++- sql/sp_head.cc | 12 +++---- sql/sql_lex.cc | 27 ++++++++------ sql/sql_lex.h | 12 +++---- sql/sql_parse.cc | 2 +- sql/sql_select.cc | 81 ++++++++++++++++++++++++------------------ sql/sql_show.cc | 2 +- sql/sql_test.cc | 6 ++-- sql/sql_view.cc | 48 ++++++++++++++++++++++--- sql/sql_yacc.yy | 22 +----------- sql/table.h | 2 +- 29 files changed, 492 insertions(+), 347 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 441da21bf1c..26292a0c57e 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -9446,7 +9446,7 @@ ha_ndbcluster::cond_push(const COND *cond) my_errno= HA_ERR_OUT_OF_MEM; DBUG_RETURN(NULL); } - DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname);); + DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname, QT_ORDINARY);); DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table)); } diff --git a/sql/item.cc b/sql/item.cc index 10c1c58aea8..f997518ac07 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -442,9 +442,10 @@ uint Item::decimal_precision() const } -void Item::print_item_w_name(String *str) +void Item::print_item_w_name(String *str, enum_query_type query_type) { - print(str); + print(str, query_type); + if (name) { THD *thd= current_thd; @@ -1128,7 +1129,7 @@ Item_splocal::this_item_addr(THD *thd, Item **) } -void Item_splocal::print(String *str) +void Item_splocal::print(String *str, enum_query_type) { str->reserve(m_name.length+8); str->append(m_name.str, m_name.length); @@ -1182,7 +1183,7 @@ Item_case_expr::this_item_addr(THD *thd, Item **) } -void Item_case_expr::print(String *str) +void Item_case_expr::print(String *str, enum_query_type) { if (str->reserve(MAX_INT_WIDTH + sizeof("case_expr@"))) return; /* purecov: inspected */ @@ -1276,12 +1277,12 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref) } -void Item_name_const::print(String *str) +void Item_name_const::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("NAME_CONST(")); - name_item->print(str); + name_item->print(str, query_type); str->append(','); - value_item->print(str); + value_item->print(str, query_type); str->append(')'); } @@ -1298,12 +1299,12 @@ public: const char *table_name_arg, const char *field_name_arg) :Item_ref(context_arg, item, table_name_arg, field_name_arg) {} - void print (String *str) + virtual inline void print (String *str, enum_query_type query_type) { if (ref) - (*ref)->print(str); + (*ref)->print(str, query_type); else - Item_ident::print(str); + Item_ident::print(str, query_type); } }; @@ -1455,7 +1456,9 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags) set(dt); } else - ; // Do nothing + { + // Do nothing + } } else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) && left_is_superset(this, &dt)) @@ -1872,7 +1875,7 @@ const char *Item_ident::full_name() const return tmp; } -void Item_ident::print(String *str) +void Item_ident::print(String *str, enum_query_type query_type) { THD *thd= current_thd; char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME]; @@ -2134,7 +2137,7 @@ String *Item_int::val_str(String *str) return str; } -void Item_int::print(String *str) +void Item_int::print(String *str, enum_query_type query_type) { // my_charset_bin is good enough for numbers str_value.set(value, &my_charset_bin); @@ -2165,7 +2168,7 @@ String *Item_uint::val_str(String *str) } -void Item_uint::print(String *str) +void Item_uint::print(String *str, enum_query_type query_type) { // latin1 is good enough for numbers str_value.set((ulonglong) value, default_charset()); @@ -2257,7 +2260,7 @@ String *Item_decimal::val_str(String *result) return result; } -void Item_decimal::print(String *str) +void Item_decimal::print(String *str, enum_query_type query_type) { my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value); str->append(str_value); @@ -2310,16 +2313,39 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value) } -void Item_string::print(String *str) +void Item_string::print(String *str, enum_query_type query_type) { - if (is_cs_specified()) + if (query_type == QT_ORDINARY && is_cs_specified()) { str->append('_'); str->append(collation.collation->csname); } str->append('\''); - str_value.print(str); + + if (query_type == QT_ORDINARY || + my_charset_same(str_value.charset(), system_charset_info)) + { + str_value.print(str); + } + else + { + THD *thd= current_thd; + LEX_STRING utf8_lex_str; + + thd->convert_string(&utf8_lex_str, + system_charset_info, + str_value.c_ptr_safe(), + str_value.length(), + str_value.charset()); + + String utf8_str(utf8_lex_str.str, + utf8_lex_str.length, + system_charset_info); + + utf8_str.print(str); + } + str->append('\''); } @@ -3086,7 +3112,7 @@ Item_param::eq(const Item *arg, bool binary_cmp) const /* End of Item_param related */ -void Item_param::print(String *str) +void Item_param::print(String *str, enum_query_type query_type) { if (state == NO_VALUE) { @@ -4799,7 +4825,7 @@ int Item_float::save_in_field(Field *field, bool no_conversions) } -void Item_float::print(String *str) +void Item_float::print(String *str, enum_query_type query_type) { if (presentation) { @@ -4917,7 +4943,7 @@ warn: } -void Item_hex_string::print(String *str) +void Item_hex_string::print(String *str, enum_query_type query_type) { char *end= (char*) str_value.ptr() + str_value.length(), *ptr= end - min(str_value.length(), sizeof(longlong)); @@ -5179,7 +5205,7 @@ Item *Item_field::update_value_transformer(uchar *select_arg) } -void Item_field::print(String *str) +void Item_field::print(String *str, enum_query_type query_type) { if (field && field->table->const_table) { @@ -5191,7 +5217,7 @@ void Item_field::print(String *str) str->append('\''); return; } - Item_ident::print(str); + Item_ident::print(str, query_type); } @@ -5531,7 +5557,7 @@ void Item_ref::cleanup() } -void Item_ref::print(String *str) +void Item_ref::print(String *str, enum_query_type query_type) { if (ref) { @@ -5542,10 +5568,10 @@ void Item_ref::print(String *str) append_identifier(thd, str, name, (uint) strlen(name)); } else - (*ref)->print(str); + (*ref)->print(str, query_type); } else - Item_ident::print(str); + Item_ident::print(str, query_type); } @@ -5735,11 +5761,11 @@ Item *Item_ref::get_tmp_table_item(THD *thd) } -void Item_ref_null_helper::print(String *str) +void Item_ref_null_helper::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("(")); if (ref) - (*ref)->print(str); + (*ref)->print(str, query_type); else str->append('?'); str->append(')'); @@ -5931,7 +5957,7 @@ error: } -void Item_default_value::print(String *str) +void Item_default_value::print(String *str, enum_query_type query_type) { if (!arg) { @@ -5939,7 +5965,7 @@ void Item_default_value::print(String *str) return; } str->append(STRING_WITH_LEN("default(")); - arg->print(str); + arg->print(str, query_type); str->append(')'); } @@ -6075,10 +6101,10 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) return FALSE; } -void Item_insert_value::print(String *str) +void Item_insert_value::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("values(")); - arg->print(str); + arg->print(str, query_type); str->append(')'); } @@ -6199,7 +6225,7 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items) } -void Item_trigger_field::print(String *str) +void Item_trigger_field::print(String *str, enum_query_type query_type) { str->append((row_version == NEW_ROW) ? "NEW" : "OLD", 3); str->append('.'); @@ -6389,13 +6415,13 @@ Item_cache* Item_cache::get_cache(const Item *item) } -void Item_cache::print(String *str) +void Item_cache::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("(")); if (example) - example->print(str); + example->print(str, query_type); else - Item::print(str); + Item::print(str, query_type); str->append(')'); } diff --git a/sql/item.h b/sql/item.h index b3cf9aa6e4c..e1c380a2a55 100644 --- a/sql/item.h +++ b/sql/item.h @@ -113,7 +113,6 @@ public: } }; - /*************************************************************************/ /* A framework to easily handle different return types for hybrid items @@ -769,20 +768,24 @@ public: */ virtual bool const_during_execution() const { return (used_tables() & ~PARAM_TABLE_BIT) == 0; } - /* - This is an essential method for correct functioning of VIEWS. - To save a view in an .frm file we need its unequivocal - definition in SQL that takes into account sql_mode and - environmental settings. Currently such definition is restored - by traversing through the parsed tree of a view and - print()'ing SQL syntax of every node to a String buffer. This - method is used to print the SQL definition of an item. The - second use of this method is for EXPLAIN EXTENDED, to print - the SQL of a query after all optimizations of the parsed tree - have been done. - */ - virtual void print(String *str_arg) { str_arg->append(full_name()); } - void print_item_w_name(String *); + + /** + This method is used for to: + - to generate a view definition query (SELECT-statement); + - to generate a SQL-query for EXPLAIN EXTENDED; + - to generate a SQL-query to be shown in INFORMATION_SCHEMA; + - debug. + + For more information about view definition query, INFORMATION_SCHEMA + query and why they should be generated from the Item-tree, @see + mysql_register_view(). + */ + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(full_name()); + } + + void print_item_w_name(String *, enum_query_type query_type); virtual void update_used_tables() {} virtual void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields) {} @@ -1134,7 +1137,7 @@ public: const Item *this_item() const; Item **this_item_addr(THD *thd, Item **); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); public: inline const LEX_STRING *my_name() const; @@ -1203,7 +1206,7 @@ public: Item_case_expr can not occur in views, so here it is only for debug purposes. */ - void print(String *str); + virtual void print(String *str, enum_query_type query_type); private: uint m_case_expr_id; @@ -1261,7 +1264,7 @@ public: String *val_str(String *sp); my_decimal *val_decimal(my_decimal *); bool is_null(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); Item_result result_type() const { @@ -1343,7 +1346,7 @@ public: const char *full_name() const; void cleanup(); bool remove_dependence_processor(uchar * arg); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); virtual bool change_context_processor(uchar *cntx) { context= (Name_resolution_context *)cntx; return FALSE; } friend bool insert_fields(THD *thd, Name_resolution_context *context, @@ -1473,7 +1476,7 @@ public: Item *safe_charset_converter(CHARSET_INFO *tocs); int fix_outer_field(THD *thd, Field **field, Item **reference); virtual Item *update_value_transformer(uchar *select_arg); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); Field::geometry_type get_geometry_type() const { DBUG_ASSERT(field_type() == MYSQL_TYPE_GEOMETRY); @@ -1511,7 +1514,12 @@ public: bool basic_const_item() const { return 1; } Item *clone_item() { return new Item_null(name); } bool is_null() { return 1; } - void print(String *str) { str->append(STRING_WITH_LEN("NULL")); } + + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(STRING_WITH_LEN("NULL")); + } + Item *safe_charset_converter(CHARSET_INFO *tocs); bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; @@ -1645,7 +1653,7 @@ public: */ virtual table_map used_tables() const { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool is_null() { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } bool basic_const_item() const; @@ -1703,7 +1711,7 @@ public: Item *clone_item() { return new Item_int(name,value,max_length); } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - void print(String *str); + virtual void print(String *str, enum_query_type query_type); Item_num *neg() { value= -value; return this; } uint decimal_precision() const { return (uint)(max_length - test(value < 0)); } @@ -1723,7 +1731,7 @@ public: String *val_str(String*); Item *clone_item() { return new Item_uint(name, value, max_length); } int save_in_field(Field *field, bool no_conversions); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); Item_num *neg (); uint decimal_precision() const { return max_length; } bool check_partition_func_processor(uchar *bool_arg) { return FALSE;} @@ -1759,7 +1767,7 @@ public: } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - void print(String *str); + virtual void print(String *str, enum_query_type query_type); Item_num *neg() { my_decimal_neg(&decimal_value); @@ -1818,7 +1826,7 @@ public: Item *clone_item() { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool eq(const Item *, bool binary_cmp) const; }; @@ -1831,7 +1839,12 @@ public: uint length) :Item_float(NullS, val_arg, decimal_par, length), func_name(str) {} - void print(String *str) { str->append(func_name); } + + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(func_name); + } + Item *safe_charset_converter(CHARSET_INFO *tocs); }; @@ -1922,7 +1935,7 @@ public: str_value.append(str, length); max_length= str_value.numchars() * collation.collation->mbmaxlen; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} bool check_partition_func_processor(uchar *int_arg) {return FALSE;} @@ -1981,7 +1994,12 @@ public: :Item_string(NullS, str, length, cs, dv), func_name(name_par) {} Item *safe_charset_converter(CHARSET_INFO *tocs); - void print(String *str) { str->append(func_name); } + + virtual inline void print(String *str, enum_query_type query_type) + { + str->append(func_name); + } + bool check_partition_func_processor(uchar *int_arg) {return TRUE;} }; @@ -2071,7 +2089,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool eq(const Item *item, bool binary_cmp) const; virtual Item *safe_charset_converter(CHARSET_INFO *tocs); bool check_partition_func_processor(uchar *int_arg) {return FALSE;} @@ -2192,7 +2210,7 @@ public: } bool walk(Item_processor processor, bool walk_subquery, uchar *arg) { return (*ref)->walk(processor, walk_subquery, arg); } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool result_as_longlong() { return (*ref)->result_as_longlong(); @@ -2339,7 +2357,7 @@ public: my_decimal *val_decimal(my_decimal *); bool val_bool(); bool get_date(MYSQL_TIME *ltime, uint fuzzydate); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); /* we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE */ @@ -2514,7 +2532,7 @@ public: enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); int save_in_field(Field *field_arg, bool no_conversions); table_map used_tables() const { return (table_map)0L; } @@ -2547,7 +2565,7 @@ public: arg(a) {} bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); int save_in_field(Field *field_arg, bool no_conversions) { return Item_field::save_in_field(field_arg, no_conversions); @@ -2618,7 +2636,7 @@ public: enum Type type() const { return TRIGGER_FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); table_map used_tables() const { return (table_map)0L; } Field *get_tmp_table_field() { return 0; } Item *copy_or_same(THD *thd) { return this; } @@ -2711,7 +2729,7 @@ public: virtual void keep_array() {} // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool eq_def(Field *field) { return cached_field ? cached_field->eq_def (field) : FALSE; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index dc868376796..ae7ea95707c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -286,10 +286,10 @@ longlong Item_func_not::val_int() higher than the precedence of NOT. */ -void Item_func_not::print(String *str) +void Item_func_not::print(String *str, enum_query_type query_type) { str->append('('); - Item_func::print(str); + Item_func::print(str, query_type); str->append(')'); } @@ -321,12 +321,12 @@ bool Item_func_not_all::empty_underlying_subquery() (test_sub_item && !test_sub_item->any_value())); } -void Item_func_not_all::print(String *str) +void Item_func_not_all::print(String *str, enum_query_type query_type) { if (show) - Item_func::print(str); + Item_func::print(str, query_type); else - args[0]->print(str); + args[0]->print(str, query_type); } @@ -1422,10 +1422,10 @@ void Item_func_truth::fix_length_and_dec() } -void Item_func_truth::print(String *str) +void Item_func_truth::print(String *str, enum_query_type query_type) { str->append('('); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" is ")); if (! affirmative) str->append(STRING_WITH_LEN("not ")); @@ -2109,16 +2109,16 @@ longlong Item_func_between::val_int() } -void Item_func_between::print(String *str) +void Item_func_between::print(String *str, enum_query_type query_type) { str->append('('); - args[0]->print(str); + args[0]->print(str, query_type); if (negated) str->append(STRING_WITH_LEN(" not")); str->append(STRING_WITH_LEN(" between ")); - args[1]->print(str); + args[1]->print(str, query_type); str->append(STRING_WITH_LEN(" and ")); - args[2]->print(str); + args[2]->print(str, query_type); str->append(')'); } @@ -2763,26 +2763,26 @@ uint Item_func_case::decimal_precision() const Fix this so that it prints the whole CASE expression */ -void Item_func_case::print(String *str) +void Item_func_case::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("(case ")); if (first_expr_num != -1) { - args[first_expr_num]->print(str); + args[first_expr_num]->print(str, query_type); str->append(' '); } for (uint i=0 ; i < ncases ; i+=2) { str->append(STRING_WITH_LEN("when ")); - args[i]->print(str); + args[i]->print(str, query_type); str->append(STRING_WITH_LEN(" then ")); - args[i+1]->print(str); + args[i+1]->print(str, query_type); str->append(' '); } if (else_expr_num != -1) { str->append(STRING_WITH_LEN("else ")); - args[else_expr_num]->print(str); + args[else_expr_num]->print(str, query_type); str->append(' '); } str->append(STRING_WITH_LEN("end)")); @@ -3706,14 +3706,14 @@ void Item_func_in::fix_length_and_dec() } -void Item_func_in::print(String *str) +void Item_func_in::print(String *str, enum_query_type query_type) { str->append('('); - args[0]->print(str); + args[0]->print(str, query_type); if (negated) str->append(STRING_WITH_LEN(" not")); str->append(STRING_WITH_LEN(" in (")); - print_args(str, 1); + print_args(str, 1, query_type); str->append(STRING_WITH_LEN("))")); } @@ -4084,19 +4084,19 @@ void Item_cond::update_used_tables() } -void Item_cond::print(String *str) +void Item_cond::print(String *str, enum_query_type query_type) { str->append('('); List_iterator_fast li(list); Item *item; if ((item=li++)) - item->print(str); + item->print(str, query_type); while ((item=li++)) { str->append(' '); str->append(func_name()); str->append(' '); - item->print(str); + item->print(str, query_type); } str->append(')'); } @@ -4279,10 +4279,10 @@ longlong Item_func_isnotnull::val_int() } -void Item_func_isnotnull::print(String *str) +void Item_func_isnotnull::print(String *str, enum_query_type query_type) { str->append('('); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" is not null)")); } @@ -5276,24 +5276,24 @@ Item *Item_equal::transform(Item_transformer transformer, uchar *arg) return Item_func::transform(transformer, arg); } -void Item_equal::print(String *str) +void Item_equal::print(String *str, enum_query_type query_type) { str->append(func_name()); str->append('('); List_iterator_fast it(fields); Item *item; if (const_item) - const_item->print(str); + const_item->print(str, query_type); else { item= it++; - item->print(str); + item->print(str, query_type); } while ((item= it++)) { str->append(','); str->append(' '); - item->print(str); + item->print(str, query_type); } str->append(')'); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 188d87a69ca..0166a18029d 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -123,7 +123,7 @@ public: virtual bool val_bool(); virtual longlong val_int(); virtual void fix_length_and_dec(); - virtual void print(String *str); + virtual void print(String *str, enum_query_type query_type); protected: Item_func_truth(Item *a, bool a_value, bool a_affirmative) @@ -338,7 +338,12 @@ public: optimize_type select_optimize() const { return OPTIMIZE_OP; } virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; } bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; } - void print(String *str) { Item_func::print_op(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + Item_func::print_op(str, query_type); + } + bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; } @@ -368,7 +373,7 @@ public: enum Functype functype() const { return NOT_FUNC; } const char *func_name() const { return "not"; } Item *neg_transformer(THD *thd); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; class Item_maxmin_subselect; @@ -433,7 +438,7 @@ public: longlong val_int(); enum Functype functype() const { return NOT_ALL_FUNC; } const char *func_name() const { return ""; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; }; void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; }; bool empty_underlying_subquery(); @@ -594,7 +599,7 @@ public: const char *func_name() const { return "between"; } bool fix_fields(THD *, Item **); void fix_length_and_dec(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } uint decimal_precision() const { return 1; } @@ -608,7 +613,11 @@ public: longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_NONE; } const char *func_name() const { return "strcmp"; } - void print(String *str) { Item_func::print(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + Item_func::print(str, query_type); + } }; @@ -711,7 +720,12 @@ public: void fix_length_and_dec(); uint decimal_precision() const { return args[0]->decimal_precision(); } const char *func_name() const { return "nullif"; } - void print(String *str) { Item_func::print(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + Item_func::print(str, query_type); + } + table_map not_null_tables() const { return 0; } bool is_null(); }; @@ -1141,7 +1155,7 @@ public: enum Item_result result_type () const { return cached_result_type; } enum_field_types field_type() const { return cached_field_type; } const char *func_name() const { return "case"; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); Item *find_item(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } void cleanup(); @@ -1208,7 +1222,7 @@ public: } optimize_type select_optimize() const { return OPTIMIZE_KEY; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return " IN "; } bool nulls_in_row(); @@ -1330,7 +1344,7 @@ public: table_map not_null_tables() const { return abort_on_null ? not_null_tables_cache : 0; } Item *neg_transformer(THD *thd); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); CHARSET_INFO *compare_collation() { return args[0]->collation.collation; } void top_level_item() { abort_on_null=1; } }; @@ -1395,7 +1409,12 @@ public: longlong val_int(); bool fix_fields(THD *thd, Item **ref); const char *func_name() const { return "regexp"; } - void print(String *str) { print_op(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + print_op(str, query_type); + } + CHARSET_INFO *compare_collation() { return cmp_collation.collation; } }; @@ -1407,7 +1426,11 @@ public: Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b) {} longlong val_int() { return 0;} const char *func_name() const { return "regex"; } - void print(String *str) { print_op(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + print_op(str, query_type); + } }; #endif /* USE_REGEX */ @@ -1444,7 +1467,7 @@ public: List* argument_list() { return &list; } table_map used_tables() const; void update_used_tables(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); @@ -1568,7 +1591,7 @@ public: void update_used_tables(); bool walk(Item_processor processor, bool walk_subquery, uchar *arg); Item *transform(Item_transformer transformer, uchar *arg); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); CHARSET_INFO *compare_collation() { return fields.head()->collation.collation; } }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 6e9371de9dc..a7b562d3407 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -374,37 +374,37 @@ table_map Item_func::not_null_tables() const } -void Item_func::print(String *str) +void Item_func::print(String *str, enum_query_type query_type) { str->append(func_name()); str->append('('); - print_args(str, 0); + print_args(str, 0, query_type); str->append(')'); } -void Item_func::print_args(String *str, uint from) +void Item_func::print_args(String *str, uint from, enum_query_type query_type) { for (uint i=from ; i < arg_count ; i++) { if (i != from) str->append(','); - args[i]->print(str); + args[i]->print(str, query_type); } } -void Item_func::print_op(String *str) +void Item_func::print_op(String *str, enum_query_type query_type) { str->append('('); for (uint i=0 ; i < arg_count-1 ; i++) { - args[i]->print(str); + args[i]->print(str, query_type); str->append(' '); str->append(func_name()); str->append(' '); } - args[arg_count-1]->print(str); + args[arg_count-1]->print(str, query_type); str->append(')'); } @@ -884,10 +884,10 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) } -void Item_func_signed::print(String *str) +void Item_func_signed::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as signed)")); } @@ -955,10 +955,10 @@ longlong Item_func_signed::val_int() } -void Item_func_unsigned::print(String *str) +void Item_func_unsigned::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as unsigned)")); } @@ -1064,7 +1064,7 @@ err: } -void Item_decimal_typecast::print(String *str) +void Item_decimal_typecast::print(String *str, enum_query_type query_type) { char len_buf[20*3 + 1]; char *end; @@ -1072,7 +1072,7 @@ void Item_decimal_typecast::print(String *str) uint precision= my_decimal_length_to_precision(max_length, decimals, unsigned_flag); str->append(STRING_WITH_LEN("cast(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as decimal(")); end=int10_to_str(precision, len_buf,10); @@ -2537,16 +2537,16 @@ longlong Item_func_locate::val_int() } -void Item_func_locate::print(String *str) +void Item_func_locate::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("locate(")); - args[1]->print(str); + args[1]->print(str, query_type); str->append(','); - args[0]->print(str); + args[0]->print(str, query_type); if (arg_count == 3) { str->append(','); - args[2]->print(str); + args[2]->print(str, query_type); } str->append(')'); } @@ -3095,7 +3095,7 @@ void Item_udf_func::cleanup() } -void Item_udf_func::print(String *str) +void Item_udf_func::print(String *str, enum_query_type query_type) { str->append(func_name()); str->append('('); @@ -3103,7 +3103,7 @@ void Item_udf_func::print(String *str) { if (i != 0) str->append(','); - args[i]->print_item_w_name(str); + args[i]->print_item_w_name(str, query_type); } str->append(')'); } @@ -3683,12 +3683,12 @@ longlong Item_func_benchmark::val_int() } -void Item_func_benchmark::print(String *str) +void Item_func_benchmark::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("benchmark(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(','); - args[1]->print(str); + args[1]->print(str, query_type); str->append(')'); } @@ -4264,22 +4264,23 @@ my_decimal *Item_func_set_user_var::val_decimal_result(my_decimal *val) } -void Item_func_set_user_var::print(String *str) +void Item_func_set_user_var::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("(@")); str->append(name.str, name.length); str->append(STRING_WITH_LEN(":=")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(')'); } -void Item_func_set_user_var::print_as_stmt(String *str) +void Item_func_set_user_var::print_as_stmt(String *str, + enum_query_type query_type) { str->append(STRING_WITH_LEN("set @")); str->append(name.str, name.length); str->append(STRING_WITH_LEN(":=")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(')'); } @@ -4652,7 +4653,7 @@ enum Item_result Item_func_get_user_var::result_type() const } -void Item_func_get_user_var::print(String *str) +void Item_func_get_user_var::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("(@")); str->append(name.str,name.length); @@ -4750,7 +4751,7 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer) } -void Item_user_var_as_out_param::print(String *str) +void Item_user_var_as_out_param::print(String *str, enum_query_type query_type) { str->append('@'); str->append(name.str,name.length); @@ -5089,12 +5090,12 @@ double Item_func_match::val_real() table->record[0], 0)); } -void Item_func_match::print(String *str) +void Item_func_match::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("(match ")); - print_args(str, 1); + print_args(str, 1, query_type); str->append(STRING_WITH_LEN(" against (")); - args[0]->print(str); + args[0]->print(str, query_type); if (flags & FT_BOOL) str->append(STRING_WITH_LEN(" in boolean mode")); else if (flags & FT_EXPAND) @@ -5505,7 +5506,7 @@ Item_result Item_func_sp::result_type() const { DBUG_ENTER("Item_func_sp::result_type"); - DBUG_PRINT("info", ("m_sp = %p", m_sp)); + DBUG_PRINT("info", ("m_sp = %p", (void *) m_sp)); DBUG_ASSERT(sp_result_field); DBUG_RETURN(sp_result_field->result_type()); } diff --git a/sql/item_func.h b/sql/item_func.h index e09b584de95..f8eb7ff6200 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -140,9 +140,9 @@ public: inline uint argument_count() const { return arg_count; } inline void remove_arguments() { arg_count=0; } void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); - void print(String *str); - void print_op(String *str); - void print_args(String *str, uint from); + virtual void print(String *str, enum_query_type query_type); + void print_op(String *str, enum_query_type query_type); + void print_args(String *str, uint from, enum_query_type query_type); virtual void fix_num_length_and_dec(); void count_only_length(); void count_real_length(); @@ -293,7 +293,12 @@ class Item_num_op :public Item_func_numhybrid public: Item_num_op(Item *a,Item *b) :Item_func_numhybrid(a, b) {} virtual void result_precision()= 0; - void print(String *str) { print_op(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + print_op(str, query_type); + } + void find_num_type(); String *str_op(String *str) { DBUG_ASSERT(0); return 0; } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} @@ -339,7 +344,7 @@ public: longlong val_int_from_str(int *error); void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=0; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); uint decimal_precision() const { return args[0]->decimal_precision(); } }; @@ -352,7 +357,7 @@ public: void fix_length_and_dec() { max_length=args[0]->max_length; unsigned_flag=1; } longlong val_int(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -373,7 +378,7 @@ public: enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } void fix_length_and_dec() {}; const char *func_name() const { return "decimal_typecast"; } - void print(String *); + virtual void print(String *str, enum_query_type query_type); }; @@ -441,7 +446,12 @@ public: longlong val_int(); const char *func_name() const { return "DIV"; } void fix_length_and_dec(); - void print(String *str) { print_op(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + print_op(str, query_type); + } + bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; @@ -843,7 +853,7 @@ public: const char *func_name() const { return "locate"; } longlong val_int(); void fix_length_and_dec(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -900,7 +910,11 @@ public: Item_func_bit(Item *a, Item *b) :Item_int_func(a, b) {} Item_func_bit(Item *a) :Item_int_func(a) {} void fix_length_and_dec() { unsigned_flag= 1; } - void print(String *str) { print_op(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + print_op(str, query_type); + } }; class Item_func_bit_or :public Item_func_bit @@ -950,7 +964,11 @@ public: Item_func_bit_neg(Item *a) :Item_func_bit(a) {} longlong val_int(); const char *func_name() const { return "~"; } - void print(String *str) { Item_func::print(str); } + + virtual inline void print(String *str, enum_query_type query_type) + { + Item_func::print(str, query_type); + } }; @@ -979,7 +997,7 @@ public: longlong val_int(); const char *func_name() const { return "benchmark"; } void fix_length_and_dec() { max_length=1; maybe_null=0; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -1076,7 +1094,7 @@ public: Item_result result_type () const { return udf.result_type(); } table_map not_null_tables() const { return 0; } bool is_expensive() { return 1; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -1313,8 +1331,8 @@ public: enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd, Item **ref); void fix_length_and_dec(); - void print(String *str); - void print_as_stmt(String *str); + virtual void print(String *str, enum_query_type query_type); + void print_as_stmt(String *str, enum_query_type query_type); const char *func_name() const { return "set_user_var"; } int save_in_field(Field *field, bool no_conversions, bool can_use_result_field); @@ -1344,7 +1362,7 @@ public: my_decimal *val_decimal(my_decimal*); String *val_str(String* str); void fix_length_and_dec(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); enum Item_result result_type() const; /* We must always return variables as strings to guard against selects of type @@ -1389,7 +1407,7 @@ public: my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); }; @@ -1467,7 +1485,7 @@ public: /* The following should be safe, even if we compare doubles */ longlong val_int() { DBUG_ASSERT(fixed == 1); return val_real() != 0.0; } double val_real(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool fix_index(); void init_search(bool no_order); diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 62be78eee9e..edbe104e307 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -224,8 +224,13 @@ public: DBUG_ASSERT(0); // Should never happened return "sp_unknown"; } - } - void print(String *str) { Item_func::print(str); } + } + + virtual inline void print(String *str, enum_query_type query_type) + { + Item_func::print(str, query_type); + } + void fix_length_and_dec() { maybe_null= 1; } bool is_null() { (void) val_int(); return null_value; } }; diff --git a/sql/item_row.cc b/sql/item_row.cc index 369aa04930e..28de03bf049 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -134,14 +134,14 @@ bool Item_row::check_cols(uint c) return 0; } -void Item_row::print(String *str) +void Item_row::print(String *str, enum_query_type query_type) { str->append('('); for (uint i= 0; i < arg_count; i++) { if (i) str->append(','); - items[i]->print(str); + items[i]->print(str, query_type); } str->append(')'); } diff --git a/sql/item_row.h b/sql/item_row.h index dd7436888f0..67441f49603 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -65,7 +65,7 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } void update_used_tables(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool walk(Item_processor processor, bool walk_subquery, uchar *arg); Item *transform(Item_transformer transformer, uchar *arg); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 42314872997..fe805d7672a 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1594,20 +1594,20 @@ void Item_func_trim::fix_length_and_dec() } } -void Item_func_trim::print(String *str) +void Item_func_trim::print(String *str, enum_query_type query_type) { if (arg_count == 1) { - Item_func::print(str); + Item_func::print(str, query_type); return; } str->append(Item_func_trim::func_name()); str->append('('); str->append(mode_name()); str->append(' '); - args[1]->print(str); + args[1]->print(str, query_type); str->append(STRING_WITH_LEN(" from ")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(')'); } @@ -2116,12 +2116,12 @@ String *Item_func_format::val_str(String *str) } -void Item_func_format::print(String *str) +void Item_func_format::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("format(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(','); - args[1]->print(str); + args[1]->print(str, query_type); str->append(')'); } @@ -2292,14 +2292,14 @@ Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg) } -void Item_func_make_set::print(String *str) +void Item_func_make_set::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("make_set(")); - item->print(str); + item->print(str, query_type); if (arg_count) { str->append(','); - print_args(str, 0); + print_args(str, 0, query_type); } str->append(')'); } @@ -2710,10 +2710,10 @@ void Item_func_conv_charset::fix_length_and_dec() max_length = args[0]->max_length*conv_charset->mbmaxlen; } -void Item_func_conv_charset::print(String *str) +void Item_func_conv_charset::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("convert(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" using ")); str->append(conv_charset->csname); str->append(')'); @@ -2781,10 +2781,10 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const } -void Item_func_set_collation::print(String *str) +void Item_func_set_collation::print(String *str, enum_query_type query_type) { str->append('('); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" collate ")); DBUG_ASSERT(args[1]->basic_const_item() && args[1]->type() == Item::STRING_ITEM); @@ -2903,10 +2903,10 @@ String *Item_func_unhex::val_str(String *str) } -void Item_func_binary::print(String *str) +void Item_func_binary::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as binary)")); } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 0d7cd66acff..81baf9a4c5f 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -225,7 +225,7 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "trim"; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); virtual const char *mode_name() const { return "both"; } }; @@ -482,7 +482,7 @@ public: Item_str_func::walk(processor, walk_subquery, arg); } Item *transform(Item_transformer transformer, uchar *arg); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -494,7 +494,7 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "format"; } - void print(String *); + virtual void print(String *str, enum_query_type query_type); }; @@ -617,7 +617,7 @@ public: collation.set(&my_charset_bin); max_length=args[0]->max_length; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); const char *func_name() const { return "cast_as_binary"; } }; @@ -719,7 +719,7 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "convert"; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; class Item_func_set_collation :public Item_str_func @@ -731,7 +731,7 @@ public: bool eq(const Item *item, bool binary_cmp) const; const char *func_name() const { return "collate"; } enum Functype functype() const { return COLLATE_FUNC; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); Item_field *filed_for_view_update() { /* this function is transparent for view updating */ diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 46b8d2e46cc..7b68d258d29 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -306,10 +306,10 @@ void Item_subselect::update_used_tables() } -void Item_subselect::print(String *str) +void Item_subselect::print(String *str, enum_query_type query_type) { str->append('('); - engine->print(str); + engine->print(str, query_type); str->append(')'); } @@ -391,10 +391,10 @@ void Item_maxmin_subselect::cleanup() } -void Item_maxmin_subselect::print(String *str) +void Item_maxmin_subselect::print(String *str, enum_query_type query_type) { str->append(max?"":"", 5); - Item_singlerow_subselect::print(str); + Item_singlerow_subselect::print(str, query_type); } @@ -630,10 +630,10 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex): } -void Item_exists_subselect::print(String *str) +void Item_exists_subselect::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("exists")); - Item_subselect::print(str); + Item_subselect::print(str, query_type); } @@ -1553,16 +1553,16 @@ err: } -void Item_in_subselect::print(String *str) +void Item_in_subselect::print(String *str, enum_query_type query_type) { if (transformed) str->append(STRING_WITH_LEN("")); else { - left_expr->print(str); + left_expr->print(str, query_type); str->append(STRING_WITH_LEN(" in ")); } - Item_subselect::print(str); + Item_subselect::print(str, query_type); } @@ -1587,18 +1587,18 @@ Item_allany_subselect::select_transformer(JOIN *join) } -void Item_allany_subselect::print(String *str) +void Item_allany_subselect::print(String *str, enum_query_type query_type) { if (transformed) str->append(STRING_WITH_LEN("")); else { - left_expr->print(str); + left_expr->print(str, query_type); str->append(' '); str->append(func->symbol(all)); str->append(all ? " all " : " any ", 5); } - Item_subselect::print(str); + Item_subselect::print(str, query_type); } @@ -2384,22 +2384,24 @@ table_map subselect_union_engine::upper_select_const_tables() } -void subselect_single_select_engine::print(String *str) +void subselect_single_select_engine::print(String *str, + enum_query_type query_type) { - select_lex->print(thd, str); + select_lex->print(thd, str, query_type); } -void subselect_union_engine::print(String *str) +void subselect_union_engine::print(String *str, enum_query_type query_type) { - unit->print(str); + unit->print(str, query_type); } -void subselect_uniquesubquery_engine::print(String *str) +void subselect_uniquesubquery_engine::print(String *str, + enum_query_type query_type) { str->append(STRING_WITH_LEN("(")); - tab->ref.items[0]->print(str); + tab->ref.items[0]->print(str, query_type); str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name.str, tab->table->s->table_name.length); KEY *key_info= tab->table->key_info+ tab->ref.key; @@ -2408,16 +2410,17 @@ void subselect_uniquesubquery_engine::print(String *str) if (cond) { str->append(STRING_WITH_LEN(" where ")); - cond->print(str); + cond->print(str, query_type); } str->append(')'); } -void subselect_indexsubquery_engine::print(String *str) +void subselect_indexsubquery_engine::print(String *str, + enum_query_type query_type) { str->append(STRING_WITH_LEN("(")); - tab->ref.items[0]->print(str); + tab->ref.items[0]->print(str, query_type); str->append(STRING_WITH_LEN(" in ")); str->append(tab->table->s->table_name.str, tab->table->s->table_name.length); KEY *key_info= tab->table->key_info+ tab->ref.key; @@ -2428,12 +2431,12 @@ void subselect_indexsubquery_engine::print(String *str) if (cond) { str->append(STRING_WITH_LEN(" where ")); - cond->print(str); + cond->print(str, query_type); } if (having) { str->append(STRING_WITH_LEN(" having ")); - having->print(str); + having->print(str, query_type); } str->append(')'); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index de4b1cbdc06..d4aa621c083 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -103,7 +103,7 @@ public: inline bool get_const_item_cache() { return const_item_cache; } Item *get_tmp_table_item(THD *thd); void update_used_tables(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); virtual bool have_guarded_conds() { return FALSE; } bool change_engine(subselect_engine *eng) { @@ -203,7 +203,7 @@ protected: public: Item_maxmin_subselect(THD *thd, Item_subselect *parent, st_select_lex *select_lex, bool max); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); void cleanup(); bool any_value() { return was_values; } void register_value() { was_values= TRUE; } @@ -234,7 +234,7 @@ public: my_decimal *val_decimal(my_decimal *); bool val_bool(); void fix_length_and_dec(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); friend class select_exists_subselect; friend class subselect_uniquesubquery_engine; @@ -312,7 +312,7 @@ public: void top_level_item() { abort_on_null=1; } inline bool is_top_level_item() { return abort_on_null; } bool test_limit(st_select_lex_unit *unit); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool fix_fields(THD *thd, Item **ref); friend class Item_ref_null_helper; @@ -335,7 +335,7 @@ public: // only ALL subquery has upper not subs_type substype() { return all?ALL_SUBS:ANY_SUBS; } trans_res select_transformer(JOIN *join); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -399,7 +399,7 @@ public: virtual bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; static table_map calc_const_tables(TABLE_LIST *); - virtual void print(String *str)= 0; + virtual void print(String *str, enum_query_type query_type)= 0; virtual bool change_result(Item_subselect *si, select_subselect *result)= 0; virtual bool no_tables()= 0; virtual bool is_executed() const { return FALSE; } @@ -430,7 +430,7 @@ public: uint8 uncacheable(); void exclude(); table_map upper_select_const_tables(); - void print (String *str); + virtual void print (String *str, enum_query_type query_type); bool change_result(Item_subselect *si, select_subselect *result); bool no_tables(); bool may_be_null(); @@ -454,7 +454,7 @@ public: uint8 uncacheable(); void exclude(); table_map upper_select_const_tables(); - void print (String *str); + virtual void print (String *str, enum_query_type query_type); bool change_result(Item_subselect *si, select_subselect *result); bool no_tables(); bool is_executed() const; @@ -511,7 +511,7 @@ public: uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; } void exclude(); table_map upper_select_const_tables() { return 0; } - void print (String *str); + virtual void print (String *str, enum_query_type query_type); bool change_result(Item_subselect *si, select_subselect *result); bool no_tables(); int scan_table(); @@ -565,7 +565,7 @@ public: having(having_arg) {} int exec(); - void print (String *str); + virtual void print (String *str, enum_query_type query_type); }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 27b964a9e15..f5a3956c1e4 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -359,14 +359,14 @@ void Item_sum::make_field(Send_field *tmp_field) } -void Item_sum::print(String *str) +void Item_sum::print(String *str, enum_query_type query_type) { str->append(func_name()); for (uint i=0 ; i < arg_count ; i++) { if (i) str->append(','); - args[i]->print(str); + args[i]->print(str, query_type); } str->append(')'); } @@ -2716,7 +2716,7 @@ void Item_udf_sum::cleanup() } -void Item_udf_sum::print(String *str) +void Item_udf_sum::print(String *str, enum_query_type query_type) { str->append(func_name()); str->append('('); @@ -2724,7 +2724,7 @@ void Item_udf_sum::print(String *str) { if (i) str->append(','); - args[i]->print(str); + args[i]->print(str, query_type); } str->append(')'); } @@ -3460,7 +3460,7 @@ String* Item_func_group_concat::val_str(String* str) } -void Item_func_group_concat::print(String *str) +void Item_func_group_concat::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("group_concat(")); if (distinct) @@ -3469,7 +3469,7 @@ void Item_func_group_concat::print(String *str) { if (i) str->append(','); - args[i]->print(str); + args[i]->print(str, query_type); } if (arg_count_order) { @@ -3478,7 +3478,7 @@ void Item_func_group_concat::print(String *str) { if (i) str->append(','); - (*order[i]->item)->print(str); + (*order[i]->item)->print(str, query_type); if (order[i]->asc) str->append(STRING_WITH_LEN(" ASC")); else diff --git a/sql/item_sum.h b/sql/item_sum.h index a3582967736..d1e6a74e85e 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -343,7 +343,7 @@ public: } virtual bool const_item() const { return forced_const; } void make_field(Send_field *field); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); void fix_num_length_and_dec(); /* @@ -984,7 +984,7 @@ public: void reset_field() {}; void update_field() {}; void cleanup(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -1257,7 +1257,7 @@ public: String* val_str(String* str); Item *copy_or_same(THD* thd); void no_rows_in_result() {} - void print(String *str); + virtual void print(String *str, enum_query_type query_type); virtual bool change_context_processor(uchar *cntx) { context= (Name_resolution_context *)cntx; return FALSE; } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index a0beadcd481..390f94945aa 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2217,23 +2217,23 @@ static const char *interval_names[]= "second_microsecond" }; -void Item_date_add_interval::print(String *str) +void Item_date_add_interval::print(String *str, enum_query_type query_type) { str->append('('); - args[0]->print(str); + args[0]->print(str, query_type); str->append(date_sub_interval?" - interval ":" + interval "); - args[1]->print(str); + args[1]->print(str, query_type); str->append(' '); str->append(interval_names[int_type]); str->append(')'); } -void Item_extract::print(String *str) +void Item_extract::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("extract(")); str->append(interval_names[int_type]); str->append(STRING_WITH_LEN(" from ")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(')'); } @@ -2374,20 +2374,20 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const return 1; } -void Item_typecast::print(String *str) +void Item_typecast::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as ")); str->append(cast_type()); str->append(')'); } -void Item_char_typecast::print(String *str) +void Item_char_typecast::print(String *str, enum_query_type query_type) { str->append(STRING_WITH_LEN("cast(")); - args[0]->print(str); + args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as char")); if (cast_length >= 0) { @@ -2822,7 +2822,7 @@ null_date: } -void Item_func_add_time::print(String *str) +void Item_func_add_time::print(String *str, enum_query_type query_type) { if (is_date) { @@ -2836,9 +2836,9 @@ void Item_func_add_time::print(String *str) else str->append(STRING_WITH_LEN("subtime(")); } - args[0]->print(str); + args[0]->print(str, query_type); str->append(','); - args[1]->print(str); + args[1]->print(str, query_type); str->append(')'); } @@ -3083,7 +3083,7 @@ null_date: } -void Item_func_timestamp_diff::print(String *str) +void Item_func_timestamp_diff::print(String *str, enum_query_type query_type) { str->append(func_name()); str->append('('); @@ -3123,7 +3123,7 @@ void Item_func_timestamp_diff::print(String *str) for (uint i=0 ; i < 2 ; i++) { str->append(','); - args[i]->print(str); + args[i]->print(str, query_type); } str->append(')'); } @@ -3163,7 +3163,7 @@ String *Item_func_get_format::val_str(String *str) } -void Item_func_get_format::print(String *str) +void Item_func_get_format::print(String *str, enum_query_type query_type) { str->append(func_name()); str->append('('); @@ -3181,7 +3181,7 @@ void Item_func_get_format::print(String *str) default: DBUG_ASSERT(0); } - args[0]->print(str); + args[0]->print(str, query_type); str->append(')'); } diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 9be7e97db49..cfcf5fab080 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -694,7 +694,7 @@ public: longlong val_int(); bool get_date(MYSQL_TIME *res, uint fuzzy_date); bool eq(const Item *item, bool binary_cmp) const; - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -711,7 +711,7 @@ class Item_extract :public Item_int_func const char *func_name() const { return "extract"; } void fix_length_and_dec(); bool eq(const Item *item, bool binary_cmp) const; - void print(String *str); + virtual void print(String *str, enum_query_type query_type); bool check_partition_func_processor(uchar *int_arg) {return FALSE;} }; @@ -735,7 +735,7 @@ public: max_length=args[0]->max_length; } virtual const char* cast_type() const= 0; - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -767,7 +767,7 @@ public: const char* cast_type() const { return "char"; }; String *val_str(String *a); void fix_length_and_dec(); - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -901,7 +901,7 @@ public: { return tmp_table_field_from_field_type(table, 0); } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); const char *func_name() const { return "add_time"; } double val_real() { return val_real_from_decimal(); } my_decimal *val_decimal(my_decimal *decimal_value) @@ -977,7 +977,7 @@ public: decimals=0; maybe_null=1; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; @@ -1001,7 +1001,7 @@ public: decimals=0; max_length=17*MY_CHARSET_BIN_MB_MAXLEN; } - void print(String *str); + virtual void print(String *str, enum_query_type query_type); }; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ea552414d9a..6c0234a9b0b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -44,6 +44,19 @@ #include "sql_plugin.h" #include "scheduler.h" +/** + Query type constants. + + QT_ORDINARY -- ordinary SQL query. + QT_IS -- SQL query to be shown in INFORMATION_SCHEMA (in utf8 and without + character set introducers). +*/ +enum enum_query_type +{ + QT_ORDINARY, + QT_IS +}; + /* TODO convert all these three maps to Bitmap classes */ typedef ulonglong table_map; /* Used for table bits in join */ #if MAX_INDEXES <= 64 @@ -1708,7 +1721,7 @@ bool mysql_manager_submit(void (*action)()); /* sql_test.cc */ #ifndef DBUG_OFF -void print_where(COND *cond,const char *info); +void print_where(COND *cond,const char *info, enum_query_type query_type); void print_cached_tables(void); void TEST_filesort(SORT_FIELD *sortorder,uint s_length); void print_plan(JOIN* join,uint idx, double record_count, double read_time, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f42a5dde8ed..8bd10e00f15 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -2933,7 +2933,7 @@ sp_instr_set::print(String *str) } str->qs_append(m_offset); str->qs_append(' '); - m_value->print(str); + m_value->print(str, QT_ORDINARY); } @@ -2961,9 +2961,9 @@ void sp_instr_set_trigger_field::print(String *str) { str->append(STRING_WITH_LEN("set_trigger_field ")); - trigger_field->print(str); + trigger_field->print(str, QT_ORDINARY); str->append(STRING_WITH_LEN(":=")); - value->print(str); + value->print(str, QT_ORDINARY); } /* @@ -3089,7 +3089,7 @@ sp_instr_jump_if_not::print(String *str) str->qs_append('('); str->qs_append(m_cont_dest); str->qs_append(STRING_WITH_LEN(") ")); - m_expr->print(str); + m_expr->print(str, QT_ORDINARY); } @@ -3177,7 +3177,7 @@ sp_instr_freturn::print(String *str) str->qs_append(STRING_WITH_LEN("freturn ")); str->qs_append((uint)m_type); str->qs_append(' '); - m_value->print(str); + m_value->print(str, QT_ORDINARY); } /* @@ -3665,7 +3665,7 @@ sp_instr_set_case_expr::print(String *str) str->qs_append(STRING_WITH_LEN(") ")); str->qs_append(m_case_expr_id); str->qs_append(' '); - m_case_expr->print(str); + m_case_expr->print(str, QT_ORDINARY); } uint diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 5352f8efbbb..b07efc62a00 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1947,7 +1947,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) } -void st_select_lex_unit::print(String *str) +void st_select_lex_unit::print(String *str, enum_query_type query_type) { bool union_all= !union_distinct; for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) @@ -1962,7 +1962,7 @@ void st_select_lex_unit::print(String *str) } if (sl->braces) str->append('('); - sl->print(thd, str); + sl->print(thd, str, query_type); if (sl->braces) str->append(')'); } @@ -1971,16 +1971,19 @@ void st_select_lex_unit::print(String *str) if (fake_select_lex->order_list.elements) { str->append(STRING_WITH_LEN(" order by ")); - fake_select_lex->print_order(str, - (ORDER *) fake_select_lex-> - order_list.first); + fake_select_lex->print_order( + str, + (ORDER *) fake_select_lex->order_list.first, + query_type); } - fake_select_lex->print_limit(thd, str); + fake_select_lex->print_limit(thd, str, query_type); } } -void st_select_lex::print_order(String *str, ORDER *order) +void st_select_lex::print_order(String *str, + ORDER *order, + enum_query_type query_type) { for (; order; order= order->next) { @@ -1991,7 +1994,7 @@ void st_select_lex::print_order(String *str, ORDER *order) str->append(buffer, length); } else - (*order->item)->print(str); + (*order->item)->print(str, query_type); if (!order->asc) str->append(STRING_WITH_LEN(" desc")); if (order->next) @@ -2000,7 +2003,9 @@ void st_select_lex::print_order(String *str, ORDER *order) } -void st_select_lex::print_limit(THD *thd, String *str) +void st_select_lex::print_limit(THD *thd, + String *str, + enum_query_type query_type) { SELECT_LEX_UNIT *unit= master_unit(); Item_subselect *item= unit->item; @@ -2019,10 +2024,10 @@ void st_select_lex::print_limit(THD *thd, String *str) str->append(STRING_WITH_LEN(" limit ")); if (offset_limit) { - offset_limit->print(str); + offset_limit->print(str, query_type); str->append(','); } - select_limit->print(str); + select_limit->print(str, query_type); } } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 744019c8ae9..b1a0d506382 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -543,7 +543,7 @@ public: inline void unclean() { cleaned= 0; } void reinit_exec_mechanism(); - void print(String *str); + void print(String *str, enum_query_type query_type); bool add_fake_select_lex(THD *thd); void init_prepare_fake_select_lex(THD *thd); @@ -762,9 +762,11 @@ public: init_select(); } bool setup_ref_array(THD *thd, uint order_group_num); - void print(THD *thd, String *str); - static void print_order(String *str, ORDER *order); - void print_limit(THD *thd, String *str); + void print(THD *thd, String *str, enum_query_type query_type); + static void print_order(String *str, + ORDER *order, + enum_query_type query_type); + void print_limit(THD *thd, String *str, enum_query_type query_type); void fix_prepare_information(THD *thd, Item **conds, Item **having_conds); /* Destroy the used execution plan (JOIN) of this subtree (this @@ -1708,8 +1710,6 @@ typedef struct st_lex : public Query_tables_list */ bool use_only_table_context; - LEX_STRING view_body_utf8; - /* Reference to a struct that contains information in various commands to add/create/drop/change table spaces. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a78ac978a4a..e1ee2bd595b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4729,7 +4729,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) char buff[1024]; String str(buff,(uint32) sizeof(buff), system_charset_info); str.length(0); - thd->lex->unit.print(&str); + thd->lex->unit.print(&str, QT_ORDINARY); str.append('\0'); push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_YES, str.ptr()); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d7e7be87d23..a520f9c57cf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -945,7 +945,8 @@ JOIN::optimize() make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0); DBUG_EXECUTE("where", print_where(table_independent_conds, - "where after opt_sum_query()");); + "where after opt_sum_query()", + QT_ORDINARY);); conds= table_independent_conds; } } @@ -1025,7 +1026,10 @@ JOIN::optimize() { conds= substitute_for_best_equal_field(conds, cond_equal, map2table); conds->update_used_tables(); - DBUG_EXECUTE("where", print_where(conds, "after substitute_best_equal");); + DBUG_EXECUTE("where", + print_where(conds, + "after substitute_best_equal", + QT_ORDINARY);); } /* @@ -2088,12 +2092,14 @@ JOIN::exec() curr_table->select_cond= curr_table->select->cond; curr_table->select_cond->top_level_item(); DBUG_EXECUTE("where",print_where(curr_table->select->cond, - "select and having");); + "select and having", + QT_ORDINARY);); curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having, ~ (table_map) 0, ~used_tables); DBUG_EXECUTE("where",print_where(curr_join->tmp_having, - "having after sort");); + "having after sort", + QT_ORDINARY);); } } { @@ -5837,7 +5843,8 @@ static void add_not_null_conds(JOIN *join) if (notnull->fix_fields(join->thd, ¬null)) DBUG_VOID_RETURN; DBUG_EXECUTE("where",print_where(notnull, - referred_tab->table->alias);); + referred_tab->table->alias, + QT_ORDINARY);); add_cond_and_fix(&referred_tab->select_cond, notnull); } } @@ -5995,7 +6002,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) make_cond_for_table(cond, join->const_table_map, (table_map) 0); - DBUG_EXECUTE("where",print_where(const_cond,"constants");); + DBUG_EXECUTE("where",print_where(const_cond,"constants", QT_ORDINARY);); for (JOIN_TAB *tab= join->join_tab+join->const_tables; tab < join->join_tab+join->tables ; tab++) { @@ -6096,7 +6103,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) } if (tmp || !cond) { - DBUG_EXECUTE("where",print_where(tmp,tab->table->alias);); + DBUG_EXECUTE("where",print_where(tmp,tab->table->alias, QT_ORDINARY);); SQL_SELECT *sel= tab->select= ((SQL_SELECT*) thd->memdup((uchar*) select, sizeof(*select))); @@ -6136,7 +6143,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) tab->select_cond= sel->cond= NULL; sel->head=tab->table; - DBUG_EXECUTE("where",print_where(tmp,tab->table->alias);); + DBUG_EXECUTE("where",print_where(tmp,tab->table->alias, QT_ORDINARY);); if (tab->quick) { /* Use quick key read if it's a constant and it's not used @@ -6248,7 +6255,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) current_map, current_map))) { - DBUG_EXECUTE("where",print_where(tmp,"cache");); + DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY);); tab->cache.select=(SQL_SELECT*) thd->memdup((uchar*) sel, sizeof(SQL_SELECT)); tab->cache.select->cond=tmp; @@ -8872,10 +8879,10 @@ optimize_cond(JOIN *join, COND *conds, List *join_list, predicate. Substitute a constant instead of this field if the multiple equality contains a constant. */ - DBUG_EXECUTE("where", print_where(conds, "original");); + DBUG_EXECUTE("where", print_where(conds, "original", QT_ORDINARY);); conds= build_equal_items(join->thd, conds, NULL, join_list, &join->cond_equal); - DBUG_EXECUTE("where",print_where(conds,"after equal_items");); + DBUG_EXECUTE("where",print_where(conds,"after equal_items", QT_ORDINARY);); /* change field = field to field = const for each found field = const */ propagate_cond_constants(thd, (I_List *) 0, conds, conds); @@ -8883,9 +8890,9 @@ optimize_cond(JOIN *join, COND *conds, List *join_list, Remove all instances of item == item Remove all and-levels where CONST item != CONST item */ - DBUG_EXECUTE("where",print_where(conds,"after const change");); + DBUG_EXECUTE("where",print_where(conds,"after const change", QT_ORDINARY);); conds= remove_eq_conds(thd, conds, cond_value) ; - DBUG_EXECUTE("info",print_where(conds,"after remove");); + DBUG_EXECUTE("info",print_where(conds,"after remove", QT_ORDINARY);); } DBUG_RETURN(conds); } @@ -13357,7 +13364,7 @@ static bool fix_having(JOIN *join, Item **having) JOIN_TAB *table=&join->join_tab[join->const_tables]; table_map used_tables= join->const_table_map | table->table->map; - DBUG_EXECUTE("where",print_where(*having,"having");); + DBUG_EXECUTE("where",print_where(*having,"having", QT_ORDINARY);); Item* sort_table_cond=make_cond_for_table(*having,used_tables,used_tables); if (sort_table_cond) { @@ -13374,9 +13381,11 @@ static bool fix_having(JOIN *join, Item **having) table->select_cond=table->select->cond; table->select_cond->top_level_item(); DBUG_EXECUTE("where",print_where(table->select_cond, - "select and having");); + "select and having", + QT_ORDINARY);); *having=make_cond_for_table(*having,~ (table_map) 0,~used_tables); - DBUG_EXECUTE("where",print_where(*having,"having after make_cond");); + DBUG_EXECUTE("where", + print_where(*having,"having after make_cond", QT_ORDINARY);); } return 0; } @@ -15043,7 +15052,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, char buff[256]; String str(buff,sizeof(buff),&my_charset_bin); str.length(0); - item->print(&str); + item->print(&str, QT_ORDINARY); item_field->name= sql_strmake(str.ptr(),str.length()); } #endif @@ -16084,7 +16093,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (thd->lex->describe & DESCRIBE_EXTENDED) { extra.append(STRING_WITH_LEN(": ")); - ((COND *)pushed_cond)->print(&extra); + ((COND *)pushed_cond)->print(&extra, QT_ORDINARY); } } else @@ -16233,9 +16242,13 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) @param thd thread handler @param str string where table should be printed @param tables list of tables in join + @query_type type of the query is being generated */ -static void print_join(THD *thd, String *str, List *tables) +static void print_join(THD *thd, + String *str, + List *tables, + enum_query_type query_type) { /* List is reversed => we should reverse it before using */ List_iterator_fast ti(*tables); @@ -16248,7 +16261,7 @@ static void print_join(THD *thd, String *str, List *tables) *t= ti++; DBUG_ASSERT(tables->elements >= 1); - (*table)->print(thd, str); + (*table)->print(thd, str, query_type); TABLE_LIST **end= table + tables->elements; for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++) @@ -16263,11 +16276,11 @@ static void print_join(THD *thd, String *str, List *tables) str->append(STRING_WITH_LEN(" straight_join ")); else str->append(STRING_WITH_LEN(" join ")); - curr->print(thd, str); + curr->print(thd, str, query_type); if (curr->on_expr) { str->append(STRING_WITH_LEN(" on(")); - curr->on_expr->print(str); + curr->on_expr->print(str, query_type); str->append(')'); } } @@ -16314,15 +16327,15 @@ Index_hint::print(THD *thd, String *str) /** Print table as it should be in join list. - @param str string where table should bbe printed + @param str string where table should be printed */ -void TABLE_LIST::print(THD *thd, String *str) +void TABLE_LIST::print(THD *thd, String *str, enum_query_type query_type) { if (nested_join) { str->append('('); - print_join(thd, str, &nested_join->join_list); + print_join(thd, str, &nested_join->join_list, query_type); str->append(')'); } else @@ -16345,7 +16358,7 @@ void TABLE_LIST::print(THD *thd, String *str) { // A derived table str->append('('); - derived->print(str); + derived->print(str, query_type); str->append(')'); cmp_name= ""; // Force printing of alias } @@ -16405,7 +16418,7 @@ void TABLE_LIST::print(THD *thd, String *str) } -void st_select_lex::print(THD *thd, String *str) +void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) { /* QQ: thd may not be set for sub queries, but this should be fixed */ if (!thd) @@ -16453,7 +16466,7 @@ void st_select_lex::print(THD *thd, String *str) first= 0; else str->append(','); - item->print_item_w_name(str); + item->print_item_w_name(str, query_type); } /* @@ -16464,7 +16477,7 @@ void st_select_lex::print(THD *thd, String *str) { str->append(STRING_WITH_LEN(" from ")); /* go through join tree */ - print_join(thd, str, &top_join_list); + print_join(thd, str, &top_join_list, query_type); } // Where @@ -16475,7 +16488,7 @@ void st_select_lex::print(THD *thd, String *str) { str->append(STRING_WITH_LEN(" where ")); if (cur_where) - cur_where->print(str); + cur_where->print(str, query_type); else str->append(cond_value != Item::COND_FALSE ? "1" : "0"); } @@ -16484,7 +16497,7 @@ void st_select_lex::print(THD *thd, String *str) if (group_list.elements) { str->append(STRING_WITH_LEN(" group by ")); - print_order(str, (ORDER *) group_list.first); + print_order(str, (ORDER *) group_list.first, query_type); switch (olap) { case CUBE_TYPE: @@ -16507,7 +16520,7 @@ void st_select_lex::print(THD *thd, String *str) { str->append(STRING_WITH_LEN(" having ")); if (cur_having) - cur_having->print(str); + cur_having->print(str, query_type); else str->append(having_value != Item::COND_FALSE ? "1" : "0"); } @@ -16515,11 +16528,11 @@ void st_select_lex::print(THD *thd, String *str) if (order_list.elements) { str->append(STRING_WITH_LEN(" order by ")); - print_order(str, (ORDER *) order_list.first); + print_order(str, (ORDER *) order_list.first, query_type); } // limit - print_limit(thd, str); + print_limit(thd, str, query_type); // PROCEDURE unsupported here } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 9f56933a114..2c4251f0fde 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1582,7 +1582,7 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) We can't just use table->query, because our SQL_MODE may trigger a different syntax, like when ANSI_QUOTES is defined. */ - table->view->unit.print(buff); + table->view->unit.print(buff, QT_ORDINARY); if (table->with_check != VIEW_CHECK_NONE) { diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 0fe299d4505..0bce4eb4a82 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -49,14 +49,14 @@ static const char *lock_descriptions[] = #ifndef DBUG_OFF void -print_where(COND *cond,const char *info) +print_where(COND *cond,const char *info, enum_query_type query_type) { if (cond) { char buff[256]; String str(buff,(uint32) sizeof(buff), system_charset_info); str.length(0); - cond->print(&str); + cond->print(&str, query_type); str.append('\0'); DBUG_LOCK_FILE; (void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info); @@ -143,7 +143,7 @@ void TEST_filesort(SORT_FIELD *sortorder,uint s_length) else { str.length(0); - sortorder->item->print(&str); + sortorder->item->print(&str, QT_ORDINARY); out.append(str); } } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index f1eb0004577..68cc8e1839a 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -720,7 +720,42 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, { LEX *lex= thd->lex; char buff[4096]; - String view_query(buff, sizeof (buff), thd->charset()); + + /* + View definition query -- a SELECT statement that fully defines view. It + is generated from the Item-tree built from the original (specified by + the user) query. The idea is that generated query should eliminates all + ambiguities and fix view structure at CREATE-time (once for all). + Item::print() virtual operation is used to generate view definition + query. + + INFORMATION_SCHEMA query (IS query) -- a SQL statement describing a + view that is shown in INFORMATION_SCHEMA. Basically, it is 'view + definition query' with text literals converted to UTF8 and without + character set introducers. + + For example: + Let's suppose we have: + CREATE TABLE t1(a INT, b INT); + User specified query: + CREATE VIEW v1(x, y) AS SELECT * FROM t1; + Generated query: + SELECT a AS x, b AS y FROM t1; + IS query: + SELECT a AS x, b AS y FROM t1; + + View definition query is stored in the client character set. + */ + char view_query_buff[4096]; + String view_query(view_query_buff, + sizeof (view_query_buff), + thd->charset()); + + char is_query_buff[4096]; + String is_query(is_query_buff, + sizeof (is_query_buff), + system_charset_info); + char md5[MD5_BUFF_LENGTH]; bool can_be_merged; char dir_buff[FN_REFLEN], path_buff[FN_REFLEN]; @@ -728,12 +763,16 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, int error= 0; DBUG_ENTER("mysql_register_view"); - /* print query */ + /* Generate view definition and IS queries. */ view_query.length(0); + is_query.length(0); { ulong sql_mode= thd->variables.sql_mode & MODE_ANSI_QUOTES; thd->variables.sql_mode&= ~MODE_ANSI_QUOTES; - lex->unit.print(&view_query); + + lex->unit.print(&view_query, QT_ORDINARY); + lex->unit.print(&is_query, QT_IS); + thd->variables.sql_mode|= sql_mode; } DBUG_PRINT("info", ("View: %s", view_query.ptr())); @@ -872,7 +911,8 @@ loop_out: lex_string_set(&view->view_connection_cl_name, view->view_creation_ctx->get_connection_cl()->name); - view->view_body_utf8= lex->view_body_utf8; + view->view_body_utf8.str= is_query.c_ptr_safe(); + view->view_body_utf8.length= is_query.length(); /* Check that table of main select do not used in subqueries. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f1689b28719..7c669851db4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -12005,27 +12005,7 @@ view_tail: if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING)) MYSQL_YYABORT; } - view_list_opt AS - { - THD *thd= YYTHD; - Lex_input_stream *lip= thd->m_lip; - - lip->body_utf8_start(thd, lip->get_cpp_ptr()); - } - view_select - { - THD *thd= YYTHD; - LEX *lex= thd->lex; - Lex_input_stream *lip= thd->m_lip; - - lip->body_utf8_append(lip->get_cpp_ptr()); - - lex->view_body_utf8.str= thd->strmake(lip->get_body_utf8_str(), - lip->get_body_utf8_length()); - lex->view_body_utf8.length= lip->get_body_utf8_length(); - - trim_whitespace(&my_charset_utf8_general_ci, &lex->view_body_utf8); - } + view_list_opt AS view_select ; view_list_opt: diff --git a/sql/table.h b/sql/table.h index 284885658e0..941964ee24e 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1148,7 +1148,7 @@ struct TABLE_LIST return derived || view || schema_table || create && !table->db_stat || !table; } - void print(THD *thd, String *str); + void print(THD *thd, String *str, enum_query_type query_type); bool check_single_table(TABLE_LIST **table, table_map map, TABLE_LIST *view); bool set_insert_values(MEM_ROOT *mem_root); -- cgit v1.2.1 From 5d26f63c9543cbb41e1fd6c7d1ac8b5fa4a315cc Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Feb 2008 17:45:09 +0300 Subject: An unused variable (compile-time warning). sql/sql_view.cc: An unused variable. --- sql/sql_view.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_view.cc b/sql/sql_view.cc index bbcb1bcb143..1cf1a22bb90 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -758,7 +758,6 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, enum_view_create_mode mode) { LEX *lex= thd->lex; - char buff[4096]; /* View definition query -- a SELECT statement that fully defines view. It -- cgit v1.2.1 From fea2a5d83dea81e231bb14bc5535b60261c7b30d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Feb 2008 19:07:07 +0400 Subject: BUG#13861 - START SLAVE UNTIL may stop 1 evnt too late if log-slave-updates and circul repl Slave SQL thread may execute one extra event when there are events skipped by slave I/O thread (e.g. originated by the same server). Whereas it was requested not to do so by the UNTIL condition. This happens because we compare with the end position of previously executed event. This is fine when there are no skipped by slave I/O thread events, as end position of previous event equals to start position of to be executed event. Otherwise this position equals to start position of skipped event. This is fixed by: - reading the event to be executed before checking if the until condition is satisfied. - comparing the start position of the event to be executed. Since we do not have the start position available, we compute it by subtracting event length from end position (which is available). - if there are no events on the event queue at the slave sql starting time, that meet until condition, we stop immediately, as in this case we do not want to wait for next event. mysql-test/r/rpl_dual_pos_advance.result: A test case for BUG#13861. mysql-test/t/rpl_dual_pos_advance.test: A test case for BUG#13861. sql/log_event.cc: Store length of event. This is needed for further calculation of the beginning of event. sql/slave.cc: Slave SQL thread may execute one extra event when there are events skipped by slave I/O thread (e.g. originated by the same server). Whereas it was requested not to do so by the UNTIL condition. This happens because we compare with the end position of previously executed event. This is fine when there are no skipped by slave I/O thread events, as end position of previous event equals to start position of to be executed event. Otherwise this position equals to start position of skipped event. This is fixed by: - reading the event to be executed before checking if the until condition is satisfied. - comparing the start position of the event to be executed. Since we do not have the start position available, we compute it by subtracting event length from end position (which is available). - if there are no events on the event queue at the slave sql starting time, that meet until condition, we stop immediately, as in this case we do not want to wait for next event. sql/slave.h: Added master_log_pos parametr to is_until_satisfied(). mysql-test/t/rpl_dual_pos_advance-slave.opt: New BitKeeper file ``mysql-test/t/rpl_dual_pos_advance-slave.opt'' --- sql/log_event.cc | 3 ++- sql/slave.cc | 68 ++++++++++++++++++++++++++++++++++++-------------------- sql/slave.h | 2 +- 3 files changed, 47 insertions(+), 26 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index a950094a018..8e14a873fc6 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -373,6 +373,7 @@ Log_event::Log_event(const char* buf, #endif when = uint4korr(buf); server_id = uint4korr(buf + SERVER_ID_OFFSET); + data_written= uint4korr(buf + EVENT_LEN_OFFSET); if (description_event->binlog_version==1) { log_pos= 0; @@ -405,7 +406,7 @@ Log_event::Log_event(const char* buf, binlog, so which will cause problems if the user uses this value in CHANGE MASTER). */ - log_pos+= uint4korr(buf + EVENT_LEN_OFFSET); + log_pos+= data_written; } DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos)); diff --git a/sql/slave.cc b/sql/slave.cc index 8a3620080f2..500683e080d 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3115,6 +3115,11 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error) Check if condition stated in UNTIL clause of START SLAVE is reached. SYNOPSYS st_relay_log_info::is_until_satisfied() + master_beg_pos position of the beginning of to be executed event + (not log_pos member of the event that points to the + beginning of the following event) + + DESCRIPTION Checks if UNTIL condition is reached. Uses caching result of last comparison of current log file name and target log file name. So cached @@ -3139,7 +3144,7 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error) false - condition not met */ -bool st_relay_log_info::is_until_satisfied() +bool st_relay_log_info::is_until_satisfied(my_off_t master_beg_pos) { const char *log_name; ulonglong log_pos; @@ -3149,7 +3154,7 @@ bool st_relay_log_info::is_until_satisfied() if (until_condition == UNTIL_MASTER_POS) { log_name= group_master_log_name; - log_pos= group_master_log_pos; + log_pos= master_beg_pos; } else { /* until_condition == UNTIL_RELAY_POS */ @@ -3228,28 +3233,6 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) wait for something for example inside of next_event(). */ pthread_mutex_lock(&rli->data_lock); - /* - This tests if the position of the end of the last previous executed event - hits the UNTIL barrier. - We would prefer to test if the position of the start (or possibly) end of - the to-be-read event hits the UNTIL barrier, this is different if there - was an event ignored by the I/O thread just before (BUG#13861 to be - fixed). - */ - if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE && - rli->is_until_satisfied()) - { - char buf[22]; - sql_print_information("Slave SQL thread stopped because it reached its" - " UNTIL position %s", llstr(rli->until_pos(), buf)); - /* - Setting abort_slave flag because we do not want additional message about - error in query execution to be printed. - */ - rli->abort_slave= 1; - pthread_mutex_unlock(&rli->data_lock); - return 1; - } Log_event * ev = next_event(rli); @@ -3266,6 +3249,27 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) int type_code = ev->get_type_code(); int exec_res; + /* + This tests if the position of the beginning of the current event + hits the UNTIL barrier. + */ + if (rli->until_condition != RELAY_LOG_INFO::UNTIL_NONE && + rli->is_until_satisfied((thd->options & OPTION_BEGIN || !ev->log_pos) ? + rli->group_master_log_pos : + ev->log_pos - ev->data_written)) + { + char buf[22]; + sql_print_information("Slave SQL thread stopped because it reached its" + " UNTIL position %s", llstr(rli->until_pos(), buf)); + /* + Setting abort_slave flag because we do not want additional message about + error in query execution to be printed. + */ + rli->abort_slave= 1; + pthread_mutex_unlock(&rli->data_lock); + delete ev; + return 1; + } /* Queries originating from this server must be skipped. Low-level events (Format_desc, Rotate, Stop) from this server @@ -3977,6 +3981,22 @@ Slave SQL thread aborted. Can't execute init_slave query"); } } + /* + First check until condition - probably there is nothing to execute. We + do not want to wait for next event in this case. + */ + pthread_mutex_lock(&rli->data_lock); + if (rli->until_condition != RELAY_LOG_INFO::UNTIL_NONE && + rli->is_until_satisfied(rli->group_master_log_pos)) + { + char buf[22]; + sql_print_information("Slave SQL thread stopped because it reached its" + " UNTIL position %s", llstr(rli->until_pos(), buf)); + pthread_mutex_unlock(&rli->data_lock); + goto err; + } + pthread_mutex_unlock(&rli->data_lock); + /* Read queries from the IO/THREAD until this thread is killed */ while (!sql_slave_killed(thd,rli)) diff --git a/sql/slave.h b/sql/slave.h index c61787cdf3b..da548e145d3 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -348,7 +348,7 @@ typedef struct st_relay_log_info void close_temporary_tables(); /* Check if UNTIL condition is satisfied. See slave.cc for more. */ - bool is_until_satisfied(); + bool is_until_satisfied(my_off_t master_beg_pos); inline ulonglong until_pos() { return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos : -- cgit v1.2.1 From 5d6ca9c2a33cf3e1496e83a746f07e81f02b5a86 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Feb 2008 16:18:31 +0100 Subject: Fix for bug#22738 Events: After stop and start disabled events could reside in the queue Disabled events weren't removed from the memory queue after the scheduler has been re-enabled. After recalculation of next execution time of an event, it might get disabled. sql/event_queue.cc: Sort the event queue in a way that the disabled events will always be at the end. We will use this for cleaning it, starting from the end. After recalculating times in the queue, after the scheduler has been enabled after disabled state, the queue should be cleaned from DISABLED events. The queue is sorted in a way such that the disabled events are at the end. Thus, we can start from the end of the queue and remove all DISABLED till we find the first with different state. sql/events.cc: Add a comment about possible problem with replication of events, disabled events and server restarts. --- sql/event_queue.cc | 38 ++++++++++++++++++++++++++++++++++++-- sql/events.cc | 7 ++++++- 2 files changed, 42 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/event_queue.cc b/sql/event_queue.cc index 898fc206c34..719a837cbfb 100644 --- a/sql/event_queue.cc +++ b/sql/event_queue.cc @@ -60,8 +60,16 @@ extern "C" int event_queue_element_compare_q(void *, uchar *, uchar *); int event_queue_element_compare_q(void *vptr, uchar* a, uchar *b) { - my_time_t lhs = ((Event_queue_element *)a)->execute_at; - my_time_t rhs = ((Event_queue_element *)b)->execute_at; + Event_queue_element *left = (Event_queue_element *)a; + Event_queue_element *right = (Event_queue_element *)b; + my_time_t lhs = left->execute_at; + my_time_t rhs = right->execute_at; + + if (left->status == Event_queue_element::DISABLED) + return right->status != Event_queue_element::DISABLED; + + if (right->status == Event_queue_element::DISABLED) + return 1; return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0)); } @@ -434,8 +442,34 @@ Event_queue::recalculate_activation_times(THD *thd) ((Event_queue_element*)queue_element(&queue, i))->update_timing_fields(thd); } queue_fix(&queue); + /* + The disabled elements are moved to the end during the `fix`. + Start from the end and remove all of the elements which are + disabled. When we find the first non-disabled one we break, as we + have removed all. The queue has been ordered in a way the disabled + events are at the end. + */ + for (i= queue.elements; i > 0; i--) + { + Event_queue_element *element = (Event_queue_element*)queue_element(&queue, i - 1); + if (element->status != Event_queue_element::DISABLED) + break; + /* + This won't cause queue re-order, because we remove + always the last element. + */ + queue_remove(&queue, i - 1); + delete element; + } UNLOCK_QUEUE_DATA(); + /* + XXX: The events are dropped only from memory and not from disk + even if `drop_list[j]->dropped` is TRUE. There will be still on the + disk till next server restart. + Please add code here to do it. + */ + DBUG_VOID_RETURN; } diff --git a/sql/events.cc b/sql/events.cc index 87385082a82..700663db7d1 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -1185,7 +1185,12 @@ Events::load_events_from_db(THD *thd) { /* If not created, a stale event - drop if immediately if - ON COMPLETION NOT PRESERVE + ON COMPLETION NOT PRESERVE. + XXX: This won't be replicated, thus the drop won't appear in + in the slave. When the slave is restarted it will drop events. + However, as the slave will be "out of sync", it might happen that + an event created on the master, after master restart, won't be + replicated to the slave correctly, as the create will fail there. */ int rc= table->file->ha_delete_row(table->record[0]); if (rc) -- cgit v1.2.1 From 482d60082fb5356511d020704ecc992d9cb0e375 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 22 Feb 2008 16:56:34 -0700 Subject: Bug #34053: normal users can enable innodb_monitor logging The check_global_access() function was made available to InnoDB, but was not defined in the embedded server library. InnoDB, as a plugin, is not recompiled when the embedded server is built. This caused a link failure when compiling applications which use the embedded server. The fix here is to always define check_global_access() externally; in the embedded server case, it is defined to just return OK. Also, don't run the test case for this bug in embedded server. mysql-test/t/innodb_bug34053.test: Disable this test on embedded server - it tests privilege checks which are not in place there. sql/mysql_priv.h: Since check_global_access() may be used from some storage engine plugins (InnoDB, currently), and the plugins are not recompiled for the embedded server, it must be defined externally even for NO_EMBEDDED_ACCESS_CHECKS. sql/sql_parse.cc: Since check_global_access() may be used from some storage engine plugins (InnoDB, currently), and the plugins are not recompiled for the embedded server, it must be defined externally even for NO_EMBEDDED_ACCESS_CHECKS. --- sql/mysql_priv.h | 5 ----- sql/sql_parse.cc | 62 ++++++++++++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 34 deletions(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5ed670c32ed..2c43959815e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1051,12 +1051,7 @@ inline bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, #endif /* MYSQL_SERVER */ #if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS -#ifndef NO_EMBEDDED_ACCESS_CHECKS bool check_global_access(THD *thd, ulong want_access); -#else -inline bool check_global_access(THD *thd, ulong want_access) -{ return false; } -#endif /*NO_EMBEDDED_ACCESS_CHECKS*/ #endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */ #ifdef MYSQL_SERVER diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 55ae30d37ad..4dd600835ce 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4989,35 +4989,6 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, } -/** - check for global access and give descriptive error message if it fails. - - @param thd Thread handler - @param want_access Use should have any of these global rights - - @warning - One gets access right if one has ANY of the rights in want_access. - This is useful as one in most cases only need one global right, - but in some case we want to check if the user has SUPER or - REPL_CLIENT_ACL rights. - - @retval - 0 ok - @retval - 1 Access denied. In this case an error is sent to the client -*/ - -bool check_global_access(THD *thd, ulong want_access) -{ - char command[128]; - if ((thd->security_ctx->master_access & want_access)) - return 0; - get_privilege_desc(command, sizeof(command), want_access); - my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); - return 1; -} - - static bool check_show_access(THD *thd, TABLE_LIST *table) { switch (get_schema_table_idx(table->schema_table)) { @@ -5260,6 +5231,39 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ + +/** + check for global access and give descriptive error message if it fails. + + @param thd Thread handler + @param want_access Use should have any of these global rights + + @warning + One gets access right if one has ANY of the rights in want_access. + This is useful as one in most cases only need one global right, + but in some case we want to check if the user has SUPER or + REPL_CLIENT_ACL rights. + + @retval + 0 ok + @retval + 1 Access denied. In this case an error is sent to the client +*/ + +bool check_global_access(THD *thd, ulong want_access) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + char command[128]; + if ((thd->security_ctx->master_access & want_access)) + return 0; + get_privilege_desc(command, sizeof(command), want_access); + my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); + return 1; +#else + return 0; +#endif +} + /**************************************************************************** Check stack size; Send error if there isn't enough stack to continue ****************************************************************************/ -- cgit v1.2.1 From 7b8717ace88805a6a243a2800fc7d3fc70d2fddc Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 24 Feb 2008 01:31:54 +0100 Subject: Bug#20752: BENCHMARK with many iterations returns too quickly In BENCHMARK(count, expr), count could overflow/wrap-around. Patch changes to a sufficiently large data-type. Adds a warning for negative count values. mysql-test/r/func_str.result: show that a negative 'count' for BENCHMARK(count, expr) throws a warning and returns NULL. mysql-test/t/func_str.test: show that a negative 'count' for BENCHMARK(count, expr) throws a warning and returns NULL. sql/item_func.cc: use ulonglong rather than ulong in BENCHMARK(count, expr) throw warning on negative 'count'; return SQL-NULL. --- sql/item_func.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index cd936412241..f6f67b148bd 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3651,18 +3651,28 @@ longlong Item_func_benchmark::val_int() String tmp(buff,sizeof(buff), &my_charset_bin); my_decimal tmp_decimal; THD *thd=current_thd; - ulong loop_count; + ulonglong loop_count; - loop_count= (ulong) args[0]->val_int(); + loop_count= (ulonglong) args[0]->val_int(); - if (args[0]->null_value) + if (args[0]->null_value || + (!args[0]->unsigned_flag && (((longlong) loop_count) < 0))) { + if (!args[0]->null_value) + { + char buff[22]; + llstr(((longlong) loop_count), buff); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_WRONG_VALUE_FOR_TYPE, ER(ER_WRONG_VALUE_FOR_TYPE), + "count", buff, "benchmark"); + } + null_value= 1; return 0; } null_value=0; - for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++) + for (ulonglong loop=0 ; loop < loop_count && !thd->killed; loop++) { switch (args[1]->result_type()) { case REAL_RESULT: -- cgit v1.2.1 From a22c3d21096f827d4eb7dfc1b3546cb758123756 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 24 Feb 2008 13:58:07 +0100 Subject: Bug#32753: PAD_CHAR_TO_FULL_LENGTH is not documented and interferes with grant tables SQL-mode PAD_CHAR_TO_FULL_LENGTH affected mysqld's user-table too. If enabled, user-name and host were space-padded and no longer matched the login-data of incoming connexions. Patch disregards pad-flag while loading privileges so ability to log in does not depend on SQL-mode. mysql-test/r/sql_mode.result: show that SQL-mode 'PAD_CHAR_TO_FULL_LENGTH' does not affect loading of privileges (and by extension, ability to log in). mysql-test/t/sql_mode.test: show that SQL-mode 'PAD_CHAR_TO_FULL_LENGTH' does not affect loading of privileges (and by extension, ability to log in). sql/sql_acl.cc: temporarily disable SQL-mode 'PAD_CHAR_TO_FULL_LENGTH' while reloading privileges --- sql/sql_acl.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 064aa6dc044..abeacd49c1f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -192,7 +192,7 @@ static void update_hostname(acl_host_and_ip *host, const char *hostname); static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); static my_bool acl_load(THD *thd, TABLE_LIST *tables); -static my_bool grant_load(TABLE_LIST *tables); +static my_bool grant_load(THD *thd, TABLE_LIST *tables); /* Convert scrambled password to binary form, according to scramble type, @@ -314,8 +314,11 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; char tmp_name[NAME_LEN+1]; int password_length; + ulong old_sql_mode= thd->variables.sql_mode; DBUG_ENTER("acl_load"); + thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; + grant_version++; /* Privileges updated */ acl_cache->clear(1); // Clear locked hostname cache @@ -622,6 +625,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) return_val=0; end: + thd->variables.sql_mode= old_sql_mode; DBUG_RETURN(return_val); } @@ -3613,7 +3617,7 @@ end_unlock: @retval TRUE Error */ -static my_bool grant_load(TABLE_LIST *tables) +static my_bool grant_load(THD *thd, TABLE_LIST *tables) { MEM_ROOT *memex_ptr; my_bool return_val= 1; @@ -3621,7 +3625,11 @@ static my_bool grant_load(TABLE_LIST *tables) bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); + ulong old_sql_mode= thd->variables.sql_mode; DBUG_ENTER("grant_load"); + + thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; + (void) hash_init(&column_priv_hash,system_charset_info, 0,0,0, (hash_get_key) get_grant_table, (hash_free_key) free_grant_table,0); @@ -3673,6 +3681,7 @@ static my_bool grant_load(TABLE_LIST *tables) return_val=0; // Return ok end_unlock: + thd->variables.sql_mode= old_sql_mode; t_table->file->ha_index_end(); my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr); DBUG_RETURN(return_val); @@ -3786,7 +3795,7 @@ my_bool grant_reload(THD *thd) old_mem= memex; init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); - if ((return_val= grant_load(tables))) + if ((return_val= grant_load(thd, tables))) { // Error. Revert to old hash DBUG_PRINT("error",("Reverting to old privileges")); grant_free(); /* purecov: deadcode */ -- cgit v1.2.1 From 9bd3b8545a44188502a1a142e6f2171ac5b600e1 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 24 Feb 2008 14:12:17 +0100 Subject: Bug#32757: hang with sql_mode set when setting some global variables If setting a system-variable provided by a plug-in failed, no OK or error was sent in some cases, hanging the client. We now send an error in the case from the ticket (integer-argument out of range in STRICT mode). We also provide a semi-generic fallback message for possible future cases like this where an error is signalled, but no message is sent to the client. The error/warning handling is unified so it's the same again for variables provided by plugins and those in the server proper. mysql-test/r/plugin.result: show that on out-of-range values, plugin interface throws errors in STRICT mode and warnings otherwise. mysql-test/t/plugin.test: show that on out-of-range values, plugin interface throws errors in STRICT mode and warnings otherwise. sql/set_var.cc: - handle signedness of values used in warnings - in STRICT mode, throw errors rather than warnings sql/sql_parse.cc: If sql_set_variables() returns with an error but no message was sent to the client, send a semi-generic one so the session won't hang and we won't fail silently. sql/sql_plugin.cc: throw a warning if more than just block-size was corrected (or an error in STRICT mode). use functions from set_var for uniform behaviour of server- and plug-in variables. storage/example/ha_example.cc: Add a ULONG system variable to example plugin so we can test integers in the plugin-interface without having to depend on the presence of innobase. --- sql/set_var.cc | 41 +++++++++++++++++++++++++++++------------ sql/sql_parse.cc | 12 ++++++++++++ sql/sql_plugin.cc | 39 ++++++++------------------------------- 3 files changed, 49 insertions(+), 43 deletions(-) (limited to 'sql') diff --git a/sql/set_var.cc b/sql/set_var.cc index a01a0b49dbc..a25bbee3350 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -123,7 +123,8 @@ static void fix_server_id(THD *thd, enum_var_type type); static ulonglong fix_unsigned(THD *thd, ulonglong num, const struct my_option *option_limits); static bool get_unsigned(THD *thd, set_var *var); -static void throw_bounds_warning(THD *thd, const char *name, ulonglong num); +bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd, + const char *name, longlong val); static KEY_CACHE *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static uchar *get_error_count(THD *thd); @@ -1106,13 +1107,29 @@ static void fix_server_id(THD *thd, enum_var_type type) } -static void throw_bounds_warning(THD *thd, const char *name, ulonglong num) +bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd, + const char *name, longlong val) { - char buf[22]; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER(ER_TRUNCATED_WRONG_VALUE), name, - ullstr(num, buf)); + if (fixed) + { + char buf[22]; + + if (unsignd) + ullstr((ulonglong) val, buf); + else + llstr(val, buf); + + if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) + { + my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf); + return TRUE; + } + + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_TRUNCATED_WRONG_VALUE, + ER(ER_TRUNCATED_WRONG_VALUE), name, buf); + } + return FALSE; } static ulonglong fix_unsigned(THD *thd, ulonglong num, @@ -1121,8 +1138,7 @@ static ulonglong fix_unsigned(THD *thd, ulonglong num, bool fixed= FALSE; ulonglong out= getopt_ull_limit_value(num, option_limits, &fixed); - if (fixed) - throw_bounds_warning(thd, option_limits->name, num); + throw_bounds_warning(thd, fixed, TRUE, option_limits->name, (longlong) num); return out; } @@ -1165,7 +1181,8 @@ bool sys_var_long_ptr_global::update(THD *thd, set_var *var) if (tmp > ULONG_MAX) { tmp= ULONG_MAX; - throw_bounds_warning(thd, name, var->save_result.ulonglong_value); + throw_bounds_warning(thd, TRUE, TRUE, name, + (longlong) var->save_result.ulonglong_value); } #endif *value= (ulong) tmp; @@ -1250,7 +1267,7 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var) /* Don't use bigger value than given with --maximum-variable-name=.. */ if ((ulong) tmp > max_system_variables.*offset) { - throw_bounds_warning(thd, name, tmp); + throw_bounds_warning(thd, TRUE, TRUE, name, (longlong) tmp); tmp= max_system_variables.*offset; } @@ -1260,7 +1277,7 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var) else if (tmp > ULONG_MAX) { tmp= ULONG_MAX; - throw_bounds_warning(thd, name, var->save_result.ulonglong_value); + throw_bounds_warning(thd, TRUE, TRUE, name, (longlong) var->save_result.ulonglong_value); } #endif diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b60a72e4c53..a74c4a01699 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3185,6 +3185,18 @@ end_with_restore_list: thd->one_shot_set|= lex->one_shot_set; send_ok(thd); } + else + { + /* + We encountered some sort of error, but no message was sent. + Send something semi-generic here since we don't know which + assignment in the list caused the error. + */ + if (!thd->is_error()) + my_error(ER_WRONG_ARGUMENTS,MYF(0),"SET"); + goto error; + } + break; } diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 2a86844c8c6..5fafa751379 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -210,6 +210,8 @@ static void reap_plugins(void); /* declared in set_var.cc */ extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error); +extern bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd, + const char *name, longlong val); #ifdef EMBEDDED_LIBRARY /* declared in sql_base.cc */ @@ -1888,16 +1890,8 @@ static int check_func_int(THD *thd, struct st_mysql_sys_var *var, else *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed); - if (fixed) - { - char buf[22]; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER(ER_TRUNCATED_WRONG_VALUE), var->name, - ullstr(tmp, buf)); - } - return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) && - (*(int *)save != (int) tmp); + return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED, + var->name, (longlong) tmp); } @@ -1916,16 +1910,8 @@ static int check_func_long(THD *thd, struct st_mysql_sys_var *var, else *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed); - if (fixed) - { - char buf[22]; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER(ER_TRUNCATED_WRONG_VALUE), var->name, - ullstr(tmp, buf)); - } - return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) && - (*(long *)save != (long) tmp); + return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED, + var->name, (longlong) tmp); } @@ -1937,7 +1923,6 @@ static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var, struct my_option options; value->val_int(value, &tmp); plugin_opt_set_limits(&options, var); - *(ulonglong *)save= getopt_ull_limit_value(tmp, &options, &fixed); if (var->flags & PLUGIN_VAR_UNSIGNED) *(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options, @@ -1945,16 +1930,8 @@ static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var, else *(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed); - if (fixed) - { - char buf[22]; - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_TRUNCATED_WRONG_VALUE, - ER(ER_TRUNCATED_WRONG_VALUE), var->name, - ullstr(tmp, buf)); - } - return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) && - (*(long long *)save != tmp); + return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED, + var->name, (longlong) tmp); } static int check_func_str(THD *thd, struct st_mysql_sys_var *var, -- cgit v1.2.1 From c37fdbcdfdc065498cfc837ac6dcb6bc78fb206b Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 24 Feb 2008 19:13:18 +0100 Subject: Pre push fixes Test file fixes for bugs 20129, 31931 and 34225 mysql-test/suite/parts/r/partition_basic_symlink_innodb.result: Manual merge, new test case to be modified for Bug#20129 mysql-test/suite/parts/r/partition_basic_symlink_myisam.result: Manual merge, new test case to be modified for Bug#20129 mysql-test/suite/parts/r/partition_engine_innodb.result: Manual merge, fix for bug#31931 mysql-test/suite/parts/r/partition_engine_myisam.result: Manual merge, fix for bug#31931 mysql-test/suite/parts/t/disabled.def: These should work now since Bug#34225 is fixed sql/ha_partition.cc: Bug#20129: partition maintenance command not working with crashed tables Fix for compiler warnings. --- sql/ha_partition.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index d97af771a00..64bee07aa1c 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1028,6 +1028,7 @@ int ha_partition::repair_partitions(THD *thd) 0 Success */ +#ifdef WL4176_IS_DONE static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, handler *file, uint flag) { @@ -1041,7 +1042,6 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, */ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED); -#ifdef WL4176_IS_DONE if (flag == OPTIMIZE_PARTS) error= file->ha_optimize(thd, check_opt); else if (flag == ANALYZE_PARTS) @@ -1058,8 +1058,8 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, if (error == HA_ADMIN_ALREADY_DONE) error= 0; DBUG_RETURN(error); -#endif } +#endif /* @@ -1080,11 +1080,13 @@ static int handle_opt_part(THD *thd, HA_CHECK_OPT *check_opt, int ha_partition::handle_opt_partitions(THD *thd, HA_CHECK_OPT *check_opt, uint flag, bool all_parts) { +#ifdef WL4176_IS_DONE List_iterator part_it(m_part_info->partitions); uint no_parts= m_part_info->no_parts; uint no_subparts= m_part_info->no_subparts; uint i= 0; int error; +#endif DBUG_ENTER("ha_partition::handle_opt_partitions"); DBUG_PRINT("enter", ("all_parts %u, flag= %u", all_parts, flag)); -- cgit v1.2.1 From 4f3eab58046a42f66abd68d547ad97a9d58ecb04 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Feb 2008 13:25:57 +0300 Subject: Fix for bug #33834: FRAC_SECOND: Applicability not clear in documentation While the manual mentions FRAC_SECOND only for the TIMESTAMPADD() function, it was also possible to use FRAC_SECOND with DATE_ADD(), DATE_SUB() and +/- INTERVAL. Fixed the parser to match the manual, i.e. using FRAC_SECOND for anything other than TIMESTAMPADD()/TIMESTAMPDIFF() now produces a syntax error. Additionally, the patch allows MICROSECOND to be used in TIMESTAMPADD/ TIMESTAMPDIFF and marks FRAC_SECOND as deprecated. mysql-test/r/func_time.result: Added a test case for bug #33834. mysql-test/t/func_time.test: Added a test case for bug #33834. sql/sql_yacc.yy: Reject FRAC_SECOND for anything other than TIMESTAMPADD() or TIMESTAMPDIFF(). Allow MICROSECOND to be used with TIMESTAMPADD()/TIMESTAMPDIFF(). Warn about FRAC_SECOND being a deprecated unit. --- sql/sql_yacc.yy | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index af57fbdb108..cb447c1187a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -458,10 +458,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 245 shift/reduce conflicts. + Currently there are 240 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 245 +%expect 240 %token END_OF_INPUT @@ -1111,6 +1111,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type interval_time_st +%type interval_time_stamp + %type storage_engines %type row_types @@ -5027,9 +5029,9 @@ simple_expr: { $$= new Item_datetime_typecast($3); } | TIMESTAMP '(' expr ',' expr ')' { $$= new Item_func_add_time($3, $5, 1, 0); } - | TIMESTAMP_ADD '(' interval_time_st ',' expr ',' expr ')' + | TIMESTAMP_ADD '(' interval_time_stamp ',' expr ',' expr ')' { $$= new Item_date_add_interval($7,$5,$3,0); } - | TIMESTAMP_DIFF '(' interval_time_st ',' expr ',' expr ')' + | TIMESTAMP_DIFF '(' interval_time_stamp ',' expr ',' expr ')' { $$= new Item_func_timestamp_diff($5,$7,$3); } | TRIM '(' expr ')' { $$= new Item_func_trim($3); } @@ -6005,21 +6007,40 @@ interval: | HOUR_MICROSECOND_SYM { $$=INTERVAL_HOUR_MICROSECOND; } | HOUR_MINUTE_SYM { $$=INTERVAL_HOUR_MINUTE; } | HOUR_SECOND_SYM { $$=INTERVAL_HOUR_SECOND; } - | MICROSECOND_SYM { $$=INTERVAL_MICROSECOND; } | MINUTE_MICROSECOND_SYM { $$=INTERVAL_MINUTE_MICROSECOND; } | MINUTE_SECOND_SYM { $$=INTERVAL_MINUTE_SECOND; } | SECOND_MICROSECOND_SYM { $$=INTERVAL_SECOND_MICROSECOND; } | YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; }; +interval_time_stamp: + interval_time_st {} + | FRAC_SECOND_SYM { + $$=INTERVAL_MICROSECOND; + /* + FRAC_SECOND was mistakenly implemented with + a wrong resolution. According to the ODBC + standard it should be nanoseconds, not + microseconds. Changing it to nanoseconds + in MySQL would mean making TIMESTAMPDIFF + and TIMESTAMPADD to return DECIMAL, since + the return value would be too big for BIGINT + Hence we just deprecate the incorrect + implementation without changing its + resolution. + */ + WARN_DEPRECATED("FRAC_SECOND", "MICROSECOND"); // Will be removed in 6.2 + } + ; + interval_time_st: DAY_SYM { $$=INTERVAL_DAY; } | WEEK_SYM { $$=INTERVAL_WEEK; } | HOUR_SYM { $$=INTERVAL_HOUR; } - | FRAC_SECOND_SYM { $$=INTERVAL_MICROSECOND; } | MINUTE_SYM { $$=INTERVAL_MINUTE; } | MONTH_SYM { $$=INTERVAL_MONTH; } | QUARTER_SYM { $$=INTERVAL_QUARTER; } | SECOND_SYM { $$=INTERVAL_SECOND; } + | MICROSECOND_SYM { $$=INTERVAL_MICROSECOND; } | YEAR_SYM { $$=INTERVAL_YEAR; } ; -- cgit v1.2.1 From b2e879cbe83f0157f36e2d44aa4290572ee63886 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Feb 2008 07:48:02 -0300 Subject: Bug#28386 the general log is incomplete The problem is that the commands COM_STMT_CLOSE, COM_STMT_RESET, COM_STMT_SEND_LONG_DATA weren't being logged to the general log. The solution is to log the general log the aforementioned commands. mysql-test/t/mysql_client_test-master.opt: Also log to table. sql/sql_prepare.cc: Log COM_STMT_CLOSE, COM_STMT_RESET and COM_STMT_SEND_LONG_DATA. tests/mysql_client_test.c: Add test case for Bug#28386 --- sql/sql_prepare.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sql') diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c06c68df8d3..a027ffe9daa 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2533,6 +2533,8 @@ void mysql_stmt_reset(THD *thd, char *packet) stmt->state= Query_arena::PREPARED; + general_log_print(thd, thd->command, NullS); + my_ok(thd); DBUG_VOID_RETURN; @@ -2562,6 +2564,7 @@ void mysql_stmt_close(THD *thd, char *packet) */ DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); (void) stmt->deallocate(); + general_log_print(thd, thd->command, NullS); thd->main_da.disable_status(); @@ -2669,6 +2672,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) stmt->last_errno= ER_OUTOFMEMORY; sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0); } + + general_log_print(thd, thd->command, NullS); + DBUG_VOID_RETURN; } -- cgit v1.2.1 From 561827e2389ef8124b5d3810ce92a5e32f96913b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Feb 2008 16:03:28 +0300 Subject: Post-merge fixes for bug #33834. --- sql/sql_yacc.yy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 732dd4fe8dd..174249cf7d4 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -508,10 +508,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 172 shift/reduce conflicts. + Currently there are 177 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 172 +%expect 177 /* Comments for TOKENS. -- cgit v1.2.1 From db9b2bdc1b229e492d0e60761d7f62db1ee0f652 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 25 Feb 2008 21:18:50 +0100 Subject: Post push fix Fixed a missed case in the patch for Bug#31931. Also makes Bug#33722 a duplicate of Bug#31931. Added tests for better coverage. Replaced some legacy function calls. mysql-test/r/partition.result: Added tests for better coverage mysql-test/r/partition_datatype.result: Added tests for better coverage mysql-test/r/partition_error.result: Added tests for better coverage mysql-test/suite/parts/inc/partition_engine.inc: Bug#31931: Mix of handlers error message Bug#33722 is fixed within this patch too mysql-test/suite/parts/r/partition_engine_innodb.result: Bug#31931: Mix of handlers error message Bug#33722 is fixed within this patch too mysql-test/suite/parts/r/partition_engine_myisam.result: Bug#31931: Mix of handlers error message Bug#33722 is fixed within this patch too mysql-test/t/partition.test: Added tests for better coverage mysql-test/t/partition_datatype.test: Added tests for better coverage mysql-test/t/partition_error.test: Added tests for Bug#31931 sql/partition_info.cc: Bug#31931: Mix of handlers error message Fixed case where given info->db_type not matched thd->lex->create_info.db_type And the check for inconsistent subpartition engines-clauses. sql/sql_partition.cc: Changed ha_legacy_type to ha_resolve_storage_engine_name sql/sql_table.cc: Changed ha_legacy_type to ha_resolve_storage_engine_name --- sql/partition_info.cc | 99 ++++++++++++++++++++++++++++++++------------------- sql/sql_partition.cc | 10 +++--- sql/sql_table.cc | 7 ++-- 3 files changed, 72 insertions(+), 44 deletions(-) (limited to 'sql') diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 6816fce7818..1d21a10beaa 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -464,15 +464,15 @@ static bool check_engine_condition(partition_element *p_elem, { DBUG_ENTER("check_engine_condition"); - DBUG_PRINT("enter", ("p_eng %u t_eng %u t_eng_set %u first %u state %u", - ha_legacy_type(p_elem->engine_type), - ha_legacy_type(*engine_type), + DBUG_PRINT("enter", ("p_eng %s t_eng %s t_eng_set %u first %u state %u", + ha_resolve_storage_engine_name(p_elem->engine_type), + ha_resolve_storage_engine_name(*engine_type), table_engine_set, *first, p_elem->part_state)); if (*first && !table_engine_set) { *engine_type= p_elem->engine_type; - DBUG_PRINT("info", ("setting table_engine = %u", - ha_legacy_type(*engine_type))); + DBUG_PRINT("info", ("setting table_engine = %s", + ha_resolve_storage_engine_name(*engine_type))); } *first= FALSE; if ((table_engine_set && @@ -522,8 +522,8 @@ bool partition_info::check_engine_mix(handlerton *engine_type, bool first= TRUE; uint no_parts= partitions.elements; DBUG_ENTER("partition_info::check_engine_mix"); - DBUG_PRINT("info", ("in: engine_type = %u, table_engine_set = %u", - ha_legacy_type(engine_type), + DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u", + ha_resolve_storage_engine_name(engine_type), table_engine_set)); if (no_parts) { @@ -532,8 +532,8 @@ bool partition_info::check_engine_mix(handlerton *engine_type, do { partition_element *part_elem= part_it++; - DBUG_PRINT("info", ("part = %d engine = %d table_engine_set %u", - i, ha_legacy_type(part_elem->engine_type), + DBUG_PRINT("info", ("part = %d engine = %s table_engine_set %u", + i, ha_resolve_storage_engine_name(part_elem->engine_type), table_engine_set)); if (is_sub_partitioned() && part_elem->subpartitions.elements) @@ -544,8 +544,8 @@ bool partition_info::check_engine_mix(handlerton *engine_type, do { partition_element *sub_elem= sub_it++; - DBUG_PRINT("info", ("sub = %d engine = %u table_engie_set %u", - j, ha_legacy_type(sub_elem->engine_type), + DBUG_PRINT("info", ("sub = %d engine = %s table_engie_set %u", + j, ha_resolve_storage_engine_name(sub_elem->engine_type), table_engine_set)); if (check_engine_condition(sub_elem, table_engine_set, &engine_type, &first)) @@ -561,8 +561,8 @@ bool partition_info::check_engine_mix(handlerton *engine_type, goto error; } while (++i < no_parts); } - DBUG_PRINT("info", ("engine_type = %u", - ha_legacy_type(engine_type))); + DBUG_PRINT("info", ("engine_type = %s", + ha_resolve_storage_engine_name(engine_type))); if (!engine_type) engine_type= old_engine_type; if (engine_type->flags & HTON_NO_PARTITION) @@ -570,8 +570,8 @@ bool partition_info::check_engine_mix(handlerton *engine_type, my_error(ER_PARTITION_MERGE_ERROR, MYF(0)); DBUG_RETURN(TRUE); } - DBUG_PRINT("info", ("out: engine_type = %u", - ha_legacy_type(engine_type))); + DBUG_PRINT("info", ("out: engine_type = %s", + ha_resolve_storage_engine_name(engine_type))); DBUG_ASSERT(engine_type != partition_hton); DBUG_RETURN(FALSE); error: @@ -859,6 +859,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, DBUG_ENTER("partition_info::check_partition_info"); DBUG_ASSERT(default_engine_type != partition_hton); + DBUG_PRINT("info", ("default table_engine = %s", + ha_resolve_storage_engine_name(table_engine))); if (check_partition_function) { int err= 0; @@ -913,10 +915,16 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, the table and all partitions/subpartitions are set. So when ALTER it is already set on table level */ - if (thd->lex->create_info.used_fields & HA_CREATE_USED_ENGINE) + if (info && info->used_fields & HA_CREATE_USED_ENGINE) { table_engine_set= TRUE; - table_engine= thd->lex->create_info.db_type; + table_engine= info->db_type; + /* if partition_hton, use thd->lex->create_info */ + if (table_engine == partition_hton) + table_engine= thd->lex->create_info.db_type; + DBUG_ASSERT(table_engine != partition_hton); + DBUG_PRINT("info", ("Using table_engine = %s", + ha_resolve_storage_engine_name(table_engine))); } else { @@ -924,6 +932,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, if (thd->lex->sql_command != SQLCOM_CREATE_TABLE) { table_engine_set= TRUE; + DBUG_PRINT("info", ("No create, table_engine = %s", + ha_resolve_storage_engine_name(table_engine))); DBUG_ASSERT(table_engine && table_engine != partition_hton); } } @@ -941,11 +951,6 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, do { partition_element *part_elem= part_it++; - if (part_elem->engine_type == NULL) - { - no_parts_not_set++; - part_elem->engine_type= default_engine_type; - } #ifdef HAVE_READLINK if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) #endif @@ -960,23 +965,29 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } if (!is_sub_partitioned()) { + if (part_elem->engine_type == NULL) + { + no_parts_not_set++; + part_elem->engine_type= default_engine_type; + } if (check_table_name(part_elem->partition_name, strlen(part_elem->partition_name))) { my_error(ER_WRONG_PARTITION_NAME, MYF(0)); goto end; } - DBUG_PRINT("info", ("part = %d engine = %d", - i, ha_legacy_type(part_elem->engine_type))); + DBUG_PRINT("info", ("part = %d engine = %s", + i, ha_resolve_storage_engine_name(part_elem->engine_type))); } else { uint j= 0; uint no_subparts_not_set= 0; List_iterator sub_it(part_elem->subpartitions); + partition_element *sub_elem; do { - partition_element *sub_elem= sub_it++; + sub_elem= sub_it++; if (check_table_name(sub_elem->partition_name, strlen(sub_elem->partition_name))) { @@ -985,24 +996,41 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, } if (sub_elem->engine_type == NULL) { - sub_elem->engine_type= default_engine_type; - no_subparts_not_set++; + if (part_elem->engine_type != NULL) + sub_elem->engine_type= part_elem->engine_type; + else + { + sub_elem->engine_type= default_engine_type; + no_subparts_not_set++; + } } - DBUG_PRINT("info", ("part = %d sub = %d engine = %u", - i, j, ha_legacy_type(sub_elem->engine_type))); + DBUG_PRINT("info", ("part = %d sub = %d engine = %s", i, j, + ha_resolve_storage_engine_name(sub_elem->engine_type))); } while (++j < no_subparts); - if (prev_no_subparts_not_set == (no_subparts + 1)) + + if (prev_no_subparts_not_set == (no_subparts + 1) && + (no_subparts_not_set == 0 || no_subparts_not_set == no_subparts)) prev_no_subparts_not_set= no_subparts_not_set; + if (!table_engine_set && - prev_no_subparts_not_set == no_subparts_not_set && - no_subparts_not_set != 0 && - no_subparts_not_set != no_subparts) + prev_no_subparts_not_set != no_subparts_not_set) { DBUG_PRINT("info", ("no_subparts_not_set = %u no_subparts = %u", no_subparts_not_set, no_subparts)); my_error(ER_MIX_HANDLER_ERROR, MYF(0)); goto end; } + + if (part_elem->engine_type == NULL) + { + if (no_subparts_not_set == 0) + part_elem->engine_type= sub_elem->engine_type; + else + { + no_parts_not_set++; + part_elem->engine_type= default_engine_type; + } + } } } while (++i < no_parts); if (!table_engine_set && @@ -1021,9 +1049,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, goto end; } - if (table_engine == partition_hton) - DBUG_PRINT("info", ("Table engine set to partition_hton")); - DBUG_ASSERT(default_engine_type == table_engine); + DBUG_ASSERT(table_engine != partition_hton && + default_engine_type == table_engine); if (eng_type) *eng_type= table_engine; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a072b7fa8e4..7eab04b073a 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3819,9 +3819,9 @@ bool mysql_unpack_partition(THD *thd, DBUG_PRINT("info", ("Successful parse")); part_info= lex.part_info; - DBUG_PRINT("info", ("default engine = %d, default_db_type = %d", - ha_legacy_type(part_info->default_engine_type), - ha_legacy_type(default_db_type))); + DBUG_PRINT("info", ("default engine = %s, default_db_type = %s", + ha_resolve_storage_engine_name(part_info->default_engine_type), + ha_resolve_storage_engine_name(default_db_type))); if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE) { if (old_lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE) @@ -4041,8 +4041,8 @@ static bool check_native_partitioned(HA_CREATE_INFO *create_info,bool *ret_val, DBUG_ASSERT(engine_type && engine_type != partition_hton); } } - DBUG_PRINT("info", ("engine_type = %u, table_engine_set = %u", - ha_legacy_type(engine_type), + DBUG_PRINT("info", ("engine_type = %s, table_engine_set = %u", + ha_resolve_storage_engine_name(engine_type), table_engine_set)); if (part_info->check_engine_mix(engine_type, table_engine_set)) goto error; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 553ce9b3f1a..3114bbc77b3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3295,8 +3295,9 @@ bool mysql_create_table_no_lock(THD *thd, } } } - DBUG_PRINT("info", ("db_type = %d", - ha_legacy_type(part_info->default_engine_type))); + DBUG_PRINT("info", ("db_type = %s create_info->db_type = %s", + ha_resolve_storage_engine_name(part_info->default_engine_type), + ha_resolve_storage_engine_name(create_info->db_type))); if (part_info->check_partition_info(thd, &engine_type, file, create_info, TRUE)) goto err; @@ -3321,7 +3322,7 @@ bool mysql_create_table_no_lock(THD *thd, Assign the partition handler as the handler of the table. */ DBUG_PRINT("info", ("db_type: %d", - ha_legacy_type(create_info->db_type))); + ha_resolve_storage_engine_name(create_info->db_type))); delete file; create_info->db_type= partition_hton; if (!(file= get_ha_partition(part_info))) -- cgit v1.2.1 From 2583c281b67ae8cf470266c7438a5852a1bd2265 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Feb 2008 07:58:46 +0100 Subject: Removed compiler warning (Missed a change of printf format) sql/sql_table.cc: wrong printf type --- sql/sql_table.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3114bbc77b3..5600abfdc87 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3321,7 +3321,7 @@ bool mysql_create_table_no_lock(THD *thd, The handler assigned to the table cannot handle partitioning. Assign the partition handler as the handler of the table. */ - DBUG_PRINT("info", ("db_type: %d", + DBUG_PRINT("info", ("db_type: %s", ha_resolve_storage_engine_name(create_info->db_type))); delete file; create_info->db_type= partition_hton; -- cgit v1.2.1 From 226e6821396b35996594be3417e4c6e73c9a9c49 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Feb 2008 16:19:23 +0300 Subject: We never check the return value of mysql_frm_type for an error. Do not try to push an error into the error stack as it will be ignored anyway. --- sql/sql_view.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1cf1a22bb90..a654721de37 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1678,7 +1678,7 @@ frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt) if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0) DBUG_RETURN(FRMTYPE_ERROR); - error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_WME | MY_NABP)); + error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP)); my_close(file, MYF(MY_WME)); if (error) -- cgit v1.2.1 From bf9bb656a65c18eb15ee475e5f58412c859ef76a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Feb 2008 12:03:59 -0300 Subject: Bug#34424 query_cache_debug.test leads to valgrind warnings Bug#34678 @@debug variable's incremental mode The problem is that the per-thread debugging settings stack wasn't being deallocated before the thread termination, leaking the stack memory. The chosen solution is to push a new state if the current is set to the initial settings and pop it (free) once the thread finishes. dbug/dbug.c: Move dbug parser out of _db_set_ to a separate function and make _db_set_ push a new stack if the corrent one is set to the initial settings. dbug/user.r: Update DBUG_SET description. mysql-test/t/disabled.def: Re-enable test case which triggered the leak. mysys/my_thr_init.c: Pop a pushed state, nop if stack is empty. sql/set_var.cc: Handle incremental debug settings. mysql-test/r/variables_debug.result: Add new test case result for Bug#34678 mysql-test/t/variables_debug.test: Add new test case for Bug#34678 --- sql/set_var.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/set_var.cc b/sql/set_var.cc index 4c77cbfff82..64c79ed3bb3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -3926,10 +3926,8 @@ bool sys_var_thd_dbug::update(THD *thd, set_var *var) if (var->type == OPT_GLOBAL) DBUG_SET_INITIAL(var ? var->value->str_value.c_ptr() : ""); else - { - DBUG_POP(); - DBUG_PUSH(var ? var->value->str_value.c_ptr() : ""); - } + DBUG_SET(var ? var->value->str_value.c_ptr() : ""); + return 0; } -- cgit v1.2.1 From e265b62b52c4fc4c1fbc0724bf4538ddaaf59a35 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 26 Feb 2008 18:44:04 +0200 Subject: Reverted wrong patch, fix for Windows 32bit build. mysys/my_getsystime.c: Added extra parenthesis to apply cast to the whole result. sql/mysqld.cc: Reversed a wrong patch. This should however be made better in the future in my_getopt.h, having own define for GET_HA_ROWS. --- sql/mysqld.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 455698d4ff4..9ca2ab5db0e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -308,7 +308,11 @@ TYPELIB thread_handling_typelib= const char *first_keyword= "first", *binary_keyword= "BINARY"; const char *my_localhost= "localhost", *delayed_user= "DELAYED"; -#define GET_HA_ROWS (~ (ha_rows) 0) +#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) +#define GET_HA_ROWS GET_ULL +#else +#define GET_HA_ROWS GET_ULONG +#endif bool opt_large_files= sizeof(my_off_t) > 4; -- cgit v1.2.1 From a4b0a2cf67356c0f8f80b5291b3c1f4f8327cb97 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Feb 2008 12:42:43 +0400 Subject: Bug #25097 mysql_server_init fails silently if no errmsg.sys is present. There was no way to return an error from the client library if no MYSQL connections was established. So here i added variables to store that king of errors and made functions like mysql_error(NULL) to return these. client/mysql.cc: Bug #25097 mysql_server_init fails silently if no errmsg.sys is present. Show the error message on std_error include/sql_common.h: Bug #25097 mysql_server_init fails silently if no errmsg.sys is present. cant_connect_sqlstate constant declared libmysql/libmysql.c: Bug #25097 mysql_server_init fails silently if no errmsg.sys is present. mysql_sqlstate(NULL) returns 'unknown_sqlstate' libmysqld/lib_sql.cc: Bug #25097 mysql_server_init fails silently if no errmsg.sys is present. EMBEDDED_SERVER version of the vprint_msg_to_log() implemented sql-common/client.c: Bug #25097 mysql_server_init fails silently if no errmsg.sys is present. mysql_server_last_errno and mysql_server_last_error introduced to store errors not related to particular connections. mysql_error(NULL) and mysql_errno(NULL) now returns these mysql_server_last_error and errno respectively sql/log.cc: Bug #25097 mysql_server_init fails silently if no errmsg.sys is present. EMBEDDED_LIBRARY implementation of the vprint_msg_to_log() moved to lib_sql.cc --- sql/log.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index e66d965c613..d1da900e1b5 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2454,12 +2454,7 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, void */ -#ifdef EMBEDDED_LIBRARY -void vprint_msg_to_log(enum loglevel level __attribute__((unused)), - const char *format __attribute__((unused)), - va_list argsi __attribute__((unused))) -{} -#else /*!EMBEDDED_LIBRARY*/ +#ifndef EMBEDDED_LIBRARY static void print_buffer_to_file(enum loglevel level, const char *buffer) { time_t skr; -- cgit v1.2.1 From 83bcd5dfab83948353b2f30bfe497f0a92d31977 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Feb 2008 21:46:06 +0400 Subject: BUG#13861 - START SLAVE UNTIL may stop 1 evnt too late if log-slave-updates and circul repl After merge fixes. mysql-test/suite/rpl/t/rpl_dual_pos_advance-slave.opt: Rename: mysql-test/t/rpl_dual_pos_advance-slave.opt -> mysql-test/suite/rpl/t/rpl_dual_pos_advance-slave.opt mysql-test/include/wait_for_slave_sql_to_stop.inc: Do not change connection if it was requested by caller (needed for circular replication tests). mysql-test/suite/rpl/t/rpl_dual_pos_advance.test: Let include/wait_for_slave_sql_to_stop.inc know that we do not want to change connection to slave. sql/rpl_rli.cc: After merge fix. sql/rpl_rli.h: After merge fix. sql/slave.cc: After merge fix. --- sql/rpl_rli.cc | 9 +++++++-- sql/rpl_rli.h | 2 +- sql/slave.cc | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 03f790b934f..96e6b194916 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -955,6 +955,11 @@ err: Check if condition stated in UNTIL clause of START SLAVE is reached. SYNOPSYS Relay_log_info::is_until_satisfied() + master_beg_pos position of the beginning of to be executed event + (not log_pos member of the event that points to the + beginning of the following event) + + DESCRIPTION Checks if UNTIL condition is reached. Uses caching result of last comparison of current log file name and target log file name. So cached @@ -979,7 +984,7 @@ err: false - condition not met */ -bool Relay_log_info::is_until_satisfied() +bool Relay_log_info::is_until_satisfied(my_off_t master_beg_pos) { const char *log_name; ulonglong log_pos; @@ -990,7 +995,7 @@ bool Relay_log_info::is_until_satisfied() if (until_condition == UNTIL_MASTER_POS) { log_name= group_master_log_name; - log_pos= group_master_log_pos; + log_pos= master_beg_pos; } else { /* until_condition == UNTIL_RELAY_POS */ diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 36daffae1af..e13ea93842c 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -296,7 +296,7 @@ public: void close_temporary_tables(); /* Check if UNTIL condition is satisfied. See slave.cc for more. */ - bool is_until_satisfied(); + bool is_until_satisfied(my_off_t master_beg_pos); inline ulonglong until_pos() { return ((until_condition == UNTIL_MASTER_POS) ? group_master_log_pos : diff --git a/sql/slave.cc b/sql/slave.cc index 8bd28c903ae..b8d1fdfbb6b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1990,7 +1990,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli) This tests if the position of the beginning of the current event hits the UNTIL barrier. */ - if (rli->until_condition != RELAY_LOG_INFO::UNTIL_NONE && + if (rli->until_condition != Relay_log_info::UNTIL_NONE && rli->is_until_satisfied((rli->is_in_group() || !ev->log_pos) ? rli->group_master_log_pos : ev->log_pos - ev->data_written)) @@ -2648,7 +2648,7 @@ Slave SQL thread aborted. Can't execute init_slave query"); do not want to wait for next event in this case. */ pthread_mutex_lock(&rli->data_lock); - if (rli->until_condition != RELAY_LOG_INFO::UNTIL_NONE && + if (rli->until_condition != Relay_log_info::UNTIL_NONE && rli->is_until_satisfied(rli->group_master_log_pos)) { char buf[22]; -- cgit v1.2.1 From f28612eae272fb56f9bb07bddf31852882af7ed8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Feb 2008 13:31:19 +0200 Subject: Bug #34747: crash in debug assertion check after derived table Was a double-free of the Unique member of Item_func_group_concat. This was not causing a crash because the Unique is a descendent of Sql_alloc. Fixed to free the Unique only if it was allocated for the instance of Item_func_group_concat it was referenced from mysql-test/r/func_gconcat.result: Bug #34747: test case mysql-test/t/func_gconcat.test: Bug #34747: test case sql/item_sum.cc: Bug #34747: free the Unique only if it was allocated for this instance of Item_func_group_concat --- sql/item_sum.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 47a7073c2e7..3d6d46ab3f4 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3460,6 +3460,6 @@ void Item_func_group_concat::print(String *str) Item_func_group_concat::~Item_func_group_concat() { - if (unique_filter) + if (!original && unique_filter) delete unique_filter; } -- cgit v1.2.1 From 1af419436456808d05063810dfbeb11ac6aae9aa Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Feb 2008 16:46:52 +0400 Subject: Bug#32167 another privilege bypass with DATA/INDEX DIRECORY(3rd version for 5.1) added new function test_if_data_home_dir() which checks that path does not contain mysql data home directory. Using of 'mysql data home'/'any db name' in DATA DIRECTORY & INDEX DIRECTORY is disallowed mysql-test/r/partition.result: test result mysql-test/r/partition_not_windows.result: result fix mysql-test/r/partition_symlink.result: result fix mysql-test/r/symlink.result: test result update mysql-test/t/partition.test: test case mysql-test/t/partition_not_windows.test: test case update mysql-test/t/partition_symlink.test: test case update mysql-test/t/symlink.test: test case sql/mysql_priv.h: new variable mysql_unpacked_real_data_home sql/mysqld.cc: new variable mysql_unpacked_real_data_home sql/partition_info.cc: new check_partition_dirs() which checks data directory and index directory for partition elements sql/partition_info.h: new check_partition_dirs() which checks data directory and index directory for partition elements sql/sql_parse.cc: added new function test_if_data_home_dir() which checks that path does not contain mysql data home directory. Using of 'mysql data home'/'any db name' in DATA DIRECTORY & INDEX DIRECTORY is disallowed --- sql/mysql_priv.h | 4 +++- sql/mysqld.cc | 4 ++++ sql/partition_info.cc | 56 ++++++++++++++++++++++++++++++++++++++++++++ sql/partition_info.h | 1 + sql/sql_parse.cc | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ea552414d9a..ea5e03489ba 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -748,6 +748,7 @@ bool check_string_byte_length(LEX_STRING *str, const char *err_msg, bool check_string_char_length(LEX_STRING *str, const char *err_msg, uint max_char_length, CHARSET_INFO *cs, bool no_error); +bool test_if_data_home_dir(const char *dir); bool parse_sql(THD *thd, class Lex_input_stream *lip, @@ -1789,7 +1790,8 @@ extern time_t server_start_time, flush_status_time; #if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS extern uint mysql_data_home_len; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], - mysql_real_data_home[]; + mysql_real_data_home[], mysql_unpacked_real_data_home[]; +extern CHARSET_INFO *character_set_filesystem; #endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */ #ifdef MYSQL_SERVER extern char *opt_mysql_tmpdir, mysql_charsets_dir[], diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6dc63012f55..a62d0afee86 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -510,6 +510,7 @@ char mysql_real_data_home[FN_REFLEN], language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], *opt_init_file, *opt_tc_log_file, def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; +char mysql_unpacked_real_data_home[FN_REFLEN]; uint reg_ext_length; const key_map key_map_empty(0); key_map key_map_full(0); // Will be initialized later @@ -8147,6 +8148,9 @@ static void fix_paths(void) pos[1]= 0; } convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); + (void) fn_format(buff, mysql_real_data_home, "", "", + (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS)); + (void) unpack_dirname(mysql_unpacked_real_data_home, buff); convert_dirname(language,language,NullS); (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 3b580422da1..3130f84bd73 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1047,4 +1047,60 @@ error: mem_alloc_error(size); DBUG_RETURN(TRUE); } + + +/* + Check if path does not contain mysql data home directory + for partition elements with data directory and index directory + + SYNOPSIS + check_partition_dirs() + part_info partition_info struct + + RETURN VALUES + 0 ok + 1 error +*/ + +bool check_partition_dirs(partition_info *part_info) +{ + if (!part_info) + return 0; + + partition_element *part_elem; + List_iterator part_it(part_info->partitions); + while ((part_elem= part_it++)) + { + if (part_elem->subpartitions.elements) + { + List_iterator sub_it(part_elem->subpartitions); + partition_element *subpart_elem; + while ((subpart_elem= sub_it++)) + { + if (test_if_data_home_dir(subpart_elem->data_file_name)) + goto dd_err; + if (test_if_data_home_dir(subpart_elem->index_file_name)) + goto id_err; + } + } + else + { + if (test_if_data_home_dir(part_elem->data_file_name)) + goto dd_err; + if (test_if_data_home_dir(part_elem->index_file_name)) + goto id_err; + } + } + return 0; + +dd_err: + my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECORY"); + return 1; + +id_err: + my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECORY"); + return 1; +} + + #endif /* WITH_PARTITION_STORAGE_ENGINE */ diff --git a/sql/partition_info.h b/sql/partition_info.h index b7d13e188f3..2859aaec3be 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -290,6 +290,7 @@ private: }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); +bool check_partition_dirs(partition_info *part_info); /* Initialize the iterator to return a single partition with given part_id */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 009b81a3893..d79fbed7acb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2364,6 +2364,28 @@ mysql_execute_command(THD *thd) "INDEX DIRECTORY option ignored"); create_info.data_file_name= create_info.index_file_name= NULL; #else + + if (test_if_data_home_dir(lex->create_info.data_file_name)) + { + my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECORY"); + res= -1; + break; + } + if (test_if_data_home_dir(lex->create_info.index_file_name)) + { + my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECORY"); + res= -1; + break; + } + +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (check_partition_dirs(thd->lex->part_info)) + { + res= -1; + break; + } +#endif + /* Fix names if symlinked tables */ if (append_file_to_dir(thd, &create_info.data_file_name, create_table->table_name) || @@ -7354,6 +7376,49 @@ bool check_string_char_length(LEX_STRING *str, const char *err_msg, } +/* + Check if path does not contain mysql data home directory + SYNOPSIS + test_if_data_home_dir() + dir directory + conv_home_dir converted data home directory + home_dir_len converted data home directory length + + RETURN VALUES + 0 ok + 1 error +*/ + +bool test_if_data_home_dir(const char *dir) +{ + char path[FN_REFLEN], conv_path[FN_REFLEN]; + uint dir_len, home_dir_len= strlen(mysql_unpacked_real_data_home); + DBUG_ENTER("test_if_data_home_dir"); + + if (!dir) + DBUG_RETURN(0); + + (void) fn_format(path, dir, "", "", + (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS)); + dir_len= unpack_dirname(conv_path, dir); + + if (home_dir_len < dir_len) + { + if (lower_case_file_system) + { + if (!my_strnncoll(character_set_filesystem, + (const uchar*) conv_path, home_dir_len, + (const uchar*) mysql_unpacked_real_data_home, + home_dir_len)) + DBUG_RETURN(1); + } + else if (!memcmp(conv_path, mysql_unpacked_real_data_home, home_dir_len)) + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} + + extern int MYSQLparse(void *thd); // from sql_yacc.cc -- cgit v1.2.1 From a0eec8abbb233d9e3f278d343eaed2e70b55161e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Feb 2008 14:23:22 +0100 Subject: Bug#34749: Server crash when using NAME_CONST() with an aggregate function NAME_CONST('whatever', -1) * MAX(whatever) bombed since -1 was not seen as constant, but as FUNCTION_UNARY_MINUS(constant) while we are at the same time pretending it was a basic const item. This confused the aggregate handlers in exciting ways. We now make NAME_CONST() behave more consistently. mysql-test/r/func_misc.result: show that a combination of NAME_CONST('x', -y) and an aggregate no longer crashes the server. mysql-test/t/func_misc.test: show that a combination of NAME_CONST('x', -y) and an aggregate no longer crashes the server. sql/ha_ndbcluster_cond.cc: tell cluster about "new" function type NEG_FUNC. (this was previous identified as UNKNOWN_FUNC, so we just handle it the same way, that's all.) sql/ha_ndbcluster_cond.h: tell cluster about "new" function type NEG_FUNC. (this was previous identified as UNKNOWN_FUNC, so we just handle it the same way, that's all.) sql/item.cc: make NAME_CONST() transparent in that type() of -constant is that of constant, not that of unary minus (id est, FUNC_ITEM). sql/item.h: Move constructor to item.cc sql/item_func.h: Revert Bug#30832; we can apply the magic more narrowly (just for NAME_CONST() rather than all Item_func_neg). Introduce new function type "NEG_FUNC." --- sql/ha_ndbcluster_cond.cc | 9 ++++++--- sql/ha_ndbcluster_cond.h | 1 + sql/item.cc | 27 ++++++++++++++++++++++++++- sql/item.h | 9 +-------- sql/item_func.h | 5 +++-- 5 files changed, 37 insertions(+), 14 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc index c7b185a92f0..f5b41959b40 100644 --- a/sql/ha_ndbcluster_cond.cc +++ b/sql/ha_ndbcluster_cond.cc @@ -117,7 +117,8 @@ void ndb_serialize_cond(const Item *item, void *arg) if (item->type() == Item::FUNC_ITEM) { Item_func *func_item= (Item_func *) item; - if (func_item->functype() == Item_func::UNKNOWN_FUNC && + if ((func_item->functype() == Item_func::UNKNOWN_FUNC || + func_item->functype() == Item_func::NEG_FUNC) && func_item->const_item()) { // Skip any arguments since we will evaluate function instead @@ -369,8 +370,9 @@ void ndb_serialize_cond(const Item *item, void *arg) { Item_func *func_item= (Item_func *) item; // Check that we expect a function or functional expression here - if (context->expecting(Item::FUNC_ITEM) || - func_item->functype() == Item_func::UNKNOWN_FUNC) + if (context->expecting(Item::FUNC_ITEM) || + func_item->functype() == Item_func::UNKNOWN_FUNC || + func_item->functype() == Item_func::NEG_FUNC) context->expect_nothing(); else { @@ -584,6 +586,7 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect(Item::FUNC_ITEM); break; } + case Item_func::NEG_FUNC: case Item_func::UNKNOWN_FUNC: { DBUG_PRINT("info", ("UNKNOWN_FUNC %s", diff --git a/sql/ha_ndbcluster_cond.h b/sql/ha_ndbcluster_cond.h index 6baf6945b58..6504df8d9d4 100644 --- a/sql/ha_ndbcluster_cond.h +++ b/sql/ha_ndbcluster_cond.h @@ -228,6 +228,7 @@ public: case (Item_func::ISNOTNULL_FUNC): { return NDB_ISNOTNULL_FUNC; } case (Item_func::LIKE_FUNC): { return NDB_LIKE_FUNC; } case (Item_func::NOT_FUNC): { return NDB_NOT_FUNC; } + case (Item_func::NEG_FUNC): { return NDB_UNKNOWN_FUNC; } case (Item_func::UNKNOWN_FUNC): { return NDB_UNKNOWN_FUNC; } case (Item_func::COND_AND_FUNC): { return NDB_COND_AND_FUNC; } case (Item_func::COND_OR_FUNC): { return NDB_COND_OR_FUNC; } diff --git a/sql/item.cc b/sql/item.cc index 713e7709bcb..acd8053cbdf 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1207,6 +1207,22 @@ bool Item_name_const::is_null() return value_item->is_null(); } + +Item_name_const::Item_name_const(Item *name_arg, Item *val): + value_item(val), name_item(name_arg) +{ + if (!(valid_args= name_item->basic_const_item() && + (value_item->basic_const_item() || + ((value_item->type() == FUNC_ITEM) && + (((Item_func *) value_item)->functype() == + Item_func::NEG_FUNC) && + (((Item_func *) value_item)->key_item()->type() != + FUNC_ITEM))))) + my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST"); + Item::maybe_null= TRUE; +} + + Item::Type Item_name_const::type() const { /* @@ -1218,8 +1234,17 @@ Item::Type Item_name_const::type() const if (item->type() == FIELD_ITEM) ((Item_field *) item)->... we return NULL_ITEM in the case to avoid wrong casting. + + valid_args guarantees value_item->basic_const_item(); if type is + FUNC_ITEM, then we have a fudged item_func_neg() on our hands + and return the underlying type. */ - return valid_args ? value_item->type() : NULL_ITEM; + return valid_args ? + (((value_item->type() == FUNC_ITEM) && + (((Item_func *) value_item)->functype() == Item_func::NEG_FUNC)) ? + ((Item_func *) value_item)->key_item()->type() : + value_item->type()) : + NULL_ITEM; } diff --git a/sql/item.h b/sql/item.h index 5f511557f47..9af98e0efdb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1113,14 +1113,7 @@ class Item_name_const : public Item Item *name_item; bool valid_args; public: - Item_name_const(Item *name_arg, Item *val): - value_item(val), name_item(name_arg) - { - if (!(valid_args= name_item->basic_const_item() & - value_item->basic_const_item())) - my_error(ER_WRONG_ARGUMENTS, MYF(0), "NAME_CONST"); - Item::maybe_null= TRUE; - } + Item_name_const(Item *name_arg, Item *val); bool fix_fields(THD *, Item **); diff --git a/sql/item_func.h b/sql/item_func.h index 940586fce01..6dcf32cba07 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -54,7 +54,8 @@ public: NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, TRIG_COND_FUNC, SUSERVAR_FUNC, GUSERVAR_FUNC, COLLATE_FUNC, - EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC }; + EXTRACT_FUNC, CHAR_TYPECAST_FUNC, FUNC_SP, UDF_FUNC, + NEG_FUNC }; enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL, OPTIMIZE_EQUAL }; enum Type type() const { return FUNC_ITEM; } @@ -466,7 +467,7 @@ public: longlong int_op(); my_decimal *decimal_op(my_decimal *); const char *func_name() const { return "-"; } - virtual bool basic_const_item() const { return args[0]->basic_const_item(); } + enum Functype functype() const { return NEG_FUNC; } void fix_length_and_dec(); void fix_num_length_and_dec(); uint decimal_precision() const { return args[0]->decimal_precision(); } -- cgit v1.2.1 From 1164e2bc7a6dc18b33e401f0a9f6949c6f2ff6ea Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Feb 2008 11:34:08 -0300 Subject: Bug#33851 Passing UNSIGNED param to EXECUTE returns ERROR 1210 The problem is that passing anything other than a integer to a limit clause in a prepared statement would fail. This limitation was introduced to avoid replication problems (e.g: replicating the statement with a string argument would cause a parse failure in the slave). The solution is to convert arguments to the limit clause to a integer value and use this converted value when persisting the query to the log. mysql-test/r/limit.result: Update test case result. mysql-test/r/ps.result: Add test case result for Bug#33851 mysql-test/r/rpl_user_variables.result: Test case result for replication of prepared statement with limit clause. mysql-test/t/limit.test: Test parameters to limit clause. mysql-test/t/ps.test: Add test case for Bug#33851 mysql-test/t/rpl_user_variables.test: Test replication of a parameter which value is converted. sql/item.cc: Convert value to integer if it's a parameter to a limit clause. sql/item.h: Flag signal that item is a parameter to a limit clause. sql/item_func.cc: Const member functions, object is not mutated. sql/sql_class.h: Const member functions, object is not mutated. sql/sql_yacc.yy: Flag that item is a parameter to a limit clause. --- sql/item.cc | 11 ++++++++--- sql/item.h | 9 ++------- sql/item_func.cc | 2 +- sql/sql_class.h | 2 +- sql/sql_yacc.yy | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index ffb18054750..a6a18e27b09 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2385,7 +2385,7 @@ default_set_param_func(Item_param *param, Item_param::Item_param(unsigned pos_in_query_arg) : - strict_type(FALSE), + limit_clause_param(FALSE), state(NO_VALUE), item_result_type(STRING_RESULT), /* Don't pretend to be a literal unless value for this item is set. */ @@ -2581,8 +2581,13 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) { item_result_type= entry->type; unsigned_flag= entry->unsigned_flag; - if (strict_type && required_result_type != item_result_type) - DBUG_RETURN(1); + if (limit_clause_param) + { + my_bool unused; + set_int(entry->val_int(&unused), MY_INT64_NUM_DECIMAL_DIGITS); + item_type= Item::INT_ITEM; + DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0); + } switch (item_result_type) { case REAL_RESULT: set_double(*(double*)entry->value); diff --git a/sql/item.h b/sql/item.h index ae3e240778a..7dc9ed4ec10 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1417,8 +1417,6 @@ class Item_param :public Item char cnvbuf[MAX_FIELD_WIDTH]; String cnvstr; Item *cnvitem; - bool strict_type; - enum Item_result required_result_type; public: enum enum_item_param_state @@ -1548,11 +1546,8 @@ public: Otherwise return FALSE. */ bool eq(const Item *item, bool binary_cmp) const; - void set_strict_type(enum Item_result result_type_arg) - { - strict_type= TRUE; - required_result_type= result_type_arg; - } + /** Item is a argument to a limit clause. */ + bool limit_clause_param; }; diff --git a/sql/item_func.cc b/sql/item_func.cc index 639e069d24e..84dd3e3ebc6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3985,7 +3985,7 @@ double user_var_entry::val_real(my_bool *null_value) /* Get the value of a variable as an integer */ -longlong user_var_entry::val_int(my_bool *null_value) +longlong user_var_entry::val_int(my_bool *null_value) const { if ((*null_value= (value == 0))) return LL(0); diff --git a/sql/sql_class.h b/sql/sql_class.h index 97f2d07b1d3..4ca8947de30 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2329,7 +2329,7 @@ class user_var_entry bool unsigned_flag; double val_real(my_bool *null_value); - longlong val_int(my_bool *null_value); + longlong val_int(my_bool *null_value) const; String *val_str(my_bool *null_value, String *str, uint decimals); my_decimal *val_decimal(my_bool *null_value, my_decimal *result); DTCollation collation; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a7c1060025d..04285fea227 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6320,7 +6320,7 @@ limit_options: limit_option: param_marker { - ((Item_param *) $1)->set_strict_type(INT_RESULT); + ((Item_param *) $1)->limit_clause_param= TRUE; } | ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); } | LONG_NUM { $$= new Item_uint($1.str, $1.length); } -- cgit v1.2.1 From 33a4e7609095388099bb3048778a5b5d164d26fa Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Feb 2008 14:55:46 -0300 Subject: Bug#34655 Compile error Rename client_last_error to last_error and client_last_errno to last_errno to not break connectors which use the internal net structure for error handling. include/mysql_com.h: Rename client_last_error to last_error, client_last_errno to last_errno. include/mysql_h.ic: Rename client_last_error to last_error, client_last_errno to last_errno. libmysql/libmysql.c: Rename client_last_error to last_error, client_last_errno to last_errno. libmysql/manager.c: Rename client_last_error to last_error, client_last_errno to last_errno. libmysqld/lib_sql.cc: Rename client_last_error to last_error, client_last_errno to last_errno. libmysqld/libmysqld.c: Rename client_last_error to last_error, client_last_errno to last_errno. server-tools/instance-manager/mysql_connection.cc: Rename client_last_error to last_error, client_last_errno to last_errno. sql/log_event.cc: Rename client_last_error to last_error, client_last_errno to last_errno. sql-common/client.c: Rename client_last_error to last_error, client_last_errno to last_errno. sql/log_event_old.cc: Rename client_last_error to last_error, client_last_errno to last_errno. sql/net_serv.cc: Rename client_last_error to last_error, client_last_errno to last_errno. sql/repl_failsafe.cc: Rename client_last_error to last_error, client_last_errno to last_errno. --- sql/log_event.cc | 2 +- sql/log_event_old.cc | 22 +++++++++++----------- sql/net_serv.cc | 24 ++++++++++++------------ sql/repl_failsafe.cc | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 7c98ccaff28..cc6ae14f160 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -137,7 +137,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, " %s, Error_code: %d;", err->msg, err->code); } - rli->report(level, thd->net.client_last_errno, + rli->report(level, thd->net.last_errno, "Could not execute %s event on table %s.%s;" "%s handler error %s; " "the event's master log %s, end_log_pos %lu", diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 13f9763debe..808356a05c7 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1529,10 +1529,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) Error reporting borrowed from Query_log_event with many excessive simplifications (we don't honour --slave-skip-errors) */ - uint actual_error= thd->net.client_last_errno; + uint actual_error= thd->net.last_errno; rli->report(ERROR_LEVEL, actual_error, "Error '%s' in %s event: when locking tables", - (actual_error ? thd->net.client_last_error : + (actual_error ? thd->net.last_error : "unexpected success or fatal error"), get_type_str()); thd->is_fatal_error= 1; @@ -1573,10 +1573,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) Error reporting borrowed from Query_log_event with many excessive simplifications (we don't honour --slave-skip-errors) */ - uint actual_error= thd->net.client_last_errno; + uint actual_error= thd->net.last_errno; rli->report(ERROR_LEVEL, actual_error, "Error '%s' on reopening tables", - (actual_error ? thd->net.client_last_error : + (actual_error ? thd->net.last_error : "unexpected success or fatal error")); thd->is_slave_error= 1; } @@ -1729,10 +1729,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) break; default: - rli->report(ERROR_LEVEL, thd->net.client_last_errno, + rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: row application failed. %s", get_type_str(), - thd->net.client_last_error ? thd->net.client_last_error : ""); + thd->net.last_error ? thd->net.last_error : ""); thd->is_slave_error= 1; break; } @@ -1779,12 +1779,12 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) if (error) { /* error has occured during the transaction */ - rli->report(ERROR_LEVEL, thd->net.client_last_errno, + rli->report(ERROR_LEVEL, thd->net.last_errno, "Error in %s event: error during transaction execution " "on table %s.%s. %s", get_type_str(), table->s->db.str, table->s->table_name.str, - thd->net.client_last_error ? thd->net.client_last_error : ""); + thd->net.last_error ? thd->net.last_error : ""); /* If one day we honour --skip-slave-errors in row-based replication, and @@ -1913,7 +1913,7 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli) example "no key found" (as this is allowed). This is a safety measure; apparently those errors (e.g. when executing a Delete_rows_log_event_old of a non-existing row, like in - rpl_row_mystery22.test, thd->net.client_last_error = "Can't + rpl_row_mystery22.test, thd->net.last_error = "Can't find record in 't1'" and last_errno=1032) do not become visible. We still prefer to wipe them out. */ @@ -2647,8 +2647,8 @@ Write_rows_log_event_old::do_exec_row(const Relay_log_info *const rli) DBUG_ASSERT(m_table != NULL); int error= write_row(rli, TRUE /* overwrite */); - if (error && !thd->net.client_last_errno) - thd->net.client_last_errno= error; + if (error && !thd->net.last_errno) + thd->net.last_errno= error; return error; } diff --git a/sql/net_serv.cc b/sql/net_serv.cc index ad653a2267d..1098e8e6832 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -127,10 +127,10 @@ my_bool my_net_init(NET *net, Vio* vio) net->error=0; net->return_errno=0; net->return_status=0; net->pkt_nr=net->compress_pkt_nr=0; net->write_pos=net->read_pos = net->buff; - net->client_last_error[0]=0; + net->last_error[0]=0; net->compress=0; net->reading_or_writing=0; net->where_b = net->remain_in_buf=0; - net->client_last_errno=0; + net->last_errno=0; #ifdef USE_QUERY_CACHE query_cache_init_query(net); #else @@ -177,7 +177,7 @@ my_bool net_realloc(NET *net, size_t length) net->max_packet_size)); /* @todo: 1 and 2 codes are identical. */ net->error= 1; - net->client_last_errno= ER_NET_PACKET_TOO_LARGE; + net->last_errno= ER_NET_PACKET_TOO_LARGE; #ifdef MYSQL_SERVER my_error(ER_NET_PACKET_TOO_LARGE, MYF(0)); #endif @@ -194,7 +194,7 @@ my_bool net_realloc(NET *net, size_t length) { /* @todo: 1 and 2 codes are identical. */ net->error= 1; - net->client_last_errno= ER_OUT_OF_RESOURCES; + net->last_errno= ER_OUT_OF_RESOURCES; /* In the server the error is reported by MY_WME flag. */ DBUG_RETURN(1); } @@ -579,7 +579,7 @@ net_real_write(NET *net,const uchar *packet, size_t len) COMP_HEADER_SIZE, MYF(MY_WME)))) { net->error= 2; - net->client_last_errno= ER_OUT_OF_RESOURCES; + net->last_errno= ER_OUT_OF_RESOURCES; /* In the server, the error is reported by MY_WME flag. */ net->reading_or_writing= 0; DBUG_RETURN(1); @@ -632,7 +632,7 @@ net_real_write(NET *net,const uchar *packet, size_t len) my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ net->error= 2; /* Close socket */ - net->client_last_errno= ER_NET_PACKET_TOO_LARGE; + net->last_errno= ER_NET_PACKET_TOO_LARGE; #ifdef MYSQL_SERVER my_error(ER_NET_PACKET_TOO_LARGE, MYF(0)); #endif @@ -662,10 +662,10 @@ net_real_write(NET *net,const uchar *packet, size_t len) } #endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */ net->error= 2; /* Close socket */ - net->client_last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED : + net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED : ER_NET_ERROR_ON_WRITE); #ifdef MYSQL_SERVER - my_error(net->client_last_errno, MYF(0)); + my_error(net->last_errno, MYF(0)); #endif /* MYSQL_SERVER */ break; } @@ -844,7 +844,7 @@ my_real_read(NET *net, size_t *complen) #endif /* EXTRA_DEBUG */ len= packet_error; net->error= 2; /* Close socket */ - net->client_last_errno= ER_NET_FCNTL_ERROR; + net->last_errno= ER_NET_FCNTL_ERROR; #ifdef MYSQL_SERVER my_error(ER_NET_FCNTL_ERROR, MYF(0)); #endif @@ -876,11 +876,11 @@ my_real_read(NET *net, size_t *complen) remain, vio_errno(net->vio), (long) length)); len= packet_error; net->error= 2; /* Close socket */ - net->client_last_errno= (vio_was_interrupted(net->vio) ? + net->last_errno= (vio_was_interrupted(net->vio) ? ER_NET_READ_INTERRUPTED : ER_NET_READ_ERROR); #ifdef MYSQL_SERVER - my_error(net->client_last_errno, MYF(0)); + my_error(net->last_errno, MYF(0)); #endif goto end; } @@ -1100,7 +1100,7 @@ my_net_read(NET *net) &complen)) { net->error= 2; /* caller will close socket */ - net->client_last_errno= ER_NET_UNCOMPRESS_ERROR; + net->last_errno= ER_NET_UNCOMPRESS_ERROR; #ifdef MYSQL_SERVER my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0)); #endif diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index f8f01d2cad1..a8953217ce1 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -699,7 +699,7 @@ int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi) if (!mi->host || !*mi->host) /* empty host */ { - strmov(mysql->net.client_last_error, "Master is not configured"); + strmov(mysql->net.last_error, "Master is not configured"); DBUG_RETURN(1); } mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout); -- cgit v1.2.1 From d40ca16156641481abd45f93e31233044f4b9df6 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Feb 2008 22:53:31 +0400 Subject: Fixed bug #34620: item_row.cc:50: Item_row::illegal_method_call(const char*): Assertion `0' failed If ROW item is a part of an expression that also has aggregate function calls (COUNT/SUM/AVG...), a "splitting" with an Item::split_sum_func2 function is applied to that ROW item. Current implementation of Item::split_sum_func2 replaces this Item_row with a newly created Item_aggregate_ref reference to it. Then the row cache tries to work with the Item_aggregate_ref object as with the Item_row object: row cache calls row-emulation methods such as cols and element_index. Item_aggregate_ref (like it's parent Item_ref) inherits dummy implementations of those methods from the hierarchy root Item, and call to them leads to failed assertions and wrong data output. Row-emulation virtual functions (cols, element_index, addr, check_cols, null_inside and bring_value) of Item_ref have been overloaded to forward calls to an underlying item reference. mysql-test/r/row.result: Added test case for bug #34620. mysql-test/t/row.test: Added test case for bug #34620. sql/item.h: Fixed bug #34620. Row-emulation virtual functions (cols, element_index, addr, check_cols, null_inside and bring_value) of Item_ref have been overloaded to forward calls to an underlying item reference. --- sql/item.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index f87499f23e3..c8b8e48b0ed 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1990,6 +1990,35 @@ public: Item_field *filed_for_view_update() { return (*ref)->filed_for_view_update(); } virtual Ref_Type ref_type() { return REF; } + + // Row emulation: forwarding of ROW-related calls to ref + uint cols() + { + return ref && result_type() == ROW_RESULT ? (*ref)->cols() : 1; + } + Item* element_index(uint i) + { + return ref && result_type() == ROW_RESULT ? (*ref)->element_index(i) : this; + } + Item** addr(uint i) + { + return ref && result_type() == ROW_RESULT ? (*ref)->addr(i) : 0; + } + bool check_cols(uint c) + { + return ref && result_type() == ROW_RESULT ? (*ref)->check_cols(c) + : Item::check_cols(c); + } + bool null_inside() + { + return ref && result_type() == ROW_RESULT ? (*ref)->null_inside() : 0; + } + void bring_value() + { + if (ref && result_type() == ROW_RESULT) + (*ref)->bring_value(); + } + }; -- cgit v1.2.1 From 8b77945615ed06a9ae0c1861943b73f46f3cbb71 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 28 Feb 2008 20:22:11 -0300 Subject: Post-merge fix for Bug 33851. The initialization order of members must match the order which they were declared in the class definition. sql/item.cc: Fix initialization order, parameter was the last one declared. --- sql/item.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index a6a18e27b09..a9e99c65580 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2385,14 +2385,14 @@ default_set_param_func(Item_param *param, Item_param::Item_param(unsigned pos_in_query_arg) : - limit_clause_param(FALSE), state(NO_VALUE), item_result_type(STRING_RESULT), /* Don't pretend to be a literal unless value for this item is set. */ item_type(PARAM_ITEM), param_type(MYSQL_TYPE_VARCHAR), pos_in_query(pos_in_query_arg), - set_param_func(default_set_param_func) + set_param_func(default_set_param_func), + limit_clause_param(FALSE) { name= (char*) "?"; /* -- cgit v1.2.1 From de534f2bc1712cbae314599ff4a230fb2fcecc39 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Feb 2008 12:21:19 +0300 Subject: Fix for Bug#31947: Declare with a reserved word succeeded. READ_ONLY token was accidentally placed into wrong place ('ident' rule). The proper place is in the 'keyword_sp' rule. The manual should be re-generated after this patch, because the manual depends on the 'keyword_sp' rule. sql/sql_yacc.yy: Move READ_ONLY token to the 'keyword_sp' rule. --- sql/sql_yacc.yy | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 108cf5e9ab3..1bd90e74f47 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -10312,12 +10312,6 @@ TEXT_STRING_filesystem: ident: IDENT_sys { $$=$1; } - | READ_ONLY_SYM - { - THD *thd= YYTHD; - $$.str= thd->strmake("read_only",9); - $$.length= 9; - } | keyword { THD *thd= YYTHD; @@ -10622,6 +10616,7 @@ keyword_sp: | QUARTER_SYM {} | QUERY_SYM {} | QUICK {} + | READ_ONLY_SYM {} | REBUILD_SYM {} | RECOVER_SYM {} | REDO_BUFFER_SIZE_SYM {} -- cgit v1.2.1 From ab6042590186ad14bbd73a64f5d1f3f77223bdb3 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Feb 2008 13:55:00 +0400 Subject: Bug#32167 another privilege bypass with DATA/INDEX DIRECORY(ver 4.1,5.0) added new function test_if_data_home_dir() which checks that path does not contain mysql data home directory. Using of mysql data home directory in DATA DIRECTORY & INDEX DIRECTORY is disallowed. mysql-test/r/symlink.result: test result mysql-test/t/symlink.test: test case sql/mysql_priv.h: new variable mysql_unpacked_real_data_home sql/mysqld.cc: new variable mysql_unpacked_real_data_home sql/sql_parse.cc: added new function test_if_data_home_dir() which checks that path does not contain mysql data home directory. Using of mysql data home directory in DATA DIRECTORY & INDEX DIRECTORY is disallowed. --- sql/mysql_priv.h | 1 + sql/mysqld.cc | 4 ++++ sql/sql_parse.cc | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b6170ba35f9..4b0031d1f2a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -890,6 +890,7 @@ void my_dbopt_free(void); extern time_t start_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[], + mysql_unpacked_real_data_home[], def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) extern MY_TMPDIR mysql_tmpdir_list; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 62105e0093a..8111df7ad4d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -390,6 +390,7 @@ const char *opt_date_time_formats[3]; char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; char *language_ptr, *default_collation_name, *default_character_set_name; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; +char mysql_unpacked_real_data_home[FN_REFLEN]; struct passwd *user_info; char server_version[SERVER_VERSION_LENGTH]; char *mysqld_unix_port, *opt_mysql_tmpdir; @@ -6896,6 +6897,9 @@ static void fix_paths(void) pos[1]= 0; } convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); + (void) fn_format(buff, mysql_real_data_home, "", "", + (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS)); + (void) unpack_dirname(mysql_unpacked_real_data_home, buff); convert_dirname(language,language,NullS); (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 24f9ef30569..4bbd425d80b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -65,7 +65,8 @@ static bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db, - const char* alias); + const char* alias); +static bool test_if_data_home_dir(const char *dir); const char *any_db="*any*"; // Special symbol for check_access @@ -2531,6 +2532,20 @@ mysql_execute_command(THD *thd) "INDEX DIRECTORY option ignored"); create_info.data_file_name= create_info.index_file_name= NULL; #else + + if (test_if_data_home_dir(lex->create_info.data_file_name)) + { + my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECORY"); + res= -1; + break; + } + if (test_if_data_home_dir(lex->create_info.index_file_name)) + { + my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECORY"); + res= -1; + break; + } + /* Fix names if symlinked tables */ if (append_file_to_dir(thd, &create_info.data_file_name, create_table->real_name) || @@ -5920,3 +5935,47 @@ Item *negate_expression(THD *thd, Item *expr) return negated; return new Item_func_not(expr); } + + +/* + Check if path does not contain mysql data home directory + + SYNOPSIS + test_if_data_home_dir() + dir directory + conv_home_dir converted data home directory + home_dir_len converted data home directory length + + RETURN VALUES + 0 ok + 1 error +*/ + +static bool test_if_data_home_dir(const char *dir) +{ + char path[FN_REFLEN], conv_path[FN_REFLEN]; + uint dir_len, home_dir_len= strlen(mysql_unpacked_real_data_home); + DBUG_ENTER("test_if_data_home_dir"); + + if (!dir) + DBUG_RETURN(0); + + (void) fn_format(path, dir, "", "", + (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS)); + dir_len= unpack_dirname(conv_path, dir); + + if (home_dir_len <= dir_len) + { + if (lower_case_file_system) + { + if (!my_strnncoll(default_charset_info, (const uchar*) conv_path, + home_dir_len, + (const uchar*) mysql_unpacked_real_data_home, + home_dir_len)) + DBUG_RETURN(1); + } + else if (!memcmp(conv_path, mysql_unpacked_real_data_home, home_dir_len)) + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} -- cgit v1.2.1 From fa9e35b48d1322b80cf3a8f6ffd4b2fde7f46c0c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Feb 2008 15:04:00 +0400 Subject: after merge fix --- sql/mysqld.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c03c9c34571..4d688d795f7 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -467,19 +467,13 @@ char log_error_file[FN_REFLEN], glob_hostname[FN_REFLEN]; char mysql_real_data_home[FN_REFLEN], language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], *opt_init_file, *opt_tc_log_file, + mysql_unpacked_real_data_home[FN_REFLEN], def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; - +char *mysql_data_home= mysql_real_data_home; const key_map key_map_empty(0); key_map key_map_full(0); // Will be initialized later const char *opt_date_time_formats[3]; - - -char compiled_default_collation_name[]= MYSQL_DEFAULT_COLLATION_NAME; -char *language_ptr, *default_collation_name, *default_character_set_name; -char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; -char mysql_unpacked_real_data_home[FN_REFLEN]; -struct passwd *user_info; char server_version[SERVER_VERSION_LENGTH]; char *mysqld_unix_port, *opt_mysql_tmpdir; const char **errmesg; /* Error messages */ -- cgit v1.2.1 From d276cd905935d9b620cd2f4260b0920a38c35348 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Feb 2008 15:11:11 +0400 Subject: Fixed bug #34830: mixed table and field names in Item_ref and Item_direct_ref constructor calls. Order of ref->field_name and ref->table_name arguments is of Item_ref and Item_direct_ref in the fix_inner_refs function is inverted. sql/sql_select.cc: Fixed bug #34830: mixed table and field names in Item_ref and Item_direct_ref constructor calls. Order of ref->field_name and ref->table_name arguments is of Item_ref and Item_direct_ref in the fix_inner_refs function is inverted. See definitions: Item_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, const char *field_name_arg, bool alias_name_used_arg= FALSE) and Item_direct_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, const char *field_name_arg, bool alias_name_used_arg= FALSE) --- sql/sql_select.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 38da4e26f5a..926b389f59f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -360,10 +360,10 @@ fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, } } new_ref= direct_ref ? - new Item_direct_ref(ref->context, item_ref, ref->field_name, - ref->table_name, ref->alias_name_used) : - new Item_ref(ref->context, item_ref, ref->field_name, - ref->table_name, ref->alias_name_used); + new Item_direct_ref(ref->context, item_ref, ref->table_name, + ref->field_name, ref->alias_name_used) : + new Item_ref(ref->context, item_ref, ref->table_name, + ref->field_name, ref->alias_name_used); if (!new_ref) return TRUE; ref->outer_ref= new_ref; -- cgit v1.2.1 From 4e7c4ab929b85eaaa91a8c678872c44fc421c396 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Feb 2008 17:50:01 +0400 Subject: wrong merge fix --- sql/sql_parse.cc | 2 -- 1 file changed, 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9e2a4bb77ac..fd16435ff9c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -76,8 +76,6 @@ static void remove_escape(char *name); static bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); static bool check_show_create_table_access(THD *thd, TABLE_LIST *table); -static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db, - const char* alias); static bool test_if_data_home_dir(const char *dir); const char *any_db="*any*"; // Special symbol for check_access -- cgit v1.2.1 From 1ed34fed3390e10ff67981c4470f46c6ce1e2a6e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 29 Feb 2008 17:56:50 +0400 Subject: Bug#23924 general_log truncates queries with character set introducers. Problem: logging of utf8-incompatible binary strings didn't work Fix: hex-encoding of incompatible sequences. mysql-test/r/log_tables.result: Adding test mysql-test/t/log_tables.test: Adding test sql/field.cc: Copying with hex escaping sql/field.h: New field flag sql/log.cc: Marking the column "general_log.argument" as hex-escaping field. sql/sql_string.cc: New function to copy strings with hex-encoding of incompatible characters. sql/sql_string.h: Prototype for the new function --- sql/field.cc | 11 ++++++++++ sql/field.h | 2 ++ sql/log.cc | 1 + sql/sql_string.cc | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ sql/sql_string.h | 3 +++ 5 files changed, 79 insertions(+) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 88fac96df89..fb14b4d5c77 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7644,6 +7644,17 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) if (value.alloc(new_length)) goto oom_error; + + if (f_is_hex_escape(flags)) + { + copy_length= my_copy_with_hex_escaping(field_charset, + (char*) value.ptr(), new_length, + from, length); + Field_blob::store_length(copy_length); + tmp= value.ptr(); + bmove(ptr + packlength, (uchar*) &tmp, sizeof(char*)); + return 0; + } /* "length" is OK as "nchars" argument to well_formed_copy_nchars as this is never used to limit the length of the data. The cut of long data diff --git a/sql/field.h b/sql/field.h index 38a0b1d5bbd..2e8a27e579a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -2069,6 +2069,7 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions); #define FIELDFLAG_NO_DEFAULT 16384 /* sql */ #define FIELDFLAG_SUM ((uint) 32768)// predit: +#fieldflag #define FIELDFLAG_MAYBE_NULL ((uint) 32768)// sql +#define FIELDFLAG_HEX_ESCAPE ((uint) 0x10000) #define FIELDFLAG_PACK_SHIFT 3 #define FIELDFLAG_DEC_SHIFT 8 #define FIELDFLAG_MAX_DEC 31 @@ -2094,3 +2095,4 @@ int set_field_to_null_with_conversions(Field *field, bool no_conversions); #define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL) #define f_no_default(x) (x & FIELDFLAG_NO_DEFAULT) #define f_bit_as_char(x) ((x) & FIELDFLAG_TREAT_BIT_AS_CHAR) +#define f_is_hex_escape(x) ((x) & FIELDFLAG_HEX_ESCAPE) diff --git a/sql/log.cc b/sql/log.cc index 9b5b2ae5a6c..328aaa45f3f 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -418,6 +418,7 @@ bool Log_to_csv_event_handler:: A positive return value in store() means truncation. Still logging a message in the log in this case. */ + table->field[5]->flags|= FIELDFLAG_HEX_ESCAPE; if (table->field[5]->store(sql_text, sql_text_len, client_cs) < 0) goto err; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 7fa3786c382..34b310931d6 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -840,6 +840,68 @@ outp: } +/** + Copy string with HEX-encoding of "bad" characters. + + @details This functions copies the string pointed by "src" + to the string pointed by "dst". Not more than "srclen" bytes + are read from "src". Any sequences of bytes representing + a not-well-formed substring (according to cs) are hex-encoded, + and all well-formed substrings (according to cs) are copied as is. + Not more than "dstlen" bytes are written to "dst". The number + of bytes written to "dst" is returned. + + @param cs character set pointer of the destination string + @param[out] dst destination string + @param dstlen size of dst + @param src source string + @param srclen length of src + + @retval result length +*/ + +size_t +my_copy_with_hex_escaping(CHARSET_INFO *cs, + char *dst, size_t dstlen, + const char *src, size_t srclen) +{ + const char *srcend= src + srclen; + char *dst0= dst; + + for ( ; src < srcend ; ) + { + size_t chlen; + if ((chlen= my_ismbchar(cs, src, srcend))) + { + if (dstlen < chlen) + break; /* purecov: inspected */ + memcpy(dst, src, chlen); + src+= chlen; + dst+= chlen; + dstlen-= chlen; + } + else if (*src & 0x80) + { + if (dstlen < 4) + break; /* purecov: inspected */ + *dst++= '\\'; + *dst++= 'x'; + *dst++= _dig_vec_upper[((unsigned char) *src) >> 4]; + *dst++= _dig_vec_upper[((unsigned char) *src) & 15]; + src++; + dstlen-= 4; + } + else + { + if (dstlen < 1) + break; /* purecov: inspected */ + *dst++= *src++; + dstlen--; + } + } + return dst - dst0; +} + /* copy a string, with optional character set conversion, diff --git a/sql/sql_string.h b/sql/sql_string.h index 128ed749b5f..b4d76a1779a 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -37,6 +37,9 @@ uint32 well_formed_copy_nchars(CHARSET_INFO *to_cs, const char **well_formed_error_pos, const char **cannot_convert_error_pos, const char **from_end_pos); +size_t my_copy_with_hex_escaping(CHARSET_INFO *cs, + char *dst, size_t dstlen, + const char *src, size_t srclen); class String { -- cgit v1.2.1 From cd9f2d1c285d1bc5f5115e517da806ccb2bd1d28 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 3 Mar 2008 20:35:44 +0300 Subject: BUG#34945: "ref_or_null queries that are null_rejecting and have a null value crash mysql" - Apply Eric Bergen's patch: in join_read_always_key(), move ha_index_init() call to before the late NULLs filtering code. - Backport function comments from 6.0. mysql-test/r/null_key.result: BUG#34945: "ref_or_null queries that are null_rejecting and have a null value crash mysql" - Testcase mysql-test/t/null_key.test: BUG#34945: "ref_or_null queries that are null_rejecting and have a null value crash mysql" - Testcase sql/sql_select.cc: BUG#34945: "ref_or_null queries that are null_rejecting and have a null value crash mysql" - Apply Eric Bergen's patch: in join_read_always_key(), move ha_index_init() call to before the late NULLs filtering code. - Backport function comments from 6.0 --- sql/sql_select.cc | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 926b389f59f..6392f7c4299 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11173,19 +11173,42 @@ join_read_key(JOIN_TAB *tab) } +/* + ref access method implementation: "read_first" function + + SYNOPSIS + join_read_always_key() + tab JOIN_TAB of the accessed table + + DESCRIPTION + This is "read_fist" function for the "ref" access method. + + The functon must leave the index initialized when it returns. + ref_or_null access implementation depends on that. + + RETURN + 0 - Ok + -1 - Row not found + 1 - Error +*/ + static int join_read_always_key(JOIN_TAB *tab) { int error; TABLE *table= tab->table; + /* Initialize the index first */ + if (!table->file->inited) + table->file->ha_index_init(tab->ref.key); + + /* Perform "Late NULLs Filtering" (see internals manual for explanations) */ for (uint i= 0 ; i < tab->ref.key_parts ; i++) { if ((tab->ref.null_rejecting & 1 << i) && tab->ref.items[i]->is_null()) return -1; - } - if (!table->file->inited) - table->file->ha_index_init(tab->ref.key); + } + if (cp_buffer_from_ref(tab->join->thd, &tab->ref)) return -1; if ((error=table->file->index_read(table->record[0], -- cgit v1.2.1 From 657ef27076d5536f7c17e0643ea5e6829678b6df Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 5 Mar 2008 12:25:55 +0200 Subject: Bug #28780 report_host is not available through SELECT @@report_host There was no way to see if report-{host,port,user,password} were set up. Fixed with introducing new global variables. The variables are made read-only because of a possible need to change them most probably require the slave server restart. Todo: transform the startup options to be CHANGE master parameters - i.e to deprecate `report-' options, and to change the new vars to be updatable at time of CHANGE master executes with new values. sql/set_var.cc: Adding associations of the server init arguments with the new global read-only variables. mysql-test/suite/rpl/r/rpl_report.result: new results file mysql-test/suite/rpl/t/rpl_report-slave.opt: options initialize the new global variables. mysql-test/suite/rpl/t/rpl_report.test: The new test to check SHOW-ability and SELECT-ablity for the report global vars. --- sql/set_var.cc | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sql') diff --git a/sql/set_var.cc b/sql/set_var.cc index 410608f154f..d44bfe4ae47 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -648,6 +648,19 @@ sys_var_thd_time_zone sys_time_zone(&vars, "time_zone"); /* Global read-only variable containing hostname */ static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname); +static sys_var_const_str_ptr sys_repl_report_host(&vars, "report_host", &report_host); +static sys_var_const_str_ptr sys_repl_report_user(&vars, "report_user", &report_user); +static sys_var_const_str_ptr sys_repl_report_password(&vars, "report_password", &report_password); + +static uchar *slave_get_report_port(THD *thd) +{ + thd->sys_var_tmp.long_value= report_port; + return (uchar*) &thd->sys_var_tmp.long_value; +} + +static sys_var_readonly sys_repl_report_port(&vars, "report_port", OPT_GLOBAL, SHOW_INT, slave_get_report_port); + + sys_var_thd_bool sys_keep_files_on_create(&vars, "keep_files_on_create", &SV::keep_files_on_create); -- cgit v1.2.1 From 0c1dd98ec883323fc79fd5ac558ed3d278a68c31 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 5 Mar 2008 16:02:33 +0300 Subject: Fix for bug #34889: mysql_client_test::test_mysql_insert_id test fails sporadically Under some circumstances, the mysql_insert_id() value after SELECT ... INSERT could return a wrong value. This could happen when the last SELECT ... INSERT did not involve an AUTO_INCREMENT column, but the value of mysql_insert_id() was changed by some previous statements. Fixed by checking the value of thd->insert_id_used in select_insert::send_eof() and returning 0 for mysql_insert_id() if it is not set. sql/sql_insert.cc: Do not return thd->last_insert_id unconditionally in select_insert::send_eof(). First check if thd->insert_id_used is non-zero, and return 0 otherwise. tests/mysql_client_test.c: Added a test case for bug #34889. --- sql/sql_insert.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 14292f1cd9d..1d324872409 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3006,7 +3006,8 @@ bool select_insert::send_eof() ((thd->client_capabilities & CLIENT_FOUND_ROWS) ? info.touched : info.updated); id= autoinc_value_of_first_inserted_row > 0 ? - autoinc_value_of_first_inserted_row : thd->last_insert_id; + autoinc_value_of_first_inserted_row : thd->insert_id_used ? + thd->last_insert_id : 0; ::send_ok(thd, (ulong) thd->row_count_func, id, buff); DBUG_RETURN(0); } -- cgit v1.2.1 From 2b7dda9e9d06f2ab6036da39250a765926c9c437 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 5 Mar 2008 09:33:32 -0500 Subject: Bug#33464: DROP FUNCTION caused a crash The cause of the crash is an assertion failure that we do not emit an error message (grant not found) and then return "ok". The assertion is valid, and we were ignoring the buggy behavior prior to the "Diagnostics" result-verification. Use an error handler to mutate innocuous missing-grant errors, when removing routines, into warnings. mysql-test/r/drop.result: Show that the crash disappears. Also prepare for the larger bug to be fixed with only minor changes to this test. mysql-test/t/drop.test: Show that the crash disappears. Also prepare for the larger bug to be fixed with only minor changes to this test. sql/sql_acl.cc: Disable a segment of code that makes a faulty assumption about the existence of a routine's defining user, until that assumption becomes true. Push a new handler onto the error-handler stack, so that when removing a routine, a missing ACL grant is now a warning instead of an error. If any unexpected error is raised then tell the caller. --- sql/sql_acl.cc | 105 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 22 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0d563ab9051..b9d72998933 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2779,6 +2779,10 @@ table_error: } +/** + @retval 0 success + @retval -1 error +*/ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, TABLE *table, const LEX_USER &combo, const char *db, const char *routine_name, @@ -2800,14 +2804,11 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, thd->security_ctx->host_or_ip, NullS); /* - The following should always succeed as new users are created before - this function is called! + New users are created before this function is called. + + There may be some cases where a routine's definer is removed but the + routine remains. */ - if (!find_acl_user(combo.host.str, combo.user.str, FALSE)) - { - my_error(ER_PASSWORD_NO_MATCH,MYF(0)); - DBUG_RETURN(-1); - } table->use_all_columns(); restore_record(table, s->default_values); // Get empty record @@ -3321,7 +3322,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } if (replace_routine_table(thd, grant_name, tables[1].table, *Str, - db_name, table_name, is_proc, rights, revoke_grant)) + db_name, table_name, is_proc, rights, + revoke_grant) != 0) { result= TRUE; continue; @@ -5949,11 +5951,11 @@ bool mysql_revoke_all(THD *thd, List &list) if (!strcmp(lex_user->user.str,user) && !strcmp(lex_user->host.str, host)) { - if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user, + if (replace_routine_table(thd,grant_proc,tables[4].table,*lex_user, grant_proc->db, grant_proc->tname, is_proc, - ~(ulong)0, 1)) + ~(ulong)0, 1) == 0) { revoked= 1; continue; @@ -5979,17 +5981,73 @@ bool mysql_revoke_all(THD *thd, List &list) } -/* - Revoke privileges for all users on a stored procedure - SYNOPSIS - sp_revoke_privileges() + +/** + If the defining user for a routine does not exist, then the ACL lookup + code should raise two errors which we should intercept. We convert the more + descriptive error into a warning, and consume the other. + + If any other errors are raised, then we set a flag that should indicate + that there was some failure we should complain at a higher level. +*/ +class Silence_routine_definer_errors : public Internal_error_handler +{ +public: + Silence_routine_definer_errors() + : is_grave(FALSE) + {} + + virtual ~Silence_routine_definer_errors() + {} + + virtual bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd); + + bool has_errors() { return is_grave; } + +private: + bool is_grave; +}; + +bool +Silence_routine_definer_errors::handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) +{ + if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) + { + switch (sql_errno) + { + case ER_NONEXISTING_PROC_GRANT: + /* Convert the error into a warning. */ + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, message); + return TRUE; + default: + is_grave= TRUE; + } + } + + return FALSE; +} + + +/** + Revoke privileges for all users on a stored procedure. Use an error handler + that converts errors about missing grants into warnings. + + @param thd The current thread. + @param db DB of the stored procedure + @param name Name of the stored procedure - RETURN + @retval 0 OK. + @retval < 0 Error. Error message not yet sent. */ @@ -6000,11 +6058,15 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, int result; TABLE_LIST tables[GRANT_TABLES]; HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash; + Silence_routine_definer_errors error_handler; DBUG_ENTER("sp_revoke_privileges"); if ((result= open_grant_tables(thd, tables))) DBUG_RETURN(result != 1); + /* Be sure to pop this before exiting this scope! */ + thd->push_internal_handler(&error_handler); + rw_wrlock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); @@ -6031,14 +6093,14 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, grant_proc->host.hostname : (char*)""; lex_user.host.length= grant_proc->host.hostname ? strlen(grant_proc->host.hostname) : 0; - if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user, - grant_proc->db, grant_proc->tname, - is_proc, ~(ulong)0, 1)) + + if (replace_routine_table(thd,grant_proc,tables[4].table,lex_user, + grant_proc->db, grant_proc->tname, + is_proc, ~(ulong)0, 1) == 0) { revoked= 1; continue; } - result= -1; // Something went wrong } counter++; } @@ -6048,10 +6110,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, rw_unlock(&LOCK_grant); close_thread_tables(thd); - if (result) - my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0)); + thd->pop_internal_handler(); - DBUG_RETURN(result); + DBUG_RETURN(error_handler.has_errors()); } -- cgit v1.2.1 From b6595704efebe3678b5696996bd84d35e3511256 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 5 Mar 2008 11:23:58 -0500 Subject: Bug#34726: open_tables() crashes server if running with --debug The DBUG code emits the current value of the proc_info member of THD, which may be set to NULL. It was wrong to dereference that value with the format string %s without verifying that it was valid. Now, insert an inline test that substitutes the string "(null)" for NULL pointers. sql/sql_class.cc: Dereferencing a NULL is illegal (though not fatal for %s on some platforms), and we have no assurance that the caller didn't call us with a valid string. --- sql/sql_class.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 75376c53f68..ead7439bc81 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -253,7 +253,8 @@ const char *set_thd_proc_info(THD *thd, const char *info, const unsigned int calling_line) { const char *old_info= thd->proc_info; - DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line, info)); + DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line, + (info != NULL) ? info : "(null)")); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.status_change(info, calling_function, calling_file, calling_line); #endif -- cgit v1.2.1 From c184cd6320ac3b5cbd1ab953d94ea1ef8c4d200e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Mar 2008 12:40:46 +0100 Subject: Bug#25132 disabled query cache: Qcache_free_blocks = 1 The initial value of free memory blocks in 0. When the query cache is enabled a new memory block gets allocated and is assigned number 1. The free memory block is later split each time query cache memory is allocated for new blocks. This means that the free memory block counter won't be reduced to zero when the number of allocated blocks are zero, but rather one. To avoid confusion this patch changes this behavior so that the free memory block counter is reset to zero when the query cache is disabled. Note that when the query cache is enabled and resized the free memory block counter was still calculated correctly. mysql-test/r/query_cache.result: test case mysql-test/t/query_cache.test: test case sql/sql_cache.cc: Restore the memory block count to 0 for consistency. --- sql/sql_cache.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql') diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 8c868971911..2bf00e7e51f 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1794,6 +1794,7 @@ void Query_cache::make_disabled() query_cache_size= 0; queries_blocks= 0; free_memory= 0; + free_memory_blocks= 0; bins= 0; steps= 0; cache= 0; -- cgit v1.2.1 From 04c5af18023014c2925c83df32f68906e706495d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Mar 2008 14:49:21 +0200 Subject: Bug#26622 MASTER_POS_WAIT does not work as documented MASTER_POS_WAIT return values are different than expected when the server is not a slave. It returns -1 instead of NULL. Fixed with correcting st_relay_log_info::wait_for_pos() to return the proper value in the case of rli info is not inited. mysql-test/r/rpl_master_pos_wait.result: results changed mysql-test/t/rpl_master_pos_wait.test: the new test to check that select master_pos_wait() to a server does not have master info returns NULL as specified. sql/slave.cc: changing the return value to correspond the specification. --- sql/slave.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index 181ad4ed8cb..d4d0655f366 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2685,7 +2685,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, longlong timeout) { if (!inited) - return -1; + return -2; int event_count = 0; ulong init_abort_pos_wait; int error=0; -- cgit v1.2.1 From 8270d9875ff44900f3c57c15711c03d0b83cbe5d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Mar 2008 18:19:47 +0300 Subject: Fix for bug #34512: CAST( AVG( double ) AS DECIMAL ) returns wrong results Casting AVG() to DECIMAL led to incorrect results when the arguments had a non-DECIMAL type, because in this case Item_sum_avg::val_decimal() performed the division by the number of arguments twice. Fixed by changing Item_sum_avg::val_decimal() to not rely on Item_sum_sum::val_decimal(), i.e. calculate sum and divide using DECIMAL arithmetics for DECIMAL arguments, and utilize val_real() with subsequent conversion to DECIMAL otherwise. mysql-test/r/func_group.result: Added a test case for bug #34512. mysql-test/t/func_group.test: Added a test case for bug #34512. sql/item_sum.cc: Do not use Item_sum_sum::val_decimal() in Item_sum_avg::val_decimal() because the first one, depending on the arguments type, may return either the sum of the arguments, or the average calculated by the virtual val_real() method of Item_sum_avg. Instead, do our own calculation based on the arguments type. --- sql/item_sum.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3d6d46ab3f4..f583fc7f988 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1206,7 +1206,15 @@ my_decimal *Item_sum_avg::val_decimal(my_decimal *val) null_value=1; return NULL; } - sum_dec= Item_sum_sum::val_decimal(&sum_buff); + + /* + For non-DECIMAL hybrid_type the division will be done in + Item_sum_avg::val_real(). + */ + if (hybrid_type != DECIMAL_RESULT) + return val_decimal_from_real(val); + + sum_dec= dec_buffs + curr_dec_buff; int2my_decimal(E_DEC_FATAL_ERROR, count, 0, &cnt); my_decimal_div(E_DEC_FATAL_ERROR, val, sum_dec, &cnt, prec_increment); return val; -- cgit v1.2.1 From 9526a24b2f3b5763ef0589c6a299c09bd0e89b17 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 6 Mar 2008 20:32:47 +0200 Subject: Bug #22234 Extra Slave Col: Slave should stop on Error Field `d` of table There was a failure in that show slave status displayed a wrong message when slave stopped at processing a row event inserting to a default-less column. The problem seem to have ceased after recent fixes in rbr code. However, the test was not updated to carry testing of the case commented-out. Uncommenting and editing the test. Notice, Bug#23907 is most probably a duplicate of this one. mysql-test/extra/rpl_tests/rpl_extraSlave_Col.test: uncommenting the test that previously failed. mysql-test/suite/rpl/r/rpl_extraCol_innodb.result: results changed due to the correct expected error message of an added test is displayed. mysql-test/suite/rpl/r/rpl_extraCol_myisam.result: results changed to reflect the test changes mysql-test/suite/rpl_ndb/r/rpl_ndb_extraCol.result: results changed to reflect the uncommented test sql/log_event.cc: correcting of a merge with bug#12713 to use the correct object holding the error code. --- sql/log_event.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 0d2f3e7e708..5461d5489eb 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -137,7 +137,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error, " %s, Error_code: %d;", err->msg, err->code); } - rli->report(level, thd->net.client_last_errno, + rli->report(level, thd->is_error()? thd->main_da.sql_errno() : 0, "Could not execute %s event on table %s.%s;" "%s handler error %s; " "the event's master log %s, end_log_pos %lu", -- cgit v1.2.1 From f613588c2bc6b1d1f735eb97eb58231a9c7d2f7f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Mar 2008 14:39:37 +0200 Subject: Bug #28780 report_host is not available through SELECT @@report_host merging and post-make-test changes. mysql-test/suite/rpl/r/rpl_report.result: results changed mysql-test/suite/rpl/t/rpl_report.test: correcting test because of non-deterministic select's result sql/set_var.cc: compilation issue --- sql/set_var.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/set_var.cc b/sql/set_var.cc index d80ae577a0d..71131df0ce3 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -648,6 +648,8 @@ sys_var_thd_time_zone sys_time_zone(&vars, "time_zone"); /* Global read-only variable containing hostname */ static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname); + +#ifndef EMBEDDED_LIBRARY static sys_var_const_str_ptr sys_repl_report_host(&vars, "report_host", &report_host); static sys_var_const_str_ptr sys_repl_report_user(&vars, "report_user", &report_user); static sys_var_const_str_ptr sys_repl_report_password(&vars, "report_password", &report_password); @@ -660,7 +662,7 @@ static uchar *slave_get_report_port(THD *thd) static sys_var_readonly sys_repl_report_port(&vars, "report_port", OPT_GLOBAL, SHOW_INT, slave_get_report_port); - +#endif sys_var_thd_bool sys_keep_files_on_create(&vars, "keep_files_on_create", &SV::keep_files_on_create); -- cgit v1.2.1 From 4aae2099c941ccbac80c855bfb6b70ec7a227a2f Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Mar 2008 13:56:15 +0100 Subject: Bug #34367: sql/sql_show.cc: create_schema_table should handle MYSQL_TYPE_NEWDECIMAL Added support for the type MYSQL_TYPE_NEWDECIMAL. It now works like MYSQL_TYPE_DECIMAL. Unfortunately there cannot be a test case until we have a working information_schema plugin as part of the source distribution. sql/sql_show.cc: Bug#34367: The fix. Corrected wrong comments and a DBUG_ENTER with wrong function name. sql/table.h: Bug#34367: Added comments to st_field_info. --- sql/sql_show.cc | 8 +++++--- sql/table.h | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6d817cb0620..8816247fb83 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5384,8 +5384,9 @@ ST_SCHEMA_TABLE *get_schema_table(enum enum_schema_tables schema_table_idx) @param thd thread handler - @param - schema_table pointer to 'shema_tables' element + + @param table_list Used to pass I_S table information(fields info, tables + parameters etc) and table name. @retval \# Pointer to created table @retval NULL Can't create table @@ -5436,6 +5437,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(NULL); break; case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: if (!(item= new Item_decimal((longlong) fields_info->value, false))) { DBUG_RETURN(0); @@ -5785,7 +5787,7 @@ int make_schema_select(THD *thd, SELECT_LEX *sel, { ST_SCHEMA_TABLE *schema_table= get_schema_table(schema_table_idx); LEX_STRING db, table; - DBUG_ENTER("mysql_schema_select"); + DBUG_ENTER("make_schema_select"); DBUG_PRINT("enter", ("mysql_schema_select: %s", schema_table->table_name)); /* We have to make non const db_name & table_name diff --git a/sql/table.h b/sql/table.h index 284885658e0..aa2e075ec62 100644 --- a/sql/table.h +++ b/sql/table.h @@ -759,12 +759,36 @@ enum enum_schema_tables typedef struct st_field_info { + /** + This is used as column name. + */ const char* field_name; + /** + For string-type columns, this is the maximum number of + characters. Otherwise, it is the 'display-length' for the column. + */ uint field_length; + /** + This denotes data type for the column. For the most part, there seems to + be one entry in the enum for each SQL data type, although there seem to + be a number of additional entries in the enum. + */ enum enum_field_types field_type; int value; + /** + This is used to set column attributes. By default, columns are @c NOT + @c NULL and @c SIGNED, and you can deviate from the default + by setting the appopriate flags. You can use either one of the flags + @c MY_I_S_MAYBE_NULL and @cMY_I_S_UNSIGNED or + combine them using the bitwise or operator @c |. Both flags are + defined in table.h. + */ uint field_flags; // Field atributes(maybe_null, signed, unsigned etc.) const char* old_name; + /** + This should be one of @c SKIP_OPEN_TABLE, + @c OPEN_FRM_ONLY or @c OPEN_FULL_TABLE. + */ uint open_method; } ST_FIELD_INFO; -- cgit v1.2.1 From 875ad6d8b8f89eed171325a1e8b31816f7edef12 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Mar 2008 13:59:36 +0100 Subject: BUG#31168: @@hostname does not replicate Problem: in mixed and statement mode, a query that refers to a system variable will use the slave's value when replayed on slave. So if the value of a system variable is inserted into a table, the slave will differ from the master. Fix: mark statements that refer to a system variable as "unsafe", meaning they will be replicated by row in mixed mode and produce a warning in statement mode. There are some exceptions: some variables are actually replicated. Those should *not* be marked as unsafe. BUG#34732: mysqlbinlog does not print default values for auto_increment variables Problem: mysqlbinlog does not print default values for some variables, including auto_increment_increment and others. So if a client executing the output of mysqlbinlog has different default values, replication will be wrong. Fix: Always print default values for all variables that are replicated. I need to fix the two bugs at the same time, because the test cases would fail if I only fixed one of them. include/m_ctype.h: Added definition of ILLEGAL_CHARSET_INFO_NUMBER. We just need a symbol for a number that will never be used by any charset. ~0U should be safe since charset numbers are sequential, starting from 0. mysql-test/include/commit.inc: Upated test to avoid making statements unsafe. mysql-test/r/commit_1innodb.result: Updated test needs updated result file. mysql-test/r/mysqlbinlog.result: Updated result file. mysql-test/r/mysqlbinlog2.result: Updated result file. mysql-test/r/user_var-binlog.result: Updated result file. mysql-test/suite/binlog/r/binlog_base64_flag.result: Updated result file. mysql-test/suite/binlog/r/binlog_stm_ctype_ucs.result: Updated result file. mysql-test/suite/binlog/r/binlog_unsafe.result: Modified test file needs modified result file. mysql-test/suite/binlog/t/binlog_base64_flag.test: Need to filter out pseudo_thread_id from result since it is nondeterministic. mysql-test/suite/binlog/t/binlog_unsafe.test: Add tests that using variables is unsafe. The 'CREATE VIEW' tests didn't make sense, so I removed them. SHOW WARNINGS is not necessary either, because we get warnings for each statement in the result file. mysql-test/suite/rpl/r/rpl_row_mysqlbinlog.result: Updated result file. mysql-test/suite/rpl/r/rpl_skip_error.result: Updated result file. mysql-test/suite/rpl/t/rpl_skip_error.test: The test used @@server_id, which is not safe to replicate, so it would have given a warning. The way it used @@server_id was hackish (issue a query on master that removes rows only on master), so I replaced it by a more robust way to do the same thing (connect to slave and insert the rows only there). Also clarified what the test case does. mysql-test/t/mysqlbinlog2.test: Use --short-form instead of manually filtering out nondeterministic stuff from mysqlbinlog (because we added the nondeterministic @@pseudo_thread_id to the output). sql/item_func.cc: Added method of Item_func_get_system_var that indicates whether the given system variable will be written to the binlog or not. sql/item_func.h: Added method of Item_func_get_system_var that indicates whether the given system variable will be written to the binlog or not. sql/log_event.cc: - auto_increment_offset was not written to the binlog if auto_increment_increment=1 - mysqlbinlog did not output default values for some variables (BUG#34732). In st_print_event_info, we remember for each variable whether it has been printed or not. This is achieved in different ways for different variables: - For auto_increment_*, lc_time_names, charset_database_number, we set the default values in st_print_event_info to something illegal, so that it will look like they have changed the first time they are seen. - For charset, sql_mode, pseudo_thread_id, we add a flag to st_print_event_info which indicates whether the variable has been printed. - Since pseudo_thread_id is now printed more often, and its value is not guaranteed to be constant across different runs of the same test script, I replaced it by a constant if --short-form is used. - Moved st_print_event_info constructor from log_event.h to log_event.cc, since it now depends on ILLEGAL_CHARSET_NUMBER, which is defined in m_ctype.h, which is better to include from a .cc file than from a header file. sql/log_event.h: Added fields to st_print_event_info that indicate whether some of the variables have been written or not. Since the initialization of charset_database_number now depends on ILLEGAL_CHARSET_INFO_NUMBER, which is defined in a header file, which we'd better not include from this header file -- I moved the constructor from here to log_event.cc. sql/set_var.cc: System variables now have a flag binlog_status, which indicates if they are written to the binlog. If nothing is specified, all variables are marked as not written to the binlog (NOT_IN_BINLOG) when created. In this file, the variables that are written to the binlog are marked with SESSION_VARIABLE_IN_BINLOG. sql/set_var.h: Added flag binlog_status to class sys_var. Added a getter and a constructor parameter that sets it. Since I had to change sys_var_thd_enum constructor anyways, I simplified it to use default values of arguments instead of three copies of the constructor. sql/sql_yacc.yy: Mark statements that refer to a system variable as "unsafe", meaning they will be replicated by row in mixed mode. Added comment to explain strange piece of code just above. mysql-test/include/diff_tables.inc: New auxiliary test file that tests whether two tables (possibly one on master and one on slave) differ. mysql-test/suite/rpl/r/rpl_variables.result: New test case needs new result file. mysql-test/suite/rpl/r/rpl_variables_stm.result: New test file needs new result file. mysql-test/suite/rpl/t/rpl_variables.test: Test that INSERT of @@variables is replicated correctly (by switching to row-based mode). mysql-test/suite/rpl/t/rpl_variables_stm.test: Test that replication of @@variables which are replicated explicitly works as expected in statement mode (without giving warnings). --- sql/item_func.cc | 6 +++ sql/item_func.h | 9 ++++ sql/log_event.cc | 116 +++++++++++++++++++++++++++--------------- sql/log_event.h | 29 +++-------- sql/set_var.cc | 132 ++++++++++++++++++++++++++++++++--------------- sql/set_var.h | 152 +++++++++++++++++++++++++++++++++---------------------- sql/sql_yacc.yy | 3 ++ 7 files changed, 283 insertions(+), 164 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 984fa9038b7..12bb0999ffc 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4789,6 +4789,12 @@ Item_func_get_system_var::fix_fields(THD *thd, Item **ref) } +bool Item_func_get_system_var::is_written_to_binlog() +{ + return var->is_written_to_binlog(var_type); +} + + longlong Item_func_inet_aton::val_int() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_func.h b/sql/item_func.h index f8eb7ff6200..9ab30a2cf93 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1435,6 +1435,15 @@ public: void fix_length_and_dec() { DBUG_ASSERT(0); } /* TODO: fix to support views */ const char *func_name() const { return "get_system_var"; } + /** + Indicates whether this system variable is written to the binlog or not. + + Variables are written to the binlog as part of "status_vars" in + Query_log_event, as an Intvar_log_event, or a Rand_log_event. + + @return true if the variable is written to the binlog, false otherwise. + */ + bool is_written_to_binlog(); }; diff --git a/sql/log_event.cc b/sql/log_event.cc index af802f52611..15f1a957149 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -14,7 +14,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef MYSQL_CLIENT +#ifdef MYSQL_CLIENT + +#include "mysql_priv.h" + +#else #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation @@ -28,7 +32,9 @@ #include "rpl_utility.h" #include "rpl_record.h" #include + #endif /* MYSQL_CLIENT */ + #include #include @@ -1589,7 +1595,7 @@ bool Query_log_event::write(IO_CACHE* file) recognize Q_CATALOG_CODE and have no problem. */ } - if (auto_increment_increment != 1) + if (auto_increment_increment != 1 || auto_increment_offset != 1) { *start++= Q_AUTO_INCREMENT; int2store(start, auto_increment_increment); @@ -2102,9 +2108,17 @@ void Query_log_event::print_query_header(IO_CACHE* file, end= strmov(end, print_event_info->delimiter); *end++='\n'; my_b_write(file, (uchar*) buff, (uint) (end-buff)); - if (flags & LOG_EVENT_THREAD_SPECIFIC_F) + if ((!print_event_info->thread_id_printed || + ((flags & LOG_EVENT_THREAD_SPECIFIC_F) && + thread_id != print_event_info->thread_id))) + { + // If --short-form, print deterministic value instead of pseudo_thread_id. my_b_printf(file,"SET @@session.pseudo_thread_id=%lu%s\n", - (ulong)thread_id, print_event_info->delimiter); + short_form ? 999999999 : (ulong)thread_id, + print_event_info->delimiter); + print_event_info->thread_id= thread_id; + print_event_info->thread_id_printed= 1; + } /* If flags2_inited==0, this is an event from 3.23 or 4.0; nothing to @@ -2151,20 +2165,14 @@ void Query_log_event::print_query_header(IO_CACHE* file, gracefully). So this code should always be good. */ - if (likely(sql_mode_inited)) + if (likely(sql_mode_inited) && + (unlikely(print_event_info->sql_mode != sql_mode || + !print_event_info->sql_mode_inited))) { - if (unlikely(!print_event_info->sql_mode_inited)) /* first Query event */ - { - print_event_info->sql_mode_inited= 1; - /* force a difference to force write */ - print_event_info->sql_mode= ~sql_mode; - } - if (unlikely(print_event_info->sql_mode != sql_mode)) - { - my_b_printf(file,"SET @@session.sql_mode=%lu%s\n", - (ulong)sql_mode, print_event_info->delimiter); - print_event_info->sql_mode= sql_mode; - } + my_b_printf(file,"SET @@session.sql_mode=%lu%s\n", + (ulong)sql_mode, print_event_info->delimiter); + print_event_info->sql_mode= sql_mode; + print_event_info->sql_mode_inited= 1; } if (print_event_info->auto_increment_increment != auto_increment_increment || print_event_info->auto_increment_offset != auto_increment_offset) @@ -2178,33 +2186,28 @@ void Query_log_event::print_query_header(IO_CACHE* file, /* TODO: print the catalog when we feature SET CATALOG */ - if (likely(charset_inited)) + if (likely(charset_inited) && + (unlikely(!print_event_info->charset_inited || + bcmp((uchar*) print_event_info->charset, (uchar*) charset, 6)))) { - if (unlikely(!print_event_info->charset_inited)) /* first Query event */ + CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME)); + if (cs_info) { - print_event_info->charset_inited= 1; - print_event_info->charset[0]= ~charset[0]; // force a difference to force write - } - if (unlikely(bcmp((uchar*) print_event_info->charset, (uchar*) charset, 6))) - { - CHARSET_INFO *cs_info= get_charset(uint2korr(charset), MYF(MY_WME)); - if (cs_info) - { - /* for mysql client */ - my_b_printf(file, "/*!\\C %s */%s\n", - cs_info->csname, print_event_info->delimiter); - } - my_b_printf(file,"SET " - "@@session.character_set_client=%d," - "@@session.collation_connection=%d," - "@@session.collation_server=%d" - "%s\n", - uint2korr(charset), - uint2korr(charset+2), - uint2korr(charset+4), - print_event_info->delimiter); - memcpy(print_event_info->charset, charset, 6); + /* for mysql client */ + my_b_printf(file, "/*!\\C %s */%s\n", + cs_info->csname, print_event_info->delimiter); } + my_b_printf(file,"SET " + "@@session.character_set_client=%d," + "@@session.collation_connection=%d," + "@@session.collation_server=%d" + "%s\n", + uint2korr(charset), + uint2korr(charset+2), + uint2korr(charset+4), + print_event_info->delimiter); + memcpy(print_event_info->charset, charset, 6); + print_event_info->charset_inited= 1; } if (time_zone_len) { @@ -8631,3 +8634,34 @@ Incident_log_event::write_data_body(IO_CACHE *file) DBUG_ENTER("Incident_log_event::write_data_body"); DBUG_RETURN(write_str(file, m_message.str, m_message.length)); } + + +#ifdef MYSQL_CLIENT +/** + The default values for these variables should be values that are + *incorrect*, i.e., values that cannot occur in an event. This way, + they will always be printed for the first event. +*/ +st_print_event_info::st_print_event_info() + :flags2_inited(0), sql_mode_inited(0), + auto_increment_increment(0),auto_increment_offset(0), charset_inited(0), + lc_time_names_number(~0), + charset_database_number(ILLEGAL_CHARSET_INFO_NUMBER), + thread_id(0), thread_id_printed(false), + base64_output_mode(BASE64_OUTPUT_UNSPEC), printed_fd_event(FALSE) +{ + /* + Currently we only use static PRINT_EVENT_INFO objects, so zeroed at + program's startup, but these explicit bzero() is for the day someone + creates dynamic instances. + */ + bzero(db, sizeof(db)); + bzero(charset, sizeof(charset)); + bzero(time_zone_str, sizeof(time_zone_str)); + delimiter[0]= ';'; + delimiter[1]= 0; + myf const flags = MYF(MY_WME | MY_NABP); + open_cached_file(&head_cache, NULL, NULL, 0, flags); + open_cached_file(&body_cache, NULL, NULL, 0, flags); +} +#endif diff --git a/sql/log_event.h b/sql/log_event.h index c46827253a3..2cf69e975f4 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -592,8 +592,9 @@ typedef struct st_print_event_info { /* Settings for database, sql_mode etc that comes from the last event - that was printed. - */ + that was printed. We cache these so that we don't have to print + them if they are unchanged. + */ // TODO: have the last catalog here ?? char db[FN_REFLEN+1]; // TODO: make this a LEX_STRING when thd->db is bool flags2_inited; @@ -606,26 +607,10 @@ typedef struct st_print_event_info char time_zone_str[MAX_TIME_ZONE_NAME_LENGTH]; uint lc_time_names_number; uint charset_database_number; - st_print_event_info() - :flags2_inited(0), sql_mode_inited(0), - auto_increment_increment(1),auto_increment_offset(1), charset_inited(0), - lc_time_names_number(0), charset_database_number(0), - base64_output_mode(BASE64_OUTPUT_UNSPEC), printed_fd_event(FALSE) - { - /* - Currently we only use static PRINT_EVENT_INFO objects, so zeroed at - program's startup, but these explicit bzero() is for the day someone - creates dynamic instances. - */ - bzero(db, sizeof(db)); - bzero(charset, sizeof(charset)); - bzero(time_zone_str, sizeof(time_zone_str)); - delimiter[0]= ';'; - delimiter[1]= 0; - myf const flags = MYF(MY_WME | MY_NABP); - open_cached_file(&head_cache, NULL, NULL, 0, flags); - open_cached_file(&body_cache, NULL, NULL, 0, flags); - } + uint thread_id; + bool thread_id_printed; + + st_print_event_info(); ~st_print_event_info() { close_cached_file(&head_cache); diff --git a/sql/set_var.cc b/sql/set_var.cc index 71131df0ce3..0d1d8b92d3b 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -161,10 +161,14 @@ static void sys_default_slow_log_path(THD *thd, enum_var_type type); static sys_var_chain vars = { NULL, NULL }; -static sys_var_thd_ulong sys_auto_increment_increment(&vars, "auto_increment_increment", - &SV::auto_increment_increment); -static sys_var_thd_ulong sys_auto_increment_offset(&vars, "auto_increment_offset", - &SV::auto_increment_offset); +static sys_var_thd_ulong +sys_auto_increment_increment(&vars, "auto_increment_increment", + &SV::auto_increment_increment, NULL, NULL, + sys_var::SESSION_VARIABLE_IN_BINLOG); +static sys_var_thd_ulong +sys_auto_increment_offset(&vars, "auto_increment_offset", + &SV::auto_increment_offset, NULL, NULL, + sys_var::SESSION_VARIABLE_IN_BINLOG); static sys_var_bool_ptr sys_automatic_sp_privileges(&vars, "automatic_sp_privileges", &sp_automatic_privileges); @@ -176,19 +180,25 @@ static sys_var_thd_binlog_format sys_binlog_format(&vars, "binlog_format", &SV::binlog_format); static sys_var_thd_ulong sys_bulk_insert_buff_size(&vars, "bulk_insert_buffer_size", &SV::bulk_insert_buff_size); -static sys_var_character_set_sv sys_character_set_server(&vars, "character_set_server", - &SV::collation_server, - &default_charset_info); +static sys_var_character_set_sv +sys_character_set_server(&vars, "character_set_server", + &SV::collation_server, &default_charset_info, 0, + sys_var::SESSION_VARIABLE_IN_BINLOG); sys_var_const_str sys_charset_system(&vars, "character_set_system", (char *)my_charset_utf8_general_ci.name); -static sys_var_character_set_database sys_character_set_database(&vars, "character_set_database"); -static sys_var_character_set_client sys_character_set_client(&vars, - "character_set_client", - &SV::character_set_client, - &default_charset_info); -static sys_var_character_set_sv sys_character_set_connection(&vars, "character_set_connection", - &SV::collation_connection, - &default_charset_info); +static sys_var_character_set_database +sys_character_set_database(&vars, "character_set_database", + sys_var::SESSION_VARIABLE_IN_BINLOG); +static sys_var_character_set_client +sys_character_set_client(&vars, "character_set_client", + &SV::character_set_client, + &default_charset_info, + sys_var::SESSION_VARIABLE_IN_BINLOG); +static sys_var_character_set_sv +sys_character_set_connection(&vars, "character_set_connection", + &SV::collation_connection, + &default_charset_info, 0, + sys_var::SESSION_VARIABLE_IN_BINLOG); static sys_var_character_set_sv sys_character_set_results(&vars, "character_set_results", &SV::character_set_results, &default_charset_info, true); @@ -199,15 +209,18 @@ static sys_var_thd_ulong sys_completion_type(&vars, "completion_type", &SV::completion_type, check_completion_type, fix_completion_type); -static sys_var_collation_sv sys_collation_connection(&vars, "collation_connection", - &SV::collation_connection, - &default_charset_info); -static sys_var_collation_sv sys_collation_database(&vars, "collation_database", - &SV::collation_database, - &default_charset_info); -static sys_var_collation_sv sys_collation_server(&vars, "collation_server", - &SV::collation_server, - &default_charset_info); +static sys_var_collation_sv +sys_collation_connection(&vars, "collation_connection", + &SV::collation_connection, &default_charset_info, + sys_var::SESSION_VARIABLE_IN_BINLOG); +static sys_var_collation_sv +sys_collation_database(&vars, "collation_database", &SV::collation_database, + &default_charset_info, + sys_var::SESSION_VARIABLE_IN_BINLOG); +static sys_var_collation_sv +sys_collation_server(&vars, "collation_server", &SV::collation_server, + &default_charset_info, + sys_var::SESSION_VARIABLE_IN_BINLOG); static sys_var_long_ptr sys_concurrent_insert(&vars, "concurrent_insert", &myisam_concurrent_insert); static sys_var_long_ptr sys_connect_timeout(&vars, "connect_timeout", @@ -303,9 +316,10 @@ static sys_var_thd_ulong sys_max_error_count(&vars, "max_error_count", &SV::max_error_count); static sys_var_thd_ulonglong sys_max_heap_table_size(&vars, "max_heap_table_size", &SV::max_heap_table_size); -static sys_var_thd_ulong sys_pseudo_thread_id(&vars, "pseudo_thread_id", - &SV::pseudo_thread_id, - check_pseudo_thread_id, 0); +static sys_var_thd_ulong sys_pseudo_thread_id(&vars, "pseudo_thread_id", + &SV::pseudo_thread_id, + check_pseudo_thread_id, 0, + sys_var::SESSION_VARIABLE_IN_BINLOG); static sys_var_thd_ha_rows sys_max_join_size(&vars, "max_join_size", &SV::max_join_size, fix_max_join_size); @@ -436,8 +450,14 @@ static sys_var_long_ptr sys_slow_launch_time(&vars, "slow_launch_time", &slow_launch_time); static sys_var_thd_ulong sys_sort_buffer(&vars, "sort_buffer_size", &SV::sortbuff_size); +/* + sql_mode should *not* have binlog_mode=SESSION_VARIABLE_IN_BINLOG: + even though it is written to the binlog, the slave ignores the + MODE_NO_DIR_IN_CREATE variable, so slave's value differs from + master's (see log_event.cc: Query_log_event::do_apply_event()). +*/ static sys_var_thd_sql_mode sys_sql_mode(&vars, "sql_mode", - &SV::sql_mode); + &SV::sql_mode); #ifdef HAVE_OPENSSL extern char *opt_ssl_ca, *opt_ssl_capath, *opt_ssl_cert, *opt_ssl_cipher, *opt_ssl_key; @@ -588,7 +608,8 @@ static sys_var_thd_bit sys_sql_notes(&vars, "sql_notes", 0, OPTION_SQL_NOTES); static sys_var_thd_bit sys_auto_is_null(&vars, "sql_auto_is_null", 0, set_option_bit, - OPTION_AUTO_IS_NULL); + OPTION_AUTO_IS_NULL, 0, + sys_var::SESSION_VARIABLE_IN_BINLOG); static sys_var_thd_bit sys_safe_updates(&vars, "sql_safe_updates", 0, set_option_bit, OPTION_SAFE_UPDATES); @@ -601,11 +622,12 @@ static sys_var_thd_bit sys_quote_show_create(&vars, "sql_quote_show_create", 0, static sys_var_thd_bit sys_foreign_key_checks(&vars, "foreign_key_checks", 0, set_option_bit, OPTION_NO_FOREIGN_KEY_CHECKS, - 1); + 1, sys_var::SESSION_VARIABLE_IN_BINLOG); static sys_var_thd_bit sys_unique_checks(&vars, "unique_checks", 0, set_option_bit, OPTION_RELAXED_UNIQUE_CHECKS, - 1); + 1, + sys_var::SESSION_VARIABLE_IN_BINLOG); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) static sys_var_thd_bit sys_profiling(&vars, "profiling", NULL, set_option_bit, @@ -618,13 +640,41 @@ static sys_var_thd_ulong sys_profiling_history_size(&vars, "profiling_history_si static sys_var_thd_ha_rows sys_select_limit(&vars, "sql_select_limit", &SV::select_limit); -static sys_var_timestamp sys_timestamp(&vars, "timestamp"); -static sys_var_last_insert_id sys_last_insert_id(&vars, "last_insert_id"); -static sys_var_last_insert_id sys_identity(&vars, "identity"); +static sys_var_timestamp sys_timestamp(&vars, "timestamp", + sys_var::SESSION_VARIABLE_IN_BINLOG); +static sys_var_last_insert_id +sys_last_insert_id(&vars, "last_insert_id", + sys_var::SESSION_VARIABLE_IN_BINLOG); +/* + identity is an alias for last_insert_id(), so that we are compatible + with Sybase +*/ +static sys_var_last_insert_id +sys_identity(&vars, "identity", sys_var::SESSION_VARIABLE_IN_BINLOG); -static sys_var_thd_lc_time_names sys_lc_time_names(&vars, "lc_time_names"); +static sys_var_thd_lc_time_names +sys_lc_time_names(&vars, "lc_time_names", sys_var::SESSION_VARIABLE_IN_BINLOG); -static sys_var_insert_id sys_insert_id(&vars, "insert_id"); +/* + insert_id should *not* be marked as written to the binlog (i.e., it + should *not* have binlog_status==SESSION_VARIABLE_IN_BINLOG), + because we want any statement that refers to insert_id explicitly to + be unsafe. (By "explicitly", we mean using @@session.insert_id, + whereas insert_id is used "implicitly" when NULL value is inserted + into an auto_increment column). + + We want statements referring explicitly to @@session.insert_id to be + unsafe, because insert_id is modified internally by the slave sql + thread when NULL values are inserted in an AUTO_INCREMENT column. + This modification interfers with the value of the + @@session.insert_id variable if @@session.insert_id is referred + explicitly by an insert statement (as is seen by executing "SET + @@session.insert_id=0; CREATE TABLE t (a INT, b INT KEY + AUTO_INCREMENT); INSERT INTO t(a) VALUES (@@session.insert_id);" in + statement-based logging mode: t will be different on master and + slave). +*/ +static sys_var_insert_id sys_insert_id(&vars, "insert_id"); static sys_var_readonly sys_error_count(&vars, "error_count", OPT_SESSION, SHOW_LONG, @@ -634,9 +684,10 @@ static sys_var_readonly sys_warning_count(&vars, "warning_count", SHOW_LONG, get_warning_count); -/* alias for last_insert_id() to be compatible with Sybase */ -static sys_var_rand_seed1 sys_rand_seed1(&vars, "rand_seed1"); -static sys_var_rand_seed2 sys_rand_seed2(&vars, "rand_seed2"); +static sys_var_rand_seed1 sys_rand_seed1(&vars, "rand_seed1", + sys_var::SESSION_VARIABLE_IN_BINLOG); +static sys_var_rand_seed2 sys_rand_seed2(&vars, "rand_seed2", + sys_var::SESSION_VARIABLE_IN_BINLOG); static sys_var_thd_ulong sys_default_week_format(&vars, "default_week_format", &SV::default_week_format); @@ -644,7 +695,8 @@ static sys_var_thd_ulong sys_default_week_format(&vars, "default_week_for sys_var_thd_ulong sys_group_concat_max_len(&vars, "group_concat_max_len", &SV::group_concat_max_len); -sys_var_thd_time_zone sys_time_zone(&vars, "time_zone"); +sys_var_thd_time_zone sys_time_zone(&vars, "time_zone", + sys_var::SESSION_VARIABLE_IN_BINLOG); /* Global read-only variable containing hostname */ static sys_var_const_str sys_hostname(&vars, "hostname", glob_hostname); diff --git a/sql/set_var.h b/sql/set_var.h index 171158fcf1e..46fe7755baf 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -48,6 +48,22 @@ struct sys_var_chain class sys_var { public: + + /** + Enumeration type to indicate for a system variable whether it will be written to the binlog or not. + */ + enum Binlog_status_enum + { + /* The variable value is not in the binlog. */ + NOT_IN_BINLOG, + /* The value of the @@session variable is in the binlog. */ + SESSION_VARIABLE_IN_BINLOG + /* + Currently, no @@global variable is ever in the binlog, so we + don't need an enumeration value for that. + */ + }; + sys_var *next; struct my_option *option_limits; /* Updated by by set_var_init() */ uint name_length; /* Updated by by set_var_init() */ @@ -55,8 +71,9 @@ public: sys_after_update_func after_update; bool no_support_one_shot; - sys_var(const char *name_arg,sys_after_update_func func= NULL) - :name(name_arg), after_update(func) + sys_var(const char *name_arg, sys_after_update_func func= NULL, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :name(name_arg), after_update(func), binlog_status(binlog_status_arg) , no_support_one_shot(1) {} virtual ~sys_var() {} @@ -71,6 +88,11 @@ public: virtual bool check(THD *thd, set_var *var); bool check_enum(THD *thd, set_var *var, const TYPELIB *enum_names); bool check_set(THD *thd, set_var *var, TYPELIB *enum_names); + bool is_written_to_binlog(enum_var_type type) + { + return (type == OPT_SESSION || type == OPT_DEFAULT) && + (binlog_status == SESSION_VARIABLE_IN_BINLOG); + } virtual bool update(THD *thd, set_var *var)=0; virtual void set_default(THD *thd_arg, enum_var_type type) {} virtual SHOW_TYPE show_type() { return SHOW_UNDEF; } @@ -86,6 +108,9 @@ public: virtual bool is_struct() { return 0; } virtual bool is_readonly() const { return 0; } virtual sys_var_pluginvar *cast_pluginvar() { return 0; } + +private: + const Binlog_status_enum binlog_status; }; @@ -232,8 +257,9 @@ class sys_var_const_str :public sys_var { public: char *value; // Pointer to const value - sys_var_const_str(sys_var_chain *chain, const char *name_arg, const char *value_arg) - :sys_var(name_arg),value((char*) value_arg) + sys_var_const_str(sys_var_chain *chain, const char *name_arg, + const char *value_arg) + :sys_var(name_arg), value((char*) value_arg) { chain_sys_var(chain); } bool check(THD *thd, set_var *var) { @@ -328,8 +354,9 @@ class sys_var_thd :public sys_var { public: sys_var_thd(const char *name_arg, - sys_after_update_func func= NULL) - :sys_var(name_arg,func) + sys_after_update_func func= NULL, + Binlog_status_enum binlog_status= NOT_IN_BINLOG) + :sys_var(name_arg, func, binlog_status) {} bool check_type(enum_var_type type) { return 0; } bool check_default(enum_var_type type) @@ -344,12 +371,13 @@ class sys_var_thd_ulong :public sys_var_thd sys_check_func check_func; public: ulong SV::*offset; - sys_var_thd_ulong(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg) - :sys_var_thd(name_arg), check_func(0), offset(offset_arg) - { chain_sys_var(chain); } - sys_var_thd_ulong(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg, - sys_check_func c_func, sys_after_update_func au_func) - :sys_var_thd(name_arg,au_func), check_func(c_func), offset(offset_arg) + sys_var_thd_ulong(sys_var_chain *chain, const char *name_arg, + ulong SV::*offset_arg, + sys_check_func c_func= NULL, + sys_after_update_func au_func= NULL, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var_thd(name_arg, au_func, binlog_status_arg), check_func(c_func), + offset(offset_arg) { chain_sys_var(chain); } bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); @@ -440,22 +468,12 @@ protected: TYPELIB *enum_names; sys_check_func check_func; public: - sys_var_thd_enum(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg, - TYPELIB *typelib) - :sys_var_thd(name_arg), offset(offset_arg), enum_names(typelib), - check_func(0) - { chain_sys_var(chain); } - sys_var_thd_enum(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg, - TYPELIB *typelib, - sys_after_update_func func) - :sys_var_thd(name_arg,func), offset(offset_arg), enum_names(typelib), - check_func(0) - { chain_sys_var(chain); } - sys_var_thd_enum(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg, - TYPELIB *typelib, sys_after_update_func func, - sys_check_func check) - :sys_var_thd(name_arg,func), offset(offset_arg), enum_names(typelib), - check_func(check) + sys_var_thd_enum(sys_var_chain *chain, const char *name_arg, + ulong SV::*offset_arg, TYPELIB *typelib, + sys_after_update_func func= NULL, + sys_check_func check= NULL) + :sys_var_thd(name_arg, func), offset(offset_arg), + enum_names(typelib), check_func(check) { chain_sys_var(chain); } bool check(THD *thd, set_var *var) { @@ -480,7 +498,7 @@ public: sys_var_thd_sql_mode(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg) :sys_var_thd_enum(chain, name_arg, offset_arg, &sql_mode_typelib, - fix_sql_mode_var) + fix_sql_mode_var) {} bool check(THD *thd, set_var *var) { @@ -534,9 +552,10 @@ public: bool reverse; sys_var_thd_bit(sys_var_chain *chain, const char *name_arg, sys_check_func c_func, sys_update_func u_func, - ulonglong bit, bool reverse_arg=0) - :sys_var_thd(name_arg), check_func(c_func), update_func(u_func), - bit_flag(bit), reverse(reverse_arg) + ulonglong bit, bool reverse_arg=0, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var_thd(name_arg, NULL, binlog_status_arg), check_func(c_func), + update_func(u_func), bit_flag(bit), reverse(reverse_arg) { chain_sys_var(chain); } bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); @@ -567,8 +586,9 @@ public: class sys_var_timestamp :public sys_var { public: - sys_var_timestamp(sys_var_chain *chain, const char *name_arg) - :sys_var(name_arg) + sys_var_timestamp(sys_var_chain *chain, const char *name_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var(name_arg, NULL, binlog_status_arg) { chain_sys_var(chain); } bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); @@ -582,8 +602,9 @@ public: class sys_var_last_insert_id :public sys_var { public: - sys_var_last_insert_id(sys_var_chain *chain, const char *name_arg) - :sys_var(name_arg) + sys_var_last_insert_id(sys_var_chain *chain, const char *name_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var(name_arg, NULL, binlog_status_arg) { chain_sys_var(chain); } bool update(THD *thd, set_var *var); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } @@ -608,8 +629,9 @@ public: class sys_var_rand_seed1 :public sys_var { public: - sys_var_rand_seed1(sys_var_chain *chain, const char *name_arg) - :sys_var(name_arg) + sys_var_rand_seed1(sys_var_chain *chain, const char *name_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var(name_arg, NULL, binlog_status_arg) { chain_sys_var(chain); } bool update(THD *thd, set_var *var); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } @@ -618,8 +640,9 @@ public: class sys_var_rand_seed2 :public sys_var { public: - sys_var_rand_seed2(sys_var_chain *chain, const char *name_arg) - :sys_var(name_arg) + sys_var_rand_seed2(sys_var_chain *chain, const char *name_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var(name_arg, NULL, binlog_status_arg) { chain_sys_var(chain); } bool update(THD *thd, set_var *var); bool check_type(enum_var_type type) { return type == OPT_GLOBAL; } @@ -629,11 +652,12 @@ public: class sys_var_collation :public sys_var_thd { public: - sys_var_collation(const char *name_arg) - :sys_var_thd(name_arg) - { + sys_var_collation(const char *name_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var_thd(name_arg, NULL, binlog_status_arg) + { no_support_one_shot= 0; - } + } bool check(THD *thd, set_var *var); SHOW_TYPE show_type() { return SHOW_CHAR; } bool check_update_type(Item_result type) @@ -648,8 +672,9 @@ class sys_var_character_set :public sys_var_thd { public: bool nullable; - sys_var_character_set(const char *name_arg, bool is_nullable= 0) : - sys_var_thd(name_arg), nullable(is_nullable) + sys_var_character_set(const char *name_arg, bool is_nullable= 0, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var_thd(name_arg, NULL, binlog_status_arg), nullable(is_nullable) { /* In fact only almost all variables derived from sys_var_character_set @@ -678,8 +703,9 @@ public: sys_var_character_set_sv(sys_var_chain *chain, const char *name_arg, CHARSET_INFO *SV::*offset_arg, CHARSET_INFO **global_default_arg, - bool is_nullable= 0) - : sys_var_character_set(name_arg, is_nullable), + bool is_nullable= 0, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + : sys_var_character_set(name_arg, is_nullable, binlog_status_arg), offset(offset_arg), global_default(global_default_arg) { chain_sys_var(chain); } void set_default(THD *thd, enum_var_type type); @@ -693,9 +719,9 @@ public: sys_var_character_set_client(sys_var_chain *chain, const char *name_arg, CHARSET_INFO *SV::*offset_arg, CHARSET_INFO **global_default_arg, - bool is_nullable= 0) + Binlog_status_enum binlog_status_arg) : sys_var_character_set_sv(chain, name_arg, offset_arg, global_default_arg, - is_nullable) + 0, binlog_status_arg) { } bool check(THD *thd, set_var *var); }; @@ -704,8 +730,10 @@ public: class sys_var_character_set_database :public sys_var_character_set { public: - sys_var_character_set_database(sys_var_chain *chain, const char *name_arg) : - sys_var_character_set(name_arg) + sys_var_character_set_database(sys_var_chain *chain, const char *name_arg, + Binlog_status_enum binlog_status_arg= + NOT_IN_BINLOG) + : sys_var_character_set(name_arg, 0, binlog_status_arg) { chain_sys_var(chain); } void set_default(THD *thd, enum_var_type type); CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); @@ -718,8 +746,9 @@ class sys_var_collation_sv :public sys_var_collation public: sys_var_collation_sv(sys_var_chain *chain, const char *name_arg, CHARSET_INFO *SV::*offset_arg, - CHARSET_INFO **global_default_arg) - :sys_var_collation(name_arg), + CHARSET_INFO **global_default_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var_collation(name_arg, binlog_status_arg), offset(offset_arg), global_default(global_default_arg) { chain_sys_var(chain); @@ -946,8 +975,9 @@ public: class sys_var_thd_time_zone :public sys_var_thd { public: - sys_var_thd_time_zone(sys_var_chain *chain, const char *name_arg): - sys_var_thd(name_arg) + sys_var_thd_time_zone(sys_var_chain *chain, const char *name_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + :sys_var_thd(name_arg, NULL, binlog_status_arg) { no_support_one_shot= 0; chain_sys_var(chain); @@ -1034,8 +1064,9 @@ public: class sys_var_thd_lc_time_names :public sys_var_thd { public: - sys_var_thd_lc_time_names(sys_var_chain *chain, const char *name_arg): - sys_var_thd(name_arg) + sys_var_thd_lc_time_names(sys_var_chain *chain, const char *name_arg, + Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) + : sys_var_thd(name_arg, NULL, binlog_status_arg) { #if MYSQL_VERSION_ID < 50000 no_support_one_shot= 0; @@ -1079,9 +1110,8 @@ public: sys_var_thd_binlog_format(sys_var_chain *chain, const char *name_arg, ulong SV::*offset_arg) :sys_var_thd_enum(chain, name_arg, offset_arg, - &binlog_format_typelib - , fix_binlog_format_after_update - ) + &binlog_format_typelib, + fix_binlog_format_after_update) {}; bool is_readonly() const; }; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1bd90e74f47..98434d15d87 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -7389,6 +7389,7 @@ variable_aux: } | '@' opt_var_ident_type ident_or_text opt_component { + /* disallow "SELECT @@global.global.variable" */ if ($3.str && $4.str && check_reserved_words(&$3)) { my_parse_error(ER(ER_SYNTAX_ERROR)); @@ -7396,6 +7397,8 @@ variable_aux: } if (!($$= get_system_var(YYTHD, $2, $3, $4))) MYSQL_YYABORT; + if (!((Item_func_get_system_var*) $$)->is_written_to_binlog()) + Lex->set_stmt_unsafe(); } ; -- cgit v1.2.1 From 44df0f6e9cece95b914f3f3b0ce3d3baa6f2dbf1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 7 Mar 2008 18:41:50 +0400 Subject: BUG#34656 - KILL a query = Assertion failed: m_status == DA_ERROR || m_status == DA_OK Reading from information_scema.tables or information_schema.columns may cause assertion failure in debug builds. This may happen under rare circumstances when information_schema fails to get information about a table (e.g. when a connection is killed). This happens because open_normal_and_derived_tables() can return an error without setting an error message in THD. But information_schema attempts to get an error message from THD unconditionally. With this fix information_schema attempts to get an error message from THD only in case error message is set in THD. mysql-test/r/information_schema.result: A test case for BUG#34656. mysql-test/t/information_schema.test: A test case for BUG#34656. sql/item_func.cc: Set proc info to "User sleep". sql/sql_show.cc: open_normal_and_derived_tables() can return an error without setting an error message in THD. That means we must access error message conditionally, only in case thd->is_error() is true. --- sql/item_func.cc | 2 ++ sql/sql_show.cc | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 65d3a627d2d..b61f683ae9f 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3722,6 +3722,7 @@ longlong Item_func_sleep::val_int() pthread_cond_init(&cond, NULL); pthread_mutex_lock(&LOCK_user_locks); + thd_proc_info(thd, "User sleep"); thd->mysys_var->current_mutex= &LOCK_user_locks; thd->mysys_var->current_cond= &cond; @@ -3733,6 +3734,7 @@ longlong Item_func_sleep::val_int() break; error= 0; } + thd_proc_info(thd, 0); pthread_mutex_unlock(&LOCK_user_locks); pthread_mutex_lock(&thd->mysys_var->mutex); thd->mysys_var->current_mutex= 0; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6d817cb0620..a6516d5bf46 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3430,7 +3430,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, /* there was errors during opening tables */ - const char *error= thd->main_da.message(); + const char *error= thd->is_error() ? thd->main_da.message() : ""; if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) @@ -3631,8 +3631,9 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS rather than in SHOW COLUMNS */ - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - thd->main_da.sql_errno(), thd->main_da.message()); + if (thd->is_error()) + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->main_da.sql_errno(), thd->main_da.message()); thd->clear_error(); res= 0; } -- cgit v1.2.1 From ec62aba3f054b6fd3eabe774fac0da825a8baf33 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 10 Mar 2008 11:12:12 +0100 Subject: Bug#34731: highest possible value for INT erroneously filtered by WHERE WHERE f1 < n ignored row if f1 was indexed integer column and f1 = TYPE_MAX ^ n = TYPE_MAX+1. The latter value when treated as TYPE overflowed (obviously). This was not handled, it is now. mysql-test/r/range.result: show that on an index int column, we no longer disregard a field val of TYPE_MAX in SELECT ... WHERE ... < TYPE_MAX+1 mysql-test/t/range.test: show that on an index int column, we no longer disregard a field val of TYPE_MAX in SELECT ... WHERE ... < TYPE_MAX+1 sql/opt_range.cc: Handle overflowing of int-types in range-optimizer. Unfortunately requires re-indentation of entire block. Overflow (err == 1) was handled, but only if field->cmp_type() != value->result_type(), which it just wasn't in our case. --- sql/opt_range.cc | 90 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 36 deletions(-) (limited to 'sql') diff --git a/sql/opt_range.cc b/sql/opt_range.cc index a8cf0f67635..c3eddbd0abf 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -4405,52 +4405,70 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, field->type() == FIELD_TYPE_DATETIME)) field->table->in_use->variables.sql_mode|= MODE_INVALID_DATES; err= value->save_in_field_no_warnings(field, 1); - if (err > 0 && field->cmp_type() != value->result_type()) + if (err > 0) { - if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && - value->result_type() == item_cmp_type(field->result_type(), - value->result_type())) - + if (field->cmp_type() != value->result_type()) { - tree= new (alloc) SEL_ARG(field, 0, 0); - tree->type= SEL_ARG::IMPOSSIBLE; - goto end; - } - else - { - /* - TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE - for the cases like int_field > 999999999999999999999999 as well. - */ - tree= 0; - if (err == 3 && field->type() == FIELD_TYPE_DATE && - (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || - type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) + if ((type == Item_func::EQ_FUNC || type == Item_func::EQUAL_FUNC) && + value->result_type() == item_cmp_type(field->result_type(), + value->result_type())) + { + tree= new (alloc) SEL_ARG(field, 0, 0); + tree->type= SEL_ARG::IMPOSSIBLE; + goto end; + } + else { /* - We were saving DATETIME into a DATE column, the conversion went ok - but a non-zero time part was cut off. + TODO: We should return trees of the type SEL_ARG::IMPOSSIBLE + for the cases like int_field > 999999999999999999999999 as well. + */ + tree= 0; + if (err == 3 && field->type() == FIELD_TYPE_DATE && + (type == Item_func::GT_FUNC || type == Item_func::GE_FUNC || + type == Item_func::LT_FUNC || type == Item_func::LE_FUNC) ) + { + /* + We were saving DATETIME into a DATE column, the conversion went ok + but a non-zero time part was cut off. - In MySQL's SQL dialect, DATE and DATETIME are compared as datetime - values. Index over a DATE column uses DATE comparison. Changing - from one comparison to the other is possible: + In MySQL's SQL dialect, DATE and DATETIME are compared as datetime + values. Index over a DATE column uses DATE comparison. Changing + from one comparison to the other is possible: - datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10' - datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10' + datetime(date_col)< '2007-12-10 12:34:55' -> date_col<='2007-12-10' + datetime(date_col)<='2007-12-10 12:34:55' -> date_col<='2007-12-10' - datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10' - datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10' + datetime(date_col)> '2007-12-10 12:34:55' -> date_col>='2007-12-10' + datetime(date_col)>='2007-12-10 12:34:55' -> date_col>='2007-12-10' - but we'll need to convert '>' to '>=' and '<' to '<='. This will - be done together with other types at the end of this function - (grep for field_is_equal_to_item) - */ + but we'll need to convert '>' to '>=' and '<' to '<='. This will + be done together with other types at the end of this function + (grep for field_is_equal_to_item) + */ + } + else + goto end; } - else - goto end; } - } - if (err < 0) + + /* + guaranteed at this point: err > 0; field and const of same type + If an integer got bounded (e.g. to within 0..255 / -128..127) + for < or >, set flags as for <= or >= (no NEAR_MAX / NEAR_MIN) + */ + else if (err == 1 && field->result_type() == INT_RESULT) + { + if (type == Item_func::LT_FUNC && (value->val_int() > 0)) + type = Item_func::LE_FUNC; + else if (type == Item_func::GT_FUNC && + !((Field_num*)field)->unsigned_flag && + !((Item_int*)value)->unsigned_flag && + (value->val_int() < 0)) + type = Item_func::GE_FUNC; + } + } + else if (err < 0) { field->table->in_use->variables.sql_mode= orig_sql_mode; /* This happens when we try to insert a NULL field in a not null column */ -- cgit v1.2.1 From 1836625fb4e42b1629b59a4f070d6849da2ee434 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 11 Mar 2008 14:42:54 +0100 Subject: BUG#31024: STOP SLAVE does not stop attempted connect()s Problem: if the IO slave thread is attempting to connect, STOP SLAVE waits for the attempt to finish. It may take a long time. Fix: don't wait, stop the slave immediately. sql/slave.cc: Send a SIGALRM signal to the slave thread when stopping it (using pthread_kill()). This breaks current socket(), connect(), poll() etc. calls, and makes the subsequent thd->awake() call effective. Also, move the definition of KICK_SLAVE to slave.cc. sql/sql_repl.h: Removed KICK_SLAVE and inlined it in slave.cc because: - it was only called once, so better to make it local to where it is used - it needed to include a preprocessor conditional in the middle --- sql/slave.cc | 15 ++++++++++++++- sql/sql_repl.h | 6 ------ 2 files changed, 14 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index d4d0655f366..5488b3c312a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -699,7 +699,20 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, while (*slave_running) // Should always be true { DBUG_PRINT("loop", ("killing slave thread")); - KICK_SLAVE(thd); + + pthread_mutex_lock(&thd->LOCK_delete); +#ifndef DONT_USE_THR_ALARM + /* + Error codes from pthread_kill are: + EINVAL: invalid signal number (can't happen) + ESRCH: thread already killed (can happen, should be ignored) + */ + IF_DBUG(int err= ) pthread_kill(thd->real_id, thr_client_alarm); + DBUG_ASSERT(err != EINVAL); +#endif + thd->awake(THD::NOT_KILLED); + pthread_mutex_unlock(&thd->LOCK_delete); + /* There is a small chance that slave thread might miss the first alarm. To protect againts it, resend the signal until it reacts diff --git a/sql/sql_repl.h b/sql/sql_repl.h index 1fbc6eb30cf..cf400218cc2 100644 --- a/sql/sql_repl.h +++ b/sql/sql_repl.h @@ -35,12 +35,6 @@ extern I_List binlog_do_db, binlog_ignore_db; extern int max_binlog_dump_events; extern my_bool opt_sporadic_binlog_dump_fail; -#define KICK_SLAVE(thd) do { \ - pthread_mutex_lock(&(thd)->LOCK_delete); \ - (thd)->awake(THD::NOT_KILLED); \ - pthread_mutex_unlock(&(thd)->LOCK_delete); \ - } while(0) - int start_slave(THD* thd, MASTER_INFO* mi, bool net_report); int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report); bool change_master(THD* thd, MASTER_INFO* mi); -- cgit v1.2.1 From 326c4e90589dd87792eacfa6e8746bc486a10ba0 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 16:13:33 +0300 Subject: A fix for Bug#34643: TRUNCATE crash if trigger and foreign key. In cases when TRUNCATE was executed by invoking mysql_delete() rather than by table recreation (for example, when TRUNCATE was issued on InnoDB table with is referenced by foreign key) triggers were invoked. In debug builds this also led to crash because of an assertion, which assumes that some preliminary actions take place before trigger invocation, which doesn't happen in case of TRUNCATE. The fix is not to execute triggers in mysql_delete() when this function is used by TRUNCATE. mysql-test/r/trigger-trans.result: Update result file. mysql-test/t/trigger-trans.test: A test case for Bug#34643: TRUNCATE crash if trigger and foreign key. sql/sql_delete.cc: Do not process triggers in TRUNCATE. --- sql/sql_delete.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a28a39a769d..3019b68d6f1 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -35,6 +35,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, READ_RECORD info; bool using_limit=limit != HA_POS_ERROR; bool transactional_table, safe_update, const_cond; + bool triggers_applicable; ha_rows deleted; uint usable_index= MAX_KEY; SELECT_LEX *select_lex= &thd->lex->select_lex; @@ -93,6 +94,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, select_lex->no_error= thd->lex->ignore; + /* NOTE: TRUNCATE must not invoke triggers. */ + + triggers_applicable= table->triggers && + thd->lex->sql_command != SQLCOM_TRUNCATE; + /* Test if the user wants to delete all rows and deletion doesn't have any side-effects (because of triggers), so we can use optimized @@ -102,8 +108,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (!using_limit && const_cond && (!conds || conds->val_int()) && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - (thd->lex->sql_command == SQLCOM_TRUNCATE || - !(table->triggers && table->triggers->has_delete_triggers())) + !(triggers_applicable && table->triggers->has_delete_triggers()) ) { deleted= table->file->records; @@ -217,7 +222,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, init_ftfuncs(thd, select_lex, 1); thd->proc_info="updating"; - if (table->triggers) + if (triggers_applicable) { table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE); if (table->triggers->has_triggers(TRG_EVENT_DELETE, @@ -239,7 +244,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!(select && select->skip_record())&& !thd->net.report_error ) { - if (table->triggers && + if (triggers_applicable && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) { @@ -250,7 +255,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (!(error=table->file->delete_row(table->record[0]))) { deleted++; - if (table->triggers && + if (triggers_applicable && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)) { -- cgit v1.2.1 From d80e7ce4e5e8aaae3473c617baaed5454bb520ed Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 16:50:24 +0300 Subject: Fix manual merge. --- sql/sql_delete.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 24eb109e6d9..7c3a046cb20 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -129,9 +129,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (!using_limit && const_cond_result && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - !triggers_applicable && - !thd->current_stmt_binlog_row_based && - !table->triggers->has_delete_triggers()) + !(triggers_applicable && + thd->current_stmt_binlog_row_based && + table->triggers->has_delete_triggers())) { /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); -- cgit v1.2.1 From b279be388e1d8208396ada701d3015b9d7cbbc4c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 17:44:40 +0300 Subject: Fix for Bug#33507: Event scheduler creates more threads than max_connections -- which results in user lockout. The problem was that the variable thread_count that contains the number of active threads was interpreted as a number of active connections. The fix is to introduce a new counter for active connections. mysql-test/r/connect.result: A test case for Bug#33507: Event scheduler creates more threads than max_connections -- which results in user lockout. mysql-test/t/connect.test: A test case for Bug#33507: Event scheduler creates more threads than max_connections -- which results in user lockout. sql/mysql_priv.h: 1. Polishing: login_connection() and end_connection() need not to be public. 2. Introduce connection_count -- a variable to contain the number of active connections. It is protected by LOCK_connection_count. sql/mysqld.cc: Use connection_count to count active connections. sql/sql_connect.cc: 1. Use connection_count to count active connections. 2. Make login_connection(), end_connection() private for the module as they had to be. --- sql/mysql_priv.h | 5 ++--- sql/mysqld.cc | 42 ++++++++++++++++++++++++++++++++++++++---- sql/sql_connect.cc | 13 +++++++------ 3 files changed, 47 insertions(+), 13 deletions(-) (limited to 'sql') diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b52e5aa745c..de40004fc6d 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -974,8 +974,6 @@ void time_out_user_resource_limits(THD *thd, USER_CONN *uc); void decrease_user_connections(USER_CONN *uc); void thd_init_client_charset(THD *thd, uint cs_number); bool setup_connection_thread_globals(THD *thd); -bool login_connection(THD *thd); -void end_connection(THD *thd); bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); @@ -1895,6 +1893,7 @@ extern bool opt_disable_networking, opt_skip_show_db; extern my_bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress; extern uint volatile thread_count, thread_running, global_read_lock; +extern uint connection_count; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_slave_compressed_protocol, use_temp_pool; @@ -1933,7 +1932,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_lock_db, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock, LOCK_global_system_variables, LOCK_user_conn, LOCK_prepared_stmt_count, - LOCK_bytes_sent, LOCK_bytes_received; + LOCK_bytes_sent, LOCK_bytes_received, LOCK_connection_count; #ifdef HAVE_OPENSSL extern pthread_mutex_t LOCK_des_key_file; #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cdd08be6573..fd9ce9e1cea 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -584,7 +584,8 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, - LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; + LOCK_user_conn, LOCK_slave_list, LOCK_active_mi, + LOCK_connection_count; /** The below lock protects access to two global server variables: max_prepared_stmt_count and prepared_stmt_count. These variables @@ -720,6 +721,11 @@ char *des_key_file; struct st_VioSSLFd *ssl_acceptor_fd; #endif /* HAVE_OPENSSL */ +/** + Number of currently active user connections. The variable is protected by + LOCK_connection_count. +*/ +uint connection_count= 0; /* Function declarations */ @@ -1341,6 +1347,7 @@ static void clean_up_mutexes() (void) pthread_mutex_destroy(&LOCK_bytes_sent); (void) pthread_mutex_destroy(&LOCK_bytes_received); (void) pthread_mutex_destroy(&LOCK_user_conn); + (void) pthread_mutex_destroy(&LOCK_connection_count); Events::destroy_mutexes(); #ifdef HAVE_OPENSSL (void) pthread_mutex_destroy(&LOCK_des_key_file); @@ -1783,6 +1790,11 @@ void unlink_thd(THD *thd) DBUG_ENTER("unlink_thd"); DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); thd->cleanup(); + + pthread_mutex_lock(&LOCK_connection_count); + --connection_count; + pthread_mutex_unlock(&LOCK_connection_count); + (void) pthread_mutex_lock(&LOCK_thread_count); thread_count--; delete thd; @@ -3453,6 +3465,7 @@ static int init_thread_environment() (void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_prepared_stmt_count, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST); + (void) pthread_mutex_init(&LOCK_connection_count, MY_MUTEX_INIT_FAST); #ifdef HAVE_OPENSSL (void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST); #ifndef HAVE_YASSL @@ -4700,6 +4713,11 @@ void create_thread_to_handle_connection(THD *thd) thread_count--; thd->killed= THD::KILL_CONNECTION; // Safety (void) pthread_mutex_unlock(&LOCK_thread_count); + + pthread_mutex_lock(&LOCK_connection_count); + --connection_count; + pthread_mutex_unlock(&LOCK_connection_count); + statistic_increment(aborted_connects,&LOCK_status); /* Can't use my_error() since store_globals has not been called. */ my_snprintf(error_message_buff, sizeof(error_message_buff), @@ -4739,15 +4757,31 @@ static void create_new_thread(THD *thd) if (protocol_version > 9) net->return_errno=1; - /* don't allow too many connections */ - if (thread_count - delayed_insert_threads >= max_connections+1 || abort_loop) + /* + Don't allow too many connections. We roughly check here that we allow + only (max_connections + 1) connections. + */ + + pthread_mutex_lock(&LOCK_connection_count); + + if (connection_count >= max_connections + 1 || abort_loop) { + pthread_mutex_unlock(&LOCK_connection_count); + DBUG_PRINT("error",("Too many connections")); close_connection(thd, ER_CON_COUNT_ERROR, 1); delete thd; DBUG_VOID_RETURN; } + + ++connection_count; + + pthread_mutex_unlock(&LOCK_connection_count); + + /* Start a new thread to handle connection. */ + pthread_mutex_lock(&LOCK_thread_count); + /* The initialization of thread_id is done in create_embedded_thd() for the embedded library. @@ -4755,13 +4789,13 @@ static void create_new_thread(THD *thd) */ thd->thread_id= thd->variables.pseudo_thread_id= thread_id++; - /* Start a new thread to handle connection */ thread_count++; if (thread_count - delayed_insert_threads > max_used_connections) max_used_connections= thread_count - delayed_insert_threads; thread_scheduler.add_connection(thd); + DBUG_VOID_RETURN; } #endif /* EMBEDDED_LIBRARY */ diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index b22a33e3e92..6f8cd6494cd 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -402,10 +402,11 @@ check_user(THD *thd, enum enum_server_command command, if (check_count) { - VOID(pthread_mutex_lock(&LOCK_thread_count)); - bool count_ok= thread_count <= max_connections + delayed_insert_threads - || (thd->main_security_ctx.master_access & SUPER_ACL); - VOID(pthread_mutex_unlock(&LOCK_thread_count)); + pthread_mutex_lock(&LOCK_connection_count); + bool count_ok= connection_count <= max_connections || + (thd->main_security_ctx.master_access & SUPER_ACL); + VOID(pthread_mutex_unlock(&LOCK_connection_count)); + if (!count_ok) { // too many connections my_error(ER_CON_COUNT_ERROR, MYF(0)); @@ -930,7 +931,7 @@ bool setup_connection_thread_globals(THD *thd) */ -bool login_connection(THD *thd) +static bool login_connection(THD *thd) { NET *net= &thd->net; int error; @@ -968,7 +969,7 @@ bool login_connection(THD *thd) This mainly updates status variables */ -void end_connection(THD *thd) +static void end_connection(THD *thd) { NET *net= &thd->net; plugin_thdvar_cleanup(thd); -- cgit v1.2.1 From b5978a9424c6213a8282713feb3734c2f92968c8 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 12:40:12 -0400 Subject: Bug#26703: DROP DATABASE fails if database contains a #mysql50# \ table with backticks (Thanks to Lu Jingdong, though I did not take his patch directly, as it contained a significant flaw.) It wasn't a backtick/parsing problem. We merely didn't anticipate and allocate enough space to handle the optional "#mysql50#" table- name prefix. Now, allocate that extra space in case we need it when we look up a legacy table to get its file's name. mysql-test/r/drop.result: Verify that databases with old-style files can be removed. mysql-test/t/drop.test: Verify that databases with old-style files can be removed. sql/sql_db.cc: Extend the size of the memory that holds the table's name, so that the legacy "mysql50" prefix fits. --- sql/sql_db.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_db.cc b/sql/sql_db.cc index d03ac7921ac..75f9f5e847d 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -1111,12 +1111,17 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, /* Drop the table nicely */ *extension= 0; // Remove extension TABLE_LIST *table_list=(TABLE_LIST*) - thd->calloc(sizeof(*table_list)+ strlen(db)+strlen(file->name)+2); + thd->calloc(sizeof(*table_list) + + strlen(db) + 1 + + MYSQL50_TABLE_NAME_PREFIX_LENGTH + + strlen(file->name) + 1); + if (!table_list) - goto err; + goto err; table_list->db= (char*) (table_list+1); table_list->table_name= strmov(table_list->db, db) + 1; VOID(filename_to_tablename(file->name, table_list->table_name, + MYSQL50_TABLE_NAME_PREFIX_LENGTH + strlen(file->name) + 1)); table_list->alias= table_list->table_name; // If lower_case_table_names=2 table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix); -- cgit v1.2.1 From 054341a6d07110dac1d05f023abd98bf7eaad39e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 12 Mar 2008 23:07:10 +0300 Subject: Fix manual merge. --- sql/sql_delete.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 7c3a046cb20..b9a7cd12662 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -103,10 +103,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, /* Error evaluating val_int(). */ DBUG_RETURN(TRUE); } - /* NOTE: TRUNCATE must not invoke triggers. */ - - triggers_applicable= table->triggers && - thd->lex->sql_command != SQLCOM_TRUNCATE; /* Test if the user wants to delete all rows and deletion doesn't have @@ -129,9 +125,9 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, */ if (!using_limit && const_cond_result && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && - !(triggers_applicable && - thd->current_stmt_binlog_row_based && - table->triggers->has_delete_triggers())) + (thd->lex->sql_command == SQLCOM_TRUNCATE || + (!thd->current_stmt_binlog_row_based && + !(table->triggers && table->triggers->has_delete_triggers())))) { /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -255,6 +251,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, init_ftfuncs(thd, select_lex, 1); thd_proc_info(thd, "updating"); + + /* NOTE: TRUNCATE must not invoke triggers. */ + + triggers_applicable= table->triggers && + thd->lex->sql_command != SQLCOM_TRUNCATE; + if (triggers_applicable && table->triggers->has_triggers(TRG_EVENT_DELETE, TRG_ACTION_AFTER)) -- cgit v1.2.1 From c167501bfb10d21a72bdf61ff59dc155280bc45e Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Mar 2008 12:02:12 +0300 Subject: Fix for Bug#35074: max_used_connections is not correct. The problem was that number of threads was used to calculate max_used_connections. The fix is to use number of active connections. mysql-test/r/connect.result: Update result file. mysql-test/t/connect.test: - Add a test case for Bug#35074: max_used_connections is not correct; - Make a test case for Bug#33507 more stable. sql/mysqld.cc: Use number of connections insetad of threads to calculate max_used_connections. --- sql/mysqld.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/mysqld.cc b/sql/mysqld.cc index fd9ce9e1cea..05f616dcd44 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4776,6 +4776,9 @@ static void create_new_thread(THD *thd) ++connection_count; + if (connection_count > max_used_connections) + max_used_connections= connection_count; + pthread_mutex_unlock(&LOCK_connection_count); /* Start a new thread to handle connection. */ @@ -4791,9 +4794,6 @@ static void create_new_thread(THD *thd) thread_count++; - if (thread_count - delayed_insert_threads > max_used_connections) - max_used_connections= thread_count - delayed_insert_threads; - thread_scheduler.add_connection(thd); DBUG_VOID_RETURN; -- cgit v1.2.1 From e85d6a915d242e8d39f021f4933c450323cec953 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 13 Mar 2008 16:39:27 +0100 Subject: Bug#33756 - query cache with concurrent_insert=0 appears broken When concurrent inserts were disabled, statements after an INSERT were not put into the query cache. This happened because we do not save the current data file length at statement start when concurrent inserts are disabled. But we checked the always zero local length against the real file length anyway. Fixed by doing the check only if concurrent inserts are not diabled. mysql-test/r/query_cache.result: Bug#33756 - query cache with concurrent_insert=0 appears broken Added test result. mysql-test/t/query_cache.test: Bug#33756 - query cache with concurrent_insert=0 appears broken Added test. sql/ha_myisam.cc: Bug#33756 - query cache with concurrent_insert=0 appears broken Changed code so that file length check is done only when concurrent inserts are possible. --- sql/ha_myisam.cc | 64 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 27 deletions(-) (limited to 'sql') diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 46afa7a8f45..8c8f027bb6b 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1954,6 +1954,7 @@ my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name, *engine_callback, ulonglong *engine_data) { + DBUG_ENTER("ha_myisam::register_query_cache_table"); /* No call back function is needed to determine if a cached statement is valid or not. @@ -1965,39 +1966,48 @@ my_bool ha_myisam::register_query_cache_table(THD *thd, char *table_name, */ *engine_data= 0; - /* - If a concurrent INSERT has happened just before the currently processed - SELECT statement, the total size of the table is unknown. + if (file->s->concurrent_insert) + { + /* + If a concurrent INSERT has happened just before the currently + processed SELECT statement, the total size of the table is + unknown. - To determine if the table size is known, the current thread's snap shot of - the table size with the actual table size are compared. + To determine if the table size is known, the current thread's snap + shot of the table size with the actual table size are compared. - If the table size is unknown the SELECT statement can't be cached. - */ - ulonglong actual_data_file_length; - ulonglong current_data_file_length; + If the table size is unknown the SELECT statement can't be cached. - /* - POSIX visibility rules specify that "2. Whatever memory values a - thread can see when it unlocks a mutex <...> can also be seen by any - thread that later locks the same mutex". In this particular case, - concurrent insert thread had modified the data_file_length in - MYISAM_SHARE before it has unlocked (or even locked) - structure_guard_mutex. So, here we're guaranteed to see at least that - value after we've locked the same mutex. We can see a later value - (modified by some other thread) though, but it's ok, as we only want - to know if the variable was changed, the actual new value doesn't matter - */ - actual_data_file_length= file->s->state.state.data_file_length; - current_data_file_length= file->save_state.data_file_length; + When concurrent inserts are disabled at table open, mi_open() + does not assign a get_status() function. In this case the local + ("current") status is never updated. We would wrongly think that + we cannot cache the statement. + */ + ulonglong actual_data_file_length; + ulonglong current_data_file_length; - if (current_data_file_length != actual_data_file_length) - { - /* Don't cache current statement. */ - return FALSE; + /* + POSIX visibility rules specify that "2. Whatever memory values a + thread can see when it unlocks a mutex <...> can also be seen by any + thread that later locks the same mutex". In this particular case, + concurrent insert thread had modified the data_file_length in + MYISAM_SHARE before it has unlocked (or even locked) + structure_guard_mutex. So, here we're guaranteed to see at least that + value after we've locked the same mutex. We can see a later value + (modified by some other thread) though, but it's ok, as we only want + to know if the variable was changed, the actual new value doesn't matter + */ + actual_data_file_length= file->s->state.state.data_file_length; + current_data_file_length= file->save_state.data_file_length; + + if (current_data_file_length != actual_data_file_length) + { + /* Don't cache current statement. */ + DBUG_RETURN(FALSE); + } } /* It is ok to try to cache current statement. */ - return TRUE; + DBUG_RETURN(TRUE); } #endif -- cgit v1.2.1 From d5f09a13def2462127a1b3c3f268866136f748d5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 10:03:01 +0800 Subject: BUG#33029 5.0 to 5.1 replication fails on dup key when inserting using a trig in SP For all 5.0 and up to 5.1.12 exclusive, when a stored routine or trigger caused an INSERT into an AUTO_INCREMENT column, the generated AUTO_INCREMENT value should not be written into the binary log, which means if a statement does not generate AUTO_INCREMENT value itself, there will be no Intvar event (SET INSERT_ID) associated with it even if one of the stored routine or trigger caused generation of such a value. And meanwhile, when executing a stored routine or trigger, it would ignore the INSERT_ID value even if there is a INSERT_ID value available set by a SET INSERT_ID statement. Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is written into the binary log, and the value will be used if available when executing the stored routine or trigger. Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12 (referenced as the buggy versions in the text below), when a statement that generates AUTO_INCREMENT value by the top statement was executed in the body of a SP, all statements in the SP after this statement would be treated as if they had generated AUTO_INCREMENT by the top statement. When a statement that did not generate AUTO_INCREMENT value by the top statement but by a function/trigger called by it, an erroneous Intvar event would be associated with the statement, this erroneous INSERT_ID value wouldn't cause problem when replicating between masters and slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID value was not used when executing functions/triggers. But when replicating from buggy versions to 5.1.12 or newer, which will use the INSERT_ID value in functions/triggers, the erroneous value will be used, which would cause duplicate entry error and cause the slave to stop. The patch for 5.0 fixed it not to generate the erroneous Intvar event, another patch for 5.1 fixed it to ignore the SET INSERT_ID value when executing functions/triggers if it is replicating from a master of buggy versions. mysql-test/include/show_binlog_events.inc: add $binlog_start parameter to set the start position when show binlog events, if not set a default value will be used. mask out column 2(Pos), 4(Server_id), table_id, and file_id sql/sql_class.cc: Reset insert_id_used after each query in SP mysql-test/r/rpl_auto_increment_bug33029.result: Add test for bug33029, test if the master generate the erroneous event or not mysql-test/t/rpl_auto_increment_bug33029.test: Add test for bug33029, test if the master generate the erroneous event or not --- sql/sql_class.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e36ed0c425f..f541c8b3677 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -622,6 +622,13 @@ void THD::cleanup_after_query() { clear_next_insert_id= 0; next_insert_id= 0; + + /* + BUG#33029, if one statement in a SP set this member to 1, all + statment after this statement in the SP would be considered used + INSERT_ID value, reset this member after each query to fix this. + */ + insert_id_used= 0; } /* Reset rand_used so that detection of calls to rand() will save random -- cgit v1.2.1 From f21ee5d00dd67e95a86e2c1776cd187a16760528 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 11:35:41 +0800 Subject: BUG#33029 5.0 to 5.1 replication fails on dup key when inserting using a trig in SP For all 5.0 and up to 5.1.12 exclusive, when a stored routine or trigger caused an INSERT into an AUTO_INCREMENT column, the generated AUTO_INCREMENT value should not be written into the binary log, which means if a statement does not generate AUTO_INCREMENT value itself, there will be no Intvar event (SET INSERT_ID) associated with it even if one of the stored routine or trigger caused generation of such a value. And meanwhile, when executing a stored routine or trigger, it would ignore the INSERT_ID value even if there is a INSERT_ID value available set by a SET INSERT_ID statement. Starting from MySQL 5.1.12, the generated AUTO_INCREMENT value is written into the binary log, and the value will be used if available when executing the stored routine or trigger. Prior fix of this bug in MySQL 5.0 and prior MySQL 5.1.12 (referenced as the buggy versions in the text below), when a statement that generates AUTO_INCREMENT value by the top statement was executed in the body of a SP, all statements in the SP after this statement would be treated as if they had generated AUTO_INCREMENT by the top statement. When a statement that did not generate AUTO_INCREMENT value by the top statement but by a function/trigger called by it, an erroneous Intvar event would be associated with the statement, this erroneous INSERT_ID value wouldn't cause problem when replicating between masters and slaves of 5.0.x or prior 5.1.12, because the erroneous INSERT_ID value was not used when executing functions/triggers. But when replicating from buggy versions to 5.1.12 or newer, which will use the INSERT_ID value in functions/triggers, the erroneous value will be used, which would cause duplicate entry error and cause the slave to stop. The patch for 5.1 fixed it to ignore the SET INSERT_ID value when executing functions/triggers if it is replicating from a master of buggy versions, another patch for 5.0 fixed it not to generate the erroneous Intvar event. mysql-test/include/show_binlog_events.inc: add $binlog_start parameter to show binlog events from a given position sql/slave.cc: Add function to check for bug#33029 sql/slave.h: Add function to check for bug#33029 sql/sql_class.cc: if master has bug#33029, reset auto_inc_intervals_forced for sub statements add a new function Discrete_intervals_list::append that takes a Discrete_interval as argument sql/sql_class.h: Add member to save and restore auto_inc_intervals_forced sql/structs.h: add copy constructor and assignment operator for Discrete_intervals_list add a new function Discrete_intervals_list::append that takes a Discrete_interval as argument mysql-test/std_data/bug33029-slave-relay-bin.000001: relay logs from a buggy 5.0 master for test case of BUG#33029 mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result: Test if the slave can process relay logs from a buggy master of BUG#33029 mysql-test/suite/binlog/t/binlog_auto_increment_bug33029-master.opt: Test if the slave can process relay logs from a buggy master of BUG#33029 mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test: Test if the slave can process relay logs from a buggy master of BUG#33029 --- sql/slave.cc | 30 ++++++++++++++++++++++++++++-- sql/slave.h | 3 ++- sql/sql_class.cc | 50 +++++++++++++++++++++++++++++++++++++++++--------- sql/sql_class.h | 1 + sql/structs.h | 21 +++++++++++++++++++++ 5 files changed, 93 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/slave.cc b/sql/slave.cc index e3a333f31d1..96419a00f18 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -4026,9 +4026,10 @@ end: has a certain bug. @param rli Relay_log_info which tells the master's version @param bug_id Number of the bug as found in bugs.mysql.com + @param report bool report error message, default TRUE @return TRUE if master has the bug, FALSE if it does not. */ -bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id) +bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id, bool report) { struct st_version_range_for_one_bug { uint bug_id; @@ -4038,7 +4039,9 @@ bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id) static struct st_version_range_for_one_bug versions_for_all_bugs[]= { {24432, { 5, 0, 24 }, { 5, 0, 38 } }, - {24432, { 5, 1, 12 }, { 5, 1, 17 } } + {24432, { 5, 1, 12 }, { 5, 1, 17 } }, + {33029, { 5, 0, 0 }, { 5, 0, 58 } }, + {33029, { 5, 1, 0 }, { 5, 1, 12 } }, }; const uchar *master_ver= rli->relay_log.description_event_for_exec->server_version_split; @@ -4054,6 +4057,9 @@ bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id) (memcmp(introduced_in, master_ver, 3) <= 0) && (memcmp(fixed_in, master_ver, 3) > 0)) { + if (!report) + return TRUE; + // a short message for SHOW SLAVE STATUS (message length constraints) my_printf_error(ER_UNKNOWN_ERROR, "master may suffer from" " http://bugs.mysql.com/bug.php?id=%u" @@ -4085,6 +4091,26 @@ bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id) return FALSE; } +/** + BUG#33029, For all 5.0 up to 5.0.58 exclusive, and 5.1 up to 5.1.12 + exclusive, if one statement in a SP generated AUTO_INCREMENT value + by the top statement, all statements after it would be considered + generated AUTO_INCREMENT value by the top statement, and a + erroneous INSERT_ID value might be associated with these statement, + which could cause duplicate entry error and stop the slave. + + Detect buggy master to work around. + */ +bool rpl_master_erroneous_autoinc(THD *thd) +{ + if (active_mi && active_mi->rli.sql_thd == thd) + { + Relay_log_info *rli= &active_mi->rli; + return rpl_master_has_bug(rli, 33029, FALSE); + } + return FALSE; +} + #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION template class I_List_iterator; template class I_List_iterator; diff --git a/sql/slave.h b/sql/slave.h index b4f1b7f7467..80d267e5b27 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -165,7 +165,8 @@ int fetch_master_table(THD* thd, const char* db_name, const char* table_name, bool show_master_info(THD* thd, Master_info* mi); bool show_binlog_info(THD* thd); -bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id); +bool rpl_master_has_bug(Relay_log_info *rli, uint bug_id, bool report=TRUE); +bool rpl_master_erroneous_autoinc(THD* thd); const char *print_slave_db_safe(const char *db); int check_expected_error(THD* thd, Relay_log_info const *rli, int error_code); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 044ea70e994..10c65f18a35 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -28,6 +28,7 @@ #include "mysql_priv.h" #include "rpl_rli.h" #include "rpl_record.h" +#include "slave.h" #include #include "log_event.h" #include @@ -2827,6 +2828,18 @@ extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all) void THD::reset_sub_statement_state(Sub_statement_state *backup, uint new_state) { +#ifndef EMBEDDED_LIBRARY + /* BUG#33029, if we are replicating from a buggy master, reset + auto_inc_intervals_forced to prevent substatement + (triggers/functions) from using erroneous INSERT_ID value + */ + if (rpl_master_erroneous_autoinc(this)) + { + backup->auto_inc_intervals_forced= auto_inc_intervals_forced; + auto_inc_intervals_forced.empty(); + } +#endif + backup->options= options; backup->in_sub_stmt= in_sub_stmt; backup->enable_slow_log= enable_slow_log; @@ -2864,6 +2877,18 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { +#ifndef EMBEDDED_LIBRARY + /* BUG#33029, if we are replicating from a buggy master, restore + auto_inc_intervals_forced so that the top statement can use the + INSERT_ID value set before this statement. + */ + if (rpl_master_erroneous_autoinc(this)) + { + auto_inc_intervals_forced= backup->auto_inc_intervals_forced; + backup->auto_inc_intervals_forced.empty(); + } +#endif + /* To save resources we want to release savepoints which were created during execution of function or trigger before leaving their savepoint @@ -3569,17 +3594,24 @@ bool Discrete_intervals_list::append(ulonglong start, ulonglong val, { /* it cannot, so need to add a new interval */ Discrete_interval *new_interval= new Discrete_interval(start, val, incr); - if (unlikely(new_interval == NULL)) // out of memory - DBUG_RETURN(1); - DBUG_PRINT("info",("adding new auto_increment interval")); - if (head == NULL) - head= current= new_interval; - else - tail->next= new_interval; - tail= new_interval; - elements++; + DBUG_RETURN(append(new_interval)); } DBUG_RETURN(0); } +bool Discrete_intervals_list::append(Discrete_interval *new_interval) +{ + DBUG_ENTER("Discrete_intervals_list::append"); + if (unlikely(new_interval == NULL)) + DBUG_RETURN(1); + DBUG_PRINT("info",("adding new auto_increment interval")); + if (head == NULL) + head= current= new_interval; + else + tail->next= new_interval; + tail= new_interval; + elements++; + DBUG_RETURN(0); +} + #endif /* !defined(MYSQL_CLIENT) */ diff --git a/sql/sql_class.h b/sql/sql_class.h index b660c615920..dfd9879b98f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -911,6 +911,7 @@ public: ulonglong first_successful_insert_id_in_prev_stmt; ulonglong first_successful_insert_id_in_cur_stmt, insert_id_for_cur_row; Discrete_interval auto_inc_interval_for_cur_row; + Discrete_intervals_list auto_inc_intervals_forced; ulonglong limit_found_rows; ha_rows cuted_fields, sent_row_count, examined_row_count; ulong client_capabilities; diff --git a/sql/structs.h b/sql/structs.h index f14cca3c5db..809175fdde4 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -314,8 +314,27 @@ private: */ Discrete_interval *current; uint elements; // number of elements + + /* helper function for copy construct and assignment operator */ + void copy_(const Discrete_intervals_list& from) + { + for (Discrete_interval *i= from.head; i; i= i->next) + { + Discrete_interval j= *i; + append(&j); + } + } public: Discrete_intervals_list() : head(NULL), current(NULL), elements(0) {}; + Discrete_intervals_list(const Discrete_intervals_list& from) + { + copy_(from); + } + void operator=(const Discrete_intervals_list& from) + { + empty(); + copy_(from); + } void empty_no_free() { head= current= NULL; @@ -331,6 +350,7 @@ public: } empty_no_free(); } + const Discrete_interval* get_next() { Discrete_interval *tmp= current; @@ -340,6 +360,7 @@ public: } ~Discrete_intervals_list() { empty(); }; bool append(ulonglong start, ulonglong val, ulonglong incr); + bool append(Discrete_interval *interval); ulonglong minimum() const { return (head ? head->minimum() : 0); }; ulonglong maximum() const { return (head ? tail->maximum() : 0); }; uint nb_elements() const { return elements; } -- cgit v1.2.1 From 45b4d937c6bb7e1483c1fdbaf15bcb20a08ae683 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 14:12:39 +0400 Subject: Bug#35108 SELECT FROM REFERENTIAL_CONSTRAINTS crashes referenced_key_name field can be uninitialized in the case when referenced table is dropped. Added codition which allows to handle this situation. mysql-test/r/information_schema_inno.result: test result mysql-test/t/information_schema_inno.test: test result sql/sql_show.cc: referenced_key_name field can be uninitialized in the case when referenced table is dropped. Added codition which allows to handle this situation. --- sql/sql_show.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 6e61ee6da5f..6becbe12ed4 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5276,8 +5276,14 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, f_key_info->referenced_db->length, cs); table->field[10]->store(f_key_info->referenced_table->str, f_key_info->referenced_table->length, cs); - table->field[5]->store(f_key_info->referenced_key_name->str, - f_key_info->referenced_key_name->length, cs); + if (f_key_info->referenced_key_name) + { + table->field[5]->store(f_key_info->referenced_key_name->str, + f_key_info->referenced_key_name->length, cs); + table->field[5]->set_notnull(); + } + else + table->field[5]->set_null(); table->field[6]->store(STRING_WITH_LEN("NONE"), cs); table->field[7]->store(f_key_info->update_method->str, f_key_info->update_method->length, cs); @@ -6480,8 +6486,8 @@ ST_FIELD_INFO referential_constraints_fields_info[]= OPEN_FULL_TABLE}, {"UNIQUE_CONSTRAINT_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, - {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, - OPEN_FULL_TABLE}, + {"UNIQUE_CONSTRAINT_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, + MY_I_S_MAYBE_NULL, 0, OPEN_FULL_TABLE}, {"MATCH_OPTION", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"UPDATE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, {"DELETE_RULE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, OPEN_FULL_TABLE}, -- cgit v1.2.1 From 9fa2d50559383785c72656dcdffa878cc3563da9 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 14:03:47 +0100 Subject: Post-merge fix. Moved the symlink handling from sql_parse.cc here. mysql-test/r/symlink.result: Post-merge fix mysql-test/t/symlink.test: Post-merge fix --- sql/sql_table.cc | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 18d8ae68008..b42045446d3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3517,8 +3517,26 @@ bool mysql_create_table_no_lock(THD *thd, create_info->table_existed= 0; // Mark that table is created #ifdef HAVE_READLINK + if (test_if_data_home_dir(create_info->data_file_name)) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY"); + goto unlock_and_end; + } + if (test_if_data_home_dir(create_info->index_file_name)) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY"); + goto unlock_and_end; + } + +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (check_partition_dirs(thd->lex->part_info)) + { + goto unlock_and_end; + } +#endif /* WITH_PARTITION_STORAGE_ENGINE */ + if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) -#endif +#endif /* HAVE_READLINK */ { if (create_info->data_file_name) push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, -- cgit v1.2.1 From 196b616accbc73d212f21e2ec84353931a2f286b Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 19:38:22 +0400 Subject: BUG#28248 - mysqldump results with MERGE ... UNION=() cannot be executed When there are no underlying tables specified for a merge table, SHOW CREATE TABLE outputs a statement that cannot be executed. The same is true for mysqldump (it generates dumps that cannot be executed). This happens because SQL parser does not accept empty UNION() clause. This patch changes the following: - it is now possible to execute CREATE/ALTER statement with empty UNION() clause. - the same as above, but still worth noting: it is now possible to remove underlying tables mapping using ALTER TABLE ... UNION=(). - SHOW CREATE TABLE does not output UNION() clause if there are no underlying tables specified for a merge table. This makes mysqldump slightly smaller. mysql-test/r/merge.result: A test case for BUG#28248. mysql-test/t/merge.test: A test case for BUG#28248. sql/ha_myisammrg.cc: Do not output UNION clause in SHOW CREATE TABLE, when there are no underlying tables defined. sql/sql_yacc.yy: Make underlying table list for MERGE engine optional. As for MERGE engine empty underlying tables list is valid, it should be valid for the parser as well. This change is mostly needed to restore dumps made by earlier MySQL versions. Also with this fix it is possible to remove underlying tables mapping by using ALTER TABLE ... UNION=(). --- sql/ha_myisammrg.cc | 6 ++++++ sql/sql_yacc.yy | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 78492d2843d..b796978f352 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -602,6 +602,12 @@ void ha_myisammrg::append_create_info(String *packet) packet->append(STRING_WITH_LEN(" INSERT_METHOD=")); packet->append(get_type(&merge_insert_method,file->merge_insert_method-1)); } + /* + There is no sence adding UNION clause in case there is no underlying + tables specified. + */ + if (file->open_tables == file->end_table) + return; packet->append(STRING_WITH_LEN(" UNION=(")); MYRG_TABLE *open_table,*first; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 04285fea227..b877a789732 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2932,7 +2932,7 @@ create_table_option: my_error(ER_WARN_DEPRECATED_SYNTAX, MYF(0), "RAID_CHUNKSIZE", "PARTITION"); MYSQL_YYABORT; } - | UNION_SYM opt_equal '(' table_list ')' + | UNION_SYM opt_equal '(' opt_table_list ')' { /* Move the union list to the merge_list */ LEX *lex=Lex; -- cgit v1.2.1 From 4597814717f4ae503923ad5ea7aacae3a95b6435 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 17:52:57 +0100 Subject: Post-merge fixes. mysql-test/extra/rpl_tests/rpl_loaddata.test: Removing SHOW MASTER STATUS that does not seem to make sense. mysql-test/extra/rpl_tests/rpl_log.test: Correcting test case to sync slave with master. mysql-test/suite/binlog/r/binlog_unsafe.result: Result change. mysql-test/suite/binlog/t/binlog_unsafe.test: Removing unsafe variable from list of safe variables. mysql-test/suite/rpl/r/rpl_loaddata.result: Result change. mysql-test/suite/rpl/r/rpl_skip_error.result: Result change. mysql-test/suite/rpl/t/rpl_skip_error.test: Correcting bad manual+automatic merge. Test is now only relevant for statement- based replication. sql/rpl_rli.cc: Correcting automerge undoing previous change of return value. Relay_log_info::wait_for_pos() should return -2 when not initialized to work correctly. --- sql/rpl_rli.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 03f790b934f..bd8246b066f 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -615,7 +615,7 @@ int Relay_log_info::wait_for_pos(THD* thd, String* log_name, DBUG_ENTER("Relay_log_info::wait_for_pos"); if (!inited) - DBUG_RETURN(-1); + DBUG_RETURN(-2); DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu", log_name->c_ptr(), (ulong) log_pos, (ulong) timeout)); -- cgit v1.2.1 From 9699767c952bf30ab4b18a15e131ba417745f855 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 23:11:59 +0400 Subject: Fixed bug #34763. Queries like: SELECT ROW(1, 2) IN (SELECT t1.a, 2) FROM t1 GROUP BY t1.a or SELECT ROW(1, 2) IN (SELECT t1.a, 2 FROM t2) FROM t1 GROUP BY t1.a lead to assertion failure in the Item_in_subselect::row_value_transformer method in debugging build, or to unexpected error message in release build: ERROR 1247 (42S22): Reference '' not supported (forward reference in item list) Unexpected error message and assertion failure have been eliminated. mysql-test/r/subselect3.result: Added test case for bug #34763. mysql-test/t/subselect3.test: Added test case for bug #34763. sql/item.cc: Fixed bug #34763. The Item_ref::fix_fields method has been modified to silently ignore not fixed outer references: by the definition, those references should be fixed later by the call to the fix_inner_refs function. sql/item_subselect.cc: Fixed bug #34763. The Item_in_subselect::row_value_transformer method has been modified to eliminate assertion failure on not fixed outer references: by the definition those references are allowed in this context and should be fixed later by the call to the fix_inner_refs function. --- sql/item.cc | 15 +++++++++------ sql/item_subselect.cc | 12 ++++++++++-- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 53e7f124ccd..36612ddea44 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5451,13 +5451,16 @@ bool Item_ref::fix_fields(THD *thd, Item **reference) DBUG_ASSERT(*ref); /* Check if this is an incorrect reference in a group function or forward - reference. Do not issue an error if this is an unnamed reference inside an - aggregate function. + reference. Do not issue an error if this is: + 1. outer reference (will be fixed later by the fix_inner_refs function); + 2. an unnamed reference inside an aggregate function. */ - if (((*ref)->with_sum_func && name && - !(current_sel->linkage != GLOBAL_OPTIONS_TYPE && - current_sel->having_fix_field)) || - !(*ref)->fixed) + if (!((*ref)->type() == REF_ITEM && + ((Item_ref *)(*ref))->ref_type() == OUTER_REF) && + (((*ref)->with_sum_func && name && + !(current_sel->linkage != GLOBAL_OPTIONS_TYPE && + current_sel->having_fix_field)) || + !(*ref)->fixed)) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, ((*ref)->with_sum_func? diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b3710841dfb..a03a7d739b2 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1232,7 +1232,11 @@ Item_in_subselect::row_value_transformer(JOIN *join) Item *item_having_part2= 0; for (uint i= 0; i < cols_num; i++) { - DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); + DBUG_ASSERT(left_expr->fixed && + select_lex->ref_pointer_array[i]->fixed || + (select_lex->ref_pointer_array[i]->type() == REF_ITEM && + ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == + Item_ref::OUTER_REF)); if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); @@ -1306,7 +1310,11 @@ Item_in_subselect::row_value_transformer(JOIN *join) for (uint i= 0; i < cols_num; i++) { Item *item, *item_isnull; - DBUG_ASSERT(left_expr->fixed && select_lex->ref_pointer_array[i]->fixed); + DBUG_ASSERT(left_expr->fixed && + select_lex->ref_pointer_array[i]->fixed || + (select_lex->ref_pointer_array[i]->type() == REF_ITEM && + ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == + Item_ref::OUTER_REF)); if (select_lex->ref_pointer_array[i]-> check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); -- cgit v1.2.1 From 063b50477296f20b22e5cc5c1f50b8302ef55c19 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 14 Mar 2008 17:40:12 -0300 Subject: Bug#35103 mysql_client_test::test_bug29948 causes sporadic failures The problem was that the COM_STMT_SEND_LONG_DATA was sending a response packet if the prepared statement wasn't found in the server (due to reconnection). The commands COM_STMT_SEND_LONG_DATA and COM_STMT_CLOSE should not send any packets, even error packets should not be sent since they are not expected by the client API. The solution is to clear generated during the execution of the aforementioned commands and to skip resend of prepared statement commands. Another fix is that if the connection breaks during the send of prepared statement command, the command is not sent again since the prepared statement is no longer in the server. libmysql/libmysql.c: The mysql handle might be reset after a reconnection. Pass the now used stmt argument to cli_advanced_command. sql-common/client.c: Don't resend command if the connection broke and it's a prepared statement command. If the session is broken, prepared statements on the server are gone, set the error accordanly. sql/sql_prepare.cc: Clear any error set during the execution of the request command. tests/mysql_client_test.c: Fix memory leak by freeing result associated with statement. Remove test case for Bug 29948 because it's not reliable in 5.0 (fixed in 5.1) due to KILL queries sending two packets for a thread that kills itself. --- sql/sql_prepare.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 18cfd8d7dfc..207183f567c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2516,7 +2516,7 @@ void mysql_stmt_close(THD *thd, char *packet) DBUG_ENTER("mysql_stmt_close"); if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) - DBUG_VOID_RETURN; + goto out; /* The only way currently a statement can be deallocated when it's @@ -2525,6 +2525,9 @@ void mysql_stmt_close(THD *thd, char *packet) DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE)); (void) stmt->deallocate(); +out: + /* clear errors, response packet is not expected */ + thd->clear_error(); DBUG_VOID_RETURN; } @@ -2591,10 +2594,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) #ifndef EMBEDDED_LIBRARY /* Minimal size of long data packet is 6 bytes */ if (packet_length <= MYSQL_LONG_DATA_HEADER) - { - my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data"); - DBUG_VOID_RETURN; - } + goto out; #endif stmt_id= uint4korr(packet); @@ -2614,7 +2614,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) stmt->last_errno= ER_WRONG_ARGUMENTS; sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "mysql_stmt_send_long_data"); - DBUG_VOID_RETURN; + goto out; } #endif @@ -2630,6 +2630,10 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) stmt->last_errno= ER_OUTOFMEMORY; sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0); } + +out: + /* clear errors, response packet is not expected */ + thd->clear_error(); DBUG_VOID_RETURN; } -- cgit v1.2.1 From 23d567aa7cb01811294a24ecda100d2a90fe8acf Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 11:16:37 -0300 Subject: Post-merge fix for Bug 35103. sql/sql_prepare.cc: Don't send unexpected error to the client. --- sql/sql_prepare.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 207183f567c..b00606aba4a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2602,7 +2602,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length) if (!(stmt=find_prepared_statement(thd, stmt_id, "mysql_stmt_send_long_data"))) - DBUG_VOID_RETURN; + goto out; param_number= uint2korr(packet); packet+= 2; -- cgit v1.2.1 From 1bb10ccfb1344ae00f3874e4a725d876e03463b7 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 15:56:53 +0100 Subject: Valgrind warnings found after bug#32943 and after merge from -main into -engines tree. hander::table_share was not updated after changing table->s. sql/ha_partition.cc: Valgrind warning after merge -main -> -engines, after bug#32943 change_table_ptr can happen in a middle of alter table rename/drop/... partition the newly created partitions must get the updated table_share too. sql/sql_base.cc: Bug#32943 was missing a call to change_table_ptr, this was found by valgrind after a merge from -main to -engines. --- sql/ha_partition.cc | 9 +++++++++ sql/sql_base.cc | 1 + 2 files changed, 10 insertions(+) (limited to 'sql') diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 64bee07aa1c..ae7e2215517 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1646,6 +1646,15 @@ void ha_partition::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share) { (*file_array)->change_table_ptr(table_arg, share); } while (*(++file_array)); + if (m_added_file && m_added_file[0]) + { + /* if in middle of a drop/rename etc */ + file_array= m_added_file; + do + { + (*file_array)->change_table_ptr(table_arg, share); + } while (*(++file_array)); + } } /* diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 01e0009ad0d..ba4f695dcb8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -747,6 +747,7 @@ void close_handle_and_leave_table_as_lock(TABLE *table) table->db_stat= 0; // Mark file closed release_table_share(table->s, RELEASE_NORMAL); table->s= share; + table->file->change_table_ptr(table, table->s); DBUG_VOID_RETURN; } -- cgit v1.2.1 From 166357b552fe777bc509ffcaeafeeeb5f0e3deed Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 16:11:26 +0100 Subject: Bug#35305: partition_symlink test failures Updated the test due to bug 32167 Corrected spelling of error message mysql-test/r/partition_not_windows.result: Updated test result due to test case changes and corrected spelling error mysql-test/r/partition_symlink.result: Bug#35305: partition_symlink test failure Updated test result due to test case changes mysql-test/r/symlink.result: Updated test result due to test case changes and corrected spelling error mysql-test/t/disabled.def: Bug#35305: partition_symlink test failure Enable the test after it has been fixed mysql-test/t/partition_not_windows.test: Removed disable/enable_query_log for better result files mysql-test/t/partition_symlink.test: Bug#35305: partition_symlink test failure Changes due to bug 32167 mysql-test/t/symlink.test: using replace_result instead of disable_query_log sql/partition_info.cc: corrected spelling sql/sql_parse.cc: corrected spelling --- sql/partition_info.cc | 4 ++-- sql/sql_parse.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/partition_info.cc b/sql/partition_info.cc index e7f4d6a62c1..8feac884c77 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1312,11 +1312,11 @@ bool check_partition_dirs(partition_info *part_info) return 0; dd_err: - my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECORY"); + my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECTORY"); return 1; id_err: - my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECORY"); + my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECTORY"); return 1; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index fb81718ff02..f2e0065f860 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2354,13 +2354,13 @@ mysql_execute_command(THD *thd) if (test_if_data_home_dir(lex->create_info.data_file_name)) { - my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECORY"); + my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECTORY"); res= -1; break; } if (test_if_data_home_dir(lex->create_info.index_file_name)) { - my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECORY"); + my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECTORY"); res= -1; break; } -- cgit v1.2.1 From 6cf64b26d8eedae3e744335736aee44975899c19 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 20:19:04 +0200 Subject: Bug #18199 PURGE BINARY LOGS fails silently with missing logs; Bug #18453 Warning/error message if there is a mismatch between ... There were three problems: 1. the reported lack of warnings for the BEFORE syntax of PURGE; 2. the similar lack of warnings for the TO syntax; 3. incompatible behaviour between the two in that the latter blanked out regardlessly of presence or lack the actual file corresponding to an index record; the former version gave up at the first mismatch. fixed with deploying the warning's generation and synronizing logics of purge_logs() and purge_logs_before_date(). my_stat() is called in either of two branches of purge_logs() (responsible for the TO syntax of PURGE) similarly to how it has behaved in the BEFORE syntax. If there is no actual binlog file, my_stat returns NULL and my_delete is not invoked. A critical error is reported to the user if a file from the index could not be retrieved info about or deleted with a system error code different than ENOENT. sql/log.cc: generating warning in two functions. refining logics to call my_stat() by purge_logs() as it happens in purge_logs_before_date(). my_delete() is called only if my_stat() ensured existance of the file. A critical error is reported to the user if a file from the index could not be my_stat():ed or my_delete():d with an error different than ENOENT. sql/share/errmsg.txt: new error message mysql-test/include/show_binary_logs.inc: a new macro - shortcut of show binary logs mysql-test/r/binlog_index.result: new results mysql-test/t/binlog_index.test: a regression test for the bugs --- sql/log.cc | 153 ++++++++++++++++++++++++++++++++++++++++++--------- sql/share/errmsg.txt | 2 + 2 files changed, 129 insertions(+), 26 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 0376facb473..1924821c91c 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1180,6 +1180,8 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads) RETURN VALUES 0 ok LOG_INFO_EOF to_log not found + LOG_INFO_FATAL if any other than ENOENT error from + my_stat() or my_delete() */ int MYSQL_LOG::purge_logs(const char *to_log, @@ -1208,33 +1210,75 @@ int MYSQL_LOG::purge_logs(const char *to_log, while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) && !log_in_use(log_info.log_file_name)) { - ulong file_size= 0; - if (decrease_log_space) //stat the file we want to delete + MY_STAT s; + if (!my_stat(log_info.log_file_name, &s, MYF(0))) { - MY_STAT s; - - /* - If we could not stat, we can't know the amount - of space that deletion will free. In most cases, - deletion won't work either, so it's not a problem. - */ - if (my_stat(log_info.log_file_name,&s,MYF(0))) - file_size= s.st_size; - else - sql_print_information("Failed to execute my_stat on file '%s'", + if (my_errno == ENOENT) + { + /* + It's not fatal if we can't stat a log file that does not exist; + If we could not stat, we won't delete. + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to execute my_stat on file '%s'", log_info.log_file_name); + my_errno= 0; + } + else + { + /* + Other than ENOENT are fatal + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } + else + { + DBUG_PRINT("info",("purging %s",log_info.log_file_name)); + if (!my_delete(log_info.log_file_name, MYF(0))) + { + if (decrease_log_space) + *decrease_log_space-= s.st_size; + } + else + { + if (my_errno == ENOENT) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to delete file '%s'", + log_info.log_file_name); + my_errno= 0; + } + else + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } } - /* - It's not fatal if we can't delete a log file ; - if we could delete it, take its size into account - */ - DBUG_PRINT("info",("purging %s",log_info.log_file_name)); - if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space) - *decrease_log_space-= file_size; if (find_next_log(&log_info, 0) || exit_loop) break; } - + /* If we get killed -9 here, the sysadmin would have to edit the log index file after restart - otherwise, this should be safe @@ -1263,6 +1307,8 @@ err: RETURN VALUES 0 ok LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated + LOG_INFO_FATAL if any other than ENOENT error from + my_stat() or my_delete() */ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) @@ -1286,11 +1332,66 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time) while (strcmp(log_file_name, log_info.log_file_name) && !log_in_use(log_info.log_file_name)) { - /* It's not fatal even if we can't delete a log file */ - if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)) || - stat_area.st_mtime >= purge_time) - break; - my_delete(log_info.log_file_name, MYF(0)); + if (!my_stat(log_info.log_file_name, &stat_area, MYF(0))) + { + if (my_errno == ENOENT) + { + /* + It's not fatal if we can't stat a log file that does not exist. + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to execute my_stat on file '%s'", + log_info.log_file_name); + my_errno= 0; + } + else + { + /* + Other than ENOENT are fatal + */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with getting info on being purged %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } + else + { + if (stat_area.st_mtime >= purge_time) + break; + if (my_delete(log_info.log_file_name, MYF(0))) + { + if (my_errno == ENOENT) + { + /* It's not fatal even if we can't delete a log file */ + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + log_info.log_file_name); + sql_print_information("Failed to delete file '%s'", + log_info.log_file_name); + my_errno= 0; + } + else + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + log_info.log_file_name); + error= LOG_INFO_FATAL; + goto err; + } + } + } if (find_next_log(&log_info, 0)) break; } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 9e6cf462113..516dba1cd08 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5641,3 +5641,5 @@ ER_NAME_BECOMES_EMPTY eng "Name '%-.64s' has become ''" ER_AMBIGUOUS_FIELD_TERM eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" +ER_LOG_PURGE_NO_FILE + eng "Being purged log %s was not found" -- cgit v1.2.1 From 809522598a9a8946a5e1fa4a981717c38466a379 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 17 Mar 2008 16:39:09 -0300 Subject: Post-merge fixes for Bug 35103 libmysql/libmysql.c: Manual merge sql/sql_class.cc: Don't send anything back to the client if disabled. sql/sql_prepare.cc: Don't send any packet back for statement close. tests/mysql_client_test.c: Manual merge --- sql/sql_class.cc | 22 ++++++++++++++++++---- sql/sql_prepare.cc | 4 ++-- 2 files changed, 20 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 376102c8bf9..594577dd89c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -395,8 +395,11 @@ Diagnostics_area::set_ok_status(THD *thd, ha_rows affected_rows_arg, { DBUG_ASSERT(! is_set()); #ifdef DBUG_OFF - /* In production, refuse to overwrite an error with an OK packet. */ - if (is_error()) + /* + In production, refuse to overwrite an error or a custom response + with an OK packet. + */ + if (is_error() || is_disabled()) return; #endif /** Only allowed to report success if has not yet reported an error */ @@ -424,8 +427,11 @@ Diagnostics_area::set_eof_status(THD *thd) DBUG_ASSERT(! is_set()); #ifdef DBUG_OFF - /* In production, refuse to overwrite an error with an EOF packet. */ - if (is_error()) + /* + In production, refuse to overwrite an error or a custom response + with an EOF packet. + */ + if (is_error() || is_disabled()) return; #endif @@ -454,6 +460,14 @@ Diagnostics_area::set_error_status(THD *thd, uint sql_errno_arg, an error can happen during the flush. */ DBUG_ASSERT(! is_set() || can_overwrite_status); +#ifdef DBUG_OFF + /* + In production, refuse to overwrite a custom response with an + ERROR packet. + */ + if (is_disabled()) + return; +#endif m_sql_errno= sql_errno_arg; strmake(m_message, message_arg, sizeof(m_message) - 1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index a027ffe9daa..c922b21af90 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2555,6 +2555,8 @@ void mysql_stmt_close(THD *thd, char *packet) Prepared_statement *stmt; DBUG_ENTER("mysql_stmt_close"); + thd->main_da.disable_status(); + if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close"))) DBUG_VOID_RETURN; @@ -2566,8 +2568,6 @@ void mysql_stmt_close(THD *thd, char *packet) (void) stmt->deallocate(); general_log_print(thd, thd->command, NullS); - thd->main_da.disable_status(); - DBUG_VOID_RETURN; } -- cgit v1.2.1 From 001829914befbbaec672334b298d152fa8727060 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 18 Mar 2008 10:45:36 +0100 Subject: Bug#25175 Too much memory used by MySQL grant system Each time the server reloads privileges containing table grants, the system will allocate too much memory than needed because of badly chosen growth prediction in the underlying dynamic arrays. This patch introduces a new signature to the hash container initializer which enables a much more pessimistic approach in favour for more efficient memory useage. This patch was supplied by Google Inc. include/hash.h: * New signature for _hash_init. * Defined new function hash_init2 which takes growth_size argument. mysys/hash.c: * New signature for _hash_init. sql/sql_acl.cc: * Changed hash_init signature so that it takes a 'growth_size' smaller than the default. Each time a GRANT_TABLE is allocated a pre-allocated dynamic array is instantiated. A large growth size can result in too many unused hash-entries per table-entry and thus be a waste of free memory. --- sql/sql_acl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3805d9fa8b6..9a218395721 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2281,7 +2281,7 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u, const char *t, ulong p, ulong c) :GRANT_NAME(h,d,u,t,p), cols(c) { - (void) hash_init(&hash_columns,system_charset_info, + (void) hash_init2(&hash_columns,4,system_charset_info, 0,0,0, (hash_get_key) get_key_column,0,0); } @@ -2329,7 +2329,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) cols= (ulong) form->field[7]->val_int(); cols = fix_rights_for_column(cols); - (void) hash_init(&hash_columns,system_charset_info, + (void) hash_init2(&hash_columns,4,system_charset_info, 0,0,0, (hash_get_key) get_key_column,0,0); if (cols) { -- cgit v1.2.1 From 7343db297a1f1ab08812c9b4471306535551ddec Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 18 Mar 2008 16:38:12 +0400 Subject: Make gcov happy. --- sql/log_event.cc | 2 +- sql/repl_failsafe.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/log_event.cc b/sql/log_event.cc index 8e14a873fc6..05dccd782ad 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -406,7 +406,7 @@ Log_event::Log_event(const char* buf, binlog, so which will cause problems if the user uses this value in CHANGE MASTER). */ - log_pos+= data_written; + log_pos+= data_written; /* purecov: inspected */ } DBUG_PRINT("info", ("log_pos: %lu", (ulong) log_pos)); diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index f1826678c9f..7f98dd2d64a 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -191,7 +191,7 @@ int register_slave(THD* thd, uchar* packet, uint packet_length) err: my_free((gptr) si, MYF(MY_WME)); - my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); + my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */ err2: return 1; } -- cgit v1.2.1 From 1626b42ca34d09844dd628f390d9ef8fb925ec13 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 18 Mar 2008 20:25:34 +0400 Subject: BUG#34768 - nondeterministic INSERT using LIMIT logged in stmt mode if binlog_format=mixed Statement-based replication of DELETE ... LIMIT, UPDATE ... LIMIT, INSERT ... SELECT ... LIMIT is not safe as order of rows is not defined. With this fix, we issue a warning that this statement is not safe to replicate in statement mode, or go to row-based mode in mixed mode. Note that we may consider a statement as safe if ORDER BY primary_key is present. However it may confuse users to see very similiar statements replicated differently. Note 2: regular UPDATE statement (w/o LIMIT) is unsafe as well, but this patch doesn't address this issue. See comment from Kristian posted 18 Mar 10:55. mysql-test/suite/binlog/r/binlog_stm_ps.result: Updated a test case according to fix for BUG#34768: INSERT ... SELECT ... LIMIT is now replicated in row mode. mysql-test/suite/binlog/r/binlog_unsafe.result: A test case for BUG#34768. mysql-test/suite/binlog/t/binlog_unsafe.test: A test case for BUG#34768. sql/sql_delete.cc: Statement-based replication of DELETE ... LIMIT is not safe as order of rows is not defined, so in mixed mode we go to row-based. sql/sql_insert.cc: Statement-based replication of INSERT ... SELECT ... LIMIT is not safe as order of rows is not defined, so in mixed mode we go to row-based. sql/sql_update.cc: Statement-based replication of UPDATE ... LIMIT is not safe as order of rows is not defined, so in mixed mode we go to row-based. --- sql/sql_delete.cc | 13 +++++++++++++ sql/sql_insert.cc | 13 +++++++++++++ sql/sql_update.cc | 13 +++++++++++++ 3 files changed, 39 insertions(+) (limited to 'sql') diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 990f7713561..abf25e96be0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -418,6 +418,19 @@ bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) DBUG_ENTER("mysql_prepare_delete"); List all_fields; + /* + Statement-based replication of DELETE ... LIMIT is not safe as order of + rows is not defined, so in mixed mode we go to row-based. + + Note that we may consider a statement as safe if ORDER BY primary_key + is present. However it may confuse users to see very similiar statements + replicated differently. + */ + if (thd->lex->current_select->select_limit) + { + thd->lex->set_stmt_unsafe(); + thd->set_current_stmt_binlog_row_based_if_mixed(); + } thd->lex->allow_sum_func= 0; if (setup_tables_and_check_access(thd, &thd->lex->select_lex.context, &thd->lex->select_lex.top_join_list, diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2be932a6040..58acf40964b 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2763,6 +2763,19 @@ bool mysql_insert_select_prepare(THD *thd) TABLE_LIST *first_select_leaf_table; DBUG_ENTER("mysql_insert_select_prepare"); + /* + Statement-based replication of INSERT ... SELECT ... LIMIT is not safe + as order of rows is not defined, so in mixed mode we go to row-based. + + Note that we may consider a statement as safe if ORDER BY primary_key + is present or we SELECT a constant. However it may confuse users to + see very similiar statements replicated differently. + */ + if (lex->current_select->select_limit) + { + lex->set_stmt_unsafe(); + thd->set_current_stmt_binlog_row_based_if_mixed(); + } /* SELECT_LEX do not belong to INSERT statement, so we can't add WHERE clause if table is VIEW diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 7c9ead7591c..77d5fd7421c 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -859,6 +859,19 @@ bool mysql_prepare_update(THD *thd, TABLE_LIST *table_list, SELECT_LEX *select_lex= &thd->lex->select_lex; DBUG_ENTER("mysql_prepare_update"); + /* + Statement-based replication of UPDATE ... LIMIT is not safe as order of + rows is not defined, so in mixed mode we go to row-based. + + Note that we may consider a statement as safe if ORDER BY primary_key + is present. However it may confuse users to see very similiar statements + replicated differently. + */ + if (thd->lex->current_select->select_limit) + { + thd->lex->set_stmt_unsafe(); + thd->set_current_stmt_binlog_row_based_if_mixed(); + } #ifndef NO_EMBEDDED_ACCESS_CHECKS table_list->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); -- cgit v1.2.1 From 3c5894baaa9dcc2d910d504ef073facfcd329f8e Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Mar 2008 14:32:28 +0100 Subject: Bug#34529: Crash on complex Falcon I_S select after ALTER .. PARTITION BY When swapping out heap I_S tables to disk, this is done after plan refinement. Thus, READ_RECORD::file will still point to the (deleted) heap handler at start of execution. This causes segmentation fault if join buffering is used and the query is a star query where the result is found to be empty before accessing some table. In this case that table has not been initialized (i.e. had its READ_RECORD re-initialized) before the cleanup routine tries to close the handler. Fixed by updating READ_RECORD::file when changing handler. mysql-test/r/information_schema.result: Bug#34529: Test result. mysql-test/t/information_schema.test: Bug#34529: Test case. sql/sql_show.cc: Bug#34529: The fix. --- sql/sql_show.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 36d154181f8..a80319785bd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4073,9 +4073,11 @@ bool get_schema_tables_result(JOIN *join, { result= 1; join->error= 1; + tab->read_record.file= table_list->table->file; table_list->schema_table_state= executed_place; break; } + tab->read_record.file= table_list->table->file; table_list->schema_table_state= executed_place; } } -- cgit v1.2.1 From 5a6996dbcde4ca833f7936413cfa090cba060af5 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 19 Mar 2008 18:44:50 +0200 Subject: Bug #35178 INSERT_ID not written to binary log for inserts against BLACKHOLE backed tables binlogging of insert into a autoincrement blackhole table ignored an explicit set insert_id. Fixed with refining of the blackhole's insert method to call update_auto_increment() that prepares binlogging the insert query with the preceeding set insert_id. Note, as the engine does not store any actual data one has to explicitly provide to the server with the value of the autoincrement column via set insert_id. Otherwise binlogging will happend with the default set insert_id=1. mysql-test/r/blackhole.result: results changed mysql-test/t/blackhole.test: a regression test for the bug added sql/ha_blackhole.cc: blackhole's insert method is refined to call update_auto_increment() that prepares binlogging the insert query with the preceeding set insert_id. --- sql/ha_blackhole.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index e477686d18e..01ede3d3bd2 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -115,7 +115,7 @@ const char *ha_blackhole::index_type(uint key_number) int ha_blackhole::write_row(byte * buf) { DBUG_ENTER("ha_blackhole::write_row"); - DBUG_RETURN(0); + DBUG_RETURN(table->next_number_field ? update_auto_increment() : 0); } int ha_blackhole::rnd_init(bool scan) -- cgit v1.2.1 From 95023bb9b0702cc9e080d67ab79cf56d2c12fd97 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Mar 2008 11:40:26 +0400 Subject: BUG#34790 - 'create server' doesn't handle out of memory scenario well enough CREATE SERVER may cause server crash if there is not enough memory to execute this operation. Fixed that create_server() and prepare_server_struct_for_insert() didn't check return value of functions that allocate memory. As this is out of memory issue fix, not test case available. sql/sql_servers.cc: Fixed that create_server() and prepare_server_struct_for_insert() didn't check return value of functions that allocate memory. --- sql/sql_servers.cc | 68 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 26 deletions(-) (limited to 'sql') diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 8203ca92eed..6255901d782 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -55,8 +55,8 @@ static bool get_server_from_table_to_cache(TABLE *table); static int insert_server(THD *thd, FOREIGN_SERVER *server_options); static int insert_server_record(TABLE *table, FOREIGN_SERVER *server); static int insert_server_record_into_cache(FOREIGN_SERVER *server); -static void prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, - FOREIGN_SERVER *server); +static FOREIGN_SERVER * +prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options); /* drop functions */ static int delete_server_record(TABLE *table, char *server_name, @@ -966,10 +966,14 @@ int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options) server_options->server_name_length)) goto end; - server= (FOREIGN_SERVER *)alloc_root(&mem, - sizeof(FOREIGN_SERVER)); - prepare_server_struct_for_insert(server_options, server); + if (!(server= prepare_server_struct_for_insert(server_options))) + { + /* purecov: begin inspected */ + error= ER_OUT_OF_RESOURCES; + goto end; + /* purecov: end */ + } error= insert_server(thd, server); @@ -1040,52 +1044,64 @@ end: SYNOPSIS prepare_server_struct_for_insert() LEX_SERVER_OPTIONS *server_options - FOREIGN_SERVER *server NOTES + As FOREIGN_SERVER members are allocated on mem_root, we do not need to + free them in case of error. RETURN VALUE - none + On success filled FOREIGN_SERVER, or NULL in case out of memory. */ -static void -prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, - FOREIGN_SERVER *server) +static FOREIGN_SERVER * +prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options) { char *unset_ptr= (char*)""; + FOREIGN_SERVER *server; DBUG_ENTER("prepare_server_struct"); + if (!(server= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER)))) + DBUG_RETURN(NULL); /* purecov: inspected */ + /* these two MUST be set */ - server->server_name= strdup_root(&mem, server_options->server_name); + if (!(server->server_name= strdup_root(&mem, server_options->server_name))) + DBUG_RETURN(NULL); /* purecov: inspected */ server->server_name_length= server_options->server_name_length; - server->host= server_options->host ? - strdup_root(&mem, server_options->host) : unset_ptr; + if (!(server->host= server_options->host ? + strdup_root(&mem, server_options->host) : unset_ptr)) + DBUG_RETURN(NULL); /* purecov: inspected */ - server->db= server_options->db ? - strdup_root(&mem, server_options->db) : unset_ptr; + if (!(server->db= server_options->db ? + strdup_root(&mem, server_options->db) : unset_ptr)) + DBUG_RETURN(NULL); /* purecov: inspected */ - server->username= server_options->username ? - strdup_root(&mem, server_options->username) : unset_ptr; + if (!(server->username= server_options->username ? + strdup_root(&mem, server_options->username) : unset_ptr)) + DBUG_RETURN(NULL); /* purecov: inspected */ - server->password= server_options->password ? - strdup_root(&mem, server_options->password) : unset_ptr; + if (!(server->password= server_options->password ? + strdup_root(&mem, server_options->password) : unset_ptr)) + DBUG_RETURN(NULL); /* purecov: inspected */ /* set to 0 if not specified */ server->port= server_options->port > -1 ? server_options->port : 0; - server->socket= server_options->socket ? - strdup_root(&mem, server_options->socket) : unset_ptr; + if (!(server->socket= server_options->socket ? + strdup_root(&mem, server_options->socket) : unset_ptr)) + DBUG_RETURN(NULL); /* purecov: inspected */ - server->scheme= server_options->scheme ? - strdup_root(&mem, server_options->scheme) : unset_ptr; + if (!(server->scheme= server_options->scheme ? + strdup_root(&mem, server_options->scheme) : unset_ptr)) + DBUG_RETURN(NULL); /* purecov: inspected */ - server->owner= server_options->owner ? - strdup_root(&mem, server_options->owner) : unset_ptr; + if (!(server->owner= server_options->owner ? + strdup_root(&mem, server_options->owner) : unset_ptr)) + DBUG_RETURN(NULL); /* purecov: inspected */ - DBUG_VOID_RETURN; + DBUG_RETURN(server); } /* -- cgit v1.2.1 From b31a1622e33b92d926e7e4346a027694156353c0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Mar 2008 11:57:30 +0400 Subject: BUG#34789 - drop server/create server leaks memory ! When CREATE SERVER is issued, it allocates memory on memory root to store cached server structure. When DROP SERVER is issued, it doesn't release this memory, as it is impossible with the memory root. We use the same allocation strategy for plugins and acl. The problem here that there was no way (except for the server restart) to force 'servers' code to release this memory. With this fix it is possible to release unused server cache memory by FLUSH PRIVILEGES. No test case for this fix. sql/sql_parse.cc: Reload servers table on FLUSH PRIVILEGES. sql/sql_servers.cc: Instead of just marking memory blocks as unused, release memory used by servers cache and initialize new memory root. This is needed for FLUSH PRIVILEGES to release unused memory blocks. --- sql/sql_parse.cc | 2 ++ sql/sql_servers.cc | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f2e0065f860..046eae4e654 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6486,6 +6486,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, result= 1; if (grant_reload(thd)) result= 1; + if (servers_reload(thd)) + result= 1; } if (tmp_thd) { diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 8203ca92eed..42abd9b4eb5 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -166,6 +166,9 @@ end: RETURN VALUES FALSE Success TRUE Error + + TODO + Revert back to old list if we failed to load new one. */ static bool servers_load(THD *thd, TABLE_LIST *tables) @@ -175,10 +178,9 @@ static bool servers_load(THD *thd, TABLE_LIST *tables) bool return_val= TRUE; DBUG_ENTER("servers_load"); - /* first, send all cached rows to sleep with the fishes, oblivion! - I expect this crappy comment replaced */ - free_root(&mem, MYF(MY_MARK_BLOCKS_FREE)); my_hash_reset(&servers_cache); + free_root(&mem, MYF(0)); + init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0); init_read_record(&read_record_info,thd,table=tables[0].table,NULL,1,0); while (!(read_record_info.read_record(&read_record_info))) -- cgit v1.2.1 From 8030bdfc16a647c15e0de5e07b5f53d263ef5ca2 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 20 Mar 2008 19:07:17 +0400 Subject: BUG#34788 - malformed federated connection url is not handled correctly - crashes server ! Creating federated table with connect string containing empty (zero-length) host name and port is evaluated as 0 (port is incorrect, omitted or 0) crashes server. This happens because federated calls strcmp() with NULL pointer. Fixed by avoiding strcmp() call if hostname is set to NULL. mysql-test/r/federated.result: A test case for BUG#34788. mysql-test/t/federated.test: A test case for BUG#34788. sql/ha_federated.cc: Fixed that parse_url() may call strcmp() with NULL pointer. --- sql/ha_federated.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index c0743bd6c9a..a5e4714c53a 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -643,12 +643,19 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, if ((strchr(share->table_name, '/'))) goto error; + /* + If hostname is omitted, we set it to NULL. According to + mysql_real_connect() manual: + The value of host may be either a hostname or an IP address. + If host is NULL or the string "localhost", a connection to the + local host is assumed. + */ if (share->hostname[0] == '\0') share->hostname= NULL; if (!share->port) { - if (strcmp(share->hostname, my_localhost) == 0) + if (!share->hostname || strcmp(share->hostname, my_localhost) == 0) share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0)); else share->port= MYSQL_PORT; -- cgit v1.2.1 From cebb6727b3c8593283f81182d06c45ca69cc0304 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Mar 2008 17:23:17 +0200 Subject: Bug #26461: Intrinsic data type bool (1 byte) redefined to BOOL (4 bytes) The bool data type was redefined to BOOL (4 bytes on windows). Removed the #define and fixed some of the warnings that were uncovered by this. Note that the fix also disables 2 warnings : 4800 : 'type' : forcing value to bool 'true' or 'false' (performance warning) 4805: 'operation' : unsafe mix of type 'type' and type 'type' in operation These warnings will be handled in a separate bug, as they are performance related or bogus. Fixed to int the return type of functions that return more than 2 distinct values. CMakeLists.txt: Bug #26461: disable the C4800 and C4805 warnings temporarily include/config-win.h: Bug #26461: - no need for this define for Windows. - windows C++ compilers have a bool type include/my_global.h: Bug #26461: removed bool_defined (no longer needed) sql/handler.h: Bug #26461: bool functions must return boolean values sql/mysql_priv.h: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/procedure.h: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_acl.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_acl.h: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_analyse.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_analyse.h: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_base.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_db.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_delete.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_load.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_parse.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_prepare.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. sql/sql_update.cc: Bug #26461: fixed return type of functions that return more than 2 distinct values. --- sql/handler.h | 2 +- sql/mysql_priv.h | 14 +++++++------- sql/procedure.h | 2 +- sql/sql_acl.cc | 6 +++--- sql/sql_acl.h | 6 +++--- sql/sql_analyse.cc | 2 +- sql/sql_analyse.h | 2 +- sql/sql_base.cc | 2 +- sql/sql_db.cc | 2 +- sql/sql_delete.cc | 4 ++-- sql/sql_load.cc | 2 +- sql/sql_parse.cc | 4 ++-- sql/sql_prepare.cc | 6 +++--- sql/sql_update.cc | 2 +- 14 files changed, 28 insertions(+), 28 deletions(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index 74c09d2d9ee..aa3377c3868 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -815,7 +815,7 @@ public: { return HA_ADMIN_NOT_IMPLEMENTED; } /* end of the list of admin commands */ - virtual bool check_and_repair(THD *thd) { return HA_ERR_WRONG_COMMAND; } + virtual bool check_and_repair(THD *thd) { return TRUE; } virtual int dump(THD* thd, int fd = -1) { return HA_ERR_WRONG_COMMAND; } virtual int disable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } virtual int enable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 59ec18e1a3d..0b488900ac5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -597,8 +597,8 @@ bool check_merge_table_access(THD *thd, char *db, bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc); bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables); -bool mysql_multi_update_prepare(THD *thd); -bool mysql_multi_delete_prepare(THD *thd); +int mysql_multi_update_prepare(THD *thd); +int mysql_multi_delete_prepare(THD *thd); bool mysql_insert_select_prepare(THD *thd); bool update_precheck(THD *thd, TABLE_LIST *tables); bool delete_precheck(THD *thd, TABLE_LIST *tables); @@ -691,7 +691,7 @@ struct Query_cache_query_flags uint build_table_path(char *buff, size_t bufflen, const char *db, const char *table, const char *ext); -bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags); @@ -731,7 +731,7 @@ pthread_handler_t handle_one_connection(void *arg); pthread_handler_t handle_bootstrap(void *arg); void end_thread(THD *thd,bool put_in_cache); void flush_thread_cache(); -bool mysql_execute_command(THD *thd); +int mysql_execute_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); void log_slow_statement(THD *thd); @@ -862,7 +862,7 @@ void prepare_triggers_for_insert_stmt(THD *thd, TABLE *table, enum_duplicates duplic); void mark_fields_used_by_triggers_for_insert_stmt(THD *thd, TABLE *table, enum_duplicates duplic); -bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); +int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, ha_rows rows, ulonglong options, bool reset_auto_increment); @@ -1106,7 +1106,7 @@ int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); void wait_for_refresh(THD *thd); int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); -bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); +int open_and_lock_tables(THD *thd,TABLE_LIST *tables); bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen); TABLE *open_temporary_table(THD *thd, const char *path, const char *db, @@ -1177,7 +1177,7 @@ inline TABLE_LIST *find_table_in_local_list(TABLE_LIST *table, bool eval_const_cond(COND *cond); /* sql_load.cc */ -bool mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list, +int mysql_load(THD *thd, sql_exchange *ex, TABLE_LIST *table_list, List &fields_vars, List &set_fields, List &set_values_list, enum enum_duplicates handle_duplicates, bool ignore, diff --git a/sql/procedure.h b/sql/procedure.h index 850d5c74db4..f1fb433a6ee 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -144,7 +144,7 @@ public: virtual int send_row(List &fields)=0; virtual bool change_columns(List &fields)=0; virtual void update_refs(void) {} - virtual bool end_of_records() { return 0; } + virtual int end_of_records() { return 0; } }; Procedure *setup_procedure(THD *thd,ORDER *proc_param,select_result *result, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e9504f423ad..e773f754e18 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1382,7 +1382,7 @@ bool acl_check_host(const char *host, const char *ip) 1 ERROR ; In this case the error is sent to the client. */ -bool check_change_password(THD *thd, const char *host, const char *user, +int check_change_password(THD *thd, const char *host, const char *user, char *new_password, uint new_password_len) { if (!initialized) @@ -2763,7 +2763,7 @@ table_error: TRUE error */ -bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, +int mysql_table_grant(THD *thd, TABLE_LIST *table_list, List &user_list, List &columns, ulong rights, bool revoke_grant) @@ -5805,7 +5805,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, < 0 Error. Error message not yet sent. */ -bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, +int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc) { Security_context *sctx= thd->security_ctx; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index b2007ccdf47..1efcd2e3b6b 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -183,13 +183,13 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd, bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, char *ip, char *db); bool acl_check_host(const char *host, const char *ip); -bool check_change_password(THD *thd, const char *host, const char *user, +int check_change_password(THD *thd, const char *host, const char *user, char *password, uint password_len); bool change_password(THD *thd, const char *host, const char *user, char *password); bool mysql_grant(THD *thd, const char *db, List &user_list, ulong rights, bool revoke); -bool mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list, +int mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list, List &column_list, ulong rights, bool revoke); bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc, @@ -225,7 +225,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, const char *db, const char *table); bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc); -bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, +int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc); bool check_routine_level_acl(THD *thd, const char *db, const char *name, bool is_proc); diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 95a7fb3d34d..2e90d00f8aa 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -683,7 +683,7 @@ int analyse::send_row(List &field_list __attribute__((unused))) } // analyse::send_row -bool analyse::end_of_records() +int analyse::end_of_records() { field_info **f = f_info; char buff[MAX_FIELD_WIDTH]; diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 21a37209e89..2a4226b2d95 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -350,7 +350,7 @@ public: virtual bool change_columns(List &fields); virtual int send_row(List &fields); virtual void end_group(void) {} - virtual bool end_of_records(void); + virtual int end_of_records(void); friend Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result, List &field_list); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index c9f20b3d71b..533b0070fee 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3046,7 +3046,7 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) The lock will automaticaly be freed by close_thread_tables() */ -bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) +int open_and_lock_tables(THD *thd, TABLE_LIST *tables) { uint counter; bool need_reopen; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 91b0c02d23b..e25ede1be03 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -449,7 +449,7 @@ bool load_db_opt_by_name(THD *thd, const char *db_name, */ -bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, bool silent) { char path[FN_REFLEN+16]; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a28a39a769d..af895c172ff 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -370,7 +370,7 @@ cleanup: FALSE OK TRUE error */ -bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) +int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) { Item *fake_conds= 0; SELECT_LEX *select_lex= &thd->lex->select_lex; @@ -433,7 +433,7 @@ extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b) TRUE Error */ -bool mysql_multi_delete_prepare(THD *thd) +int mysql_multi_delete_prepare(THD *thd) { LEX *lex= thd->lex; TABLE_LIST *aux_tables= (TABLE_LIST *)lex->auxiliary_table_list.first; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index d687ceff393..4da3c19bb3c 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -110,7 +110,7 @@ static bool write_execute_load_query_log_event(THD *thd, TRUE - error / FALSE - success */ -bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, +int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, List &fields_vars, List &set_fields, List &set_values, enum enum_duplicates handle_duplicates, bool ignore, diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8bdbd812529..98e04e45bdd 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2500,10 +2500,10 @@ static void reset_one_shot_variables(THD *thd) TRUE Error */ -bool +int mysql_execute_command(THD *thd) { - bool res= FALSE; + int res= FALSE; bool need_start_waiting= FALSE; // have protection against global read lock int up_result= 0; LEX *lex= thd->lex; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 18cfd8d7dfc..220b9a0bcd8 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1403,7 +1403,7 @@ error: */ static bool select_like_stmt_test(Prepared_statement *stmt, - bool (*specific_prepare)(THD *thd), + int (*specific_prepare)(THD *thd), ulong setup_tables_done_option) { DBUG_ENTER("select_like_stmt_test"); @@ -1441,7 +1441,7 @@ static bool select_like_stmt_test(Prepared_statement *stmt, static bool select_like_stmt_test_with_open_n_lock(Prepared_statement *stmt, TABLE_LIST *tables, - bool (*specific_prepare)(THD *thd), + int (*specific_prepare)(THD *thd), ulong setup_tables_done_option) { DBUG_ENTER("select_like_stmt_test_with_open_n_lock"); @@ -1630,7 +1630,7 @@ error: because mysql_handle_derived uses local tables lists. */ -static bool mysql_insert_select_prepare_tester(THD *thd) +static int mysql_insert_select_prepare_tester(THD *thd) { SELECT_LEX *first_select= &thd->lex->select_lex; TABLE_LIST *second_table= ((TABLE_LIST*)first_select->table_list.first)-> diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 84349a40977..541704cfaf1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -716,7 +716,7 @@ static table_map get_table_map(List *items) TRUE Error */ -bool mysql_multi_update_prepare(THD *thd) +int mysql_multi_update_prepare(THD *thd) { LEX *lex= thd->lex; TABLE_LIST *table_list= lex->query_tables; -- cgit v1.2.1 From d05f6b9fb8a5c02ef27390c34ebe97c26dda7923 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Mar 2008 18:34:12 +0300 Subject: A patch for Bug#21854: Problems with CREATE TRIGGER without DEFINER clause in --skip-grant-tables mode. Update error message. mysql-test/r/information_schema_db.result: Update result file. mysql-test/r/sp-security.result: Update result file. mysql-test/r/trigger_notembedded.result: Update result file. mysql-test/r/view_grant.result: Update result file. sql/share/errmsg.txt: Update error message. --- sql/share/errmsg.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 693140e642a..7990baa6bb7 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5584,8 +5584,7 @@ ER_VIEW_OTHER_USER eng "You need the SUPER privilege for creation view with '%-.192s'@'%-.192s' definer" ger "Sie brauchen die SUPER-Berechtigung, um einen View mit dem Definierer '%-.192s'@'%-.192s' zu erzeugen" ER_NO_SUCH_USER - eng "There is no '%-.64s'@'%-.64s' registered" - ger "'%-.64s'@'%-.64s' ist nicht registriert" + eng "The user specified as a definer ('%-.64s'@'%-.64s') does not exist" ER_FORBID_SCHEMA_CHANGE eng "Changing schema from '%-.192s' to '%-.192s' is not allowed." ger "Wechsel des Schemas von '%-.192s' auf '%-.192s' ist nicht erlaubt" -- cgit v1.2.1 From 194e43ee68e9f1acb9d1ef380894c4fc4c27f22e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Mar 2008 12:08:04 -0600 Subject: Bug#8759 (Stored Procedures: SQLSTATE '00000' should be illegal) Fixed the parser to reject SQLSTATE '00000', since '00000' is the successful completion condition, and can not be caught by an exception handler in SQL. mysql-test/r/sp-error.result: Bug#8759 (Stored Procedures: SQLSTATE '00000' should be illegal) mysql-test/t/sp-error.test: Bug#8759 (Stored Procedures: SQLSTATE '00000' should be illegal) sql/sp_pcontext.cc: Bug#8759 (Stored Procedures: SQLSTATE '00000' should be illegal) --- sql/sp_pcontext.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sql') diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc index 8babbd52ff6..414ea12cd7a 100644 --- a/sql/sp_pcontext.cc +++ b/sql/sp_pcontext.cc @@ -51,6 +51,8 @@ sp_cond_check(LEX_STRING *sqlstate) (c < 'A' || 'Z' < c)) return FALSE; } + if (strcmp(sqlstate->str, "00000") == 0) + return FALSE; return TRUE; } -- cgit v1.2.1 From 28cd75fec42e327950056617c7dea8ae4d2f6395 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 22 Mar 2008 11:32:24 +0300 Subject: Fix for Bug#34274: Invalid handling of 'DEFAULT 0' for YEAR data type. The problem was that for some unknown reason 0 was not allowed as a default value for YEAR data type. That was coded before BK. However the Manual does not say a word about such a limitation. Also, it looks inconsistent with other data types. The fix is to allow 0 as a default value. mysql-test/r/create.result: Update result file. mysql-test/t/create.test: Add a test case for Bug#34274: Invalid handling of 'DEFAULT 0' for YEAR data type. sql/unireg.cc: Allow 0 as a default value for YEAR data type. --- sql/unireg.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/unireg.cc b/sql/unireg.cc index 38f09a7946c..abab4632fe4 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -979,9 +979,7 @@ static bool make_empty_rec(THD *thd, File file,enum legacy_db_type table_type, type= (Field::utype) MTYP_TYPENR(field->unireg_check); - if (field->def && - (regfield->real_type() != MYSQL_TYPE_YEAR || - field->def->val_int() != 0)) + if (field->def) { int res= field->def->save_in_field(regfield, 1); /* If not ok or warning of level 'note' */ -- cgit v1.2.1 From 7bcbc7f2d5078d308c25f7d1c92995c64af7b8bc Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 23 Mar 2008 14:29:35 +0200 Subject: merge bug 26461 to 5.1-opt --- sql/handler.h | 2 +- sql/log.cc | 2 +- sql/sql_table.cc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/handler.h b/sql/handler.h index 9800f4974c3..a3743c78f34 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -1883,7 +1883,7 @@ private: { return HA_ADMIN_NOT_IMPLEMENTED; } virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt) { return HA_ADMIN_NOT_IMPLEMENTED; } - virtual bool check_and_repair(THD *thd) { return HA_ERR_WRONG_COMMAND; } + virtual bool check_and_repair(THD *thd) { return TRUE; } virtual int disable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } virtual int enable_indexes(uint mode) { return HA_ERR_WRONG_COMMAND; } virtual int discard_or_import_tablespace(my_bool discard) diff --git a/sql/log.cc b/sql/log.cc index c2e0c85acfe..67438da6008 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1005,7 +1005,7 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command, current_time= my_time(0); while (*current_handler) - error+= (*current_handler++)-> + error|= (*current_handler++)-> log_general(thd, current_time, user_host_buff, user_host_len, id, command_name[(uint) command].str, diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c62d0545fda..2baf26f5953 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -42,7 +42,7 @@ static int copy_data_between_tables(TABLE *from,TABLE *to, static bool prepare_blob_field(THD *thd, Create_field *sql_field); static bool check_engine(THD *, const char *, HA_CREATE_INFO *); -static bool +static int mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Alter_info *alter_info, bool tmp_table, @@ -2173,7 +2173,7 @@ int prepare_create_field(Create_field *sql_field, TRUE error */ -static bool +static int mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, Alter_info *alter_info, bool tmp_table, -- cgit v1.2.1 From 5ad505dda2d8ae019f6abfbf6eb9091cea1a5c55 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Mar 2008 12:47:57 +0400 Subject: BUG#35509 - Federated leaks memory when connecting to localhost/default port When creating federated table that points to unspecified host or localhost on unspecified port or port is 0, small memory leak occurs. This happens because we make a copy of unix socket path, which is never freed. With this fix we do not make a copy of unix socket path, instead share->socket points to MYSQL_UNIX_ADDR constant directly. This fix is covered by a test case for BUG34788. Affects 5.0 only. mysql-test/t/federated.test: A test case for BUG#35509. sql/ha_federated.cc: When creating federated table we call parse_url() to check if connect string is correct. parse_url() may make a copy of unix socket path if port is not specified or 0 and host is not specified or 'localhost'. This copy is never freed. As there is no need to make a copy of unix socket path, let share->socket point to MYSQL_UNIX_ADDR directly. --- sql/ha_federated.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index a5e4714c53a..d414dc34f02 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -656,7 +656,7 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, if (!share->port) { if (!share->hostname || strcmp(share->hostname, my_localhost) == 0) - share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0)); + share->socket= (char*) MYSQL_UNIX_ADDR; else share->port= MYSQL_PORT; } @@ -1342,7 +1342,6 @@ static int free_share(FEDERATED_SHARE *share) { hash_delete(&federated_open_tables, (byte*) share); my_free((gptr) share->scheme, MYF(MY_ALLOW_ZERO_PTR)); - my_free((gptr) share->socket, MYF(MY_ALLOW_ZERO_PTR)); thr_lock_delete(&share->lock); VOID(pthread_mutex_destroy(&share->mutex)); my_free((gptr) share, MYF(0)); -- cgit v1.2.1 From 811fb145eaf694485395934c81c7576a000e2cc7 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Mar 2008 17:37:53 +0400 Subject: BUG#34789 - drop server/create server leaks memory ! BUG#34790 - 'create server' doesn't handle out of memory scenario well enough This is an addition to fixes for these bugs, which makes gcov happy. mysql-test/r/federated.result: CREATE SERVER is only tested by federated_server.test, which requires big-test option. Added dummy test case to make gcov happy. mysql-test/t/federated.test: CREATE SERVER is only tested by federated_server.test, which requires big-test option. Added dummy test case to make gcov happy. sql/sql_parse.cc: Make gcov happy. --- sql/sql_parse.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 046eae4e654..a2708632a56 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -6487,7 +6487,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, if (grant_reload(thd)) result= 1; if (servers_reload(thd)) - result= 1; + result= 1; /* purecov: inspected */ } if (tmp_thd) { -- cgit v1.2.1 From 2daa01682775d42bbe00d3fb41e0865079240de8 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Mar 2008 15:20:42 +0100 Subject: Eliminating compiler warnings. sql/set_var.h: Changing order of initializer list for sys_var class constructor to eliminate compiler warning. mysql-test/suite/binlog/combinations: New BitKeeper file ``mysql-test/suite/binlog/combinations'' --- sql/set_var.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/set_var.h b/sql/set_var.h index 46fe7755baf..b33a3a968bb 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -73,8 +73,8 @@ public: bool no_support_one_shot; sys_var(const char *name_arg, sys_after_update_func func= NULL, Binlog_status_enum binlog_status_arg= NOT_IN_BINLOG) - :name(name_arg), after_update(func), binlog_status(binlog_status_arg) - , no_support_one_shot(1) + :name(name_arg), after_update(func), no_support_one_shot(1), + binlog_status(binlog_status_arg) {} virtual ~sys_var() {} void chain_sys_var(sys_var_chain *chain_arg) -- cgit v1.2.1 From 2d5a444d1fac9dc1866231355ea791ea0545fdd8 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 25 Mar 2008 18:18:58 +0200 Subject: Fix for Bug #27944 Filtering THD::client capabilities The server used to trust blindly information from the client about its capabilities. During the connection handshake the server sends information about what it supports and then the client sends back a set of capabilities which cover all of the server's or less. Before this changeset the server didn't check whether the flags sent by the client were valid for the server. For example, if the server doesn't support compressed protocol but the client does and sends that bit turned on, the server didn't check it. The change make the server code less error prone to problems related to the value of THD::client_capabilities. Clearly there is no vulnerability being fixed but this is a maintainenance fix to prevent misusage in the future. include/mysql_com.h: List all CLIENT flags in a common defition. Add also a definition which excludes flags, which are optoinal. sql/sql_connect.cc: Renamed client_flags to server_capabilities to reflect what the server supports. Only allow from the client the flags the server supports. --- sql/sql_connect.cc | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc index b22a33e3e92..b3acfd99991 100644 --- a/sql/sql_connect.cc +++ b/sql/sql_connect.cc @@ -700,20 +700,24 @@ static int check_connection(THD *thd) bzero((char*) &thd->remote, sizeof(thd->remote)); } vio_keepalive(net->vio, TRUE); + + ulong server_capabilites; { /* buff[] needs to big enough to hold the server_version variable */ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64]; - ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | - CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); + server_capabilites= CLIENT_BASIC_FLAGS; if (opt_using_transactions) - client_flags|=CLIENT_TRANSACTIONS; + server_capabilites|= CLIENT_TRANSACTIONS; #ifdef HAVE_COMPRESS - client_flags |= CLIENT_COMPRESS; + server_capabilites|= CLIENT_COMPRESS; #endif /* HAVE_COMPRESS */ #ifdef HAVE_OPENSSL if (ssl_acceptor_fd) - client_flags |= CLIENT_SSL; /* Wow, SSL is available! */ + { + server_capabilites |= CLIENT_SSL; /* Wow, SSL is available! */ + server_capabilites |= CLIENT_SSL_VERIFY_SERVER_CERT; + } #endif /* HAVE_OPENSSL */ end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1; @@ -732,7 +736,7 @@ static int check_connection(THD *thd) */ end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1; - int2store(end, client_flags); + int2store(end, server_capabilites); /* write server characteristics: up to 16 bytes allowed */ end[2]=(char) default_charset_info->number; int2store(end+3, thd->server_status); @@ -762,7 +766,7 @@ static int check_connection(THD *thd) if (thd->packet.alloc(thd->variables.net_buffer_length)) return 1; /* The error is set by alloc(). */ - thd->client_capabilities=uint2korr(net->read_pos); + thd->client_capabilities= uint2korr(net->read_pos); if (thd->client_capabilities & CLIENT_PROTOCOL_41) { thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16; @@ -777,6 +781,11 @@ static int check_connection(THD *thd) thd->max_client_packet_length= uint3korr(net->read_pos+2); end= (char*) net->read_pos+5; } + /* + Disable those bits which are not supported by the server. + This is a precautionary measure, if the client lies. See Bug#27944. + */ + thd->client_capabilities&= server_capabilites; if (thd->client_capabilities & CLIENT_IGNORE_SPACE) thd->variables.sql_mode|= MODE_IGNORE_SPACE; -- cgit v1.2.1 From b4b72fb306a1f816c0a39fe4a1eb70fa894ed70b Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Mar 2008 19:37:36 +0300 Subject: Fix for bug #34928: Confusion by having Primary Key and Index The bug is a regression introduced in 5.1 by the patch for bug28404. Under some circumstances test_if_skip_sort_order() could leave some data structures in an inconsistent state so that some parts of code could assume the selected execution strategy for GROUP BY/DISTINCT as a loose index scan (e.g. JOIN_TAB::is_using_loose_index_scan()), while the actual strategy chosen was an ordered index scan, which led to wrong data being returned. Fixed test_if_skip_sort_order() so that when changing the type for a join table, select->quick is reset not only for EXPLAIN, but for the actual join execution as well, to not confuse code that depends on its value to determine the chosen GROUP BY/DISTINCT strategy. mysql-test/r/distinct.result: Added a test case for bug #34928. mysql-test/t/distinct.test: Added a test case for bug #34928. sql/sql_select.cc: When changing the table's join type to JT_NEXT in test_if_skip_sort_order(), also reset select->quick because other code may depend on its value to determine the GROUP BY/DISTINCT execution strategy. --- sql/sql_select.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 57bcb0b5942..1117df942dd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13158,6 +13158,11 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, tab->read_first_record= best_key_direction > 0 ? join_read_first:join_read_last; tab->type=JT_NEXT; // Read with index_first(), index_next() + if (select && select->quick) + { + delete select->quick; + select->quick= 0; + } if (table->covering_keys.is_set(best_key)) { table->key_read=1; @@ -13168,11 +13173,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, { tab->ref.key= -1; tab->ref.key_parts= 0; - if (select && select->quick) - { - delete select->quick; - select->quick= 0; - } if (select_limit < table_records) tab->limit= select_limit; } -- cgit v1.2.1 From 0b8342ba4e3c0426569f3256a8d951e168a7d52d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 26 Mar 2008 22:43:12 +0400 Subject: Fixed bug #35193. View definition as SELECT ... FROM DUAL WHERE ... has valid syntax, but use of such view in SELECT or SHOW CREATE VIEW syntax causes unexpected syntax error. Server omits FROM DUAL clause when storing view body string in a .frm file for further evaluation. However, syntax of SELECT-witout-FROM query is more restrictive than SELECT FROM DUAL syntax, and doesn't allow the WHERE clause. NOTE: this syntax difference is not documented. View registration procedure has been modified to preserve original structure of view's body. mysql-test/r/view.result: Added test case for bug #35193. mysql-test/t/view.test: Added test case for bug #35193. sql/sql_select.cc: Fixed bug #35193. The st_select_lex::print function always omits FROM DUAL clause, even if original SELECT query has the WHERE clause. The mysql_register_view function uses this function to reconstruct a body of view's AS clause for further evaluation and stores that reconstructed clause in a .frm file. SELECT without FROM syntax is more restrictive than SELECT FROM DUAL syntax: second one allows the WHERE clause, but first one is not. Use of this view in SELECT or SHOW CREATE VIEW queries causes unexpected syntax errors. The st_select_lex::print function has been modified to reconstruct FROM DUAL clause in queries when needed. TODO: Syntax difference is not documented and should be eliminated, however improvement of the SELECT-without-FROM syntax is not trivial and leads to significant modification of grammar file because of additional shift/reduce conflicts. --- sql/sql_select.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6392f7c4299..bb3030a721c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -15806,6 +15806,14 @@ void st_select_lex::print(THD *thd, String *str) /* go through join tree */ print_join(thd, str, &top_join_list); } + else if (where) + { + /* + "SELECT 1 FROM DUAL WHERE 2" should not be printed as + "SELECT 1 WHERE 2": the 1st syntax is valid, but the 2nd is not. + */ + str->append(STRING_WITH_LEN(" from DUAL ")); + } // Where Item *cur_where= where; -- cgit v1.2.1 From fb27979e6538e0f7c263b3d9f7400190f762e2fd Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 Mar 2008 01:13:39 +0100 Subject: Recommit of antonys previous commit. Bug#21413 "Engine table handler used by multiple threads in REPLACE DELAYED" When executing a REPLACE DELAYED statement, the storage engine ::extra() method was invoked by a different thread than the thread which has acquired the handler instance. This did not cause problems within the current server and with the current storage engines. But it has the potential to confuse future storage engines. Added code to avoid surplus calls to extra() method in case of DELAYED which avoids calling storage engine from a different thread than expected. No test case. This change does not change behavior in conjunction with current storage engines. So it cannot be tested by the regression test suite. sql/sql_insert.cc: Bug#21413 When performing DELAYED operations, we should not call the storage engine methods from the 'wrong' context. Ensure that the calls to the methods are appropiately guarded by either moving calls to sections where the lock_type is checked. No need to copy all elements of TABLE_LIST when opening table using open_ltable(). --- sql/sql_insert.cc | 44 ++++++++++++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 14 deletions(-) (limited to 'sql') diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f5bbba742a5..2e371971838 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -315,18 +315,23 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, error=0; id=0; thd->proc_info="update"; - if (duplic != DUP_ERROR || ignore) - table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - /* - let's *try* to start bulk inserts. It won't necessary - start them as values_list.elements should be greater than - some - handler dependent - threshold. - So we call start_bulk_insert to perform nesessary checks on - values_list.elements, and - if nothing else - to initialize - the code to make the call of end_bulk_insert() below safe. - */ +#ifndef EMBEDDED_LIBRARY if (lock_type != TL_WRITE_DELAYED) +#endif /* EMBEDDED_LIBRARY */ + { + if (duplic != DUP_ERROR || ignore) + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + + /* + let's *try* to start bulk inserts. It won't necessary + start them as values_list.elements should be greater than + some - handler dependent - threshold. + So we call start_bulk_insert to perform nesessary checks on + values_list.elements, and - if nothing else - to initialize + the code to make the call of end_bulk_insert() below safe. + */ table->file->start_bulk_insert(values_list.elements); + } while ((values= its++)) { @@ -415,6 +420,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, else if (table->next_number_field && info.copied) id=table->next_number_field->val_int(); // Return auto_increment value + if (duplic != DUP_ERROR || ignore) + table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + /* Invalidate the table in the query cache if something changed. For the transactional algorithm to work the invalidation must be @@ -455,8 +463,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, table->next_number_field=0; thd->count_cuted_fields= CHECK_FIELD_IGNORE; thd->next_insert_id=0; // Reset this if wrongly used - if (duplic != DUP_ERROR || ignore) - table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); /* Reset value of LAST_INSERT_ID if no rows where inserted */ if (!info.copied && thd->insert_id_used) @@ -561,7 +567,12 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(-1); } } - if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) + /* + Only call extra() handler method if we are not performing a DELAYED + operation. It will instead be executed by delayed insert thread. + */ + if ((duplic == DUP_UPDATE || duplic == DUP_REPLACE) && + (insert_table_list->lock_type != TL_WRITE_DELAYED)) table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); DBUG_RETURN(0); @@ -930,9 +941,11 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) my_error(ER_OUT_OF_RESOURCES,MYF(0)); goto err1; } - tmp->table_list= *table_list; // Needed to open table + /* We only need the db and table name to open tables with open_ltable() */ tmp->table_list.db= tmp->thd.db; + tmp->table_list.db_length= table_list->db_length; tmp->table_list.alias= tmp->table_list.real_name=tmp->thd.query; + tmp->table_list.real_name_length= table_list->real_name_length; tmp->lock(); pthread_mutex_lock(&tmp->mutex); if ((error=pthread_create(&tmp->thd.real_id,&connection_attrib, @@ -1491,6 +1504,9 @@ bool delayed_insert::handle_inserts(void) info.ignore= row->ignore; info.handle_duplicates= row->dup; + if (info.handle_duplicates == DUP_UPDATE || + info.handle_duplicates == DUP_REPLACE) + table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); if (info.ignore || info.handle_duplicates != DUP_ERROR) { -- cgit v1.2.1 From 9d661efd7f85b4208b9220434a0d5b5f21ac5070 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 Mar 2008 19:49:32 +0300 Subject: Bug#27219: Aggregate functions in ORDER BY. Mixing aggregate functions and non-grouping columns is not allowed in the ONLY_FULL_GROUP_BY mode. However in some cases the error wasn't thrown because of insufficient check. In order to check more thoroughly the new algorithm employs a list of outer fields used in a sum function and a SELECT_LEX::full_group_by_flag. Each non-outer field checked to find out whether it's aggregated or not and the current select is marked accordingly. All outer fields that are used under an aggregate function are added to the Item_sum::outer_fields list and later checked by the Item_sum::check_sum_func function. mysql-test/t/group_by.test: Added a test case for the bug#27219: Aggregate functions in ORDER BY. mysql-test/r/group_by.result: Added a test case for the bug#27219: Aggregate functions in ORDER BY. sql/sql_select.cc: Bug#27219: Aggregate functions in ORDER BY. Implementation of new check for mixing non aggregated fields and aggregation function in the ONLY_FULL_GROUP_BY mode. sql/sql_lex.cc: Bug#27219: Aggregate functions in ORDER BY. Initialization of the full_group_by_flag bitmap. SELECT_LEX::test_limit function doesn't reset ORDER BY clause anymore. sql/sql_lex.h: Bug#27219: Aggregate functions in ORDER BY. The full_group_by_flag is added to the SELECT_LEX class. sql/item_sum.h: Bug#27219: Aggregate functions in ORDER BY. The outer_fields list is added to the Item_sum class. sql/mysql_priv.h: Bug#27219: Aggregate functions in ORDER BY. Defined a set of constants used in the new check for mixing non aggregated fields and sum functions in the ONLY_FULL_GROUP_BY_MODE. sql/item_subselect.cc: Bug#27219: Aggregate functions in ORDER BY. The Item_in_subselect::select_in_like_transformer function now drops ORDER BY clause in all selects in a subquery. sql/item_sum.cc: Bug#27219: Aggregate functions in ORDER BY. Now the Item_sum::check_sum_func function now checks whether fields in the outer_fields list are aggregated or not and marks selects accordingly. sql/item.cc: Bug#27219: Aggregate functions in ORDER BY. Now the Item_field::fix_fields function checks whether the field is aggregated or not and marks its select_lex accordingly. --- sql/item.cc | 28 ++++++++++++++++++---- sql/item_subselect.cc | 14 +++++++++++ sql/item_sum.cc | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ sql/item_sum.h | 7 ++++++ sql/mysql_priv.h | 7 ++++++ sql/sql_lex.cc | 3 +-- sql/sql_lex.h | 11 ++++++++- sql/sql_select.cc | 34 ++++----------------------- 8 files changed, 132 insertions(+), 36 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 6f0119393e7..85756dcb124 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3925,9 +3925,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) } if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) goto error; - else if (!ret) - return FALSE; outer_fixed= TRUE; + if (!ret) + goto mark_non_agg_field; } else if (!from_field) goto error; @@ -3939,9 +3939,9 @@ bool Item_field::fix_fields(THD *thd, Item **reference) int ret; if ((ret= fix_outer_field(thd, &from_field, reference)) < 0) goto error; - else if (!ret) - return FALSE; outer_fixed= 1; + if (!ret) + goto mark_non_agg_field; } /* @@ -4007,6 +4007,26 @@ bool Item_field::fix_fields(THD *thd, Item **reference) thd->lex->current_select->non_agg_fields.push_back(this); marker= thd->lex->current_select->cur_pos_in_select_list; } +mark_non_agg_field: + if (fixed && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) + { + /* + Mark selects according to presence of non aggregated fields. + Fields from outer selects added to the aggregate function + outer_fields list as its unknown at the moment whether it's + aggregated or not. + */ + if (!thd->lex->in_sum_func) + cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + else + { + if (outer_fixed) + thd->lex->in_sum_func->outer_fields.push_back(this); + else if (thd->lex->in_sum_func->nest_level != + thd->lex->current_select->nest_level) + cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED; + } + } return FALSE; error: diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b3710841dfb..1c81a4ac3a1 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1434,6 +1434,19 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) DBUG_ENTER("Item_in_subselect::select_in_like_transformer"); + { + /* + IN/SOME/ALL/ANY subqueries aren't support LIMIT clause. Without it + ORDER BY clause becomes meaningless thus we drop it here. + */ + SELECT_LEX *sl= current->master_unit()->first_select(); + for (; sl; sl= sl->next_select()) + { + if (sl->join) + sl->join->order= 0; + } + } + if (changed) { DBUG_RETURN(RES_OK); @@ -1468,6 +1481,7 @@ Item_in_subselect::select_in_like_transformer(JOIN *join, Comp_creator *func) transformed= 1; arena= thd->activate_stmt_arena_if_needed(&backup); + /* Both transformers call fix_fields() only for Items created inside them, and all that items do not make permanent changes in current item arena diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 3d6d46ab3f4..42c934261b0 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -66,6 +66,7 @@ bool Item_sum::init_sum_func_check(THD *thd) aggr_sel= NULL; max_arg_level= -1; max_sum_func_level= -1; + outer_fields.empty(); return FALSE; } @@ -175,6 +176,7 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) MYF(0)); return TRUE; } + if (in_sum_func) { /* @@ -195,6 +197,68 @@ bool Item_sum::check_sum_func(THD *thd, Item **ref) set_if_bigger(in_sum_func->max_sum_func_level, aggr_level); set_if_bigger(in_sum_func->max_sum_func_level, max_sum_func_level); } + + /* + Check that non-aggregated fields and sum functions aren't mixed in the + same select in the ONLY_FULL_GROUP_BY mode. + */ + if (outer_fields.elements) + { + Item_field *field; + /* + Here we compare the nesting level of the select to which an outer field + belongs to with the aggregation level of the sum function. All fields in + the outer_fields list are checked. + + If the nesting level is equal to the aggregation level then the field is + aggregated by this sum function. + If the nesting level is less than the aggregation level then the field + belongs to an outer select. In this case if there is an embedding sum + function add current field to functions outer_fields list. If there is + no embedding function then the current field treated as non aggregated + and the select it belongs to is marked accordingly. + If the nesting level is greater than the aggregation level then it means + that this field was added by an inner sum function. + Consider an example: + + select avg ( <-- we are here, checking outer.f1 + select ( + select sum(outer.f1 + inner.f1) from inner + ) from outer) + from most_outer; + + In this case we check that no aggregate functions are used in the + select the field belongs to. If there are some then an error is + raised. + */ + List_iterator of(outer_fields); + while ((field= of++)) + { + SELECT_LEX *sel= field->cached_table->select_lex; + if (sel->nest_level < aggr_level) + { + if (in_sum_func) + { + /* + Let upper function decide whether this field is a non + aggregated one. + */ + in_sum_func->outer_fields.push_back(field); + } + else + sel->full_group_by_flag|= NON_AGG_FIELD_USED; + } + if (sel->nest_level > aggr_level && + (sel->full_group_by_flag & SUM_FUNC_USED) && + !sel->group_list.elements) + { + my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, + ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); + return TRUE; + } + } + } + aggr_sel->full_group_by_flag|= SUM_FUNC_USED; update_used_tables(); thd->lex->in_sum_func= in_sum_func; return FALSE; diff --git a/sql/item_sum.h b/sql/item_sum.h index bf0abe53eea..d39fc96e254 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -239,6 +239,13 @@ public: int8 max_arg_level; /* max level of unbound column references */ int8 max_sum_func_level;/* max level of aggregation for embedded functions */ bool quick_group; /* If incremental update of fields */ + /* + This list is used by the check for mixing non aggregated fields and + sum functions in the ONLY_FULL_GROUP_BY_MODE. We save all outer fields + directly or indirectly used under this function it as it's unclear + at the moment of fixing outer field whether it's aggregated or not. + */ + List outer_fields; protected: table_map used_tables_cache; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 59ec18e1a3d..6352647a154 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1044,6 +1044,13 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, bool allow_null_cond, int *error); extern Item **not_found_item; +/* + A set of constants used for checking non aggregated fields and sum + functions mixture in the ONLY_FULL_GROUP_BY_MODE. +*/ +#define NON_AGG_FIELD_USED 1 +#define SUM_FUNC_USED 2 + /* This enumeration type is used only by the function find_item_in_list to return the info on how an item has been resolved against a list diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index f1b4ffc949d..6bfcd982b04 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1253,6 +1253,7 @@ void st_select_lex::init_select() non_agg_fields.empty(); cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); + full_group_by_flag= 0; } /* @@ -1491,8 +1492,6 @@ bool st_select_lex::test_limit() "LIMIT & IN/ALL/ANY/SOME subquery"); return(1); } - // no sense in ORDER BY without LIMIT - order_list.empty(); return(0); } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index f216f51b0e4..cde4c3a97b3 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -611,7 +611,16 @@ public: joins on the right. */ List *prev_join_using; - + /* + Bitmap used in the ONLY_FULL_GROUP_BY_MODE to prevent mixture of aggregate + functions and non aggregated fields when GROUP BY list is absent. + Bits: + 0 - non aggregated fields are used in this select, + defined as NON_AGG_FIELD_USED. + 1 - aggregate functions are used in this select, + defined as SUM_FUNC_USED. + */ + uint8 full_group_by_flag; void init_query(); void init_select(); st_select_lex_unit* master_unit(); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6392f7c4299..8c5d09f4e16 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -568,37 +568,13 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check if there are references to un-aggregated columns when computing aggregate functions with implicit grouping (there is no GROUP BY). - TODO: Add check of calculation of GROUP functions and fields: - SELECT COUNT(*)+table.col1 from table1; */ - if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) + if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !group_list && + select_lex->full_group_by_flag == (NON_AGG_FIELD_USED | SUM_FUNC_USED)) { - if (!group_list) - { - uint flag=0; - List_iterator_fast it(fields_list); - Item *item; - while ((item= it++)) - { - if (item->with_sum_func) - flag|=1; - else if (!(flag & 2) && !item->const_during_execution()) - flag|=2; - } - if (having) - { - if (having->with_sum_func) - flag |= 1; - else if (!having->const_during_execution()) - flag |= 2; - } - if (flag == 3) - { - my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, - ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); - DBUG_RETURN(-1); - } - } + my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS, + ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0)); + DBUG_RETURN(-1); } { /* Caclulate the number of groups */ -- cgit v1.2.1 From 77fbeeab2464d5f035a7393eb11953604a4ac3f8 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 Mar 2008 19:39:21 +0200 Subject: Bug #35206: select query result different if the key is indexed or not The code for executing indexed ORDER BY was not setting all the internal fields correctly when selecting to execute ORDER BY over and index. Fixed by change the access method to one that will use the quick indexed access if one is selected while selecting indexed ORDER BY. mysql-test/r/order_by.result: Bug #35206: test case mysql-test/t/order_by.test: Bug #35206: test case sql/sql_select.cc: Bug #35206: Change the access method when selecting a quick indexed access. --- sql/sql_select.cc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 57bcb0b5942..bbfa41623b2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13177,6 +13177,23 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, tab->limit= select_limit; } } + else if (tab->type != JT_ALL) + { + /* + We're about to use a quick access to the table. + We need to change the access method so as the quick access + method is actually used. + */ + DBUG_ASSERT(tab->select->quick); + tab->type=JT_ALL; + tab->use_quick=1; + tab->ref.key= -1; + tab->ref.key_parts=0; // Don't use ref key. + tab->read_first_record= join_init_read_record; + /* + TODO: update the number of records in join->best_positions[tablenr] + */ + } } used_key_parts= best_key_parts; order_direction= best_key_direction; -- cgit v1.2.1 From f56d77dadf324d62f21e3fff7f460a8aba464605 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 13:16:41 +0100 Subject: BUG#29020 (Event results not correctly replicated to slave in RBR): The bug allow multiple executing transactions working with non-transactional to interfere with each others by interleaving the events of different trans- actions. Bug is fixed by writing non-transactional events to the transaction cache and flushing the cache to the binary log at statement commit. To mimic the behavior of normal statement-based replication, we flush the transaction cache in row- based mode when there is no committed statements in the transaction cache, which means we are committing the first one. This means that it will be written to the binary log as a "mini-transaction" with just the rows for the statement. Note that the changes here does not take effect when building the server with HAVE_TRANSACTIONS set to false, but it is not clear if this was possible before this patch either. For row-based logging, we also have that when AUTOCOMMIT=1, the code now always generates a BEGIN/COMMIT pair for single statements, or BEGIN/ROLLBACK pair in the case of non-transactional changes in a statement that was rolled back. Note that for the case where changes to a non-transactional table causes a rollback due to error, the statement will now be logged with a BEGIN/ROLLBACK pair, even though some changes has been committed to the non-transactional table. mysql-test/extra/rpl_tests/rpl_row_delayed_ins.test: Removing SHOW BINLOG EVENTS causing test to be non-deterministic. mysql-test/r/ctype_cp932_binlog_row.result: Result change. mysql-test/suite/binlog/r/binlog_base64_flag.result: Result change. mysql-test/suite/binlog/r/binlog_multi_engine.result: Result file change. mysql-test/suite/binlog/r/binlog_row_binlog.result: Result file change. mysql-test/suite/binlog/r/binlog_row_ctype_ucs.result: Result file change. mysql-test/suite/binlog/r/binlog_row_insert_select.result: Result file change. mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result: Result file change. mysql-test/suite/binlog/r/binlog_stm_binlog.result: Result file change. mysql-test/suite/binlog/t/binlog_base64_flag.test: Removing table that will be used in test to prevent failing if preceeding tests forgot to drop the table. mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result: Result file change. mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result: Result file change. mysql-test/suite/rpl/r/rpl_row_create_table.result: Result file change. mysql-test/suite/rpl/r/rpl_row_delayed_ins.result: Result file change. mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result: Result file change. mysql-test/suite/rpl/r/rpl_row_inexist_tbl.result: Result file change. mysql-test/suite/rpl/r/rpl_row_log.result: Result file change. mysql-test/suite/rpl/r/rpl_row_log_innodb.result: Result file change. mysql-test/suite/rpl/r/rpl_row_until.result: Result file change. mysql-test/suite/rpl/r/rpl_slave_skip.result: Result file change. mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result: Result file change. mysql-test/suite/rpl/r/rpl_truncate_2myisam.result: Result file change. mysql-test/suite/rpl/t/rpl_row_create_table.test: Binlog position change. mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test: Binlog position change. mysql-test/suite/rpl/t/rpl_row_mysqlbinlog.test: Binlog position change. Added stop position to mysqlbinlog argments to prevent extreneous output. mysql-test/suite/rpl/t/rpl_row_until.test: Binlog position change. mysql-test/suite/rpl/t/rpl_slave_skip.test: Binlog position change. mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test: Removing extreneous SHOW BINLOG EVENTS causing test to be non-deterministic. mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result: Result change. sql/log.cc: Adding variable at_least_one_stmt to denote that there is at least one statement committed to the transaction cache (but there might be more). Removing duplicate checks from binlog_end_trans(). The transaction cache should always be committed or rolled back when this function is called. Correcting conditions for binlog_rollback() and binlog_commit() and removing the previous "invisible commit" in favor of always using explicit commits in the binary log. sql/log_event.cc: Marking table map event to be cached. Removing Muted_query_log_event from code. sql/log_event.h: Removing unused class Muted_query_log_event. sql/sql_insert.cc: Adding missing call to ha_autocommit_or_rollback() for delayed thread. Marking CREATE-SELECT statements as transactional, since they don't need to be logged. --- sql/log.cc | 181 +++++++++++++++++++++++++++++++++++++++--------------- sql/log_event.cc | 17 +---- sql/log_event.h | 25 -------- sql/sql_insert.cc | 12 ++-- 4 files changed, 138 insertions(+), 97 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 6a9673989ea..4946cfd765c 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -52,8 +52,6 @@ LOGGER logger; MYSQL_BIN_LOG mysql_bin_log; ulong sync_binlog_counter= 0; -static Muted_query_log_event invisible_commit; - static bool test_if_number(const char *str, long *res, bool allow_wildcards); static int binlog_init(void *p); @@ -155,7 +153,7 @@ private: class binlog_trx_data { public: binlog_trx_data() - : m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF) + : m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF), at_least_one_stmt(0) { trans_log.end_of_file= max_binlog_cache_size; } @@ -188,6 +186,16 @@ public: reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0); if (pos < before_stmt_pos) before_stmt_pos= MY_OFF_T_UNDEF; + + /* + The only valid positions that can be truncated to are at the + beginning of a statement. We are relying on this fact to be able + to set the at_least_one_stmt flag correctly. In other word, if + we are truncating to the beginning of the transaction cache, + there will be no statements in the cache, otherwhise, we will + have at least one statement in the transaction cache. + */ + at_least_one_stmt= (pos > 0); } /* @@ -213,6 +221,12 @@ public: IO_CACHE trans_log; // The transaction cache + /** + Boolean that is true if there is at least one statement in the + transaction cache. + */ + bool at_least_one_stmt; + private: /* Pending binrows event. This event is the event where the rows are @@ -1373,26 +1387,20 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data, inside a stored function. */ thd->binlog_flush_pending_rows_event(TRUE); + + error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev); + trx_data->reset(); + /* - We write the transaction cache to the binary log if either we're - committing the entire transaction, or if we are doing an - autocommit outside a transaction. - */ - if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT))) + We need to step the table map version after writing the + transaction cache to disk. + */ + mysql_bin_log.update_table_map_version(); + statistic_increment(binlog_cache_use, &LOCK_status); + if (trans_log->disk_writes != 0) { - error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev); - trx_data->reset(); - /* - We need to step the table map version after writing the - transaction cache to disk. - */ - mysql_bin_log.update_table_map_version(); - statistic_increment(binlog_cache_use, &LOCK_status); - if (trans_log->disk_writes != 0) - { - statistic_increment(binlog_cache_disk_use, &LOCK_status); - trans_log->disk_writes= 0; - } + statistic_increment(binlog_cache_disk_use, &LOCK_status); + trans_log->disk_writes= 0; } } else @@ -1431,6 +1439,8 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) return 0; } +#define YESNO(X) ((X) ? "yes" : "no") + /** This function is called once after each statement. @@ -1439,10 +1449,8 @@ static int binlog_prepare(handlerton *hton, THD *thd, bool all) @param hton The binlog handlerton. @param thd The client thread that executes the transaction. - @param all true if this is the last statement before a COMMIT - statement; false if either this is a statement in a - transaction but not the last, or if this is a statement - not inside a BEGIN block and autocommit is on. + @param all This is @c true if this is a real transaction commit, and + @false otherwise. @see handlerton::commit */ @@ -1458,26 +1466,86 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) trx_data->reset(); DBUG_RETURN(0); } + /* - Write commit event if at least one of the following holds: - - the user sends an explicit COMMIT; or - - the autocommit flag is on, and we are not inside a BEGIN. - However, if the user has not sent an explicit COMMIT, and we are - either inside a BEGIN or run with autocommit off, then this is not - the end of a transaction and we should not write a commit event. + Decision table for committing a transaction. The top part, the + *conditions* represent different cases that can occur, and hte + bottom part, the *actions*, represent what should be done in that + particular case. + + Real transaction 'all' was true + + Statement in cache There were at least one statement in the + transaction cache + + In transaction We are inside a transaction + + Stmt modified non-trans The statement being committed modified a + non-transactional table + + All modified non-trans Some statement before this one in the + transaction modified a non-transactional + table + + + ============================= = = = = = = = = = = = = = = = = + Real transaction N N N N N N N N N N N N N N N N + Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y + In transaction N N N N Y Y Y Y N N N N Y Y Y Y + Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y + All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y + + Action: (C)ommit/(A)ccumulate C C - C A C - C - - - - A A - A + ============================= = = = = = = = = = = = = = = = = + + + ============================= = = = = = = = = = = = = = = = = + Real transaction Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y + Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y + In transaction N N N N Y Y Y Y N N N N Y Y Y Y + Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y + All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y + + (C)ommit/(A)ccumulate/(-) - - - - C C - C - - - - C C - C + ============================= = = = = = = = = = = = = = = = = + + In other words, we commit the transaction if and only if both of + the following are true: + - We are not in a transaction and committing a statement + + - We are in a transaction and one (or more) of the following are + true: + + - A full transaction is committed + + OR + + - A non-transactional statement is committed and there is + no statement cached + + Otherwise, we accumulate the statement */ - if (all || !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) + ulonglong const in_transaction= + thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); + DBUG_PRINT("debug", + ("all: %d, empty: %s, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", + all, + YESNO(trx_data->empty()), + YESNO(in_transaction), + YESNO(thd->transaction.all.modified_non_trans_table), + YESNO(thd->transaction.stmt.modified_non_trans_table))); + if (in_transaction && + (all || + (!trx_data->at_least_one_stmt && + thd->transaction.stmt.modified_non_trans_table)) || + !in_transaction && !all) { Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) int error= binlog_end_trans(thd, trx_data, &qev, all); DBUG_RETURN(error); } - else - { - int error= binlog_end_trans(thd, trx_data, &invisible_commit, all); - DBUG_RETURN(error); - } + DBUG_RETURN(0); } /** @@ -1490,10 +1558,8 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) @param hton The binlog handlerton. @param thd The client thread that executes the transaction. - @param all true if this is the last statement before a COMMIT - statement; false if either this is a statement in a - transaction but not the last, or if this is a statement - not inside a BEGIN block and autocommit is on. + @param all This is @c true if this is a real transaction rollback, and + @false otherwise. @see handlerton::rollback */ @@ -1509,21 +1575,36 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all) DBUG_RETURN(0); } - /* - Update the binary log with a BEGIN/ROLLBACK block if we have - cached some queries and we updated some non-transactional - table. Such cases should be rare (updating a - non-transactional table inside a transaction...) - */ - if (unlikely(thd->transaction.all.modified_non_trans_table || - (thd->options & OPTION_KEEP_LOG))) + DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", + YESNO(all), + YESNO(thd->transaction.all.modified_non_trans_table), + YESNO(thd->transaction.stmt.modified_non_trans_table))); + if (all && thd->transaction.all.modified_non_trans_table || + !all && thd->transaction.stmt.modified_non_trans_table || + (thd->options & OPTION_KEEP_LOG)) { + /* + We write the transaction cache with a rollback last if we have + modified any non-transactional table. We do this even if we are + committing a single statement that has modified a + non-transactional table since it can have modified a + transactional table in that statement as well, which needs to be + rolled back on the slave. + */ Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) error= binlog_end_trans(thd, trx_data, &qev, all); } - else + else if (all && !thd->transaction.all.modified_non_trans_table || + !all && !thd->transaction.stmt.modified_non_trans_table) + { + /* + If we have modified only transactional tables, we can truncate + the transaction cache without writing anything to the binary + log. + */ error= binlog_end_trans(thd, trx_data, 0, all); + } DBUG_RETURN(error); } diff --git a/sql/log_event.cc b/sql/log_event.cc index cc6ae14f160..5e625edf3d9 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2602,21 +2602,6 @@ Query_log_event::do_shall_skip(Relay_log_info *rli) #endif -/************************************************************************** - Muted_query_log_event methods -**************************************************************************/ - -#ifndef MYSQL_CLIENT -/* - Muted_query_log_event::Muted_query_log_event() -*/ -Muted_query_log_event::Muted_query_log_event() - :Query_log_event() -{ -} -#endif - - /************************************************************************** Start_log_event_v3 methods **************************************************************************/ @@ -7054,7 +7039,7 @@ int Table_map_log_event::save_field_metadata() #if !defined(MYSQL_CLIENT) Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid, bool is_transactional, uint16 flags) - : Log_event(thd, 0, is_transactional), + : Log_event(thd, 0, true), m_table(tbl), m_dbnam(tbl->s->db.str), m_dblen(m_dbnam ? tbl->s->db.length : 0), diff --git a/sql/log_event.h b/sql/log_event.h index c46827253a3..8342cb17851 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -1614,31 +1614,6 @@ public: /* !!! Public in this patch to allow old usage */ }; -/** - @class Muted_query_log_event - - Pretends to log SQL queries, but doesn't actually do so. This is - used internally only and never written to any binlog. - - @section Muted_query_log_event_binary_format Binary Format - - This log event is not stored, and thus the binary format is 0 bytes - long. Note that not even the Common-Header is stored. -*/ -class Muted_query_log_event: public Query_log_event -{ -public: -#ifndef MYSQL_CLIENT - Muted_query_log_event(); - - bool write(IO_CACHE* file) { return(false); }; - virtual bool write_post_header_for_derived(IO_CACHE* file) { return FALSE; } -#else - Muted_query_log_event() {} -#endif -}; - - #ifdef HAVE_REPLICATION /** diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2be932a6040..8971e8eab42 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2426,6 +2426,7 @@ pthread_handler_t handle_delayed_insert(void *arg) */ di->table->file->ha_release_auto_increment(); mysql_unlock_tables(thd, lock); + ha_autocommit_or_rollback(thd, 0); di->group_count=0; pthread_mutex_lock(&di->mutex); } @@ -3676,14 +3677,11 @@ void select_create::abort() { DBUG_ENTER("select_create::abort"); - /* - Disable binlog, because we "roll back" partial inserts in ::abort - by removing the table, even for non-transactional tables. - */ - tmp_disable_binlog(thd); /* In select_insert::abort() we roll back the statement, including - truncating the transaction cache of the binary log. + truncating the transaction cache of the binary log. To do this, we + pretend that the statement is transactional, even though it might + be the case that it was not. We roll back the statement prior to deleting the table and prior to releasing the lock on the table, since there might be potential @@ -3694,7 +3692,9 @@ void select_create::abort() of the table succeeded or not, since we need to reset the binary log state. */ + tmp_disable_binlog(thd); select_insert::abort(); + thd->transaction.stmt.modified_non_trans_table= FALSE; reenable_binlog(thd); -- cgit v1.2.1 From 4ae69fc2b14edab79b841a57fb6acb3c28ca76a1 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 17:24:23 +0200 Subject: fixed a hand in 5.1-marvel : Removed a double release of the mutex on error --- sql/sql_plugin.cc | 5 ----- 1 file changed, 5 deletions(-) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 4735cd569fc..106984823a5 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1446,8 +1446,6 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) - { - pthread_mutex_unlock(&LOCK_plugin); goto error; } } @@ -1459,10 +1457,7 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); pthread_mutex_lock(&LOCK_plugin); if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) - { - pthread_mutex_unlock(&LOCK_plugin); goto error; - } } pthread_mutex_unlock(&LOCK_plugin); name.length= dl.length= 0; -- cgit v1.2.1 From 4ec65151dc8e1b30b05a84c2f3a8bd2b9ce641c6 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 18:59:13 +0300 Subject: Fix for Bug#35469: server crash with LOAD DATA INFILE to a VIEW. The problem was that LOAD DATA code (sql_load.cc) didn't take into account that there may be items, representing references to other columns. This is a usual case in views. The crash happened because Item_direct_view_ref was casted to Item_user_var_as_out_param, which is not a base class. The fix is to 1) Handle references properly; 2) Ensure that an item is treated as a user variable only when it is a user variable indeed; 3) Report an error if LOAD DATA is used to load data into non-updatable column. mysql-test/r/loaddata.result: Update result file. mysql-test/t/loaddata.test: Add a test case form Bug#35469: server crash with LOAD DATA INFILE to a VIEW. sql/share/errmsg.txt: Introduce a new error. sql/sql_load.cc: Handle reference-items properly. mysql-test/std_data/bug35649.data: Add a data file for the test case. --- sql/share/errmsg.txt | 4 ++++ sql/sql_load.cc | 56 +++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 14 deletions(-) (limited to 'sql') diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 9e6cf462113..a3514776d6e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5641,3 +5641,7 @@ ER_NAME_BECOMES_EMPTY eng "Name '%-.64s' has become ''" ER_AMBIGUOUS_FIELD_TERM eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" + +ER_LOAD_DATA_INVALID_COLUMN + eng "Invalid column reference (%-.64s) in LOAD DATA" + diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 4da3c19bb3c..e9fd04dff15 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -233,9 +233,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, while ((item= it++)) { - if (item->type() == Item::FIELD_ITEM) + Item *real_item= item->real_item(); + + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field*)item)->field; + Field *field= ((Item_field*)real_item)->field; if (field->flags & BLOB_FLAG) { use_blobs= 1; @@ -244,7 +246,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else tot_length+= field->field_length; } - else + else if (item->type() == Item::STRING_ITEM) use_vars= 1; } if (use_blobs && !ex->line_term->length() && !field_term->length()) @@ -705,6 +707,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, { uint length; byte *pos; + Item *real_item; if (read_info.read_field()) break; @@ -716,14 +719,17 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, pos=read_info.row_start; length=(uint) (read_info.row_end-pos); + real_item= item->real_item(); + if (!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL"))) || (length == 1 && read_info.found_null)) { - if (item->type() == Item::FIELD_ITEM) + + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name, @@ -740,25 +746,39 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_WARN_NULL_TO_NOTNULL, 1); } } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_null_value( read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } + continue; } - if (item->type() == Item::FIELD_ITEM) + if (real_item->type() == Item::FIELD_ITEM) { - - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; field->set_notnull(); read_info.row_end[0]=0; // Safe to change end marker if (field == table->next_number_field) table->auto_increment_field_not_null= TRUE; field->store((char*) pos, length, read_info.read_charset); } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, - read_info.read_charset); + read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } } if (read_info.error) break; @@ -774,9 +794,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, break; for (; item ; item= it++) { - if (item->type() == Item::FIELD_ITEM) + Item *real_item= item->real_item(); + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name, @@ -796,9 +817,16 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_WARN_TOO_FEW_RECORDS, ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_null_value( read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } } } -- cgit v1.2.1 From 1d9f9abce36a81c8e6a9751940ff292a1ca15e2a Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 18:43:13 +0200 Subject: fixed compiler error in 5.1-marvel. --- sql/sql_plugin.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 106984823a5..811b82ebe05 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1447,7 +1447,6 @@ static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv, free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE)); if (plugin_add(tmp_root, &name, &dl, argc, argv, REPORT_TO_LOG)) goto error; - } } plugin_dl_del(&dl); // reduce ref count } -- cgit v1.2.1 From a9089cf460c7d7be3d8b843c948f0c707822878e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 14:02:27 -0400 Subject: Bug#26243 mysql command line crash after control-c - Backported the 5.1 DBUG to 5.0. - Avoid memory cleanup race on Windows client for CTRL-C client/mysql.cc: Bug#26243 mysql command line crash after control-c - On Windows, the sigint handler shouldn't call mysql_end because the main thread will do so automatically. - Remove unnecessary signal call from the sigint handler. - Call my_end with proper value. dbug/dbug.c: Bug#26243 mysql command line crash after control-c - Backported the 5.1 DBUG library. The old version uses a non-thread safe global variable 'static struct state *stack'. dbug/factorial.c: Bug#26243 mysql command line crash after control-c - Backported the 5.1 DBUG library. The old version uses a non-thread safe global variable 'static struct state *stack'. dbug/user.r: Bug#26243 mysql command line crash after control-c - Backported the 5.1 DBUG library. The old version uses a non-thread safe global variable 'static struct state *stack'. include/my_dbug.h: Bug#26243 mysql command line crash after control-c - Backported the 5.1 DBUG library. The old version uses a non-thread safe global variable 'static struct state *stack'. libmysql/libmysql.c: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. myisam/mi_open.c: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/ha_federated.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/ha_innodb.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/ha_myisammrg.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/item_cmpfunc.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/mysqld.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/net_serv.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/opt_range.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/set_var.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/slave.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/sql_cache.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. sql/sql_select.cc: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. tests/mysql_client_test.c: Bug#26243 mysql command line crash after control-c - Update for new DBUG library. --- sql/ha_federated.cc | 2 +- sql/ha_innodb.cc | 2 +- sql/ha_myisammrg.cc | 2 +- sql/item_cmpfunc.cc | 2 +- sql/mysqld.cc | 13 ++++--------- sql/net_serv.cc | 4 ++-- sql/opt_range.cc | 6 +----- sql/set_var.cc | 2 +- sql/slave.cc | 2 +- sql/sql_cache.cc | 6 +++--- sql/sql_select.cc | 2 +- 11 files changed, 17 insertions(+), 26 deletions(-) (limited to 'sql') diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index ac1e0962ffb..35648ea19c7 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1088,7 +1088,7 @@ bool ha_federated::create_where_from_key(String *to, uint store_length= key_part->store_length; uint part_length= min(store_length, length); needs_quotes= 1; - DBUG_DUMP("key, start of loop", (char *) ptr, length); + DBUG_DUMP("key, start of loop", ptr, length); if (key_part->null_bit) { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 2d2007c8fdd..a2de8ea1d0b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4250,7 +4250,7 @@ ha_innobase::rnd_pos( int error; uint keynr = active_index; DBUG_ENTER("rnd_pos"); - DBUG_DUMP("key", (char*) pos, ref_length); + DBUG_DUMP("key", pos, ref_length); statistic_increment(current_thd->status_var.ha_read_rnd_count, &LOCK_status); diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 78492d2843d..02d0eaf2af3 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -126,7 +126,7 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno)); return (my_errno ? my_errno : -1); } - DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")) + DBUG_PRINT("info", ("ha_myisammrg::open myrg_extrafunc...")); myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref); if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED || test_if_locked == HA_OPEN_ABORT_IF_LOCKED)) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 17345e76bba..16f3e51d615 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4130,7 +4130,7 @@ longlong Item_is_not_null_test::val_int() } if (args[0]->is_null()) { - DBUG_PRINT("info", ("null")) + DBUG_PRINT("info", ("null")); owner->was_null|= 1; DBUG_RETURN(0); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b8df51e9e58..b8f675ff696 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1071,12 +1071,9 @@ pthread_handler_t kill_server_thread(void *arg __attribute__((unused))) extern "C" sig_handler print_signal_warning(int sig) { - if (!DBUG_IN_USE) - { - if (global_system_variables.log_warnings) - sql_print_warning("Got signal %d from thread %ld", - sig, my_thread_id()); - } + if (global_system_variables.log_warnings) + sql_print_warning("Got signal %d from thread %ld", + sig, my_thread_id()); #ifdef DONT_REMEMBER_SIGNAL my_sigset(sig,print_signal_warning); /* int. thread system calls */ #endif @@ -1718,7 +1715,7 @@ void end_thread(THD *thd, bool put_in_cache) ! abort_loop && !kill_cached_threads) { /* Don't kill the thread, just put it in cache for reuse */ - DBUG_PRINT("info", ("Adding thread to cache")) + DBUG_PRINT("info", ("Adding thread to cache")); cached_thread_count++; while (!abort_loop && ! wake_thread && ! kill_cached_threads) (void) pthread_cond_wait(&COND_thread_cache, &LOCK_thread_count); @@ -3623,8 +3620,6 @@ int main(int argc, char **argv) MY_INIT(argv[0]); // init my_sys library & pthreads /* ^^^ Nothing should be before this line! */ - DEBUGGER_OFF; - /* Set signal used to kill MySQL */ #if defined(SIGUSR2) thr_kill_signal= thd_lib_detected == THD_LIB_LT ? SIGINT : SIGUSR2; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 017a2eb9ecd..a40764577fd 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -394,7 +394,7 @@ my_net_write(NET *net,const char *packet,ulong len) if (net_write_buff(net,(char*) buff,NET_HEADER_SIZE)) return 1; #ifndef DEBUG_DATA_PACKETS - DBUG_DUMP("packet_header",(char*) buff,NET_HEADER_SIZE); + DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE); #endif return test(net_write_buff(net,packet,len)); } @@ -892,7 +892,7 @@ my_real_read(NET *net, ulong *complen) if (i == 0) { /* First parts is packet length */ ulong helping; - DBUG_DUMP("packet_header",(char*) net->buff+net->where_b, + DBUG_DUMP("packet_header", net->buff+net->where_b, NET_HEADER_SIZE); if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr) { diff --git a/sql/opt_range.cc b/sql/opt_range.cc index c3eddbd0abf..17a4701b515 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -9570,8 +9570,6 @@ static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, int idx; char buff[1024]; DBUG_ENTER("print_sel_tree"); - if (! _db_on_) - DBUG_VOID_RETURN; String tmp(buff,sizeof(buff),&my_charset_bin); tmp.length(0); @@ -9601,8 +9599,6 @@ static void print_ror_scans_arr(TABLE *table, const char *msg, struct st_ror_scan_info **end) { DBUG_ENTER("print_ror_scans"); - if (! _db_on_) - DBUG_VOID_RETURN; char buff[1024]; String tmp(buff,sizeof(buff),&my_charset_bin); @@ -9665,7 +9661,7 @@ static void print_quick(QUICK_SELECT_I *quick, const key_map *needed_reg) { char buf[MAX_KEY/8+1]; DBUG_ENTER("print_quick"); - if (! _db_on_ || !quick) + if (!quick) DBUG_VOID_RETURN; DBUG_LOCK_FILE; diff --git a/sql/set_var.cc b/sql/set_var.cc index a99b063a97e..84766e511ca 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1990,7 +1990,7 @@ void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type, { DATE_TIME_FORMAT *old; DBUG_ENTER("sys_var_date_time_format::update2"); - DBUG_DUMP("positions",(char*) new_value->positions, + DBUG_DUMP("positions", new_value->positions, sizeof(new_value->positions)); if (type == OPT_GLOBAL) diff --git a/sql/slave.cc b/sql/slave.cc index 8a3620080f2..2cd4b00cca9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3339,7 +3339,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) } DBUG_PRINT("info", ("thd->options: %s", - (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")) + (thd->options & OPTION_BEGIN) ? "OPTION_BEGIN" : "")); /* Protect against common user error of setting the counter to 1 diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 8c868971911..f8906a17c12 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -315,13 +315,13 @@ TODO list: #define MUTEX_UNLOCK(M) {DBUG_PRINT("lock", ("mutex unlock 0x%lx",\ (ulong)(M))); pthread_mutex_unlock(M);} #define RW_WLOCK(M) {DBUG_PRINT("lock", ("rwlock wlock 0x%lx",(ulong)(M))); \ - if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")) \ + if (!rw_wrlock(M)) DBUG_PRINT("lock", ("rwlock wlock ok")); \ else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); } #define RW_RLOCK(M) {DBUG_PRINT("lock", ("rwlock rlock 0x%lx", (ulong)(M))); \ - if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")) \ + if (!rw_rdlock(M)) DBUG_PRINT("lock", ("rwlock rlock ok")); \ else DBUG_PRINT("lock", ("rwlock wlock FAILED %d", errno)); } #define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \ - if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")) \ + if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \ else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); } #define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \ pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));} diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 6392f7c4299..ef3abb06b1e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -14470,7 +14470,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, ifield->db_name= iref->db_name; } #ifndef DBUG_OFF - if (_db_on_ && !item_field->name) + if (!item_field->name) { char buff[256]; String str(buff,sizeof(buff),&my_charset_bin); -- cgit v1.2.1 From e44403fe31963ef9fe8a574f0e159b9b0b67e196 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 19:57:39 +0100 Subject: Fixes to eliminate compiler warnings. sql/log.cc: Reordering initialalizer list to eliminate compiler warnings. --- sql/log.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index fa59b837abc..fcb81e05ab3 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -153,7 +153,7 @@ private: class binlog_trx_data { public: binlog_trx_data() - : m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF), at_least_one_stmt(0) + : at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF) { trans_log.end_of_file= max_binlog_cache_size; } -- cgit v1.2.1 From 18a01ce9246616e2a3f131d69c132109335c9359 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 29 Mar 2008 09:52:16 +0200 Subject: fixed warnings and compile errors from the fix for bug 26243 --- sql/ha_federated.cc | 2 +- sql/ha_innodb.cc | 2 +- sql/ha_ndbcluster.cc | 34 ++++++++++++++++------------------ sql/ha_ndbcluster_cond.cc | 2 +- 4 files changed, 19 insertions(+), 21 deletions(-) (limited to 'sql') diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 7a7d65a3d34..2ccfeba74cb 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1095,7 +1095,7 @@ bool ha_federated::create_where_from_key(String *to, uint store_length= key_part->store_length; uint part_length= min(store_length, length); needs_quotes= 1; - DBUG_DUMP("key, start of loop", ptr, length); + DBUG_DUMP("key, start of loop", (uchar *)ptr, length); if (key_part->null_bit) { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index a2de8ea1d0b..1be6137460b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4250,7 +4250,7 @@ ha_innobase::rnd_pos( int error; uint keynr = active_index; DBUG_ENTER("rnd_pos"); - DBUG_DUMP("key", pos, ref_length); + DBUG_DUMP("key", (uchar *)pos, ref_length); statistic_increment(current_thd->status_var.ha_read_rnd_count, &LOCK_status); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index e3ab2b67e26..0a75b328ca0 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -677,7 +677,7 @@ int ha_ndbcluster::set_ndb_key(NdbOperation *ndb_op, Field *field, DBUG_PRINT("enter", ("%d: %s, ndb_type: %u, len=%d", fieldnr, field->field_name, field->type(), pack_len)); - DBUG_DUMP("key", (char*)field_ptr, pack_len); + DBUG_DUMP("key", (uchar*)field_ptr, pack_len); DBUG_ASSERT(ndb_supported_type(field->type())); DBUG_ASSERT(! (field->flags & BLOB_FLAG)); @@ -699,7 +699,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, DBUG_PRINT("enter", ("%d: %s, type: %u, len=%d, is_null=%s", fieldnr, field->field_name, field->type(), pack_len, field->is_null()?"Y":"N")); - DBUG_DUMP("value", (char*) field_ptr, pack_len); + DBUG_DUMP("value", (uchar*) field_ptr, pack_len); DBUG_ASSERT(ndb_supported_type(field->type())); { @@ -737,7 +737,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, // Set value to NULL DBUG_RETURN((ndb_op->setValue(fieldnr, (char*)NULL, pack_len) != 0)); DBUG_PRINT("info", ("bit field")); - DBUG_DUMP("value", (char*)&bits, pack_len); + DBUG_DUMP("value", (uchar*)&bits, pack_len); #ifdef WORDS_BIGENDIAN /* store lsw first */ bits = ((bits >> 32) & 0x00000000FFFFFFFFLL) @@ -768,7 +768,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, DBUG_PRINT("value", ("set blob ptr: %p len: %u", blob_ptr, blob_len)); - DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26)); + DBUG_DUMP("value", (uchar*)blob_ptr, min(blob_len, 26)); if (set_blob_value) *set_blob_value= TRUE; @@ -1007,8 +1007,8 @@ int ha_ndbcluster::get_metadata(const char *path) ("metadata, pack_length: %d getFrmLength: %d memcmp: %d", pack_length, tab->getFrmLength(), memcmp(pack_data, tab->getFrmData(), pack_length))); - DBUG_DUMP("pack_data", (char*)pack_data, pack_length); - DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength()); + DBUG_DUMP("pack_data", (uchar*)pack_data, pack_length); + DBUG_DUMP("frm", (uchar*)tab->getFrmData(), tab->getFrmLength()); error= 3; invalidating_ndb_table= FALSE; } @@ -1502,7 +1502,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) int res; DBUG_ENTER("pk_read"); DBUG_PRINT("enter", ("key_len: %u", key_len)); - DBUG_DUMP("key", (char*)key, key_len); + DBUG_DUMP("key", (uchar*)key, key_len); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -1514,7 +1514,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) { // This table has no primary key, use "hidden" primary key DBUG_PRINT("info", ("Using hidden key")); - DBUG_DUMP("key", (char*)key, 8); + DBUG_DUMP("key", (uchar*)key, 8); if (set_hidden_key(op, no_fields, key)) ERR_RETURN(trans->getNdbError()); @@ -1797,7 +1797,7 @@ int ha_ndbcluster::unique_index_read(const byte *key, NdbIndexOperation *op; DBUG_ENTER("ha_ndbcluster::unique_index_read"); DBUG_PRINT("enter", ("key_len: %u, index: %u", key_len, active_index)); - DBUG_DUMP("key", (char*)key, key_len); + DBUG_DUMP("key", (uchar*)key, key_len); NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -2126,7 +2126,7 @@ int ha_ndbcluster::set_bounds(NdbIndexScanOperation *op, { DBUG_PRINT("info", ("key %d:%d offset=%d length=%d last=%d bound=%d", j, i, tot_len, part_len, p.part_last, p.bound_type)); - DBUG_DUMP("info", (const char*)p.part_ptr, part_store_len); + DBUG_DUMP("info", (const uchar*)p.part_ptr, part_store_len); // Set bound if not cancelled via type -1 if (p.bound_type != -1) @@ -2644,7 +2644,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) // Require that the PK for this record has previously been // read into m_ref - DBUG_DUMP("key", m_ref, NDB_HIDDEN_PRIMARY_KEY_LENGTH); + DBUG_DUMP("key", (uchar *)m_ref, NDB_HIDDEN_PRIMARY_KEY_LENGTH); if (set_hidden_key(op, table->s->fields, m_ref)) ERR_RETURN(op->getNdbError()); @@ -2864,8 +2864,6 @@ void ha_ndbcluster::print_results() DBUG_ENTER("print_results"); #ifndef DBUG_OFF - if (!_db_on_) - DBUG_VOID_RETURN; char buf_type[MAX_FIELD_WIDTH], buf_val[MAX_FIELD_WIDTH]; String type(buf_type, sizeof(buf_type), &my_charset_bin); @@ -3341,7 +3339,7 @@ void ha_ndbcluster::position(const byte *record) memcpy(ref, m_ref, ref_length); } - DBUG_DUMP("ref", (char*)ref, ref_length); + DBUG_DUMP("ref", (uchar*)ref, ref_length); DBUG_VOID_RETURN; } @@ -6132,14 +6130,14 @@ ha_ndbcluster::register_query_cache_table(THD *thd, if (!is_autocommit) { - DBUG_PRINT("exit", ("Can't register table during transaction")) + DBUG_PRINT("exit", ("Can't register table during transaction")); DBUG_RETURN(FALSE); } if (ndb_get_commitcount(thd, m_dbname, m_tabname, &commit_count)) { *engine_data= 0; - DBUG_PRINT("exit", ("Error, could not get commitcount")) + DBUG_PRINT("exit", ("Error, could not get commitcount")); DBUG_RETURN(FALSE); } *engine_data= commit_count; @@ -6263,7 +6261,7 @@ static int packfrm(const void *data, uint len, } DBUG_PRINT("info", ("org_len: %lu comp_len: %lu", org_len, comp_len)); - DBUG_DUMP("compressed", (char*)data, org_len); + DBUG_DUMP("compressed", (uchar*)data, org_len); error= 2; blob_len= sizeof(frm_blob_struct::frm_blob_header)+org_len; @@ -6307,7 +6305,7 @@ static int unpackfrm(const void **unpack_data, uint *unpack_len, DBUG_PRINT("blob",("ver: %lu complen: %lu orglen: %lu", ver,complen,orglen)); - DBUG_DUMP("blob->data", (char*) blob->data, complen); + DBUG_DUMP("blob->data", (uchar*) blob->data, complen); if (ver != 1) { diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc index f5b41959b40..37e710acff4 100644 --- a/sql/ha_ndbcluster_cond.cc +++ b/sql/ha_ndbcluster_cond.cc @@ -1419,7 +1419,7 @@ int ha_ndbcluster_cond::generate_scan_filter_from_key(NdbScanOperation *op, uint32 pack_len= field->pack_length(); const byte* ptr= key; DBUG_PRINT("info", ("Filtering value for %s", field->field_name)); - DBUG_DUMP("key", (char*)ptr, pack_len); + DBUG_DUMP("key", (uchar*)ptr, pack_len); if (key_part->null_bit) { DBUG_PRINT("info", ("Generating ISNULL filter")); -- cgit v1.2.1 From 8ae5aa3bd81124ed4d3c7e74139b028fd091cefc Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 29 Mar 2008 16:12:23 +0200 Subject: fixes for warnings and compile errors for the fix of bug 26243 --- sql/ha_berkeley.cc | 8 ++++---- sql/mysqld.cc | 2 +- sql/sql_union.cc | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index fbfd5031656..1de40db2724 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -467,7 +467,7 @@ berkeley_cmp_packed_key(DB *file, const DBT *new_key, const DBT *saved_key) KEY_PART_INFO *key_part= key->key_part, *end=key_part+key->key_parts; uint key_length=new_key->size; - DBUG_DUMP("key_in_index", saved_key_ptr, saved_key->size); + DBUG_DUMP("key_in_index", (uchar *)saved_key_ptr, saved_key->size); for (; key_part != end && (int) key_length > 0; key_part++) { int cmp; @@ -903,7 +903,7 @@ DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff, key_length-=key_part->length; } key->size= (u_int32_t) (buff - (char*) key->data); - DBUG_DUMP("key",(char*) key->data, key->size); + DBUG_DUMP("key",(uchar*) key->data, key->size); DBUG_RETURN(key); } @@ -947,7 +947,7 @@ DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff, key_length-=key_part->store_length; } key->size= (u_int32_t) (buff - (char*) key->data); - DBUG_DUMP("key",(char*) key->data, key->size); + DBUG_DUMP("key",(uchar*) key->data, key->size); DBUG_RETURN(key); } @@ -1705,7 +1705,7 @@ DBT *ha_berkeley::get_pos(DBT *to, byte *pos) pos+=key_part->field->packed_col_length((char*) pos,key_part->length); to->size= (uint) (pos- (byte*) to->data); } - DBUG_DUMP("key", (char*) to->data, to->size); + DBUG_DUMP("key", (uchar*) to->data, to->size); return to; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index b8f675ff696..c239530f2fc 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6943,7 +6943,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), switch(optid) { case '#': #ifndef DBUG_OFF - DBUG_PUSH(argument ? argument : default_dbug_option); + DBUG_SET_INITIAL(argument ? argument : default_dbug_option); #endif opt_endinfo=1; /* unireg: memory allocation */ break; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 25a0540e4dd..da5e118b069 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -444,7 +444,9 @@ bool st_select_lex_unit::exec() } /* re-enabling indexes for next subselect iteration */ if (union_distinct && table->file->enable_indexes(HA_KEY_SWITCH_ALL)) + { DBUG_ASSERT(0); + } } for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { -- cgit v1.2.1 From 11714e6842f906901ac8e3ff9ac003ae0058fce7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 29 Mar 2008 17:50:46 +0200 Subject: fixed warnings from the fix of 26243 --- sql/examples/ha_tina.cc | 2 +- sql/item_func.cc | 2 +- sql/lock.cc | 2 +- sql/sql_analyse.cc | 24 ++++++++++++------------ 4 files changed, 15 insertions(+), 15 deletions(-) (limited to 'sql') diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 0d1d821cf17..0b57fe86e62 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -883,7 +883,7 @@ int ha_tina::delete_all_rows() DBUG_ENTER("ha_tina::delete_all_rows"); if (!records_is_known) - return (my_errno=HA_ERR_WRONG_COMMAND); + DBUG_RETURN(my_errno=HA_ERR_WRONG_COMMAND); /* Invalidate all cached mmap pages */ if (free_mmap(share)) diff --git a/sql/item_func.cc b/sql/item_func.cc index a6fb8a94b69..7416471d630 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5115,7 +5115,7 @@ double Item_func_match::val_real() DBUG_RETURN(-1.0); if (key != NO_SUCH_KEY && table->null_row) /* NULL row from an outer join */ - return 0.0; + DBUG_RETURN(0.0); if (join_key) { diff --git a/sql/lock.cc b/sql/lock.cc index cf06be5f95f..47458702033 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -703,7 +703,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, { my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0), table_ptr[i]->s->db, table_ptr[i]->s->table_name); - return 0; + DBUG_RETURN(0); } } diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 2e90d00f8aa..4b3264069b5 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -195,13 +195,13 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) */ for (; str != end && my_isspace(system_charset_info, *str); str++) ; if (str == end) - return 0; + DBUG_RETURN(0); if (*str == '-') { info->negative = 1; if (++str == end || *str == '0') // converting -0 to a number - return 0; // might lose information + DBUG_RETURN(0); // might lose information } else info->negative = 0; @@ -219,33 +219,33 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) int error; info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error); if (info->integers == 1) - return 0; // a single number can't be zerofill + DBUG_RETURN(0); // a single number can't be zerofill info->maybe_zerofill = 1; - return 1; // a zerofill number, or an integer + DBUG_RETURN(1); // a zerofill number, or an integer } if (*str == '.' || *str == 'e' || *str == 'E') { if (info->zerofill) // can't be zerofill anymore - return 0; + DBUG_RETURN(0); if ((str + 1) == end) // number was something like '123[.eE]' { char *endpos= (char*) str; int error; info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error); - return 1; + DBUG_RETURN(1); } if (*str == 'e' || *str == 'E') // number may be something like '1e+50' { str++; if (*str != '-' && *str != '+') - return 0; + DBUG_RETURN(0); for (str++; str != end && my_isdigit(system_charset_info,*str); str++) ; if (str == end) { info->is_float = 1; // we can't use variable decimals here - return 1; + DBUG_RETURN(1); } - return 0; + DBUG_RETURN(0); } for (str++; *(end - 1) == '0'; end--); // jump over zeros at the end if (str == end) // number was something like '123.000' @@ -253,17 +253,17 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len) char *endpos= (char*) str; int error; info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error); - return 1; + DBUG_RETURN(1); } for (; str != end && my_isdigit(system_charset_info,*str); str++) info->decimals++; if (str == end) { info->dval = my_atof(begin); - return 1; + DBUG_RETURN(1); } } - return 0; + DBUG_RETURN(0); } -- cgit v1.2.1 From 2a001d5389241f0f3cd3debe295ec3ed3c0eea3c Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 30 Mar 2008 00:54:08 +0200 Subject: Bug #35675 reset master finds assert if a binlog file can not be deleted If a binlog file is manually replaced with a namesake directory the internal purging did not handle the error of deleting the file so that eventually a post-execution guards fires an assert. Fixed with reusing a snippet of code for bug@18199 to tolerate lack of the file but no other error at an attempt to delete it. The same applied to the index file deletion. The cset carries pieces of manual merging. mysql-test/r/binlog_index.result: new results mysql-test/r/ctype_big5.result: results changed mysql-test/suite/binlog/r/binlog_auto_increment_bug33029.result: new results mysql-test/suite/binlog/r/binlog_stm_blackhole.result: new results mysql-test/suite/binlog/t/binlog_auto_increment_bug33029.test: cleanup. still todo: to let the test run multiple times w/o restarting the server (just ./mtr test) mysql-test/suite/rpl/r/rpl_stm_auto_increment_bug33029.result: results changed mysql-test/suite/rpl/t/rpl_stm_auto_increment_bug33029.test: guarding the test with statement format condition as the logics of the test requires sql/log.cc: two changes. One for the bug, other manual merge. The bug change needs MYF(0) to pass to my_delete because not all error out of the function are critical. The finer check is done on the caller of my_delete similarly how it was implemented for bug@18199 fixes. Non-existance of a file is not a critical error. sql/sql_class.cc: manual merge, removing extra automatically brought hunk. --- sql/log.cc | 74 +++++++++++++++++++++++++++++++++++++++++++------------- sql/sql_class.cc | 13 ---------- 2 files changed, 57 insertions(+), 30 deletions(-) (limited to 'sql') diff --git a/sql/log.cc b/sql/log.cc index 8789dce4cd4..6e6a29c59b7 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2746,14 +2746,62 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) for (;;) { - my_delete_allow_opened(linfo.log_file_name, MYF(MY_WME)); + if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0) + { + if (my_errno == ENOENT) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + linfo.log_file_name); + sql_print_information("Failed to delete file '%s'", + linfo.log_file_name); + my_errno= 0; + error= 0; + } + else + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + linfo.log_file_name); + error= 1; + goto err; + } + } if (find_next_log(&linfo, 0)) break; } /* Start logging with a new file */ close(LOG_CLOSE_INDEX); - my_delete_allow_opened(index_file_name, MYF(MY_WME)); // Reset (open will update) + if ((error= my_delete_allow_opened(index_file_name, MYF(0)))) // Reset (open will update) + { + if (my_errno == ENOENT) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE), + index_file_name); + sql_print_information("Failed to delete file '%s'", + index_file_name); + my_errno= 0; + error= 0; + } + else + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_BINLOG_PURGE_FATAL_ERR, + "a problem with deleting %s; " + "consider examining correspondence " + "of your binlog index file " + "to the actual binlog files", + index_file_name); + error= 1; + goto err; + } + } if (!thd->slave_thread) need_start_event=1; if (!open_index_file(index_file_name, 0)) @@ -2913,6 +2961,7 @@ int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads 0 ok @retval LOG_INFO_EOF to_log not found + LOG_INFO_EMFILE too many files opened LOG_INFO_FATAL if any other than ENOENT error from my_stat() or my_delete() */ @@ -3004,28 +3053,19 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log, "of your binlog index file " "to the actual binlog files", log_info.log_file_name); + if (my_errno == EMFILE) + { + DBUG_PRINT("info", + ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); + error= LOG_INFO_EMFILE; + } error= LOG_INFO_FATAL; goto err; } } } - /* - It's not fatal if we can't delete a log file ; - if we could delete it, take its size into account - */ - DBUG_PRINT("info",("purging %s",log_info.log_file_name)); - if (!my_delete(log_info.log_file_name, MYF(0)) && decrease_log_space) - *decrease_log_space-= file_size; ha_binlog_index_purge_file(current_thd, log_info.log_file_name); - if (current_thd->is_slave_error) { - DBUG_PRINT("info",("slave error: %d", current_thd->is_slave_error)); - if (my_errno == EMFILE) { - DBUG_PRINT("info",("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno)); - ret = LOG_INFO_EMFILE; - break; - } - } if (find_next_log(&log_info, 0) || exit_loop) break; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 247cccfa838..48ab3ea64c1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1069,19 +1069,6 @@ bool THD::store_globals() void THD::cleanup_after_query() { - last_insert_id_used= FALSE; - if (clear_next_insert_id) - { - clear_next_insert_id= 0; - next_insert_id= 0; - - /* - BUG#33029, if one statement in a SP set this member to 1, all - statment after this statement in the SP would be considered used - INSERT_ID value, reset this member after each query to fix this. - */ - insert_id_used= 0; - } /* Reset rand_used so that detection of calls to rand() will save random seeds if needed by the slave. -- cgit v1.2.1 From 6edab4bc081b29894f3eaf70468d989ea956ff18 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 30 Mar 2008 15:46:37 -0400 Subject: Bug#26243 - Cleanup Valgrind error --- sql/tztime.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/tztime.cc b/sql/tztime.cc index bedbf921cae..b7381e2ed95 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2278,7 +2278,7 @@ my_tz_find(const String * name, TABLE_LIST *tz_tables) DBUG_ENTER("my_tz_find"); DBUG_PRINT("enter", ("time zone name='%s'", - name ? ((String *)name)->c_ptr() : "NULL")); + name ? ((String *)name)->c_ptr_safe() : "NULL")); DBUG_ASSERT(!time_zone_tables_exist || tz_tables || current_thd->slave_thread); -- cgit v1.2.1 From c481f6b3cf80f471321d2ef4e7c68fe9e6e5d0ca Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Apr 2008 18:50:35 +0200 Subject: Post-merge fixes. sql/share/errmsg.txt: Reverting error message to before merge. --- sql/share/errmsg.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 1dbba191f09..894e2094968 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5522,8 +5522,8 @@ ER_M_BIGGER_THAN_D 42000 S1009 eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.192s')." ger "Für FLOAT(M,D), DOUBLE(M,D) oder DECIMAL(M,D) muss M >= D sein (Feld '%-.192s')" ER_WRONG_LOCK_OF_SYSTEM_TABLE - eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables" - ger "Sie können Schreibsperren auf der Systemtabelle '%-.64s.%-.64s' nicht mit anderen Tabellen kombinieren" + eng "You can't combine write-locking of system tables with other tables or lock types" + ger "Sie können Schreibsperren auf der Systemtabelle nicht mit anderen Tabellen kombinieren" ER_CONNECT_TO_FOREIGN_DATA_SOURCE eng "Unable to connect to foreign data source: %.64s" ger "Kann nicht mit Fremddatenquelle verbinden: %.64s" -- cgit v1.2.1
charset_database_numberQ_CHARSET_DATABASE_NUMBER == 8Q_CHARSET_DATABASE_CODE == 8 2 byte integer The value of the collation_database system variable (in the @@ -1457,11 +1461,11 @@ protected: In newer versions, "CREATE TABLE" has been changed to take the character set from the database of the created table, rather than - the database of the current database. This makes a difference - when creating a table in another database than the current one. - "LOAD DATA INFILE" has not yet changed to do this, but there are - plans to eventually do it, and to make collation_database - read-only. + the character set of the current database. This makes a + difference when creating a table in another database than the + current one. "LOAD DATA INFILE" has not yet changed to do this, + but there are plans to eventually do it, and to make + collation_database read-only. This field is written if it is not 0.