Commit c758512a authored by unknown's avatar unknown

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
......@@ -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;
......@@ -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;
......@@ -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);
......
......@@ -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();
};
......
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