summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/mysqltest.c13
-rw-r--r--mysql-test/r/alter_table.result4
-rw-r--r--mysql-test/r/mysqltest.result1
-rw-r--r--mysql-test/r/sp-code.result2
-rw-r--r--mysql-test/r/sp-error.result2
-rw-r--r--mysql-test/r/sp.result100
-rw-r--r--mysql-test/r/variables.result4
-rw-r--r--mysql-test/r/view_grant.result8
-rw-r--r--mysql-test/t/alter_table.test10
-rw-r--r--mysql-test/t/mysqltest.test8
-rw-r--r--mysql-test/t/sp.test89
-rw-r--r--mysql-test/t/type_decimal.test1
-rw-r--r--sql/share/errmsg.txt4
-rw-r--r--sql/sp_head.cc143
-rw-r--r--sql/sp_head.h88
-rw-r--r--sql/sp_pcontext.h9
-rw-r--r--sql/sp_rcontext.cc2
-rw-r--r--sql/sql_handler.cc7
-rw-r--r--sql/sql_yacc.yy19
19 files changed, 366 insertions, 148 deletions
diff --git a/client/mysqltest.c b/client/mysqltest.c
index 2beef73d568..98097b1896e 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -2500,19 +2500,8 @@ int connect_n_handle_errors(struct st_query *q, MYSQL* con, const char* host,
*create_conn= 0;
goto err;
}
- else
- {
- handle_no_error(q);
- /*
- Fail if there was no error but we expected it.
- We also don't want to have connection in this case.
- */
- mysql_close(con);
- *create_conn= 0;
- error= 1;
- goto err;
- }
+ handle_no_error(q);
/*
TODO: change this to 0 in future versions, but the 'kill' test relies on
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index e218e008525..a62a30be5b7 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -617,3 +617,7 @@ select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn');
i v
4 3r4f
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/mysqltest.result b/mysql-test/r/mysqltest.result
index 1646260c218..f2d57fccad2 100644
--- a/mysql-test/r/mysqltest.result
+++ b/mysql-test/r/mysqltest.result
@@ -361,6 +361,7 @@ OK
mysqltest: In included file "./var/tmp/con.sql": At line 7: Connection limit exhausted - increase MAX_CONS in mysqltest.c
mysqltest: In included file "./var/tmp/con.sql": At line 3: connection 'test_con1' not found in connection pool
mysqltest: In included file "./var/tmp/con.sql": At line 2: Connection test_con1 already exists
+connect(localhost,root,,test,MASTER_PORT,MASTER_SOCKET);
Output from mysqltest-x.inc
Output from mysqltest-x.inc
Output from mysqltest-x.inc
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-error.result b/mysql-test/r/sp-error.result
index 1241e05fa74..a74a18375d5 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -522,7 +522,7 @@ fetch c into v;
end|
delete from t1|
call bug7299()|
-ERROR 02000: No data to FETCH
+ERROR 02000: No data - zero rows fetched, selected, or processed
drop procedure bug7299|
create procedure bug9073()
begin
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 24beec04c4e..a025c0503cd 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -522,7 +522,7 @@ delete from t1|
create table t3 ( s char(16), d int)|
call into_test4()|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from t3|
s d
into4 NULL
@@ -1787,10 +1787,10 @@ end|
call bug1863(10)|
Warnings:
Note 1051 Unknown table 'temp_t1'
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
call bug1863(10)|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from t4|
f1 rc t3
2 0 NULL
@@ -2084,10 +2084,10 @@ end|
call bug4579_1()|
call bug4579_1()|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
call bug4579_1()|
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
drop procedure bug4579_1|
drop procedure bug4579_2|
drop table t3|
@@ -2507,7 +2507,7 @@ call bug7743("OneWord")|
var
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
call bug7743("anotherword")|
var
2
@@ -2515,7 +2515,7 @@ call bug7743("AnotherWord")|
var
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
drop procedure bug7743|
drop table t4|
delete from t3|
@@ -4296,6 +4296,90 @@ 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|
@@ -4340,7 +4424,7 @@ After NOT FOUND condtition is triggered
xid xdone
1 0
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
call bug15231_3()|
Result
Missed it (correct)
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index d192ee6fe1c..8ee6dfe53cf 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -537,10 +537,10 @@ select @@query_prealloc_size = @test;
create table t1 (a int);
select a into @x from t1;
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
show warnings;
Level Code Message
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
drop table t1;
set @@warning_count=1;
ERROR HY000: Variable 'warning_count' is a read only variable
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index daf34362b5d..f7156bbb701 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -350,12 +350,12 @@ select * from v1;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v2;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v3;
ERROR HY000: View 'mysqltest.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
select * from v4;
@@ -396,12 +396,12 @@ select * from v3;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v4;
f2()
NULL
Warnings:
-Warning 1329 No data to FETCH
+Warning 1329 No data - zero rows fetched, selected, or processed
select * from v5;
ERROR HY000: View 'mysqltest.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
drop view v1, v2, v3, v4, v5;
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index 3cddd752763..6d0ec720840 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -439,3 +439,13 @@ select * from t1;
alter table t1 add unique key (i, v);
select * from t1 where i between 2 and 4 and v in ('def','3r4f','lmn');
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/mysqltest.test b/mysql-test/t/mysqltest.test
index f928f0d3e6f..a59788ae229 100644
--- a/mysql-test/t/mysqltest.test
+++ b/mysql-test/t/mysqltest.test
@@ -909,7 +909,13 @@ select "a" as col1, "c" as col2;
--error 1
--exec echo "source var/tmp/con.sql;" | $MYSQL_TEST 2>&1
-
+# connect when "disable_abort_on_error" caused "connection not found"
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--disable_abort_on_error
+connect (con1,localhost,root,,);
+connection default;
+connection con1;
+--enable_abort_on_error
# ----------------------------------------------------------------------------
# Test mysqltest arguments
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 95147cc969b..836d24340ef 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -3753,7 +3753,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|
@@ -5048,6 +5048,93 @@ 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
diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test
index 1f6310cb819..07347322453 100644
--- a/mysql-test/t/type_decimal.test
+++ b/mysql-test/t/type_decimal.test
@@ -376,3 +376,4 @@ insert INTO t2 SELECT * FROM t1;
select * from t2;
drop table t1, t2;
+
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 80910a8fd81..084ab31c459 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5172,8 +5172,8 @@ ER_SP_WRONG_NO_OF_FETCH_ARGS
eng "Incorrect number of FETCH variables"
ger "Falsche Anzahl von FETCH-Variablen"
ER_SP_FETCH_NO_DATA 02000
- eng "No data to FETCH"
- ger "Keine Daten mit FETCH abzuholen"
+ eng "No data - zero rows fetched, selected, or processed"
+ ger "Keine Daten - null Zeilen geholt (fetch), ausgewählt oder verarbeitet"
ER_SP_DUP_PARAM 42000
eng "Duplicate parameter: %s"
ger "Doppelter Parameter: %s"
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 33eb652208f..e1af0b7d939 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -433,7 +433,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;
@@ -442,6 +443,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);
@@ -1751,6 +1753,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)
{
@@ -1964,7 +1999,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()
@@ -1987,7 +2025,7 @@ void sp_head::optimize()
else
{
if (src != dst)
- {
+ { // Move the instruction and update prev. jumps
sp_instr *ibp;
List_iterator_fast<sp_instr> li(bp);
@@ -1995,8 +2033,7 @@ void sp_head::optimize()
while ((ibp= li++))
{
sp_instr_jump *ji= static_cast<sp_instr_jump *>(ibp);
- if (ji->m_dest == src)
- ji->m_dest= dst;
+ ji->set_destination(src, dst);
}
}
i->opt_move(dst, &bp);
@@ -2430,67 +2467,6 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *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
*/
@@ -2511,7 +2487,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;
@@ -2529,11 +2508,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);
}
@@ -2550,9 +2531,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<sp_instr> *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 e4ef7526683..37ab486c6f3 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;
@@ -265,6 +266,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:
} bp_t;
List<bp_t> 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<sp_instr_jump_if_not> 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.
@@ -668,50 +693,17 @@ public:
m_dest= dest;
}
-protected:
-
- sp_instr *m_optdest; // Used during optimization
-
-}; // 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)
+ virtual void set_destination(uint old_dest, uint new_dest)
{
- return m_ip;
+ if (m_dest == old_dest)
+ m_dest= new_dest;
}
-private:
+protected:
- Item *m_expr; // The condition
- sp_lex_keeper m_lex_keeper;
+ sp_instr *m_optdest; // Used during optimization
-}; // class sp_instr_jump_if : public sp_instr_jump
+}; // class sp_instr_jump : public sp_instr
class sp_instr_jump_if_not : public sp_instr_jump
@@ -721,12 +713,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()
@@ -745,10 +741,20 @@ public:
return m_ip;
}
+ virtual void opt_move(uint dst, List<sp_instr> *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 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);
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 78eacd02e56..9dfa20da522 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -422,12 +422,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_yacc.yy b/sql/sql_yacc.yy
index 513dc0b7416..a116dc27891 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2288,7 +2288,9 @@ sp_proc_stmt:
;
sp_proc_stmt_if:
- IF sp_if END IF {}
+ IF { Lex->sphead->new_cont_backpatch(NULL); }
+ sp_if END IF
+ { Lex->sphead->do_cont_backpatch(); }
;
sp_proc_stmt_statement:
@@ -2366,13 +2368,17 @@ sp_proc_stmt_case_simple:
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(); }
;
sp_proc_stmt_case:
CASE_SYM
- { Lex->sphead->reset_lex(YYTHD); }
+ {
+ Lex->sphead->reset_lex(YYTHD);
+ Lex->sphead->new_cont_backpatch(NULL);
+ }
expr WHEN_SYM
{
LEX *lex= Lex;
@@ -2396,6 +2402,7 @@ sp_proc_stmt_case:
sp_case END CASE_SYM
{
Lex->spcont->pop_case_expr_id();
+ Lex->sphead->do_cont_backpatch();
}
;
@@ -2686,6 +2693,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);
}
@@ -2744,6 +2752,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);
}
@@ -2873,6 +2882,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);
}
@@ -2884,6 +2894,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); }
@@ -2897,6 +2908,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;
}
;