Commit c758512a authored by unknown's avatar unknown
Browse files

A fix and test case for Bug#9777 " Empty set returned by Prepared Statement when it

 should return a non empty one"
(see comments for the changed files for details).


mysql-test/r/ps.result:
  A test case for Bug#9777: tests results fixed.
mysql-test/t/ps.test:
  A test case for Bug#9777
sql/item.cc:
  A fix for Bug#9777: when creating a constant item from within 
  Item_int_with_ref::new_item, create the item by value, not by name.
  This should work with prepared statements placeholders.
  Item_int_with_ref is a special optimization case used
   when we compare datetime constants with datetime value.
  Converting the item to integer early is OK as it is in line
  with the purpose of Item_int_with_ref - to speed up comparison by 
  using integers.
  Minor cleanups.
sql/item.h:
  Declaration for Item_int_with_ref::new_item
parent f3883ad0
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -519,3 +519,41 @@ c1 c2
200887	860
200887	200887
deallocate prepare stmt;
drop table t1;
create table t1 (
id bigint(20) not null auto_increment,
code varchar(20) character set utf8 collate utf8_bin not null default '',
company_name varchar(250) character set utf8 collate utf8_bin default null,
setup_mode tinyint(4) default null,
start_date datetime default null,
primary key  (id), unique key code (code)
);
create table t2 (
id bigint(20) not null auto_increment,
email varchar(250) character set utf8 collate utf8_bin default null,
name varchar(250) character set utf8 collate utf8_bin default null,
t1_id bigint(20) default null,
password varchar(250) character set utf8 collate utf8_bin default null,
primary_contact tinyint(4) not null default '0',
email_opt_in tinyint(4) not null default '1',
primary key  (id), unique key email (email), key t1_id (t1_id),
constraint t2_fk1 foreign key (t1_id) references t1 (id)
);
insert into t1 values
(1, 'demo', 'demo s', 0, current_date()),
(2, 'code2', 'name 2', 0, current_date()),
(3, 'code3', 'name 3', 0, current_date());
insert into t2 values
(2, 'email1', 'name1', 3, 'password1', 0, 0),
(3, 'email2', 'name1', 1, 'password2', 1, 0),
(5, 'email3', 'name3', 2, 'password3', 0, 0);
prepare stmt from 'select t2.id from t2, t1 where (t1.id=? and t2.t1_id=t1.id)';
set @a=1;
execute stmt using @a;
id
3
select t2.id from t2, t1 where (t1.id=1 and t2.t1_id=t1.id);
id
3
deallocate prepare stmt;
drop table t1, t2;
+47 −0
Original line number Diff line number Diff line
@@ -522,3 +522,50 @@ set @a=200887, @b=860;
# this query did not return all matching rows
execute stmt using @a, @b;
deallocate prepare stmt;
drop table t1;

#
# Bug#9777 - another occurrence of the problem stated in Bug#9096:
# we can not compare basic constants by their names, because a placeholder
# is a basic constant while his name is always '?'
#

create table t1 (
   id bigint(20) not null auto_increment,
   code varchar(20) character set utf8 collate utf8_bin not null default '',
   company_name varchar(250) character set utf8 collate utf8_bin default null,
   setup_mode tinyint(4) default null,
   start_date datetime default null,
   primary key  (id), unique key code (code)
);

create table t2 (
   id bigint(20) not null auto_increment,
   email varchar(250) character set utf8 collate utf8_bin default null,
   name varchar(250) character set utf8 collate utf8_bin default null,
   t1_id bigint(20) default null,
   password varchar(250) character set utf8 collate utf8_bin default null,
   primary_contact tinyint(4) not null default '0',
   email_opt_in tinyint(4) not null default '1',
   primary key  (id), unique key email (email), key t1_id (t1_id),
   constraint t2_fk1 foreign key (t1_id) references t1 (id)
);

insert into t1 values
(1, 'demo', 'demo s', 0, current_date()),
(2, 'code2', 'name 2', 0, current_date()),
(3, 'code3', 'name 3', 0, current_date());

insert into t2 values
(2, 'email1', 'name1', 3, 'password1', 0, 0),
(3, 'email2', 'name1', 1, 'password2', 1, 0),
(5, 'email3', 'name3', 2, 'password3', 0, 0);

prepare stmt from 'select t2.id from t2, t1 where (t1.id=? and t2.t1_id=t1.id)';
set @a=1;
execute stmt using @a;

select t2.id from t2, t1 where (t1.id=1 and t2.t1_id=t1.id);

deallocate prepare stmt;
drop table t1, t2;
+23 −1
Original line number Diff line number Diff line
@@ -769,6 +769,13 @@ Item_uint::Item_uint(const char *str_arg, uint length):
}


Item_uint::Item_uint(const char *str_arg, longlong i, uint length):
  Item_int(str_arg, i, length)
{
  unsigned_flag= 1;
}


String *Item_uint::val_str(String *str)
{
  // following assert is redundant, because fixed=1 assigned in constructor
@@ -1377,7 +1384,9 @@ Item_param::new_item()
  case NULL_VALUE:
    return new Item_null(name);
  case INT_VALUE:
    return new Item_int(name, value.integer, max_length);
    return (unsigned_flag ?
            new Item_uint(name, value.integer, max_length) :
            new Item_int(name, value.integer, max_length));
  case REAL_VALUE:
    return new Item_real(name, value.real, decimals, max_length);
  case STRING_VALUE:
@@ -2023,6 +2032,19 @@ bool Item_int::eq(const Item *arg, bool binary_cmp) const
}


Item *Item_int_with_ref::new_item()
{
  DBUG_ASSERT(ref->basic_const_item());
  /*
    We need to evaluate the constant to make sure it works with
    parameter markers.
  */
  return (ref->unsigned_flag ?
          new Item_uint(ref->name, ref->val_int(), ref->max_length) :
          new Item_int(ref->name, ref->val_int(), ref->max_length));
}


Item_num *Item_uint::neg()
{
  return new Item_real(name, - ((double) value), 0, max_length);
+2 −5
Original line number Diff line number Diff line
@@ -651,6 +651,7 @@ class Item_uint :public Item_int
{
public:
  Item_uint(const char *str_arg, uint length);
  Item_uint(const char *str_arg, longlong i, uint length);
  Item_uint(uint32 i) :Item_int((longlong) i, 10) 
    { unsigned_flag= 1; }
  double val()
@@ -1046,11 +1047,7 @@ class Item_int_with_ref :public Item_int
  {
    return ref->save_in_field(field, no_conversions);
  }
  Item *new_item()
  {
    return (ref->unsigned_flag)? new Item_uint(ref->name, ref->max_length) :
                                 new Item_int(ref->name, ref->max_length);
  }
  Item *new_item();
};