diff options
author | unknown <pem@mysql.com> | 2005-12-06 13:34:18 +0100 |
---|---|---|
committer | unknown <pem@mysql.com> | 2005-12-06 13:34:18 +0100 |
commit | 47fe447536b84908e176db62ef821afee0f923ff (patch) | |
tree | 22e589d866e2e6c9864012307d0df61496105a96 | |
parent | b04f21b571ebe197029614309cd1d1c11ff0e85d (diff) | |
parent | d4088df5e9a02e714d85f79bec3ea97cdd8128c6 (diff) | |
download | mariadb-git-47fe447536b84908e176db62ef821afee0f923ff.tar.gz |
Merge mysql.com:/usr/local/bk/mysql-5.0
into mysql.com:/usr/home/pem/bug14233/mysql-5.0
mysql-test/r/sp-error.result:
Auto merged
mysql-test/t/sp.test:
Auto merged
sql/sp.cc:
Auto merged
sql/sp.h:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_trigger.h:
Auto merged
sql/sql_yacc.yy:
Auto merged
sql/share/errmsg.txt:
SCCS merged
-rw-r--r-- | mysql-test/r/sp-destruct.result | 77 | ||||
-rw-r--r-- | mysql-test/r/sp-error.result | 2 | ||||
-rw-r--r-- | mysql-test/t/sp-destruct.test | 124 | ||||
-rw-r--r-- | mysql-test/t/sp.test | 2 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sp.cc | 100 | ||||
-rw-r--r-- | sql/sp.h | 10 | ||||
-rw-r--r-- | sql/sql_base.cc | 47 | ||||
-rw-r--r-- | sql/sql_parse.cc | 8 | ||||
-rw-r--r-- | sql/sql_trigger.h | 2 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 5 |
11 files changed, 332 insertions, 47 deletions
diff --git a/mysql-test/r/sp-destruct.result b/mysql-test/r/sp-destruct.result new file mode 100644 index 00000000000..1b720be9403 --- /dev/null +++ b/mysql-test/r/sp-destruct.result @@ -0,0 +1,77 @@ +use test; +drop procedure if exists bug14233; +drop function if exists bug14233; +drop table if exists t1; +drop view if exists v1; +create procedure bug14233() +set @x = 42; +create function bug14233_f() returns int +return 42; +create table t1 (id int); +create trigger t1_ai after insert on t1 for each row call bug14233(); +alter table mysql.proc drop type; +call bug14233(); +ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5) +create view v1 as select bug14233_f(); +ERROR HY000: Failed to load routine test.bug14233_f. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5) +insert into t1 values (0); +ERROR HY000: Failed to load routine test.bug14233. The table mysql.proc is missing, corrupt, or contains bad data (internal code -5) +flush table mysql.proc; +call bug14233(); +ERROR HY000: Incorrect information in file: './mysql/proc.frm' +create view v1 as select bug14233_f(); +ERROR HY000: Incorrect information in file: './mysql/proc.frm' +insert into t1 values (0); +ERROR HY000: Incorrect information in file: './mysql/proc.frm' +flush table mysql.proc; +call bug14233(); +ERROR 42S02: Table 'mysql.proc' doesn't exist +create view v1 as select bug14233_f(); +ERROR 42S02: Table 'mysql.proc' doesn't exist +insert into t1 values (0); +ERROR 42S02: Table 'mysql.proc' doesn't exist +flush table mysql.proc; +flush privileges; +delete from mysql.proc where name like 'bug14233%'; +insert into mysql.proc +( +db, name, type, specific_name, language, sql_data_access, is_deterministic, +security_type, param_list, returns, body, definer, created, modified, +sql_mode, comment +) +values +( +'test', 'bug14233_1', 'FUNCTION', 'bug14233_1', 'SQL', 'READS_SQL_DATA', 'NO', +'DEFINER', '', 'int(10)', +'select count(*) from mysql.user', +'root@localhost', NOW() , '0000-00-00 00:00:00', '', '' +), +( +'test', 'bug14233_2', 'FUNCTION', 'bug14233_2', 'SQL', 'READS_SQL_DATA', 'NO', +'DEFINER', '', 'int(10)', +'begin declare x int; select count(*) into x from mysql.user; end', +'root@localhost', NOW() , '0000-00-00 00:00:00', '', '' +), +( +'test', 'bug14233_3', 'PROCEDURE', 'bug14233_3', 'SQL', 'READS_SQL_DATA','NO', +'DEFINER', '', '', +'alksj wpsj sa ^#!@ ', +'root@localhost', NOW() , '0000-00-00 00:00:00', '', '' +); +select bug14233_1(); +ERROR HY000: Failed to load routine test.bug14233_1. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +create view v1 as select bug14233_1(); +ERROR HY000: Failed to load routine test.bug14233_1. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +select bug14233_2(); +ERROR HY000: Failed to load routine test.bug14233_2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +create view v1 as select bug14233_2(); +ERROR HY000: Failed to load routine test.bug14233_2. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +call bug14233_3(); +ERROR HY000: Failed to load routine test.bug14233_3. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +drop trigger t1_ai; +create trigger t1_ai after insert on t1 for each row call bug14233_3(); +insert into t1 values (0); +ERROR HY000: Failed to load routine test.bug14233_3. The table mysql.proc is missing, corrupt, or contains bad data (internal code -6) +delete from mysql.proc where name like 'bug14233%'; +drop trigger t1_ai; +drop table t1; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 963f14820be..67b4f377790 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -124,7 +124,7 @@ begin declare x int; set x = val+3; end| -ERROR 42000: No RETURN found in FUNCTION f +ERROR 42000: No RETURN found in FUNCTION test.f create function f(val int) returns int begin declare x int; diff --git a/mysql-test/t/sp-destruct.test b/mysql-test/t/sp-destruct.test new file mode 100644 index 00000000000..a2a66090866 --- /dev/null +++ b/mysql-test/t/sp-destruct.test @@ -0,0 +1,124 @@ +# +# Destructive stored procedure tests +# +# We do horrible things to the mysql.proc table here, so any unexpected +# failures here might leave it in an undetermined state. +# +# In the case of trouble you might want to skip this. +# + +# We're using --system things that probably doesn't work on Windows. +--source include/not_windows.inc + +# Backup proc table +--system rm -rf var/master-data/mysql/backup +--system mkdir var/master-data/mysql/backup +--system cp var/master-data/mysql/proc.* var/master-data/mysql/backup/ + +use test; + +--disable_warnings +drop procedure if exists bug14233; +drop function if exists bug14233; +drop table if exists t1; +drop view if exists v1; +--enable_warnings + +create procedure bug14233() + set @x = 42; + +create function bug14233_f() returns int + return 42; + +create table t1 (id int); +create trigger t1_ai after insert on t1 for each row call bug14233(); + +# Unsupported tampering with the mysql.proc definition +alter table mysql.proc drop type; +--error ER_SP_PROC_TABLE_CORRUPT +call bug14233(); +--error ER_SP_PROC_TABLE_CORRUPT +create view v1 as select bug14233_f(); +--error ER_SP_PROC_TABLE_CORRUPT +insert into t1 values (0); + +flush table mysql.proc; + +# Thrashing the .frm file +--system echo 'saljdlfa' > var/master-data/mysql/proc.frm +--error ER_NOT_FORM_FILE +call bug14233(); +--error ER_NOT_FORM_FILE +create view v1 as select bug14233_f(); +--error ER_NOT_FORM_FILE +insert into t1 values (0); + + +flush table mysql.proc; + +# Drop the mysql.proc table +--system rm var/master-data/mysql/proc.* +--error ER_NO_SUCH_TABLE +call bug14233(); +--error ER_NO_SUCH_TABLE +create view v1 as select bug14233_f(); +--error ER_NO_SUCH_TABLE +insert into t1 values (0); + +# Restore mysql.proc +--system mv var/master-data/mysql/backup/* var/master-data/mysql/ +--system rmdir var/master-data/mysql/backup + +flush table mysql.proc; +flush privileges; + +delete from mysql.proc where name like 'bug14233%'; + +# Unsupported editing of mysql.proc, circumventing checks in "create ..." +insert into mysql.proc +( + db, name, type, specific_name, language, sql_data_access, is_deterministic, + security_type, param_list, returns, body, definer, created, modified, + sql_mode, comment +) +values +( + 'test', 'bug14233_1', 'FUNCTION', 'bug14233_1', 'SQL', 'READS_SQL_DATA', 'NO', + 'DEFINER', '', 'int(10)', + 'select count(*) from mysql.user', + 'root@localhost', NOW() , '0000-00-00 00:00:00', '', '' +), +( + 'test', 'bug14233_2', 'FUNCTION', 'bug14233_2', 'SQL', 'READS_SQL_DATA', 'NO', + 'DEFINER', '', 'int(10)', + 'begin declare x int; select count(*) into x from mysql.user; end', + 'root@localhost', NOW() , '0000-00-00 00:00:00', '', '' +), +( + 'test', 'bug14233_3', 'PROCEDURE', 'bug14233_3', 'SQL', 'READS_SQL_DATA','NO', + 'DEFINER', '', '', + 'alksj wpsj sa ^#!@ ', + 'root@localhost', NOW() , '0000-00-00 00:00:00', '', '' +); + +--error ER_SP_PROC_TABLE_CORRUPT +select bug14233_1(); +--error ER_SP_PROC_TABLE_CORRUPT +create view v1 as select bug14233_1(); + +--error ER_SP_PROC_TABLE_CORRUPT +select bug14233_2(); +--error ER_SP_PROC_TABLE_CORRUPT +create view v1 as select bug14233_2(); + +--error ER_SP_PROC_TABLE_CORRUPT +call bug14233_3(); +drop trigger t1_ai; +create trigger t1_ai after insert on t1 for each row call bug14233_3(); +--error ER_SP_PROC_TABLE_CORRUPT +insert into t1 values (0); + +# Clean-up +delete from mysql.proc where name like 'bug14233%'; +drop trigger t1_ai; +drop table t1; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 760110b0a64..81f7609a468 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -13,6 +13,8 @@ # Tests that require multiple connections, except security/privilege tests, # go to sp-thread. # Tests that uses 'goto' to into sp-goto.test (currently disabled) +# Tests that destroys system tables (e.g. mysql.proc) for error testing +# go to sp-destruct. use test; diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index f67ad3a9fd2..d7a534fb7b9 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5600,3 +5600,5 @@ ER_OLD_FILE_FORMAT eng "'%-.64s' has an old format, you should re-create the '%s' object(s)" ER_SP_RECURSION_LIMIT eng "Recursive limit %d (as set by the max_sp_recursion_depth variable) was exceeded for routine %.64s" +ER_SP_PROC_TABLE_CORRUPT + eng "Failed to load routine %s. The table mysql.proc is missing, corrupt, or contains bad data (internal code %d)" diff --git a/sql/sp.cc b/sql/sp.cc index 8991cc78b5e..7dc872f6225 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -1446,21 +1446,23 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src) first_no_prelock - If true, don't add tables or cache routines used by the body of the first routine (i.e. *start) will be executed in non-prelocked mode. + tabs_changed - Set to TRUE some tables were added, FALSE otherwise NOTE If some function is missing this won't be reported here. Instead this fact will be discovered during query execution. RETURN VALUE - TRUE - some tables were added - FALSE - no tables were added. + 0 - success + non-0 - failure */ -static bool +static int sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, Sroutine_hash_entry *start, - bool first_no_prelock) + bool first_no_prelock, bool *tabs_changed) { - bool result= FALSE; + int ret= 0; + int tabschnd= 0; /* Set if tables changed */ bool first= TRUE; DBUG_ENTER("sp_cache_routines_and_add_tables_aux"); @@ -1481,12 +1483,45 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, name.m_name.str+= 1; name.m_name.length= name.m_qname.length - name.m_db.length - 1; - if (db_find_routine(thd, type, &name, &sp) == SP_OK) + switch ((ret= db_find_routine(thd, type, &name, &sp))) { - if (type == TYPE_ENUM_FUNCTION) - sp_cache_insert(&thd->sp_func_cache, sp); - else - sp_cache_insert(&thd->sp_proc_cache, sp); + case SP_OK: + { + if (type == TYPE_ENUM_FUNCTION) + sp_cache_insert(&thd->sp_func_cache, sp); + else + sp_cache_insert(&thd->sp_proc_cache, sp); + } + break; + case SP_KEY_NOT_FOUND: + ret= SP_OK; + break; + case SP_OPEN_TABLE_FAILED: + /* + Force it to attempt opening it again on subsequent calls; + otherwise we will get one error message the first time, and + then ER_SP_PROC_TABLE_CORRUPT (below) on subsequent tries. + */ + mysql_proc_table_exists= 1; + /* Fall through */ + default: + /* + Any error when loading an existing routine is either some problem + with the mysql.proc table, or a parse error because the contents + has been tampered with (in which case we clear that error). + */ + if (ret == SP_PARSE_ERROR) + thd->clear_error(); + if (!thd->net.report_error) + { + char n[NAME_LEN*2+2]; + + /* m_qname.str is not always \0 terminated */ + memcpy(n, name.m_qname.str, name.m_qname.length); + n[name.m_qname.length]= '\0'; + my_error(ER_SP_PROC_TABLE_CORRUPT, MYF(0), n, ret); + } + break; } } if (sp) @@ -1494,12 +1529,15 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, if (!(first && first_no_prelock)) { sp_update_stmt_used_routines(thd, lex, &sp->m_sroutines); - result|= sp->add_used_tables_to_table_list(thd, &lex->query_tables_last); + tabschnd|= + sp->add_used_tables_to_table_list(thd, &lex->query_tables_last); } } first= FALSE; } - DBUG_RETURN(result); + if (tabs_changed) /* it can be NULL */ + *tabs_changed= tabschnd; + DBUG_RETURN(ret); } @@ -1514,18 +1552,20 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex, lex - LEX representing statement first_no_prelock - If true, don't add tables or cache routines used by the body of the first routine (i.e. *start) + tabs_changed - Set to TRUE some tables were added, FALSE otherwise RETURN VALUE - TRUE - some tables were added - FALSE - no tables were added. + 0 - success + non-0 - failure */ -bool -sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock) +int +sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock, + bool *tabs_changed) { return sp_cache_routines_and_add_tables_aux(thd, lex, (Sroutine_hash_entry *)lex->sroutines_list.first, - first_no_prelock); + first_no_prelock, tabs_changed); } @@ -1539,16 +1579,21 @@ sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool first_no_prelock) thd - thread context lex - LEX representing statement aux_lex - LEX representing view + + RETURN VALUE + 0 - success + non-0 - failure */ -void +int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) { Sroutine_hash_entry **last_cached_routine_ptr= (Sroutine_hash_entry **)lex->sroutines_list.next; sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines_list); - (void)sp_cache_routines_and_add_tables_aux(thd, lex, - *last_cached_routine_ptr, FALSE); + return sp_cache_routines_and_add_tables_aux(thd, lex, + *last_cached_routine_ptr, FALSE, + NULL); } @@ -1562,12 +1607,18 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) thd - thread context lex - LEX respresenting statement triggers - triggers of the table + + RETURN VALUE + 0 - success + non-0 - failure */ -void +int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, Table_triggers_list *triggers) { + int ret= 0; + if (add_used_routine(lex, thd->stmt_arena, &triggers->sroutines_key)) { Sroutine_hash_entry **last_cached_routine_ptr= @@ -1585,10 +1636,11 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, } } } - (void)sp_cache_routines_and_add_tables_aux(thd, lex, - *last_cached_routine_ptr, - FALSE); + ret= sp_cache_routines_and_add_tables_aux(thd, lex, + *last_cached_routine_ptr, + FALSE, NULL); } + return ret; } @@ -84,11 +84,11 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena, sp_name *rt, char rt_type); void sp_remove_not_own_routines(LEX *lex); void sp_update_sp_used_routines(HASH *dst, HASH *src); -bool sp_cache_routines_and_add_tables(THD *thd, LEX *lex, - bool first_no_prelock); -void sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, - LEX *aux_lex); -void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, +int sp_cache_routines_and_add_tables(THD *thd, LEX *lex, + bool first_no_prelock, bool *tabs_changed); +int sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, + LEX *aux_lex); +int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, Table_triggers_list *triggers); extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 39e15675e47..35f4bd9a05f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1984,15 +1984,25 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) if (!thd->prelocked_mode && !thd->lex->requires_prelocking() && thd->lex->sroutines_list.elements) { - bool first_no_prelocking, need_prelocking; + bool first_no_prelocking, need_prelocking, tabs_changed; TABLE_LIST **save_query_tables_last= thd->lex->query_tables_last; DBUG_ASSERT(thd->lex->query_tables == *start); sp_get_prelocking_info(thd, &need_prelocking, &first_no_prelocking); - if ((sp_cache_routines_and_add_tables(thd, thd->lex, - first_no_prelocking) || - *start) && need_prelocking) + if (sp_cache_routines_and_add_tables(thd, thd->lex, + first_no_prelocking, + &tabs_changed)) + { + /* + Serious error during reading stored routines from mysql.proc table. + Something's wrong with the table or its contents, and an error has + been emitted; we must abort. + */ + result= -1; + goto err; + } + else if ((tabs_changed || *start) && need_prelocking) { query_tables_last_own= save_query_tables_last; *start= thd->lex->query_tables; @@ -2116,9 +2126,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) tables->lock_type >= TL_WRITE_ALLOW_WRITE) { if (!query_tables_last_own) - query_tables_last_own= thd->lex->query_tables_last; - sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex, - tables->table->triggers); + query_tables_last_own= thd->lex->query_tables_last; + if (sp_cache_routines_and_add_tables_for_triggers(thd, thd->lex, + tables->table->triggers)) + { + /* + Serious error during reading stored routines from mysql.proc table. + Something's wrong with the table or its contents, and an error has + been emitted; we must abort. + */ + result= -1; + goto err; + } } free_root(&new_frm_mem, MYF(MY_KEEP_PREALLOC)); } @@ -2139,9 +2158,21 @@ process_view_routines: /* We have at least one table in TL here. */ if (!query_tables_last_own) query_tables_last_own= thd->lex->query_tables_last; - sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables->view); + if (sp_cache_routines_and_add_tables_for_view(thd, thd->lex, + tables->view)) + { + /* + Serious error during reading stored routines from mysql.proc table. + Something's wrong with the table or its contents, and an error has + been emitted; we must abort. + */ + result= -1; + goto err; + } } } + + err: thd->proc_info=0; free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 94ce66bd71d..7430cbffeeb 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4133,14 +4133,6 @@ end_with_restore_list: } } #endif - if (lex->sphead->m_type == TYPE_ENUM_FUNCTION && - !(lex->sphead->m_flags & sp_head::HAS_RETURN)) - { - my_error(ER_SP_NORETURN, MYF(0), name); - delete lex->sphead; - lex->sphead= 0; - goto error; - } /* We need to copy name and db in order to use them for diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 6be42d7b868..143f9f4d5bd 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -117,7 +117,7 @@ public: void set_table(TABLE *new_table); friend class Item_trigger_field; - friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, + friend int sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, Table_triggers_list *triggers); private: diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c20b1792718..fbcb3de7907 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1407,6 +1407,11 @@ create_function_tail: YYABORT; lex->sql_command= SQLCOM_CREATE_SPFUNCTION; sp->init_strings(YYTHD, lex, lex->spname); + if (!(sp->m_flags & sp_head::HAS_RETURN)) + { + my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str); + YYABORT; + } /* Restore flag if it was cleared above */ if (sp->m_old_cmq) YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; |