Commit 2860a772 authored by unknown's avatar unknown
Browse files

Fixes for bug#8115 "Server Crash with prepared statement"

 and bug#8849 "problem with insert statement with table alias's": 
make equality propagation work in stored procedures and prepared 
statements.
Equality propagation can change AND/OR structure of ON expressions,
so the fix is to provide each execution of PS/SP with it's own
copy of AND/OR tree. We have been doing that already for WHERE clauses,
now ON clauses are also copied.


mysql-test/r/ps.result:
  Bug#8115: test results fixed.
mysql-test/r/sp.result:
  Bug#8849: test results fixed.
mysql-test/t/ps.test:
  A test case for Bug#8115 "Server Crash with prepared statement".
mysql-test/t/sp.test:
  A test case for Bug#8849 "problem with insert statement with table 
  alias's".
sql/item_cmpfunc.cc:
  Comment a parse tree transformation.
sql/item_cmpfunc.h:
  Comment how Item_equal works with PS/SP.
sql/mysql_priv.h:
  Add declaration for init_stmt_after_parse.
sql/sp_head.cc:
  Call init_stmt_after_parse in restore_lex(), which is used to
  grab TABLE_LIST and SELECT_LEX list of a parsed substatement of
  stored procedure. This is a necessary post-init step which 
  must be done for any statement which can be executed many times.
sql/sql_prepare.cc:
  Implement init_stmt_after_parse() which prepares AND/OR
  structure of all ON expressions and WHERE clauses of a statement
  for copying.
sql/sql_select.cc:
  Implementation of equality propagation inspected with regard to 
  prepared statements and stored procedures. We now restore
  AND/OR structure of every ON expression in addition to AND/OR
  structure of WHERE clauses when reexecuting a PS/SP.
sql/table.h:
  Add declaration for TABLE::prep_on_expr.
parent 66d2d13a
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -499,3 +499,28 @@ SELECT FOUND_ROWS();
FOUND_ROWS()
2
deallocate prepare stmt;
create table t1 (a char(3) not null, b char(3) not null,
c char(3) not null, primary key  (a, b, c));
create table t2 like t1;
prepare stmt from
"select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
  where t1.a=1";
execute stmt;
a
execute stmt;
a
execute stmt;
a
prepare stmt from
"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
left outer join t2 t3 on t3.a=? where t1.a=?";
set @a:=1, @b:=1, @c:=1;
execute stmt using @a, @b, @c;
a	b	c	a	b	c
execute stmt using @a, @b, @c;
a	b	c	a	b	c
execute stmt using @a, @b, @c;
a	b	c	a	b	c
deallocate prepare stmt;
drop table t1,t2;
+38 −0
Original line number Diff line number Diff line
@@ -2542,3 +2542,41 @@ drop procedure bug7992|
drop table t3|
drop table t1;
drop table t2;
CREATE TABLE t1 (
lpitnumber int(11) default NULL,
lrecordtype int(11) default NULL
);
CREATE TABLE t2 (
lbsiid int(11) NOT NULL default '0',
ltradingmodeid int(11) NOT NULL default '0',
ltradingareaid int(11) NOT NULL default '0',
csellingprice decimal(19,4) default NULL,
PRIMARY KEY  (lbsiid,ltradingmodeid,ltradingareaid)
);
CREATE TABLE t3 (
lbsiid int(11) NOT NULL default '0',
ltradingareaid int(11) NOT NULL default '0',
PRIMARY KEY  (lbsiid,ltradingareaid)
);
CREATE PROCEDURE bug8849()
begin
insert into t3
(
t3.lbsiid,
t3.ltradingareaid
)
select distinct t1.lpitnumber, t2.ltradingareaid
from
t2 join t1 on
t1.lpitnumber = t2.lbsiid
and t1.lrecordtype = 1
left join t2 as price01 on
price01.lbsiid = t2.lbsiid and
price01.ltradingmodeid = 1 and
t2.ltradingareaid = price01.ltradingareaid;
end|
call bug8849();
call bug8849();
call bug8849();
drop procedure bug8849;
drop tables t1,t2,t3;
+33 −0
Original line number Diff line number Diff line
@@ -507,3 +507,36 @@ SELECT FOUND_ROWS();
execute stmt;                                                                   
SELECT FOUND_ROWS();                                                            
deallocate prepare stmt;

#
# Bug#8115: equality propagation and prepared statements
#

create table t1 (a char(3) not null, b char(3) not null,
                 c char(3) not null, primary key  (a, b, c));
create table t2 like t1;

# reduced query
prepare stmt from
  "select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
  where t1.a=1";
execute stmt;
execute stmt;
execute stmt;

# original query
prepare stmt from
"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
left outer join t2 t3 on t3.a=? where t1.a=?";

set @a:=1, @b:=1, @c:=1;

execute stmt using @a, @b, @c;
execute stmt using @a, @b, @c;
execute stmt using @a, @b, @c;

deallocate prepare stmt;

drop table t1,t2;
+49 −0
Original line number Diff line number Diff line
@@ -3086,3 +3086,52 @@ delimiter ;|
drop table t1;
drop table t2;

#
# Bug#8849: rolling back changes to AND/OR structure of ON and WHERE clauses 
# in SP
# 

CREATE TABLE t1 (
  lpitnumber int(11) default NULL,
  lrecordtype int(11) default NULL
);

CREATE TABLE t2 (
  lbsiid int(11) NOT NULL default '0',
  ltradingmodeid int(11) NOT NULL default '0',
  ltradingareaid int(11) NOT NULL default '0',
  csellingprice decimal(19,4) default NULL,
  PRIMARY KEY  (lbsiid,ltradingmodeid,ltradingareaid)
);

CREATE TABLE t3 (
  lbsiid int(11) NOT NULL default '0',
  ltradingareaid int(11) NOT NULL default '0',
  PRIMARY KEY  (lbsiid,ltradingareaid)
);

delimiter |;
CREATE PROCEDURE bug8849()
begin
  insert into t3
  (
   t3.lbsiid,
   t3.ltradingareaid
  )
  select distinct t1.lpitnumber, t2.ltradingareaid
  from
    t2 join t1 on
      t1.lpitnumber = t2.lbsiid
      and t1.lrecordtype = 1
    left join t2 as price01 on
      price01.lbsiid = t2.lbsiid and
      price01.ltradingmodeid = 1 and
      t2.ltradingareaid = price01.ltradingareaid;
end|
delimiter ;|

call bug8849();
call bug8849();
call bug8849();
drop procedure bug8849;
drop tables t1,t2,t3;
+17 −6
Original line number Diff line number Diff line
@@ -2289,6 +2289,21 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)

  if (check_stack_overrun(thd, buff))
    return TRUE;				// Fatal error flag is set!
  /*
    The following optimization reduces the depth of an AND-OR tree.
    E.g. a WHERE clause like
      F1 AND (F2 AND (F2 AND F4))
    is parsed into a tree with the same nested structure as defined
    by braces. This optimization will transform such tree into
      AND (F1, F2, F3, F4).
    Trees of OR items are flattened as well:
      ((F1 OR F2) OR (F3 OR F4))   =>   OR (F1, F2, F3, F4)
    Items for removed AND/OR levels will dangle until the death of the
    entire statement.
    The optimization is currently prepared statements and stored procedures
    friendly as it doesn't allocate any memory and its effects are durable
    (i.e. do not depend on PS/SP arguments).
  */
  while ((item=li++))
  {
    table_map tmp_table_map;
@@ -3265,6 +3280,7 @@ Item_equal::Item_equal(Item *c, Item_field *f)
  const_item= c;
}


Item_equal::Item_equal(Item_equal *item_equal)
  : Item_bool_func(), eval_item(0), cond_false(0)
{
@@ -3301,12 +3317,7 @@ void Item_equal::add(Item_field *f)

uint Item_equal::members()
{
  uint count= 0;
  List_iterator_fast<Item_field> li(fields);
  Item_field *item;
  while ((item= li++))
    count++;
  return count;
  return fields.elements;
}


Loading