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/r/create.result b/mysql-test/r/create.result index bbd4a60c5b1..848b84e2b8c 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -598,6 +598,11 @@ DESC t2; Field Type Null Key Default Extra f2 varchar(171) 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/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/r/sp.result b/mysql-test/r/sp.result index d56cf086cdf..4c2f7b7f03b 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3624,8 +3624,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 )| @@ -3650,18 +3648,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 @@ -3691,9 +3677,6 @@ Caught it select * from t3| x 42 -call bug7049_6()| -Result -Caught it select bug7049_2()| bug7049_2() 1 @@ -3702,8 +3685,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| @@ -4387,4 +4368,143 @@ id county 2 NULL drop table t3| drop procedure bug15441| +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 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/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/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; diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 162db3d0c0a..f7b9002faa0 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -504,6 +504,13 @@ CREATE TABLE t2 AS SELECT LEFT(f1,171) AS f2 FROM t1 UNION SELECT LEFT(f1,171) A 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/mysql-test/t/sp.test b/mysql-test/t/sp.test index a1eba73635e..68ce9cdb118 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3824,7 +3824,7 @@ drop procedure if exists bug7088_2| --disable_parsing # temporarily disabled until Bar fixes BUG#11986 create procedure bug6063() - lâbel: begin end| + lâbel: begin end| call bug6063()| # QQ Known bug: this will not show the label correctly. show create procedure bug6063| @@ -4364,8 +4364,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 @@ -4399,22 +4397,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 @@ -4439,7 +4421,6 @@ select * from t3| delete from t3| call bug7049_4()| select * from t3| -call bug7049_6()| select bug7049_2()| drop table t3| @@ -4447,8 +4428,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| @@ -5154,6 +5133,155 @@ call bug15441('Yale')| drop table t3| drop procedure bug15441| +# +# 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()| +# 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()| + +drop procedure bug14498_1| +drop procedure bug14498_2| +drop procedure bug14498_3| +drop procedure bug14498_4| +drop procedure bug14498_5| + +# +# BUG#15231: Stored procedure bug with not found condition handler +# +--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/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; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 96bf2c51b02..8853ee97e98 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -430,7 +430,8 @@ 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_recursion_level(0), m_next_cached_sp(0), - m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this) + m_first_instance(this), m_first_free_instance(this), m_last_cached_sp(this), + m_cont_level(0) { m_return_field_def.charset = NULL; @@ -439,6 +440,7 @@ sp_head::sp_head() 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); @@ -1735,6 +1737,39 @@ sp_head::fill_field_definition(THD *thd, LEX *lex, } +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(longlong created, longlong modified, st_sp_chistics *chistics, ulong sql_mode) @@ -1949,7 +1984,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() @@ -1972,7 +2010,7 @@ void sp_head::optimize() else { if (src != dst) - { + { // Move the instruction and update prev. jumps sp_instr *ibp; List_iterator_fast li(bp); @@ -1980,8 +2018,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); @@ -2414,67 +2451,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) -{ - /* jump_if dest ... */ - if (str->reserve(SP_INSTR_UINT_MAXLEN+8+32)) // Add some for the expr. too - return; - str->qs_append(STRING_WITH_LEN("jump_if ")); - str->qs_append(m_dest); - str->qs_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 */ @@ -2496,7 +2472,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; @@ -2514,11 +2493,13 @@ void sp_instr_jump_if_not::print(String *str) { /* jump_if_not dest ... */ - if (str->reserve(SP_INSTR_UINT_MAXLEN+12+32)) // Add some for the expr. too + if (str->reserve(2*SP_INSTR_UINT_MAXLEN+14+32)) // Add some for the expr. too return; str->qs_append(STRING_WITH_LEN("jump_if_not ")); str->qs_append(m_dest); - str->qs_append(' '); + str->append('('); + str->qs_append(m_cont_dest); + str->append(") "); m_expr->print(str); } @@ -2535,9 +2516,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 2eebd35f6dc..bd50afebde7 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -41,6 +41,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; @@ -266,6 +267,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) @@ -356,6 +369,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. @@ -669,6 +694,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 @@ -676,45 +707,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 */ @@ -722,12 +714,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() @@ -746,10 +742,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/sp_pcontext.h b/sql/sp_pcontext.h index 6d803362d86..d1cd7b964c2 100644 --- a/sql/sp_pcontext.h +++ b/sql/sp_pcontext.h @@ -52,6 +52,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; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index eca87e69f8e..215de01e657 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; } 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) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 849619ae0f8..b1a24543a6b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -886,6 +886,7 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields--; sql_field->flags= dup_field->flags; + sql_field->interval= dup_field->interval; it2.remove(); // Remove first (create) definition select_field_pos--; break; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 49f2182e12a..714be26887c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1982,14 +1982,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 { LEX *lex= Lex; @@ -2013,6 +2020,7 @@ sp_proc_stmt: sp_case END CASE_SYM { Lex->spcont->pop_case_expr_id(); + Lex->sphead->do_cont_backpatch(); } | sp_labeled_control {} @@ -2281,6 +2289,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); } @@ -2339,6 +2348,7 @@ sp_case: i= new sp_instr_jump_if_not(ip, ctx, expr, lex); } sp->push_backpatch(i, ctx->push_label((char *)"", 0)); + sp->add_cont_backpatch(i); sp->add_instr(i); sp->restore_lex(YYTHD); } @@ -2468,6 +2478,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); } @@ -2479,6 +2490,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); } @@ -2492,6 +2504,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; } ;