diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c173c9cb49..e4dc16040a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,10 @@ SET(WITH_MYISAMMRG_STORAGE_ENGINE TRUE) ADD_DEFINITIONS(-DWITH_MYISAMMRG_STORAGE_ENGINE) SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_myisammrg_plugin") +IF(WITH_COMMUNITY_FEATURES) + ADD_DEFINITIONS(-DENABLED_PROFILING -DCOMMUNITY_SERVER) +ENDIF(WITH_COMMUNITY_FEATURES) + IF(WITH_ARCHIVE_STORAGE_ENGINE) ADD_DEFINITIONS(-DWITH_ARCHIVE_STORAGE_ENGINE) SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_archive_plugin") diff --git a/client/mysql.cc b/client/mysql.cc index 860fc3a5f6e..5f360b83dc1 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1979,7 +1979,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)))) @@ -2000,7 +2000,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/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); 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/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/r/mysql.result b/mysql-test/r/mysql.result index a04eb1ca1aa..e704f81e187 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -198,6 +198,7 @@ COUNT (*) 1 COUNT (*) 1 +ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno) End of 5.0 tests WARNING: --server-arg option not supported in this configuration. Warning (Code 1286): Unknown table engine 'nonexistent' diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 35d61ce757d..17ab2b79043 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1660,3 +1660,13 @@ declare continue handler for sqlstate '00000' set @x=0; end$$ ERROR 42000: Bad SQLSTATE: '00000' LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc; +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/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/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index ba5cc243c01..2bb9a02e9d7 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -349,6 +349,14 @@ 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 +# +--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 + --echo End of 5.0 tests # diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 8d7c6d75a34..66b960c938f 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -2435,3 +2435,16 @@ delimiter ;$$ # LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc; remove_file $MYSQLTEST_VARDIR/tmp/proc.txt; + +# +# 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 0c8f236a27c..85e5de7b980 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5802,6 +5802,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 @@ -5834,7 +5842,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 2dfc5310643..7c92c827c87 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6177,3 +6177,6 @@ ER_TOO_LONG_TABLE_COMMENT ER_TOO_LONG_FIELD_COMMENT eng "Comment for field '%-.64s' is too long (max = %lu)" por "Comentário para o campo '%-.64s' é longo demais (max = %lu)" + +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/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 4d4e4d24684..e6655856969 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3198,26 +3198,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; @@ -3228,22 +3226,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); } @@ -3324,9 +3320,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; } @@ -3351,16 +3346,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); } @@ -6157,21 +6150,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; @@ -6181,6 +6173,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)))) @@ -6231,8 +6224,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; } @@ -6248,8 +6244,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_derived.cc b/sql/sql_derived.cc index 41be98621a6..37adf5c403a 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -179,6 +179,7 @@ exit: { if (thd->is_error() && (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || + thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST)) { thd->clear_error(); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b96ac91679b..03da3c2338a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -433,6 +433,16 @@ 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 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); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 62106a2500b..22b7d2e359c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1976,4 +1976,6 @@ extern bool is_lex_native_function(const LEX_STRING *name); @} (End of group Semantic_Analysis) */ +int my_missing_function_error(const LEX_STRING &token, const char *name); + #endif /* MYSQL_SERVER */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8f1d3842245..438ce2bad28 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3880,7 +3880,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 { 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), diff --git a/sql/table.cc b/sql/table.cc index d24ee4c6a27..7e8d5ac98b4 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -779,7 +779,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, strpos=disk_buff+6; if (!(rec_per_key= (ulong*) alloc_root(&share->mem_root, - sizeof(ulong*)*key_parts))) + sizeof(ulong)*key_parts))) goto err; for (i=0 ; i < keys ; i++, keyinfo++) @@ -3341,6 +3341,7 @@ void TABLE_LIST::hide_view_error(THD *thd) if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST || + thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION || thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR || thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR || thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR || 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 diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 1845859ec81..cf290e2018a 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -1807,7 +1807,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[0])*share->key_parts); + sizeof(table->key_info[0].rec_per_key[0])*share->key_parts); if (share->tmp_table == NO_TMP_TABLE) pthread_mutex_unlock(&share->mutex); 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))) diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 7e25309ae70..1e82983b97c 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -925,11 +925,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)); } }