From f75ac7fb82d426b7392781b6292dc9780aae3b8d Mon Sep 17 00:00:00 2001 From: "andrey@lmy004." <> Date: Thu, 1 Sep 2005 00:13:02 +0200 Subject: [PATCH 01/12] fix for bug#12913 (Simple SQL can crash server or connection) (not initialized member leads to server crash) --- mysql-test/r/create.result | 5 +++++ mysql-test/t/create.test | 7 +++++++ sql/sql_table.cc | 1 + 3 files changed, 13 insertions(+) diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 95757fbd7dc..4de428868a0 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -587,6 +587,11 @@ DESC t2; Field Type Null Key Default Extra f2 varchar(86) YES NULL DROP TABLE t1,t2; +CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1; +SELECT * FROM t12913; +f1 +a +DROP TABLE t12913; create database mysqltest; use mysqltest; drop database mysqltest; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 55321a81f5e..5c69d8f7edf 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -501,6 +501,13 @@ AS f2 FROM t1; DESC t2; DROP TABLE t1,t2; +# +# Bug#12913 Simple SQL can crash server or connection +# +CREATE TABLE t12913 (f1 ENUM ('a','b')) AS SELECT 'a' AS f1; +SELECT * FROM t12913; +DROP TABLE t12913; + # # Bug#11028: Crash on create table like # diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 92db0143980..b8ef6ed342a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -649,6 +649,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->decimals= dup_field->decimals; sql_field->flags= dup_field->flags; sql_field->unireg_check= dup_field->unireg_check; + sql_field->interval= dup_field->interval; it2.remove(); // Remove first (create) definition select_field_pos--; break; From 58db54364f964f7fb7f324bd2b3f8d5fb18b7706 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Fri, 4 Nov 2005 15:37:39 +0100 Subject: [PATCH 02/12] Fixed BUG#14498: Stored procedures: hang if undefined variable and exception The problem was to continue at the right place in the code after the test expression in a flow control statement fails with an exception (internally, the test in sp_instr_jump_if_not), and the exception is caught by a continue handler. Execution must then be resumed after the the entire flow control statement (END IF, END WHILE, etc). --- mysql-test/r/sp.result | 84 +++++++++++++++++++++++++ mysql-test/t/sp.test | 86 +++++++++++++++++++++++++ sql/sp_head.cc | 140 ++++++++++++++++++++++------------------- sql/sp_head.h | 88 ++++++++++++++------------ sql/sql_yacc.yy | 20 +++++- 5 files changed, 308 insertions(+), 110 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 1f3f7dba7da..7a3d519ebb9 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3575,4 +3575,88 @@ DROP VIEW bug13095_v1 DROP PROCEDURE IF EXISTS bug13095; DROP VIEW IF EXISTS bug13095_v1; DROP TABLE IF EXISTS bug13095_t1; +drop procedure if exists bug14498_1| +drop procedure if exists bug14498_2| +drop procedure if exists bug14498_3| +drop procedure if exists bug14498_4| +drop procedure if exists bug14498_5| +create procedure bug14498_1() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +if v then +select 'yes' as 'v'; +else +select 'no' as 'v'; +end if; +select 'done' as 'End'; +end| +create procedure bug14498_2() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +while v do +select 'yes' as 'v'; +end while; +select 'done' as 'End'; +end| +create procedure bug14498_3() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +repeat +select 'maybe' as 'v'; +until v end repeat; +select 'done' as 'End'; +end| +create procedure bug14498_4() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +case v +when 1 then +select '1' as 'v'; +when 2 then +select '2' as 'v'; +else +select '?' as 'v'; +end case; +select 'done' as 'End'; +end| +create procedure bug14498_5() +begin +declare continue handler for sqlexception select 'error' as 'Handler'; +case +when v = 1 then +select '1' as 'v'; +when v = 2 then +select '2' as 'v'; +else +select '?' as 'v'; +end case; +select 'done' as 'End'; +end| +call bug14498_1()| +Handler +error +End +done +call bug14498_2()| +Handler +error +End +done +call bug14498_3()| +v +maybe +Handler +error +End +done +call bug14498_5()| +Handler +error +End +done +drop procedure bug14498_1| +drop procedure bug14498_2| +drop procedure bug14498_3| +drop procedure bug14498_4| +drop procedure bug14498_5| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index ab57139bb77..19169273cba 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4489,6 +4489,92 @@ DROP TABLE IF EXISTS bug13095_t1; delimiter |; +# +# BUG#14498: Stored procedures: hang if undefined variable and exception +# +--disable_warnings +drop procedure if exists bug14498_1| +drop procedure if exists bug14498_2| +drop procedure if exists bug14498_3| +drop procedure if exists bug14498_4| +drop procedure if exists bug14498_5| +--enable_warnings + +create procedure bug14498_1() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + if v then + select 'yes' as 'v'; + else + select 'no' as 'v'; + end if; + select 'done' as 'End'; +end| + +create procedure bug14498_2() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + while v do + select 'yes' as 'v'; + end while; + select 'done' as 'End'; +end| + +create procedure bug14498_3() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + repeat + select 'maybe' as 'v'; + until v end repeat; + select 'done' as 'End'; +end| + +create procedure bug14498_4() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + case v + when 1 then + select '1' as 'v'; + when 2 then + select '2' as 'v'; + else + select '?' as 'v'; + end case; + select 'done' as 'End'; +end| + +create procedure bug14498_5() +begin + declare continue handler for sqlexception select 'error' as 'Handler'; + + case + when v = 1 then + select '1' as 'v'; + when v = 2 then + select '2' as 'v'; + else + select '?' as 'v'; + end case; + select 'done' as 'End'; +end| + +call bug14498_1()| +call bug14498_2()| +call bug14498_3()| +# QQ We can't call this at the moment, due to a known bug (BUG#14643) +#call bug14498_4()| +call bug14498_5()| + +drop procedure bug14498_1| +drop procedure bug14498_2| +drop procedure bug14498_3| +drop procedure bug14498_4| +drop procedure bug14498_5| + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_head.cc b/sql/sp_head.cc index abc66ce0b21..7d3a708a5a8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -437,13 +437,14 @@ sp_head::operator delete(void *ptr, size_t size) sp_head::sp_head() :Query_arena(&main_mem_root, INITIALIZED_FOR_SP), - m_flags(0), m_returns_cs(NULL) + m_flags(0), m_returns_cs(NULL), m_cont_level(0) { extern byte * sp_table_key(const byte *ptr, uint *plen, my_bool first); DBUG_ENTER("sp_head::sp_head"); m_backpatch.empty(); + m_cont_backpatch.empty(); m_lex.empty(); hash_init(&m_sptabs, system_charset_info, 0, 0, 0, sp_table_key, 0, 0); hash_init(&m_sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); @@ -1568,6 +1569,39 @@ sp_head::check_backpatch(THD *thd) return 0; } +void +sp_head::new_cont_backpatch(sp_instr_jump_if_not *i) +{ + m_cont_level+= 1; + if (i) + { + /* Use the cont. destination slot to store the level */ + i->m_cont_dest= m_cont_level; + (void)m_cont_backpatch.push_front(i); + } +} + +void +sp_head::add_cont_backpatch(sp_instr_jump_if_not *i) +{ + i->m_cont_dest= m_cont_level; + (void)m_cont_backpatch.push_front(i); +} + +void +sp_head::do_cont_backpatch() +{ + uint dest= instructions(); + uint lev= m_cont_level--; + sp_instr_jump_if_not *i; + + while ((i= m_cont_backpatch.head()) && i->m_cont_dest == lev) + { + i->m_cont_dest= dest; + (void)m_cont_backpatch.pop(); + } +} + void sp_head::set_info(char *definer, uint definerlen, longlong created, longlong modified, @@ -1782,7 +1816,10 @@ sp_head::show_create_function(THD *thd) /* - TODO: what does this do?? + Do some minimal optimization of the code: + 1) Mark used instructions + 1.1) While doing this, shortcut jumps to jump instructions + 2) Compact the code, removing unused instructions */ void sp_head::optimize() @@ -1805,7 +1842,7 @@ void sp_head::optimize() else { if (src != dst) - { + { // Move the instruction and update prev. jumps sp_instr *ibp; List_iterator_fast li(bp); @@ -1813,8 +1850,7 @@ void sp_head::optimize() while ((ibp= li++)) { sp_instr_jump *ji= static_cast(ibp); - if (ji->m_dest == src) - ji->m_dest= dst; + ji->set_destination(src, dst); } } i->opt_move(dst, &bp); @@ -2144,65 +2180,6 @@ sp_instr_jump::opt_move(uint dst, List *bp) } -/* - sp_instr_jump_if class functions -*/ - -int -sp_instr_jump_if::execute(THD *thd, uint *nextp) -{ - DBUG_ENTER("sp_instr_jump_if::execute"); - DBUG_PRINT("info", ("destination: %u", m_dest)); - DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); -} - -int -sp_instr_jump_if::exec_core(THD *thd, uint *nextp) -{ - Item *it; - int res; - - it= sp_prepare_func_item(thd, &m_expr); - if (!it) - res= -1; - else - { - res= 0; - if (it->val_bool()) - *nextp = m_dest; - else - *nextp = m_ip+1; - } - - return res; -} - -void -sp_instr_jump_if::print(String *str) -{ - str->reserve(12); - str->append("jump_if "); - str->qs_append(m_dest); - str->append(' '); - m_expr->print(str); -} - -uint -sp_instr_jump_if::opt_mark(sp_head *sp) -{ - sp_instr *i; - - marked= 1; - if ((i= sp->get_instr(m_dest))) - { - m_dest= i->opt_shortcut_jump(sp, this); - m_optdest= sp->get_instr(m_dest); - } - sp->opt_mark(m_dest); - return m_ip+1; -} - - /* sp_instr_jump_if_not class functions */ @@ -2224,7 +2201,10 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) it= sp_prepare_func_item(thd, &m_expr); if (! it) + { res= -1; + *nextp = m_cont_dest; + } else { res= 0; @@ -2241,10 +2221,12 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) void sp_instr_jump_if_not::print(String *str) { - str->reserve(16); + str->reserve(24); str->append("jump_if_not "); str->qs_append(m_dest); - str->append(' '); + str->append('('); + str->qs_append(m_cont_dest); + str->append(") "); m_expr->print(str); } @@ -2261,9 +2243,35 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) m_optdest= sp->get_instr(m_dest); } sp->opt_mark(m_dest); + if ((i= sp->get_instr(m_cont_dest))) + { + m_cont_dest= i->opt_shortcut_jump(sp, this); + m_cont_optdest= sp->get_instr(m_cont_dest); + } + sp->opt_mark(m_cont_dest); return m_ip+1; } +void +sp_instr_jump_if_not::opt_move(uint dst, List *bp) +{ + /* + cont. destinations may point backwards after shortcutting jumps + during the mark phase. If it's still pointing forwards, only + push this for backpatching if sp_instr_jump::opt_move() will not + do it (i.e. if the m_dest points backwards). + */ + if (m_cont_dest > m_ip) + { // Forward + if (m_dest < m_ip) + bp->push_back(this); + } + else if (m_cont_optdest) + m_cont_dest= m_cont_optdest->m_ip; // Backward + /* This will take care of m_dest and m_ip */ + sp_instr_jump::opt_move(dst, bp); +} + /* sp_instr_freturn class functions diff --git a/sql/sp_head.h b/sql/sp_head.h index ed0f3987e01..e822ed96c02 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -38,6 +38,7 @@ sp_get_flags_for_command(LEX *lex); struct sp_label; class sp_instr; +class sp_instr_jump_if_not; struct sp_cond_type; struct sp_pvar; @@ -240,6 +241,18 @@ public: int check_backpatch(THD *thd); + // Start a new cont. backpatch level. If 'i' is NULL, the level is just incr. + void + new_cont_backpatch(sp_instr_jump_if_not *i); + + // Add an instruction to the current level + void + add_cont_backpatch(sp_instr_jump_if_not *i); + + // Backpatch (and pop) the current level to the current position. + void + do_cont_backpatch(); + char *name(uint *lenp = 0) const { if (lenp) @@ -309,6 +322,18 @@ private: sp_instr *instr; } bp_t; List m_backpatch; // Instructions needing backpatching + /* + We need a special list for backpatching of conditional jump's continue + destination (in the case of a continue handler catching an error in + the test), since it would otherwise interfere with the normal backpatch + mechanism - jump_if_not instructions have two different destination + which are to be patched differently. + Since these occur in a more restricted way (always the same "level" in + the code), we don't need the label. + */ + List m_cont_backpatch; + uint m_cont_level; // The current cont. backpatch level + /* Multi-set representing optimized list of tables to be locked by this routine. Does not include tables which are used by invoked routines. @@ -622,6 +647,12 @@ public: m_dest= dest; } + virtual void set_destination(uint old_dest, uint new_dest) + { + if (m_dest == old_dest) + m_dest= new_dest; + } + protected: sp_instr *m_optdest; // Used during optimization @@ -629,45 +660,6 @@ protected: }; // class sp_instr_jump : public sp_instr -class sp_instr_jump_if : public sp_instr_jump -{ - sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */ - void operator=(sp_instr_jump_if &); - -public: - - sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) - : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) - {} - - sp_instr_jump_if(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) - : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) - {} - - virtual ~sp_instr_jump_if() - {} - - virtual int execute(THD *thd, uint *nextp); - - virtual int exec_core(THD *thd, uint *nextp); - - virtual void print(String *str); - - virtual uint opt_mark(sp_head *sp); - - virtual uint opt_shortcut_jump(sp_head *sp, sp_instr *start) - { - return m_ip; - } - -private: - - Item *m_expr; // The condition - sp_lex_keeper m_lex_keeper; - -}; // class sp_instr_jump_if : public sp_instr_jump - - class sp_instr_jump_if_not : public sp_instr_jump { sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */ @@ -675,12 +667,16 @@ class sp_instr_jump_if_not : public sp_instr_jump public: + uint m_cont_dest; // Where continue handlers will go + sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, LEX *lex) - : sp_instr_jump(ip, ctx), m_expr(i), m_lex_keeper(lex, TRUE) + : sp_instr_jump(ip, ctx), m_cont_dest(0), m_expr(i), + m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} sp_instr_jump_if_not(uint ip, sp_pcontext *ctx, Item *i, uint dest, LEX *lex) - : sp_instr_jump(ip, ctx, dest), m_expr(i), m_lex_keeper(lex, TRUE) + : sp_instr_jump(ip, ctx, dest), m_cont_dest(0), m_expr(i), + m_lex_keeper(lex, TRUE), m_cont_optdest(0) {} virtual ~sp_instr_jump_if_not() @@ -699,10 +695,20 @@ public: return m_ip; } + virtual void opt_move(uint dst, List *ibp); + + virtual void set_destination(uint old_dest, uint new_dest) + { + sp_instr_jump::set_destination(old_dest, new_dest); + if (m_cont_dest == old_dest) + m_cont_dest= new_dest; + } + private: Item *m_expr; // The condition sp_lex_keeper m_lex_keeper; + sp_instr *m_cont_optdest; // Used during optimization }; // class sp_instr_jump_if_not : public sp_instr_jump diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 109dcd7e86a..a93ac1e7061 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2009,14 +2009,21 @@ sp_proc_stmt: } sp->restore_lex(YYTHD); } - | IF sp_if END IF {} + | IF + { Lex->sphead->new_cont_backpatch(NULL); } + sp_if END IF + { Lex->sphead->do_cont_backpatch(); } | CASE_SYM WHEN_SYM { Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE; + Lex->sphead->new_cont_backpatch(NULL); } - sp_case END CASE_SYM {} + sp_case END CASE_SYM { Lex->sphead->do_cont_backpatch(); } | CASE_SYM - { Lex->sphead->reset_lex(YYTHD); } + { + Lex->sphead->reset_lex(YYTHD); + Lex->sphead->new_cont_backpatch(NULL); + } expr WHEN_SYM { /* We "fake" this by using an anonymous variable which we @@ -2038,6 +2045,7 @@ sp_proc_stmt: sp_case END CASE_SYM { Lex->spcont->pop_pvar(); + Lex->sphead->do_cont_backpatch(); } | sp_labeled_control {} @@ -2306,6 +2314,7 @@ sp_if: $2, lex); sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_cont_backpatch(i); sp->add_instr(i); sp->restore_lex(YYTHD); } @@ -2360,6 +2369,7 @@ sp_case: lex->variables_used= 1; } sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_cont_backpatch(i); sp->add_instr(i); sp->restore_lex(YYTHD); } @@ -2489,6 +2499,7 @@ sp_unlabeled_control: /* Jumping forward */ sp->push_backpatch(i, lex->spcont->last_label()); + sp->new_cont_backpatch(i); sp->add_instr(i); sp->restore_lex(YYTHD); } @@ -2500,6 +2511,7 @@ sp_unlabeled_control: sp_instr_jump *i = new sp_instr_jump(ip, lex->spcont, lab->ip); lex->sphead->add_instr(i); + lex->sphead->do_cont_backpatch(); } | REPEAT_SYM sp_proc_stmts1 UNTIL_SYM { Lex->sphead->reset_lex(YYTHD); } @@ -2513,6 +2525,8 @@ sp_unlabeled_control: lex); lex->sphead->add_instr(i); lex->sphead->restore_lex(YYTHD); + /* We can shortcut the cont_backpatch here */ + i->m_cont_dest= ip+1; } ; From 99451444992443f1d11e9442a438b2c4b8940ca6 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 13 Dec 2005 13:12:42 +0100 Subject: [PATCH 03/12] Fixed BUG#15231: Stored procedure bug with not found condition handler Make the distinction between "exception conditions" and "completion conditions" (warning and "no data") as defined by the standard. The latter should not terminate a routine if no handler is found in the lexical scope. --- mysql-test/r/sp.result | 74 +++++++++++++++++++++++++++---------- mysql-test/t/sp.test | 83 +++++++++++++++++++++++++++++++----------- sql/sp_rcontext.cc | 23 ++++++++---- 3 files changed, 133 insertions(+), 47 deletions(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index ded9754f172..288d25262e8 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3557,8 +3557,6 @@ drop procedure if exists bug7049_1| drop procedure if exists bug7049_2| drop procedure if exists bug7049_3| drop procedure if exists bug7049_4| -drop procedure if exists bug7049_5| -drop procedure if exists bug7049_6| drop function if exists bug7049_1| drop function if exists bug7049_2| create table t3 ( x int unique )| @@ -3583,18 +3581,6 @@ select 'Caught it' as 'Result'; call bug7049_3(); select 'Missed it' as 'Result'; end| -create procedure bug7049_5() -begin -declare x decimal(2,1); -set x = 'zap'; -end| -create procedure bug7049_6() -begin -declare exit handler for sqlwarning -select 'Caught it' as 'Result'; -call bug7049_5(); -select 'Missed it' as 'Result'; -end| create function bug7049_1() returns int begin @@ -3624,9 +3610,6 @@ Caught it select * from t3| x 42 -call bug7049_6()| -Result -Caught it select bug7049_2()| bug7049_2() 1 @@ -3635,8 +3618,6 @@ drop procedure bug7049_1| drop procedure bug7049_2| drop procedure bug7049_3| drop procedure bug7049_4| -drop procedure bug7049_5| -drop procedure bug7049_6| drop function bug7049_1| drop function bug7049_2| drop function if exists bug13941| @@ -4320,4 +4301,59 @@ id county 2 NULL drop table t3| drop procedure bug15441| +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| +create table t3 (id int not null)| +create procedure bug15231_1() +begin +declare xid integer; +declare xdone integer default 0; +declare continue handler for not found set xdone = 1; +set xid=null; +call bug15231_2(xid); +select xid, xdone; +end| +create procedure bug15231_2(inout ioid integer) +begin +select "Before NOT FOUND condition is triggered" as '1'; +select id into ioid from t3 where id=ioid; +select "After NOT FOUND condtition is triggered" as '2'; +if ioid is null then +set ioid=1; +end if; +end| +create procedure bug15231_3() +begin +declare exit handler for sqlwarning +select 'Caught it (wrong)' as 'Result'; +call bug15231_4(); +end| +create procedure bug15231_4() +begin +declare x decimal(2,1); +set x = 'zap'; +select 'Missed it (correct)' as 'Result'; +end| +call bug15231_1()| +1 +Before NOT FOUND condition is triggered +2 +After NOT FOUND condtition is triggered +xid xdone +1 0 +Warnings: +Warning 1329 No data to FETCH +call bug15231_3()| +Result +Missed it (correct) +Warnings: +Warning 1366 Incorrect decimal value: 'zap' for column 'x' at row 1 +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index f73288f04ba..8af5b4719a1 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4288,8 +4288,6 @@ drop procedure if exists bug7049_1| drop procedure if exists bug7049_2| drop procedure if exists bug7049_3| drop procedure if exists bug7049_4| -drop procedure if exists bug7049_5| -drop procedure if exists bug7049_6| drop function if exists bug7049_1| drop function if exists bug7049_2| --enable_warnings @@ -4323,22 +4321,6 @@ begin select 'Missed it' as 'Result'; end| -create procedure bug7049_5() -begin - declare x decimal(2,1); - - set x = 'zap'; -end| - -create procedure bug7049_6() -begin - declare exit handler for sqlwarning - select 'Caught it' as 'Result'; - - call bug7049_5(); - select 'Missed it' as 'Result'; -end| - create function bug7049_1() returns int begin @@ -4363,7 +4345,6 @@ select * from t3| delete from t3| call bug7049_4()| select * from t3| -call bug7049_6()| select bug7049_2()| drop table t3| @@ -4371,8 +4352,6 @@ drop procedure bug7049_1| drop procedure bug7049_2| drop procedure bug7049_3| drop procedure bug7049_4| -drop procedure bug7049_5| -drop procedure bug7049_6| drop function bug7049_1| drop function bug7049_2| @@ -5078,6 +5057,68 @@ call bug15441('Yale')| drop table t3| drop procedure bug15441| + +# +# BUG#15231: +# +--disable_warnings +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| +--enable_warnings + +create table t3 (id int not null)| + +create procedure bug15231_1() +begin + declare xid integer; + declare xdone integer default 0; + declare continue handler for not found set xdone = 1; + + set xid=null; + call bug15231_2(xid); + select xid, xdone; +end| + +create procedure bug15231_2(inout ioid integer) +begin + select "Before NOT FOUND condition is triggered" as '1'; + select id into ioid from t3 where id=ioid; + select "After NOT FOUND condtition is triggered" as '2'; + + if ioid is null then + set ioid=1; + end if; +end| + +create procedure bug15231_3() +begin + declare exit handler for sqlwarning + select 'Caught it (wrong)' as 'Result'; + + call bug15231_4(); +end| + +create procedure bug15231_4() +begin + declare x decimal(2,1); + + set x = 'zap'; + select 'Missed it (correct)' as 'Result'; +end| + +call bug15231_1()| +call bug15231_3()| + +drop table if exists t3| +drop procedure if exists bug15231_1| +drop procedure if exists bug15231_2| +drop procedure if exists bug15231_3| +drop procedure if exists bug15231_4| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index eca87e69f8e..c36c904f45d 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -160,6 +160,10 @@ sp_rcontext::set_return_value(THD *thd, Item *return_value_item) } +#define IS_WARNING_CONDITION(S) ((S)[0] == '0' && (S)[1] == '1') +#define IS_NOT_FOUND_CONDITION(S) ((S)[0] == '0' && (S)[1] == '2') +#define IS_EXCEPTION_CONDITION(S) ((S)[0] != '0' || (S)[1] > '2') + bool sp_rcontext::find_handler(uint sql_errno, MYSQL_ERROR::enum_warning_level level) @@ -193,18 +197,17 @@ sp_rcontext::find_handler(uint sql_errno, found= i; break; case sp_cond_type_t::warning: - if ((sqlstate[0] == '0' && sqlstate[1] == '1' || - level == MYSQL_ERROR::WARN_LEVEL_WARN) && - found < 0) + if ((IS_WARNING_CONDITION(sqlstate) || + level == MYSQL_ERROR::WARN_LEVEL_WARN) && + found < 0) found= i; break; case sp_cond_type_t::notfound: - if (sqlstate[0] == '0' && sqlstate[1] == '2' && - found < 0) + if (IS_NOT_FOUND_CONDITION(sqlstate) && found < 0) found= i; break; case sp_cond_type_t::exception: - if ((sqlstate[0] != '0' || sqlstate[1] > '2') && + if (IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR && found < 0) found= i; @@ -213,7 +216,13 @@ sp_rcontext::find_handler(uint sql_errno, } if (found < 0) { - if (m_prev_runtime_ctx) + /* + Only "exception conditions" are propagated to handlers in calling + contexts. If no handler is found locally for a "completion condition" + (warning or "not found") we will simply resume execution. + */ + if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && + level == MYSQL_ERROR::WARN_LEVEL_ERROR) return m_prev_runtime_ctx->find_handler(sql_errno, level); return FALSE; } From 1d83ff5b986be421bfdfc6f55ac542b09e73de56 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 13 Dec 2005 13:22:15 +0100 Subject: [PATCH 04/12] Added bug synopsis in comment for sp.test case BUG#15231. --- mysql-test/t/sp.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 8af5b4719a1..2c323a6d2c6 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5059,7 +5059,7 @@ drop procedure bug15441| # -# BUG#15231: +# BUG#15231: Stored procedure bug with not found condition handler # --disable_warnings drop table if exists t3| From a1b2960a8abcaa6aa9696869f83435cd3121b47d Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Mon, 16 Jan 2006 15:22:29 +0100 Subject: [PATCH 05/12] Post-review fix (BUG#14498). --- sql/sp_pcontext.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h index bd2259cb6fb..2fd40159b6c 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -44,6 +44,15 @@ typedef struct sp_pvar #define SP_LAB_BEGIN 2 // Label at BEGIN #define SP_LAB_ITER 3 // Label at iteration control +/* + An SQL/PSM label. Can refer to the identifier used with the + "label_name:" construct which may precede some SQL/PSM statements, or + to an implicit implementation-dependent identifier which the parser + inserts before a high-level flow control statement such as + IF/WHILE/REPEAT/LOOP, when such statement is rewritten into + a combination of low-level jump/jump_if instructions and labels. +*/ + typedef struct sp_label { char *name; From 5863337b8f5b07d0f043a406a36e9555350c6b58 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Mon, 16 Jan 2006 17:55:22 +0100 Subject: [PATCH 06/12] Post-merge fixes (BUG#14498) --- mysql-test/r/sp-code.result | 2 +- mysql-test/t/sp.test | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/sp-code.result b/mysql-test/r/sp-code.result index e6c4ffe1731..943471c2261 100644 --- a/mysql-test/r/sp-code.result +++ b/mysql-test/r/sp-code.result @@ -49,7 +49,7 @@ Pos Instruction 9 set err@1 1 10 hreturn 5 11 cfetch c@0 n@4 -12 jump_if_not 15 isnull(n@4) +12 jump_if_not 15(17) isnull(n@4) 13 set nulls@2 (nulls@2 + 1) 14 jump 17 15 set count@3 (count@3 + 1) diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 7b311088090..b5751c6da63 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -5230,7 +5230,9 @@ end| call bug14498_1()| call bug14498_2()| call bug14498_3()| -# QQ We can't call this at the moment, due to a known bug (BUG#14643) +# We couldn't call this before, due to a known bug (BUG#14643) +# QQ We still can't since the new set_case_expr instruction breaks +# the semantics of case; it won't crash, but will get the wrong result. #call bug14498_4()| call bug14498_5()| From f693473fff6e59014dc8d6f6d474d67ed346841f Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Mon, 16 Jan 2006 22:31:13 +0300 Subject: [PATCH 07/12] A test case for Bug#7670 "Loss of precision for some integer values stored into DOUBLE column" (Can't repeat) --- mysql-test/r/type_decimal.result | 13 +++++++++++++ mysql-test/t/type_decimal.test | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index d7f5f9fa328..df5abfe8ae3 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -772,3 +772,16 @@ productid zlevelprice 003trans 39.98 004trans 31.18 drop table t1, t2; +create table t1 (a double(53,0)); +insert into t1 values (9988317491112007680) ,(99883133042600208184115200); +select a from t1; +a +9988317491112007680 +99883133042600208184115200 +truncate t1; +insert into t1 values (9988317491112007680.0) ,(99883133042600208184115200.0); +select a from t1; +a +9988317491112007680 +99883133042600208184115200 +drop table t1; diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 1f6310cb819..e06b828f9e6 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -376,3 +376,16 @@ insert INTO t2 SELECT * FROM t1; select * from t2; drop table t1, t2; + +# +# A test case for Bug#7670 "Loss of precision for some integer values stored +# into DOUBLE column": check that there is no truncation +# when inserting big integers into double columns. +# +create table t1 (a double(53,0)); +insert into t1 values (9988317491112007680) ,(99883133042600208184115200); +select a from t1; +truncate t1; +insert into t1 values (9988317491112007680.0) ,(99883133042600208184115200.0); +select a from t1; +drop table t1; From 41ff5c80daea1a52b33cff51d417a4127c9f7a27 Mon Sep 17 00:00:00 2001 From: "jani@a193-229-222-105.elisa-laajakaista.fi" <> Date: Mon, 16 Jan 2006 23:15:00 +0200 Subject: [PATCH 08/12] Changed condition similar to code in 4.1. --- sql/sql_handler.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index e9e1e79daaf..1cd7778a053 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -421,12 +421,13 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, if (!lock) goto err0; // mysql_lock_tables() printed error message already - if (cond && ((!cond->fixed && - cond->fix_fields(thd, &cond)) || cond->check_cols(1))) + if (cond) { if (table->query_id != thd->query_id) cond->cleanup(); // File was reopened - goto err0; + if ((!cond->fixed && + cond->fix_fields(thd, &cond)) || cond->check_cols(1)) + goto err0; } if (keyname) From 3d1675831169484000bbb783a36c3be0a19b8a96 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Tue, 17 Jan 2006 00:28:00 +0300 Subject: [PATCH 09/12] A test case for Bug#6073 "ALTER TABLE minor glitch" (can't repeat) --- mysql-test/r/alter_table.result | 4 ++++ mysql-test/t/alter_table.test | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index f224a10c9bd..5c50b3cd79d 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -562,3 +562,7 @@ desc t1; Field Type Null Key Default Extra mycol int(10) NO 0 drop table t1; +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index f4245abfe86..cfa6182543b 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -412,3 +412,13 @@ create table t1 (mycol int(10) not null); alter table t1 alter column mycol set default 0; desc t1; drop table t1; + +# +# Bug#6073 "ALTER table minor glich": ALTER TABLE complains that an index +# without # prefix is not allowed for TEXT columns, while index +# is defined with prefix. +# +create table t1 (t varchar(255) default null, key t (t(80))) +engine=myisam default charset=latin1; +alter table t1 change t t text; +drop table t1; From 739ba76d646efe19d14e3aee068d92471fcf8f5a Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Tue, 17 Jan 2006 01:03:03 +0300 Subject: [PATCH 10/12] A fix for Bug#13337 "ps test fails if configure wo/ usc2" --- mysql-test/r/ctype_ucs.result | 19 +++++++++++++++++++ mysql-test/r/ps.result | 19 ------------------- mysql-test/t/ctype_ucs.test | 14 ++++++++++++++ mysql-test/t/ps.test | 13 ------------- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index 3ca56548de9..0e12ec88662 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -684,3 +684,22 @@ select f1 from t1 where f1 like 'a%'; f1 a drop table t1; +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +utext +lily +river +execute stmt using @param1; +utext +lily +river +select utext from t1 where utext like '%%'; +utext +lily +river +drop table t1; +deallocate prepare stmt; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index aa9ff083cbb..ba9336c20bb 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -639,25 +639,6 @@ execute stmt using @a, @b; ?=? 1 deallocate prepare stmt; -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -utext -lily -river -execute stmt using @param1; -utext -lily -river -select utext from t1 where utext like '%%'; -utext -lily -river -drop table t1; -deallocate prepare stmt; create table t1 (a int); prepare stmt from "select ??"; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1 diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index 3b3c2c70f32..ed55287ca05 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -427,4 +427,18 @@ insert into t1 values('a'); create index t1f1 on t1(f1); select f1 from t1 where f1 like 'a%'; drop table t1; + +# +# Bug#9442 Set parameter make query fail if column character set is UCS2 +# +create table t1 (utext varchar(20) character set ucs2); +insert into t1 values ("lily"); +insert into t1 values ("river"); +prepare stmt from 'select utext from t1 where utext like ?'; +set @param1='%%'; +execute stmt using @param1; +execute stmt using @param1; +select utext from t1 where utext like '%%'; +drop table t1; +deallocate prepare stmt; # End of 4.1 tests diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 23eb2e11ae3..b0755d06414 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -665,19 +665,6 @@ set @b='CHRISTINE'; execute stmt using @a, @b; deallocate prepare stmt; # -# Bug#9442 Set parameter make query fail if column character set is UCS2 -# -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -execute stmt using @param1; -select utext from t1 where utext like '%%'; -drop table t1; -deallocate prepare stmt; -# # Bug#11299 "prepared statement makes wrong SQL syntax in binlog which stops # replication": check that errouneous queries with placeholders are not # allowed From 4fd615abdbf4049bf23fb4325ac2bdeaca2497a0 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Tue, 17 Jan 2006 01:22:01 +0300 Subject: [PATCH 11/12] A post-merge fix. --- mysql-test/t/ctype_ucs.test | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index f2f872af9d0..04de13f8228 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -429,20 +429,6 @@ insert into t1 values('a'); create index t1f1 on t1(f1); select f1 from t1 where f1 like 'a%'; drop table t1; - -# -# Bug#9442 Set parameter make query fail if column character set is UCS2 -# -create table t1 (utext varchar(20) character set ucs2); -insert into t1 values ("lily"); -insert into t1 values ("river"); -prepare stmt from 'select utext from t1 where utext like ?'; -set @param1='%%'; -execute stmt using @param1; -execute stmt using @param1; -select utext from t1 where utext like '%%'; -drop table t1; -deallocate prepare stmt; # End of 4.1 tests # From ba01e04a2cfc9a3d80dbc3bd5dd10eab4bbe8fa5 Mon Sep 17 00:00:00 2001 From: "pem@mysql.com" <> Date: Tue, 17 Jan 2006 12:48:48 +0100 Subject: [PATCH 12/12] Post-review fix. (BUG#15231) --- sql/sp_rcontext.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index c36c904f45d..215de01e657 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -220,7 +220,7 @@ sp_rcontext::find_handler(uint sql_errno, Only "exception conditions" are propagated to handlers in calling contexts. If no handler is found locally for a "completion condition" (warning or "not found") we will simply resume execution. - */ + */ if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) && level == MYSQL_ERROR::WARN_LEVEL_ERROR) return m_prev_runtime_ctx->find_handler(sql_errno, level);