From b243283e693452549457bd9ccf73918965809571 Mon Sep 17 00:00:00 2001 From: MySQL Build Team Date: Wed, 20 May 2009 23:04:34 +0200 Subject: [PATCH 01/10] Updates to build with community features enabled for community builds. --- CMakeLists.txt | 4 ++++ include/config-win.h | 3 --- support-files/mysql.spec.sh | 2 ++ win/configure.js | 1 + 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f66453ef492..91c3a804eea 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,10 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFORCE_INIT_OF_VARS") # Note that some engines are always compiled in, MyISAM, MyISAMMRG, HEAP +IF(WITH_COMMUNITY_FEATURES) + ADD_DEFINITIONS(-DENABLED_PROFILING -DCOMMUNITY_SERVER) +ENDIF(WITH_COMMUNITY_FEATURES) + IF(WITH_ARCHIVE_STORAGE_ENGINE) ADD_DEFINITIONS(-DHAVE_ARCHIVE_DB) ENDIF(WITH_ARCHIVE_STORAGE_ENGINE) diff --git a/include/config-win.h b/include/config-win.h index 39affd3b8e9..ab463a7c142 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -206,9 +206,6 @@ typedef uint rf_SetTimer; /* If LOAD DATA LOCAL INFILE should be enabled by default */ #define ENABLED_LOCAL_INFILE 1 -/* If query profiling should be enabled by default */ -#define ENABLED_PROFILING 1 - /* Convert some simple functions to Posix */ #define my_sigset(A,B) signal((A),(B)) diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index fa3c3a8b4ce..584c0abc777 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -264,6 +264,8 @@ sh -c "PATH=\"${MYSQL_BUILD_PATH:-$PATH}\" \ --includedir=%{_includedir} \ --mandir=%{_mandir} \ --enable-thread-safe-client \ + --enable-community-features \ + --enable-profiling \ --with-readline ; \ # Add this for more debugging support # --with-debug diff --git a/win/configure.js b/win/configure.js index 0de09fb318c..8370497ea4b 100755 --- a/win/configure.js +++ b/win/configure.js @@ -39,6 +39,7 @@ try var parts = args.Item(i).split('='); switch (parts[0]) { + case "WITH_COMMUNITY_FEATURES": case "WITH_ARCHIVE_STORAGE_ENGINE": case "WITH_BERKELEY_STORAGE_ENGINE": case "WITH_BLACKHOLE_STORAGE_ENGINE": From d31b6e47844bb277c69eb9a8993a1024cbdca629 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 27 May 2009 13:11:28 +0500 Subject: [PATCH 02/10] Bug#43940 64-bit windows myisamchk doesn't support key_buffer_size > 4G The fix is to allow myisamchk to use >4G key_buffer_size on win64 include/myisam.h: use ulonglong instead of ulong for use_buffers storage/myisam/myisamchk.c: use ulonglong instead of ulong for use_buffers --- include/myisam.h | 3 ++- storage/myisam/myisamchk.c | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/myisam.h b/include/myisam.h index d7bfdf7191e..02251eeacb4 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -404,7 +404,8 @@ typedef struct st_mi_check_param my_off_t keydata,totaldata,key_blocks,start_check_pos; ha_rows total_records,total_deleted; ha_checksum record_checksum,glob_crc; - ulong use_buffers,read_buffer_length,write_buffer_length, + ulonglong use_buffers; + ulong read_buffer_length,write_buffer_length, sort_buffer_length,sort_key_blocks; uint out_flag,warning_printed,error_printed,verbose; uint opt_sort_key,total_files,max_level; diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c index ac0be2f01cc..75678375ce7 100644 --- a/storage/myisam/myisamchk.c +++ b/storage/myisam/myisamchk.c @@ -287,8 +287,8 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, { "key_buffer_size", OPT_KEY_BUFFER_SIZE, "", (uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0, - GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD, - (long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0}, + GET_ULL, REQUIRED_ARG, USE_BUFFER_INIT, MALLOC_OVERHEAD, + SIZE_T_MAX, MALLOC_OVERHEAD, IO_SIZE, 0}, { "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "", (uchar**) &opt_key_cache_block_size, (uchar**) &opt_key_cache_block_size, 0, @@ -1102,7 +1102,7 @@ static int myisamchk(MI_CHECK *param, char * filename) { if (param->testflag & (T_EXTEND | T_MEDIUM)) VOID(init_key_cache(dflt_key_cache,opt_key_cache_block_size, - param->use_buffers, 0, 0)); + (size_t) param->use_buffers, 0, 0)); VOID(init_io_cache(¶m->read_cache,datafile, (uint) param->read_buffer_length, READ_CACHE, @@ -1525,8 +1525,8 @@ static int mi_sort_records(MI_CHECK *param, if (share->state.key_root[sort_key] == HA_OFFSET_ERROR) DBUG_RETURN(0); /* Nothing to do */ - init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers, - 0, 0); + init_key_cache(dflt_key_cache, opt_key_cache_block_size, + (size_t) param->use_buffers, 0, 0); if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length, WRITE_CACHE,share->pack.header_length,1, MYF(MY_WME | MY_WAIT_IF_FULL))) From 808bed557ee4175ba22a63341d190c21e487a54e Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Wed, 27 May 2009 12:24:25 +0400 Subject: [PATCH 03/10] Bug #44638: mysql_upgrade, mysqlcheck output instance unclear Dump all connection-related arguments when running mysqlcheck from mysql_upgrade. No test case, since the output depends on the test suite configuration and platform. client/mysql_upgrade.c: Dump all connection-related arguments when running mysqlcheck from mysql_upgrade. --- client/mysql_upgrade.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index cbc60d8acad..bbc0e0f57ec 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -39,6 +39,7 @@ static uint my_end_arg= 0; static char *opt_user= (char*)"root"; static DYNAMIC_STRING ds_args; +static DYNAMIC_STRING conn_args; static char *opt_password= 0; static my_bool tty_password= 0; @@ -135,6 +136,7 @@ static void free_used_memory(void) free_defaults(defaults_argv); dynstr_free(&ds_args); + dynstr_free(&conn_args); } @@ -204,7 +206,7 @@ static void add_one_option(DYNAMIC_STRING* ds, } } dynstr_append_os_quoted(ds, "--", opt->name, eq, arg, NullS); - dynstr_append(&ds_args, " "); + dynstr_append(ds, " "); } @@ -256,6 +258,15 @@ get_one_option(int optid, const struct my_option *opt, case 'f': /* --force */ add_option= FALSE; break; + + case 'h': /* --host */ + case 'W': /* --pipe */ + case 'P': /* --port */ + case 'S': /* --socket */ + case OPT_MYSQL_PROTOCOL: /* --protocol */ + case OPT_SHARED_MEMORY_BASE_NAME: /* --shared-memory-base-name */ + add_one_option(&conn_args, opt, argument); + break; } if (add_option) @@ -603,6 +614,20 @@ static void create_mysql_upgrade_info_file(void) } +/* + Print connection-related arguments. +*/ + +static void print_conn_args(const char *tool_name) +{ + if (conn_args.str[0]) + verbose("Running '%s' with connection arguments: %s", tool_name, + conn_args.str); + else + verbose("Running '%s with default connection arguments", tool_name); +} + + /* Check and upgrade(if neccessary) all tables in the server using "mysqlcheck --check-upgrade .." @@ -610,7 +635,7 @@ static void create_mysql_upgrade_info_file(void) static int run_mysqlcheck_upgrade(void) { - verbose("Running 'mysqlcheck'..."); + print_conn_args("mysqlcheck"); return run_tool(mysqlcheck_path, NULL, /* Send output from mysqlcheck directly to screen */ "--no-defaults", @@ -624,7 +649,7 @@ static int run_mysqlcheck_upgrade(void) static int run_mysqlcheck_fixnames(void) { - verbose("Running 'mysqlcheck'..."); + print_conn_args("mysqlcheck"); return run_tool(mysqlcheck_path, NULL, /* Send output from mysqlcheck directly to screen */ "--no-defaults", @@ -753,7 +778,8 @@ int main(int argc, char **argv) strncpy(self_name, argv[0], FN_REFLEN); } - if (init_dynamic_string(&ds_args, "", 512, 256)) + if (init_dynamic_string(&ds_args, "", 512, 256) || + init_dynamic_string(&conn_args, "", 512, 256)) die("Out of memory"); load_defaults("my", load_default_groups, &argc, &argv); From f54beb2dccb921296a4c0bec1aa45e5dd6e53a69 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 27 May 2009 15:34:21 +0500 Subject: [PATCH 04/10] Bug#41212 crash after race condition between merge table and table_cache evictions On 64-bit Windows: querying MERGE table with keys may cause server crash.The problem is generic and may affect any statement accessing MERGE table cardinality values. When MERGE engine was copying cardinality statistics, it was using incorrect size of element in cardinality statistics array (sizeof(ptr)==8 instead of sizeof(ulong)==4), causing access of memory beyond of the allocated bounds. sql/ha_myisam.cc: When copying rec_per_key array (an array of ulong) use proper size of element, that is sizeof(ulong). sql/ha_myisammrg.cc: When copying rec_per_key array (an array of ulong) use proper size of element, that is sizeof(ulong). sql/table.cc: When allocating rec_per_key array (an array of ulong) use proper size of element, that is sizeof(ulong). --- sql/ha_myisam.cc | 2 +- sql/ha_myisammrg.cc | 4 ++-- sql/table.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 5ed791d0f68..95b7b338131 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1684,7 +1684,7 @@ int ha_myisam::info(uint flag) if (share->key_parts) memcpy((char*) table->key_info[0].rec_per_key, (char*) misam_info.rec_per_key, - sizeof(table->key_info[0].rec_per_key)*share->key_parts); + sizeof(table->key_info[0].rec_per_key[0])*share->key_parts); raid_type= misam_info.raid_type; raid_chunks= misam_info.raid_chunks; raid_chunksize= misam_info.raid_chunksize; diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index f15a37efdc5..fef2e21d271 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -402,11 +402,11 @@ int ha_myisammrg::info(uint flag) with such a number, it'll be an error later anyway. */ bzero((char*) table->key_info[0].rec_per_key, - sizeof(table->key_info[0].rec_per_key) * table->s->key_parts); + sizeof(table->key_info[0].rec_per_key[0]) * table->s->key_parts); #endif memcpy((char*) table->key_info[0].rec_per_key, (char*) mrg_info.rec_per_key, - sizeof(table->key_info[0].rec_per_key) * + sizeof(table->key_info[0].rec_per_key[0]) * min(file->keys, table->s->key_parts)); } } diff --git a/sql/table.cc b/sql/table.cc index c559b4bb7fd..55a9b50605d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -233,7 +233,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, ulong *rec_per_key; if (!(rec_per_key= (ulong*) alloc_root(&outparam->mem_root, - sizeof(ulong*)*key_parts))) + sizeof(ulong)*key_parts))) goto err; for (i=0 ; i < keys ; i++, keyinfo++) From 80730df7d634e1a620c864d6665d6e66ccad447a Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 27 May 2009 16:05:29 +0300 Subject: [PATCH 05/10] Bug #38159: Function parsing problem generates misleading error message Added a more detailed error message on calling an ambiguous missing function. mysql-test/r/ps.result: Bug #38159: fixed existing tests mysql-test/r/sp-error.result: Bug #38159: test case mysql-test/t/ps.test: Bug #38159: fixed existing tests mysql-test/t/sp-error.test: Bug #38159: test case sql/item_func.cc: Bug #38159: generate more detailed error message sql/share/errmsg.txt: Bug #38159: add a more detailed error message sql/sql_derived.cc: Bug #38159: treat the detailed error message the same way as the generic one sql/sql_lex.cc: Bug #38159: - detect if the token is ambiguous and print the appropriate error. - backport is_lex_native_function() from 5.1 sql/sql_lex.h: Bug #38159: detect if the token is ambiguous and print the appropriate error. sql/sql_yacc.yy: Bug #38159: generate more detailed error message sql/table.cc: Bug #38159: treat the detailed error message the same way as the generic one --- mysql-test/r/ps.result | 4 ++-- mysql-test/r/sp-error.result | 10 ++++++++++ mysql-test/t/ps.test | 4 ++-- mysql-test/t/sp-error.test | 13 +++++++++++++ sql/item_func.cc | 10 +++++++++- sql/share/errmsg.txt | 3 +++ sql/sql_derived.cc | 1 + sql/sql_lex.cc | 16 ++++++++++++++++ sql/sql_lex.h | 2 ++ sql/sql_yacc.yy | 3 +-- sql/table.cc | 1 + 11 files changed, 60 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index 43c50998e20..e8e75c82b93 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -502,7 +502,7 @@ deallocate prepare stmt; create table t1 (a varchar(20)); insert into t1 values ('foo'); prepare stmt FROM 'SELECT char_length (a) FROM t1'; -ERROR 42000: FUNCTION test.char_length does not exist +ERROR 42000: FUNCTION test.char_length does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual drop table t1; prepare stmt from "SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0"; execute stmt; @@ -1147,7 +1147,7 @@ End of 4.1 tests. create table t1 (a varchar(20)); insert into t1 values ('foo'); prepare stmt FROM 'SELECT char_length (a) FROM t1'; -ERROR 42000: FUNCTION test.char_length does not exist +ERROR 42000: FUNCTION test.char_length does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual drop table t1; create table t1 (a char(3) not null, b char(3) not null, c char(3) not null, primary key (a, b, c)); diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index e83e8c2c71d..bf25f93cceb 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1520,3 +1520,13 @@ CALL p1((SELECT * FROM t1))| ERROR 21000: Subquery returns more than 1 row DROP PROCEDURE IF EXISTS p1| DROP TABLE t1| +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); +SELECT MAX (a) FROM t1 WHERE b = 999999; +ERROR 42000: FUNCTION test.MAX does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual +SELECT AVG (a) FROM t1 WHERE b = 999999; +AVG (a) +NULL +SELECT non_existent (a) FROM t1 WHERE b = 999999; +ERROR 42000: FUNCTION test.non_existent does not exist +DROP TABLE t1; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index d9e593fd76f..99bc198259e 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -530,7 +530,7 @@ deallocate prepare stmt; # create table t1 (a varchar(20)); insert into t1 values ('foo'); ---error 1305 +--error ER_FUNC_INEXISTENT_NAME_COLLISION prepare stmt FROM 'SELECT char_length (a) FROM t1'; drop table t1; @@ -1239,7 +1239,7 @@ drop table t1; # create table t1 (a varchar(20)); insert into t1 values ('foo'); ---error 1305 +--error ER_FUNC_INEXISTENT_NAME_COLLISION prepare stmt FROM 'SELECT char_length (a) FROM t1'; drop table t1; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index c839b1e4374..8143fd56c6d 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2190,3 +2190,16 @@ delimiter ;| #drop procedure if exists bugNNNN| #--enable_warnings #create procedure bugNNNN... + +# +# Bug #38159: Function parsing problem generates misleading error message +# + +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,1), (2,2); +--error ER_FUNC_INEXISTENT_NAME_COLLISION +SELECT MAX (a) FROM t1 WHERE b = 999999; +SELECT AVG (a) FROM t1 WHERE b = 999999; +--error ER_SP_DOES_NOT_EXIST +SELECT non_existent (a) FROM t1 WHERE b = 999999; +DROP TABLE t1; diff --git a/sql/item_func.cc b/sql/item_func.cc index 46e0f30d94e..6737b8cd1b0 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5401,6 +5401,14 @@ Item_func_sp::func_name() const } +int my_missing_function_error(const LEX_STRING &token, const char *func_name) +{ + if (token.length && is_lex_native_function (&token)) + return my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name); + else + return my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name); +} + /** @brief Initialize the result field by creating a temporary dummy table @@ -5434,7 +5442,7 @@ Item_func_sp::init_result_field(THD *thd) if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name, &thd->sp_func_cache, TRUE))) { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); + my_missing_function_error (m_name->m_name, m_name->m_qname.str); context->process_error(thd); DBUG_RETURN(TRUE); } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index c688ba88b7b..6113b18579f 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5649,3 +5649,6 @@ ER_XA_RBTIMEOUT XA106 eng "XA_RBTIMEOUT: Transaction branch was rolled back: took too long" ER_XA_RBDEADLOCK XA102 eng "XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected" + +ER_FUNC_INEXISTENT_NAME_COLLISION 42000 + eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual" diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 830d1b7c36f..46718f74bd4 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -148,6 +148,7 @@ exit: if (orig_table_list->view) { if (thd->net.last_errno == ER_BAD_FIELD_ERROR || + thd->net.last_errno == ER_FUNC_INEXISTENT_NAME_COLLISION || thd->net.last_errno == ER_SP_DOES_NOT_EXIST) { thd->clear_error(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 436f41dd209..e7c87527d78 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -265,6 +265,22 @@ bool is_keyword(const char *name, uint len) return get_hash_symbol(name,len,0)!=0; } +/** + Check if name is a sql function + + @param name checked name + + @return is this a lex native function or not + @retval 0 name is a function + @retval 1 name isn't a function +*/ + +bool is_lex_native_function(const LEX_STRING *name) +{ + DBUG_ASSERT(name != NULL); + return (get_hash_symbol(name->str, (uint) name->length, 1) != 0); +} + /* make a copy of token before ptr and set yytoklen */ static LEX_STRING get_token(Lex_input_stream *lip, uint skip, uint length) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 5c0367632e1..627003880d9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1390,3 +1390,5 @@ extern void lex_end(LEX *lex); extern int MYSQLlex(void *arg, void *yythd); extern char *skip_rear_comments(CHARSET_INFO *cs, char *begin, char *end); +extern bool is_lex_native_function(const LEX_STRING *name); +int my_missing_function_error(const LEX_STRING &token, const char *name); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 61020a3eed0..37d2658f46f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -5968,8 +5968,7 @@ simple_expr: Reusing ER_SP_DOES_NOT_EXIST have a message consistent with the case when a default database exist, see below. */ - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), - "FUNCTION", $1.str); + my_missing_function_error ($1, $1.str); MYSQL_YYABORT; } diff --git a/sql/table.cc b/sql/table.cc index 55a9b50605d..3f34281f746 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2138,6 +2138,7 @@ void TABLE_LIST::hide_view_error(THD *thd) /* Hide "Unknown column" or "Unknown function" error */ if (thd->net.last_errno == ER_BAD_FIELD_ERROR || thd->net.last_errno == ER_SP_DOES_NOT_EXIST || + thd->net.last_errno == ER_FUNC_INEXISTENT_NAME_COLLISION || thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR || thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR || thd->net.last_errno == ER_TABLEACCESS_DENIED_ERROR || From 1b91400ac6758e3ce28a4ee18123a5c5117c9f7e Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 28 May 2009 13:34:30 +0500 Subject: [PATCH 06/10] Bug#37268 'binary' character set makes CLI-internal commands case sensitive The fix is to use case insensitive collation for mysql client command search. client/mysql.cc: The fix is to use case insensitive collation for mysql client command search. mysql-test/r/mysql.result: test result mysql-test/t/mysql.test: test case --- client/mysql.cc | 4 ++-- mysql-test/r/mysql.result | 1 + mysql-test/t/mysql.test | 7 +++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/client/mysql.cc b/client/mysql.cc index 89f1f28bb1b..b7d66071ca5 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1949,7 +1949,7 @@ static COMMANDS *find_command(char *name,char cmd_char) */ if (strstr(name, "\\g") || (strstr(name, delimiter) && !(strlen(name) >= 9 && - !my_strnncoll(charset_info, + !my_strnncoll(&my_charset_latin1, (uchar*) name, 9, (const uchar*) "delimiter", 9)))) @@ -1970,7 +1970,7 @@ static COMMANDS *find_command(char *name,char cmd_char) { if (commands[i].func && ((name && - !my_strnncoll(charset_info,(uchar*)name,len, + !my_strnncoll(&my_charset_latin1, (uchar*)name, len, (uchar*)commands[i].name,len) && !commands[i].name[len] && (!end || (end && commands[i].takes_params))) || diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index 5f315bca9c2..d1e8ba1e253 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -198,4 +198,5 @@ COUNT (*) 1 COUNT (*) 1 +ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (1) End of 5.0 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 0425b4b9022..45077b5ef80 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -348,4 +348,11 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug31060.sql; --exec $MYSQL --ignore-spaces -e "SELECT COUNT (*)" --exec $MYSQL -b -i -e "SELECT COUNT (*)" +# +# Bug#37268 'binary' character set makes CLI-internal commands case sensitive +# +--error 1 +--exec $MYSQL --default-character-set=binary test -e "CONNECT test invalid_hostname" 2>&1 +--exec $MYSQL --default-character-set=binary test -e "DELIMITER //" 2>&1 + --echo End of 5.0 tests From 4cfc9d771a606117f37e543c1a117887cc58ec40 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 28 May 2009 16:19:49 +0500 Subject: [PATCH 07/10] test case fix --- mysql-test/r/mysql.result | 2 +- mysql-test/t/mysql.test | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index d1e8ba1e253..4affd884753 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -198,5 +198,5 @@ COUNT (*) 1 COUNT (*) 1 -ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (1) +ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno) End of 5.0 tests diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index 45077b5ef80..b2d7400d156 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -351,6 +351,7 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug31060.sql; # # Bug#37268 'binary' character set makes CLI-internal commands case sensitive # +--replace_regex /\([0-9]*\)/(errno)/ --error 1 --exec $MYSQL --default-character-set=binary test -e "CONNECT test invalid_hostname" 2>&1 --exec $MYSQL --default-character-set=binary test -e "DELIMITER //" 2>&1 From 858e118ab9520dc52882b0b796be5c4e975f4451 Mon Sep 17 00:00:00 2001 From: Narayanan V Date: Fri, 29 May 2009 15:01:00 +0530 Subject: [PATCH 08/10] Bug#44811 Tests with utf8 charset fail with ibmdb2i on 64bit MySQL wmemset was being used to fill the row buffers. wmemset was intended to fill the buffer with 16-bit UCS2 pad values. However, the 64-bit version of wmemset uses 32-bit wide characters and thus filled the buffer incorrectly. In some cases, the null byte map would be overwritten, causing ctype_utf8.test and ibmdb2i_rir.test to fail, giving the error message CPF5035. This patch eliminates the use of wmemset to fill the row buffer. wmemset has been replaced with memset16, which always fills memory with 16-bit values. storage/ibmdb2i/db2i_conversion.cc: Bug#44811 Tests with utf8 charset fail with ibmdb2i on 64bit MySQL Eliminate the use of wmemset to fill the row buffer. Replace wmemset with memset16, which always fills memory with 16-bit values. storage/ibmdb2i/db2i_misc.h: Bug#44811 Tests with utf8 charset fail with ibmdb2i on 64bit MySQL Eliminate the use of wmemset to fill the row buffer. Replace wmemset with memset16, which always fills memory with 16-bit values. --- storage/ibmdb2i/db2i_conversion.cc | 4 ++-- storage/ibmdb2i/db2i_misc.h | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/storage/ibmdb2i/db2i_conversion.cc b/storage/ibmdb2i/db2i_conversion.cc index bdb8085d937..0acde10a4cd 100644 --- a/storage/ibmdb2i/db2i_conversion.cc +++ b/storage/ibmdb2i/db2i_conversion.cc @@ -1085,7 +1085,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char if (bytesToStore) memcpy(db2Buf, dataToStore, bytesToStore); if (bytesToPad) - wmemset((wchar_t*)(db2Buf + bytesToStore), 0x0020, bytesToPad/2); + memset16((db2Buf + bytesToStore), 0x0020, bytesToPad/2); } else { @@ -1108,7 +1108,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char bytesToStore = db2BytesToStore; } if (db2BytesToStore < maxDb2BytesToStore) // If need to pad - wmemset((wchar_t*)(db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2); + memset16((db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2); } if (db2FieldType == QMY_VARGRAPHIC) diff --git a/storage/ibmdb2i/db2i_misc.h b/storage/ibmdb2i/db2i_misc.h index 9e20f01208b..f0b527aaad0 100644 --- a/storage/ibmdb2i/db2i_misc.h +++ b/storage/ibmdb2i/db2i_misc.h @@ -109,5 +109,21 @@ bool isOrdinaryIdentifier(const char* s) } return true; } + +/** + Fill memory with a 16-bit word. + @param p Pointer to space to fill. + @param v Value to fill + @param l Length of space (in 16-bit words) +*/ +void memset16(void* p, uint16 v, size_t l) +{ + uint16* p2=(uint16*)p; + while (l--) + { + *(p2++) = v; + } +} + #endif From 66e0ee6639e068f5f713a639d9001a81a7bd1013 Mon Sep 17 00:00:00 2001 From: Kristofer Pettersson Date: Fri, 29 May 2009 15:37:54 +0200 Subject: [PATCH 09/10] Bug#44658 Create procedure makes server crash when user does not have ALL privilege MySQL crashes if a user without proper privileges attempts to create a procedure. The crash happens because more than one error state is pushed onto the Diagnostic area. In this particular case the user is denied to implicitly create a new user account with the implicitly granted privileges ALTER- and EXECUTE ROUTINE. The new account is needed if the original user account contained a host mask. A user account with a host mask is a distinct user account in this context. An alternative would be to first get the most permissive user account which include the current user connection and then assign privileges to that account. This behavior change is considered out of scope for this bug patch. The implicit assignment of privileges when a user creates a stored routine is a considered to be a feature for user convenience and as such it is not a critical operation. Any failure to complete this operation is thus considered non-fatal (an error becomes a warning). The patch back ports a stack implementation of the internal error handler interface. This enables the use of multiple error handlers so that it is possible to intercept and cancel errors thrown by lower layers. This is needed as a error handler already is used in the call stack emitting the errors which needs to be converted. mysql-test/r/grant.result: * Added test case for bug44658 mysql-test/t/grant.test: * Added test case for bug44658 sql/sp.cc: * Removed non functional parameter no_error and my_error calls as all errors from this function will be converted to a warning anyway. * Change function return type from int to bool. sql/sp.h: * Removed non functional parameter no_error and my_error calls as all errors from this function will be converted to a warning anyway. * Changed function return value from int to bool sql/sql_acl.cc: * Removed the non functional no_error parameter from the function prototype. The function is called from two places and in one of the places we now ignore errors through error handlers. * Introduced the parameter write_to_binlog * Introduced an error handler to cancel any error state from mysql_routine_grant. * Moved my_ok() signal from mysql_routine_grant to make it easier to avoid setting the wrong state in the Diagnostic area. * Changed the broken error state in sp_grant_privileges() to a warning so that if "CREATE PROCEDURE" fails because "Password hash isn't a hexidecimal number" it is still clear what happened. sql/sql_acl.h: * Removed the non functional no_error parameter from the function prototype. The function is called from two places and in one of the places we now ignore errors through error handlers. * Introduced the parameter write_to_binlog * Changed return type for sp_grant_privileges() from int to bool sql/sql_class.cc: * Back ported implementation of internal error handler from 6.0 branch sql/sql_class.h: * Back ported implementation of internal error handler from 6.0 branch sql/sql_parse.cc: * Moved my_ok() signal from mysql_routine_grant() to make it easier to avoid setting the wrong state in the Diagnostic area. --- mysql-test/r/grant.result | 55 ++++++++++++++++++++++++++ mysql-test/t/grant.test | 54 ++++++++++++++++++++++++++ sql/sp.cc | 28 ++++++------- sql/sp.h | 4 +- sql/sql_acl.cc | 82 ++++++++++++++++++++------------------- sql/sql_acl.h | 4 +- sql/sql_class.cc | 29 +++++++++----- sql/sql_class.h | 30 +++++++++++++- sql/sql_parse.cc | 4 +- 9 files changed, 221 insertions(+), 69 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index de80a83d538..a677d71b266 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -1358,3 +1358,58 @@ DROP USER 'userbug33464'@'localhost'; USE test; DROP DATABASE dbbug33464; SET @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators; +CREATE USER user1; +CREATE USER user2; +GRANT CREATE ON db1.* TO 'user1'@'localhost'; +GRANT CREATE ROUTINE ON db1.* TO 'user1'@'localhost'; +GRANT CREATE ON db1.* TO 'user2'@'%'; +GRANT CREATE ROUTINE ON db1.* TO 'user2'@'%'; +FLUSH PRIVILEGES; +SHOW GRANTS FOR 'user1'@'localhost'; +Grants for user1@localhost +GRANT USAGE ON *.* TO 'user1'@'localhost' +GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user1'@'localhost' +** Connect as user1 and create a procedure. +** The creation will imply implicitly assigned +** EXECUTE and ALTER ROUTINE privileges to +** the current user user1@localhost. +SELECT @@GLOBAL.sql_mode; +@@GLOBAL.sql_mode + +SELECT @@SESSION.sql_mode; +@@SESSION.sql_mode + +CREATE DATABASE db1; +CREATE PROCEDURE db1.proc1(p1 INT) +BEGIN +SET @x = 0; +REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT; +END ;|| +** Connect as user2 and create a procedure. +** Implicitly assignment of privileges will +** fail because the user2@localhost is an +** unknown user. +CREATE PROCEDURE db1.proc2(p1 INT) +BEGIN +SET @x = 0; +REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT; +END ;|| +Warnings: +Warning 1404 Failed to grant EXECUTE and ALTER ROUTINE privileges +SHOW GRANTS FOR 'user1'@'localhost'; +Grants for user1@localhost +GRANT USAGE ON *.* TO 'user1'@'localhost' +GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user1'@'localhost' +GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `db1`.`proc1` TO 'user1'@'localhost' +SHOW GRANTS FOR 'user2'; +Grants for user2@% +GRANT USAGE ON *.* TO 'user2'@'%' +GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user2'@'%' +DROP PROCEDURE db1.proc1; +DROP PROCEDURE db1.proc2; +REVOKE ALL ON db1.* FROM 'user1'@'localhost'; +REVOKE ALL ON db1.* FROM 'user2'@'%'; +DROP USER 'user1'; +DROP USER 'user1'@'localhost'; +DROP USER 'user2'; +DROP DATABASE db1; diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 2e42bdbf06c..bcd393bd6ab 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -1471,5 +1471,59 @@ DROP DATABASE dbbug33464; SET @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators; +# +# Bug#44658 Create procedure makes server crash when user does not have ALL privilege +# +CREATE USER user1; +CREATE USER user2; +GRANT CREATE ON db1.* TO 'user1'@'localhost'; +GRANT CREATE ROUTINE ON db1.* TO 'user1'@'localhost'; +GRANT CREATE ON db1.* TO 'user2'@'%'; +GRANT CREATE ROUTINE ON db1.* TO 'user2'@'%'; +FLUSH PRIVILEGES; +SHOW GRANTS FOR 'user1'@'localhost'; +connect (con1,localhost,user1,,); +--echo ** Connect as user1 and create a procedure. +--echo ** The creation will imply implicitly assigned +--echo ** EXECUTE and ALTER ROUTINE privileges to +--echo ** the current user user1@localhost. +SELECT @@GLOBAL.sql_mode; +SELECT @@SESSION.sql_mode; +CREATE DATABASE db1; +DELIMITER ||; +CREATE PROCEDURE db1.proc1(p1 INT) + BEGIN + SET @x = 0; + REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT; + END ;|| +DELIMITER ;|| + +connect (con2,localhost,user2,,); +--echo ** Connect as user2 and create a procedure. +--echo ** Implicitly assignment of privileges will +--echo ** fail because the user2@localhost is an +--echo ** unknown user. +DELIMITER ||; +CREATE PROCEDURE db1.proc2(p1 INT) + BEGIN + SET @x = 0; + REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT; + END ;|| +DELIMITER ;|| + +connection default; +SHOW GRANTS FOR 'user1'@'localhost'; +SHOW GRANTS FOR 'user2'; +disconnect con1; +disconnect con2; +DROP PROCEDURE db1.proc1; +DROP PROCEDURE db1.proc2; +REVOKE ALL ON db1.* FROM 'user1'@'localhost'; +REVOKE ALL ON db1.* FROM 'user2'@'%'; +DROP USER 'user1'; +DROP USER 'user1'@'localhost'; +DROP USER 'user2'; +DROP DATABASE db1; + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc diff --git a/sql/sp.cc b/sql/sp.cc index 8c8149d0afc..069cb722c2d 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1308,13 +1308,20 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, /** This is used by sql_acl.cc:mysql_routine_grant() and is used to find the routines in 'routines'. + + @param thd Thread handler + @param routines List of needles in the hay stack + @param any Any of the needles are good enough + + @return + @retval FALSE Found. + @retval TRUE Not found */ -int -sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error) +bool +sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any) { TABLE_LIST *routine; - bool result= 0; bool sp_object_found; DBUG_ENTER("sp_exists_routine"); for (routine= routines; routine; routine= routine->next_global) @@ -1336,21 +1343,16 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error) if (sp_object_found) { if (any) - DBUG_RETURN(1); - result= 1; + break; } else if (!any) { - if (!no_error) - { - my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE", - routine->table_name); - DBUG_RETURN(-1); - } - DBUG_RETURN(0); + my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE", + routine->table_name); + DBUG_RETURN(TRUE); } } - DBUG_RETURN(result); + DBUG_RETURN(FALSE); } diff --git a/sql/sp.h b/sql/sp.h index 75088ea0b83..75c6856f64b 100644 --- a/sql/sp.h +++ b/sql/sp.h @@ -39,8 +39,8 @@ sp_head * sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp, bool cache_only); -int -sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any, bool no_error); +bool +sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any); int sp_routine_exists_in_table(THD *thd, int type, sp_name *name); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b1dbb7031ce..83cf37e32dc 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3191,26 +3191,24 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, } -/* +/** Store routine level grants in the privilege tables - SYNOPSIS - mysql_routine_grant() - thd Thread handle - table_list List of routines to give grant - is_proc true indicates routine list are procedures - user_list List of users to give grant - rights Table level grant - revoke_grant Set to 1 if this is a REVOKE command + @param thd Thread handle + @param table_list List of routines to give grant + @param is_proc Is this a list of procedures? + @param user_list List of users to give grant + @param rights Table level grant + @param revoke_grant Is this is a REVOKE command? - RETURN - 0 ok - 1 error + @return + @retval FALSE Success. + @retval TRUE An error occurred. */ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, List &user_list, ulong rights, - bool revoke_grant, bool no_error) + bool revoke_grant, bool write_to_binlog) { List_iterator str_list (user_list); LEX_USER *Str, *tmp_Str; @@ -3221,22 +3219,20 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (!initialized) { - if (!no_error) - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), - "--skip-grant-tables"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-grant-tables"); DBUG_RETURN(TRUE); } if (rights & ~PROC_ACLS) { - if (!no_error) - my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE), - MYF(0)); + my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE), + MYF(0)); DBUG_RETURN(TRUE); } if (!revoke_grant) { - if (sp_exist_routines(thd, table_list, is_proc, no_error)<0) + if (sp_exist_routines(thd, table_list, is_proc)) DBUG_RETURN(TRUE); } @@ -3317,9 +3313,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, { if (revoke_grant) { - if (!no_error) - my_error(ER_NONEXISTING_PROC_GRANT, MYF(0), - Str->user.str, Str->host.str, table_name); + my_error(ER_NONEXISTING_PROC_GRANT, MYF(0), + Str->user.str, Str->host.str, table_name); result= TRUE; continue; } @@ -3344,16 +3339,14 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } thd->mem_root= old_root; pthread_mutex_unlock(&acl_cache->lock); - if (!result && !no_error) + + if (write_to_binlog) { write_bin_log(thd, TRUE, thd->query, thd->query_length); } rw_unlock(&LOCK_grant); - if (!result && !no_error) - my_ok(thd); - /* Tables are automatically closed */ DBUG_RETURN(result); } @@ -6150,21 +6143,20 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, } -/* +/** Grant EXECUTE,ALTER privilege for a stored procedure - SYNOPSIS - sp_grant_privileges() - thd The current thread. - db DB of the stored procedure - name Name of the stored procedure + @param thd The current thread. + @param sp_db + @param sp_name + @param is_proc - RETURN - 0 OK. - < 0 Error. Error message not yet sent. + @return + @retval FALSE Success + @retval TRUE An error occured. Error message not yet sent. */ -int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, +bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool is_proc) { Security_context *sctx= thd->security_ctx; @@ -6174,6 +6166,7 @@ int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, bool result; ACL_USER *au; char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1]; + Dummy_error_handler error_handler; DBUG_ENTER("sp_grant_privileges"); if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user)))) @@ -6224,8 +6217,11 @@ int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, } else { - my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); - return -1; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_PASSWD_LENGTH, + ER(ER_PASSWD_LENGTH), + SCRAMBLED_PASSWORD_CHAR_LENGTH); + return TRUE; } combo->password.str= passwd_buff; } @@ -6241,8 +6237,14 @@ int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh)); + /* + Only care about whether the operation failed or succeeded + as all errors will be handled later. + */ + thd->push_internal_handler(&error_handler); result= mysql_routine_grant(thd, tables, is_proc, user_list, - DEFAULT_CREATE_PROC_ACLS, 0, 1); + DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE); + thd->pop_internal_handler(); DBUG_RETURN(result); } diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 9ae17a4bf02..a8090fba2e7 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -233,7 +233,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list, bool revoke); bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc, List &user_list, ulong rights, - bool revoke, bool no_error); + bool revoke, bool write_to_binlog); my_bool grant_init(); void grant_free(void); my_bool grant_reload(THD *thd); @@ -264,7 +264,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); -int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, +bool 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_class.cc b/sql/sql_class.cc index cf5fdcf27a7..a853ad103ea 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -674,31 +674,40 @@ THD::THD() void THD::push_internal_handler(Internal_error_handler *handler) { - /* - TODO: The current implementation is limited to 1 handler at a time only. - THD and sp_rcontext need to be modified to use a common handler stack. - */ - DBUG_ASSERT(m_internal_handler == NULL); - m_internal_handler= handler; + if (m_internal_handler) + { + handler->m_prev_internal_handler= m_internal_handler; + m_internal_handler= handler; + } + else + { + m_internal_handler= handler; + } } bool THD::handle_error(uint sql_errno, const char *message, MYSQL_ERROR::enum_warning_level level) { - if (m_internal_handler) + if (!m_internal_handler) + return FALSE; + + for (Internal_error_handler *error_handler= m_internal_handler; + error_handler; + error_handler= m_internal_handler->m_prev_internal_handler) { - return m_internal_handler->handle_error(sql_errno, message, level, this); + if (error_handler->handle_error(sql_errno, message, level, this)) + return TRUE; } - return FALSE; // 'FALSE', as per coding style + return FALSE; } void THD::pop_internal_handler() { DBUG_ASSERT(m_internal_handler != NULL); - m_internal_handler= NULL; + m_internal_handler= m_internal_handler->m_prev_internal_handler; } extern "C" diff --git a/sql/sql_class.h b/sql/sql_class.h index ce4524fb982..4e9322dee05 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1036,7 +1036,10 @@ show_system_thread(enum_thread_type thread) class Internal_error_handler { protected: - Internal_error_handler() {} + Internal_error_handler() : + m_prev_internal_handler(NULL) + {} + virtual ~Internal_error_handler() {} public: @@ -1069,6 +1072,28 @@ public: const char *message, MYSQL_ERROR::enum_warning_level level, THD *thd) = 0; +private: + Internal_error_handler *m_prev_internal_handler; + friend class THD; +}; + + +/** + Implements the trivial error handler which cancels all error states + and prevents an SQLSTATE to be set. +*/ + +class Dummy_error_handler : public Internal_error_handler +{ +public: + bool handle_error(uint sql_errno, + const char *message, + MYSQL_ERROR::enum_warning_level level, + THD *thd) + { + /* Ignore error */ + return TRUE; + } }; @@ -2210,6 +2235,9 @@ public: thd_scheduler scheduler; public: + inline Internal_error_handler *get_internal_handler() + { return m_internal_handler; } + /** Add an internal error handler to the thread execution context. @param handler the exception handler to add diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6dbe4a4fd8d..403e7bca964 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3883,7 +3883,9 @@ end_with_restore_list: res= mysql_routine_grant(thd, all_tables, lex->type == TYPE_ENUM_PROCEDURE, lex->users_list, grants, - lex->sql_command == SQLCOM_REVOKE, 0); + lex->sql_command == SQLCOM_REVOKE, TRUE); + if (!res) + my_ok(thd); } else { From 2ba60c19c34d38a513bda6ee9c3a2bb407e2034c Mon Sep 17 00:00:00 2001 From: "Tatiana A. Nurnberg" Date: Fri, 29 May 2009 16:22:24 +0200 Subject: [PATCH 10/10] Bug#39200: optimize table does not recognize ROW_FORMAT=COMPRESSED When doing ALTER TABLE, we forgot to point out that we actually have ROW_FORMAT information (from the original table), so we dropped to "sensible defaults". This affects both ALTER TABLE and OPTIMIZE TABLE which may fall back on ALTER TABLE for InnoDB. We now flag that we do indeed know the row-type, thereby preserving compression-type etc. No .test in 5.1 since we'd need a reasonable new plugin from InnoDB to show this properly; in higher versions, maria can demonstrate this. sql/sql_table.cc: In mysql_alter_table() flag that we have row-type info from old table. In compare_tables(), we must explicitly check whether row-type has changed (rather than rely on the flag which will always be set at this point now). --- sql/sql_table.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5397128855a..d5317995948 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -5314,7 +5314,7 @@ compare_tables(TABLE *table, create_info->used_fields & HA_CREATE_USED_ENGINE || create_info->used_fields & HA_CREATE_USED_CHARSET || create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET || - create_info->used_fields & HA_CREATE_USED_ROW_FORMAT || + (table->s->row_type != create_info->row_type) || create_info->used_fields & HA_CREATE_USED_PACK_KEYS || create_info->used_fields & HA_CREATE_USED_MAX_ROWS || (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) || @@ -6307,7 +6307,10 @@ view_err: } if (create_info->row_type == ROW_TYPE_NOT_USED) + { create_info->row_type= table->s->row_type; + create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT; + } DBUG_PRINT("info", ("old type: %s new type: %s", ha_resolve_storage_engine_name(old_db_type),