Commit 15dbab1c authored by konstantin@mysql.com's avatar konstantin@mysql.com

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).
parent 5198f496
...@@ -519,3 +519,41 @@ c1 c2 ...@@ -519,3 +519,41 @@ c1 c2
200887 860 200887 860
200887 200887 200887 200887
deallocate prepare stmt; 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; ...@@ -522,3 +522,50 @@ set @a=200887, @b=860;
# this query did not return all matching rows # this query did not return all matching rows
execute stmt using @a, @b; execute stmt using @a, @b;
deallocate prepare stmt; 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): ...@@ -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) String *Item_uint::val_str(String *str)
{ {
// following assert is redundant, because fixed=1 assigned in constructor // following assert is redundant, because fixed=1 assigned in constructor
...@@ -1377,7 +1384,9 @@ Item_param::new_item() ...@@ -1377,7 +1384,9 @@ Item_param::new_item()
case NULL_VALUE: case NULL_VALUE:
return new Item_null(name); return new Item_null(name);
case INT_VALUE: 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: case REAL_VALUE:
return new Item_real(name, value.real, decimals, max_length); return new Item_real(name, value.real, decimals, max_length);
case STRING_VALUE: case STRING_VALUE:
...@@ -2023,6 +2032,19 @@ bool Item_int::eq(const Item *arg, bool binary_cmp) const ...@@ -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() Item_num *Item_uint::neg()
{ {
return new Item_real(name, - ((double) value), 0, max_length); return new Item_real(name, - ((double) value), 0, max_length);
......
...@@ -651,6 +651,7 @@ class Item_uint :public Item_int ...@@ -651,6 +651,7 @@ class Item_uint :public Item_int
{ {
public: public:
Item_uint(const char *str_arg, uint length); 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) Item_uint(uint32 i) :Item_int((longlong) i, 10)
{ unsigned_flag= 1; } { unsigned_flag= 1; }
double val() double val()
...@@ -1046,11 +1047,7 @@ class Item_int_with_ref :public Item_int ...@@ -1046,11 +1047,7 @@ class Item_int_with_ref :public Item_int
{ {
return ref->save_in_field(field, no_conversions); return ref->save_in_field(field, no_conversions);
} }
Item *new_item() Item *new_item();
{
return (ref->unsigned_flag)? new Item_uint(ref->name, ref->max_length) :
new Item_int(ref->name, ref->max_length);
}
}; };
......
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