Commit 842bf0b1 authored by unknown's avatar unknown

Fixed BUG#3157: Crash if stored procedure contains IF EXISTS,

and BUG#336: Subselects with tables does not work as values for
local SP variables (which was closed before with a temp. fix, but not
actually fixed).


mysql-test/r/sp-error.result:
  Moved test case for BUG#336 to sp.test, as it's not generating an error any longer.
mysql-test/r/sp.result:
  Move test case for BUG#336 from sp-error.test and added new test case
  for BUG#3157.
mysql-test/t/sp-error.test:
  Moved test case for BUG#336 to sp.test, as it's not generating an error any longer.
mysql-test/t/sp.test:
  Move test case for BUG#336 from sp-error.test and added new test case
  for BUG#3157.
sql/sp_head.cc:
  Open and close tables in set, jump-if[-not] and freturn instructions if
  the value expression is a subselect.
sql/sp_head.h:
  Store tables in set, jump-if[-not] and freturn instructions if
  the value expression is a subselect.
sql/sql_yacc.yy:
  Store tables in set, jump-if[-not] and freturn instructions if
  the value expression is a subselect.
parent fbf7da2d
...@@ -299,12 +299,6 @@ ERROR 42S22: Unknown column 'valname' in 'order clause' ...@@ -299,12 +299,6 @@ ERROR 42S22: Unknown column 'valname' in 'order clause'
drop procedure bug1965| drop procedure bug1965|
select 1 into a| select 1 into a|
ERROR 42000: Undeclared variable: a ERROR 42000: Undeclared variable: a
create procedure bug336(id char(16))
begin
declare x int;
set x = (select sum(t.data) from test.t2 t);
end|
ERROR 0A000: Subselect value not supported
create function bug1654() create function bug1654()
returns int returns int
return (select sum(t.data) from test.t2 t)| return (select sum(t.data) from test.t2 t)|
......
...@@ -1674,6 +1674,36 @@ create table t2 as select * from t; ...@@ -1674,6 +1674,36 @@ create table t2 as select * from t;
end| end|
call bug4904()| call bug4904()|
drop procedure bug4904| drop procedure bug4904|
create procedure bug336(out y int)
begin
declare x int;
set x = (select sum(t.data) from test.t1 t);
set y = x;
end|
insert into t1 values ("a", 2), ("b", 3)|
call bug336(@y)|
select @y|
@y
5
delete from t1|
drop procedure bug336|
create procedure bug3157()
begin
if exists(select * from t1) then
set @n= @n + 1;
end if;
if (select count(*) from t1) then
set @n= @n + 1;
end if;
end|
set @n = 0|
insert into t1 values ("a", 1)|
call bug3157()|
select @n|
@n
2
delete from t1|
drop procedure bug3157|
drop table if exists fac| drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)| create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned) create procedure ifac(n int unsigned)
......
...@@ -400,16 +400,6 @@ drop procedure bug1965| ...@@ -400,16 +400,6 @@ drop procedure bug1965|
--error 1326 --error 1326
select 1 into a| select 1 into a|
#
# BUG#336
#
--error 1334
create procedure bug336(id char(16))
begin
declare x int;
set x = (select sum(t.data) from test.t2 t);
end|
# #
# BUG#1654 # BUG#1654
# #
......
...@@ -1808,6 +1808,42 @@ call bug4904()| ...@@ -1808,6 +1808,42 @@ call bug4904()|
drop procedure bug4904| drop procedure bug4904|
#
# BUG#336
#
create procedure bug336(out y int)
begin
declare x int;
set x = (select sum(t.data) from test.t1 t);
set y = x;
end|
insert into t1 values ("a", 2), ("b", 3)|
call bug336(@y)|
select @y|
delete from t1|
drop procedure bug336|
#
# BUG#3157
#
create procedure bug3157()
begin
if exists(select * from t1) then
set @n= @n + 1;
end if;
if (select count(*) from t1) then
set @n= @n + 1;
end if;
end|
set @n = 0|
insert into t1 values ("a", 1)|
call bug3157()|
select @n|
delete from t1|
drop procedure bug3157|
# #
# Some "real" examples # Some "real" examples
......
...@@ -1180,13 +1180,26 @@ sp_instr_set::execute(THD *thd, uint *nextp) ...@@ -1180,13 +1180,26 @@ sp_instr_set::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_set::execute"); DBUG_ENTER("sp_instr_set::execute");
DBUG_PRINT("info", ("offset: %u", m_offset)); DBUG_PRINT("info", ("offset: %u", m_offset));
Item *it= sp_eval_func_item(thd, m_value, m_type); Item *it;
int res;
if (! it) if (tables &&
((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
(res= open_and_lock_tables(thd, tables))))
DBUG_RETURN(-1); DBUG_RETURN(-1);
thd->spcont->set_item(m_offset, it);
it= sp_eval_func_item(thd, m_value, m_type);
if (! it)
res= -1;
else
{
res= 0;
thd->spcont->set_item(m_offset, it);
}
*nextp = m_ip+1; *nextp = m_ip+1;
DBUG_RETURN(0); if (thd->lock || thd->open_tables || thd->derived_tables)
close_thread_tables(thd);
DBUG_RETURN(res);
} }
void void
...@@ -1265,15 +1278,28 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp) ...@@ -1265,15 +1278,28 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_jump_if::execute"); DBUG_ENTER("sp_instr_jump_if::execute");
DBUG_PRINT("info", ("destination: %u", m_dest)); DBUG_PRINT("info", ("destination: %u", m_dest));
Item *it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); Item *it;
int res;
if (!it) if (tables &&
((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
(res= open_and_lock_tables(thd, tables))))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (it->val_int())
*nextp = m_dest; it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (!it)
res= -1;
else else
*nextp = m_ip+1; {
DBUG_RETURN(0); res= 0;
if (it->val_int())
*nextp = m_dest;
else
*nextp = m_ip+1;
}
if (thd->lock || thd->open_tables || thd->derived_tables)
close_thread_tables(thd);
DBUG_RETURN(res);
} }
void void
...@@ -1309,15 +1335,28 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp) ...@@ -1309,15 +1335,28 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_jump_if_not::execute"); DBUG_ENTER("sp_instr_jump_if_not::execute");
DBUG_PRINT("info", ("destination: %u", m_dest)); DBUG_PRINT("info", ("destination: %u", m_dest));
Item *it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY); Item *it;
int res;
if (! it) if (tables &&
((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
(res= open_and_lock_tables(thd, tables))))
DBUG_RETURN(-1); DBUG_RETURN(-1);
if (! it->val_int())
*nextp = m_dest; it= sp_eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
if (! it)
res= -1;
else else
*nextp = m_ip+1; {
DBUG_RETURN(0); res= 0;
if (! it->val_int())
*nextp = m_dest;
else
*nextp = m_ip+1;
}
if (thd->lock || thd->open_tables || thd->derived_tables)
close_thread_tables(thd);
DBUG_RETURN(res);
} }
void void
...@@ -1352,13 +1391,24 @@ int ...@@ -1352,13 +1391,24 @@ int
sp_instr_freturn::execute(THD *thd, uint *nextp) sp_instr_freturn::execute(THD *thd, uint *nextp)
{ {
DBUG_ENTER("sp_instr_freturn::execute"); DBUG_ENTER("sp_instr_freturn::execute");
Item *it= sp_eval_func_item(thd, m_value, m_type); Item *it;
int res;
if (! it) if (tables &&
((res= check_table_access(thd, SELECT_ACL, tables, 0)) ||
(res= open_and_lock_tables(thd, tables))))
DBUG_RETURN(-1); DBUG_RETURN(-1);
thd->spcont->set_result(it);
it= sp_eval_func_item(thd, m_value, m_type);
if (! it)
res= -1;
else
{
res= 0;
thd->spcont->set_result(it);
}
*nextp= UINT_MAX; *nextp= UINT_MAX;
DBUG_RETURN(0); DBUG_RETURN(res);
} }
void void
......
...@@ -351,8 +351,10 @@ class sp_instr_set : public sp_instr ...@@ -351,8 +351,10 @@ class sp_instr_set : public sp_instr
public: public:
TABLE_LIST *tables;
sp_instr_set(uint ip, uint offset, Item *val, enum enum_field_types type) sp_instr_set(uint ip, uint offset, Item *val, enum enum_field_types type)
: sp_instr(ip), m_offset(offset), m_value(val), m_type(type) : sp_instr(ip), tables(NULL), m_offset(offset), m_value(val), m_type(type)
{} {}
virtual ~sp_instr_set() virtual ~sp_instr_set()
...@@ -421,12 +423,14 @@ class sp_instr_jump_if : public sp_instr_jump ...@@ -421,12 +423,14 @@ class sp_instr_jump_if : public sp_instr_jump
public: public:
TABLE_LIST *tables;
sp_instr_jump_if(uint ip, Item *i) sp_instr_jump_if(uint ip, Item *i)
: sp_instr_jump(ip), m_expr(i) : sp_instr_jump(ip), tables(NULL), m_expr(i)
{} {}
sp_instr_jump_if(uint ip, Item *i, uint dest) sp_instr_jump_if(uint ip, Item *i, uint dest)
: sp_instr_jump(ip, dest), m_expr(i) : sp_instr_jump(ip, dest), tables(NULL), m_expr(i)
{} {}
virtual ~sp_instr_jump_if() virtual ~sp_instr_jump_if()
...@@ -457,12 +461,14 @@ class sp_instr_jump_if_not : public sp_instr_jump ...@@ -457,12 +461,14 @@ class sp_instr_jump_if_not : public sp_instr_jump
public: public:
TABLE_LIST *tables;
sp_instr_jump_if_not(uint ip, Item *i) sp_instr_jump_if_not(uint ip, Item *i)
: sp_instr_jump(ip), m_expr(i) : sp_instr_jump(ip), tables(NULL), m_expr(i)
{} {}
sp_instr_jump_if_not(uint ip, Item *i, uint dest) sp_instr_jump_if_not(uint ip, Item *i, uint dest)
: sp_instr_jump(ip, dest), m_expr(i) : sp_instr_jump(ip, dest), tables(NULL), m_expr(i)
{} {}
virtual ~sp_instr_jump_if_not() virtual ~sp_instr_jump_if_not()
...@@ -493,8 +499,10 @@ class sp_instr_freturn : public sp_instr ...@@ -493,8 +499,10 @@ class sp_instr_freturn : public sp_instr
public: public:
TABLE_LIST *tables;
sp_instr_freturn(uint ip, Item *val, enum enum_field_types type) sp_instr_freturn(uint ip, Item *val, enum enum_field_types type)
: sp_instr(ip), m_value(val), m_type(type) : sp_instr(ip), tables(NULL), m_value(val), m_type(type)
{} {}
virtual ~sp_instr_freturn() virtual ~sp_instr_freturn()
......
...@@ -1434,7 +1434,8 @@ sp_opt_inout: ...@@ -1434,7 +1434,8 @@ sp_opt_inout:
sp_proc_stmts: sp_proc_stmts:
/* Empty */ {} /* Empty */ {}
| sp_proc_stmts sp_proc_stmt ';' | sp_proc_stmts { Lex->query_tables= 0; } sp_proc_stmt ';'
; ;
sp_decls: sp_decls:
...@@ -1483,6 +1484,8 @@ sp_decl: ...@@ -1483,6 +1484,8 @@ sp_decl:
sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(), sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(),
i, it, type); i, it, type);
in->tables= lex->query_tables;
lex->query_tables= 0;
lex->sphead->add_instr(in); lex->sphead->add_instr(in);
lex->spcont->set_isset(i, TRUE); lex->spcont->set_isset(i, TRUE);
lex->spcont->set_default(i, it); lex->spcont->set_default(i, it);
...@@ -1799,6 +1802,8 @@ sp_proc_stmt: ...@@ -1799,6 +1802,8 @@ sp_proc_stmt:
dummy.str= (char *)""; dummy.str= (char *)"";
dummy.length= 0; dummy.length= 0;
lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in); lex->spcont->push_pvar(&dummy, MYSQL_TYPE_STRING, sp_param_in);
i->tables= lex->query_tables;
lex->query_tables= 0;
lex->sphead->add_instr(i); lex->sphead->add_instr(i);
lex->sphead->m_simple_case= TRUE; lex->sphead->m_simple_case= TRUE;
} }
...@@ -2047,11 +2052,14 @@ sp_fetch_list: ...@@ -2047,11 +2052,14 @@ sp_fetch_list:
sp_if: sp_if:
expr THEN_SYM expr THEN_SYM
{ {
sp_head *sp= Lex->sphead; LEX *lex= Lex;
sp_pcontext *ctx= Lex->spcont; sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
uint ip= sp->instructions(); uint ip= sp->instructions();
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $1); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $1);
i->tables= lex->query_tables;
lex->query_tables= 0;
sp->push_backpatch(i, ctx->push_label((char *)"", 0)); sp->push_backpatch(i, ctx->push_label((char *)"", 0));
sp->add_instr(i); sp->add_instr(i);
} }
...@@ -2105,6 +2113,8 @@ sp_case: ...@@ -2105,6 +2113,8 @@ sp_case:
lex->variables_used= 1; lex->variables_used= 1;
} }
sp->push_backpatch(i, ctx->push_label((char *)"", 0)); sp->push_backpatch(i, ctx->push_label((char *)"", 0));
i->tables= lex->query_tables;
lex->query_tables= 0;
sp->add_instr(i); sp->add_instr(i);
} }
sp_proc_stmts sp_proc_stmts
...@@ -2240,6 +2250,8 @@ sp_unlabeled_control: ...@@ -2240,6 +2250,8 @@ sp_unlabeled_control:
/* Jumping forward */ /* Jumping forward */
sp->push_backpatch(i, lex->spcont->last_label()); sp->push_backpatch(i, lex->spcont->last_label());
i->tables= lex->query_tables;
lex->query_tables= 0;
sp->add_instr(i); sp->add_instr(i);
} }
sp_proc_stmts END WHILE_SYM sp_proc_stmts END WHILE_SYM
...@@ -2258,6 +2270,8 @@ sp_unlabeled_control: ...@@ -2258,6 +2270,8 @@ sp_unlabeled_control:
sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */ sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $4, lab->ip); sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $4, lab->ip);
i->tables= lex->query_tables;
lex->query_tables= 0;
lex->sphead->add_instr(i); lex->sphead->add_instr(i);
} }
; ;
...@@ -6776,11 +6790,6 @@ option_value: ...@@ -6776,11 +6790,6 @@ option_value:
sp_instr_set *i; sp_instr_set *i;
Item *it; Item *it;
if ($3 && $3->type() == Item::SUBSELECT_ITEM)
{ /* QQ For now, just disallow subselects as values */
send_error(lex->thd, ER_SP_SUBSELECT_NYI);
YYABORT;
}
spv= lex->spcont->find_pvar(&$1.base_name); spv= lex->spcont->find_pvar(&$1.base_name);
if ($3) if ($3)
...@@ -6791,6 +6800,8 @@ option_value: ...@@ -6791,6 +6800,8 @@ option_value:
it= new Item_null(); it= new Item_null();
i= new sp_instr_set(lex->sphead->instructions(), i= new sp_instr_set(lex->sphead->instructions(),
spv->offset, it, spv->type); spv->offset, it, spv->type);
i->tables= lex->query_tables;
lex->query_tables= 0;
lex->sphead->add_instr(i); lex->sphead->add_instr(i);
spv->isset= TRUE; spv->isset= TRUE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment