Commit 248eb4a9 authored by unknown's avatar unknown

Merge tulin@bk-internal.mysql.com:/home/bk/mysql-5.0

into dl145b.mysql.com:/home/ndbdev/tomas/mysql-5.1


sql/item.cc:
  Auto merged
parents 30322975 2275c048
...@@ -570,3 +570,28 @@ id ...@@ -570,3 +570,28 @@ id
deallocate prepare stmt| deallocate prepare stmt|
drop procedure p1| drop procedure p1|
drop table t1| drop table t1|
drop table if exists t1;
Warnings:
Note 1051 Unknown table 't1'
create table t1 (c1 int(11) not null, c2 int(11) not null,
primary key (c1,c2), key c2 (c2), key c1 (c1));
insert into t1 values (200887, 860);
insert into t1 values (200887, 200887);
select * from t1 where (c1=200887 and c2=200887) or c2=860;
c1 c2
200887 860
200887 200887
prepare stmt from
"select * from t1 where (c1=200887 and c2=200887) or c2=860";
execute stmt;
c1 c2
200887 860
200887 200887
prepare stmt from
"select * from t1 where (c1=200887 and c2=?) or c2=?";
set @a=200887, @b=860;
execute stmt using @a, @b;
c1 c2
200887 860
200887 200887
deallocate prepare stmt;
...@@ -88,7 +88,7 @@ date numfacture expedition ...@@ -88,7 +88,7 @@ date numfacture expedition
0000-00-00 00:00:00 1212 0001-00-00 00:00:00 0000-00-00 00:00:00 1212 0001-00-00 00:00:00
EXPLAIN SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00'; EXPLAIN SELECT * FROM t1 WHERE expedition='0001-00-00 00:00:00';
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref expedition expedition 8 const 1 Using where 1 SIMPLE t1 ref expedition expedition 8 const 1
drop table t1; drop table t1;
create table t1 (a datetime not null, b datetime not null); create table t1 (a datetime not null, b datetime not null);
insert into t1 values (now(), now()); insert into t1 values (now(), now());
......
...@@ -587,3 +587,30 @@ deallocate prepare stmt| ...@@ -587,3 +587,30 @@ deallocate prepare stmt|
drop procedure p1| drop procedure p1|
drop table t1| drop table t1|
delimiter ;| delimiter ;|
#
# Bug#9096 "select doesn't return all matched records if prepared statements
# is used"
# The bug was is bad co-operation of the optimizer's algorithm which determines
# which keys can be used to execute a query, constants propagation
# part of the optimizer and parameter markers used by prepared statements.
drop table if exists t1;
create table t1 (c1 int(11) not null, c2 int(11) not null,
primary key (c1,c2), key c2 (c2), key c1 (c1));
insert into t1 values (200887, 860);
insert into t1 values (200887, 200887);
select * from t1 where (c1=200887 and c2=200887) or c2=860;
prepare stmt from
"select * from t1 where (c1=200887 and c2=200887) or c2=860";
execute stmt;
prepare stmt from
"select * from t1 where (c1=200887 and c2=?) or c2=?";
set @a=200887, @b=860;
# this query did not return all matching rows
execute stmt using @a, @b;
deallocate prepare stmt;
...@@ -558,6 +558,11 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) ...@@ -558,6 +558,11 @@ void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
bool Item::eq(const Item *item, bool binary_cmp) const bool Item::eq(const Item *item, bool binary_cmp) const
{ {
/*
Note, that this is never TRUE if item is a Item_param:
for all basic constants we have special checks, and Item_param's
type() can be only among basic constant types.
*/
return type() == item->type() && name && item->name && return type() == item->type() && name && item->name &&
!my_strcasecmp(system_charset_info,name,item->name); !my_strcasecmp(system_charset_info,name,item->name);
} }
...@@ -602,7 +607,7 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs) ...@@ -602,7 +607,7 @@ Item *Item_string::safe_charset_converter(CHARSET_INFO *tocs)
bool Item_string::eq(const Item *item, bool binary_cmp) const bool Item_string::eq(const Item *item, bool binary_cmp) const
{ {
if (type() == item->type()) if (type() == item->type() && item->basic_const_item())
{ {
if (binary_cmp) if (binary_cmp)
return !stringcmp(&str_value, &item->str_value); return !stringcmp(&str_value, &item->str_value);
...@@ -1444,6 +1449,24 @@ void Item_decimal::print(String *str) ...@@ -1444,6 +1449,24 @@ void Item_decimal::print(String *str)
} }
bool Item_decimal::eq(const Item *item, bool binary_cmp) const
{
if (type() == item->type() && item->basic_const_item())
{
/*
We need to cast off const to call val_decimal(). This should
be OK for a basic constant. Additionally, we can pass 0 as
a true decimal constant will return its internal decimal
storage and ignore the argument.
*/
Item *arg= (Item*) item;
my_decimal *value= arg->val_decimal(0);
return !my_decimal_cmp(&decimal_value, value);
}
return 0;
}
String *Item_float::val_str(String *str) String *Item_float::val_str(String *str)
{ {
// following assert is redundant, because fixed=1 assigned in constructor // following assert is redundant, because fixed=1 assigned in constructor
...@@ -2195,6 +2218,72 @@ bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -2195,6 +2218,72 @@ bool Item_param::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
} }
bool Item_param::basic_const_item() const
{
if (state == NO_VALUE || state == TIME_VALUE)
return FALSE;
return TRUE;
}
Item *
Item_param::new_item()
{
/* see comments in the header file */
switch (state) {
case NULL_VALUE:
return new Item_null(name);
case INT_VALUE:
return new Item_int(name, value.integer, max_length);
case REAL_VALUE:
return new Item_float(name, value.real, decimals, max_length);
case STRING_VALUE:
case LONG_DATA_VALUE:
return new Item_string(name, str_value.c_ptr_quick(), str_value.length(),
str_value.charset());
case TIME_VALUE:
break;
case NO_VALUE:
default:
DBUG_ASSERT(0);
};
return 0;
}
bool
Item_param::eq(const Item *arg, bool binary_cmp) const
{
Item *item;
if (!basic_const_item() || !arg->basic_const_item() || arg->type() != type())
return FALSE;
/*
We need to cast off const to call val_int(). This should be OK for
a basic constant.
*/
item= (Item*) arg;
switch (state) {
case NULL_VALUE:
return TRUE;
case INT_VALUE:
return value.integer == item->val_int() &&
unsigned_flag == item->unsigned_flag;
case REAL_VALUE:
return value.real == item->val_real();
case STRING_VALUE:
case LONG_DATA_VALUE:
if (binary_cmp)
return !stringcmp(&str_value, &item->str_value);
return !sortcmp(&str_value, &item->str_value, collation.collation);
default:
break;
}
return FALSE;
}
/* End of Item_param related */
void Item_param::print(String *str) void Item_param::print(String *str)
{ {
if (state == NO_VALUE) if (state == NO_VALUE)
...@@ -3412,6 +3501,22 @@ int Item_decimal::save_in_field(Field *field, bool no_conversions) ...@@ -3412,6 +3501,22 @@ int Item_decimal::save_in_field(Field *field, bool no_conversions)
} }
bool Item_int::eq(const Item *arg, bool binary_cmp) const
{
/* No need to check for null value as basic constant can't be NULL */
if (arg->basic_const_item() && arg->type() == type())
{
/*
We need to cast off const to call val_int(). This should be OK for
a basic constant.
*/
Item *item= (Item*) arg;
return item->val_int() == value && item->unsigned_flag == unsigned_flag;
}
return FALSE;
}
Item_num *Item_uint::neg() Item_num *Item_uint::neg()
{ {
Item_decimal *item= new Item_decimal(value, 0); Item_decimal *item= new Item_decimal(value, 0);
...@@ -3499,6 +3604,21 @@ void Item_float::print(String *str) ...@@ -3499,6 +3604,21 @@ void Item_float::print(String *str)
In number context this is a longlong value. In number context this is a longlong value.
*/ */
bool Item_float::eq(const Item *arg, bool binary_cmp) const
{
if (arg->basic_const_item() && arg->type() == type())
{
/*
We need to cast off const to call val_int(). This should be OK for
a basic constant.
*/
Item *item= (Item*) arg;
return item->val_real() == value;
}
return FALSE;
}
inline uint char_val(char X) inline uint char_val(char X)
{ {
return (uint) (X >= '0' && X <= '9' ? X-'0' : return (uint) (X >= '0' && X <= '9' ? X-'0' :
...@@ -3569,6 +3689,17 @@ int Item_hex_string::save_in_field(Field *field, bool no_conversions) ...@@ -3569,6 +3689,17 @@ int Item_hex_string::save_in_field(Field *field, bool no_conversions)
} }
bool Item_hex_string::eq(const Item *arg, bool binary_cmp) const
{
if (arg->basic_const_item() && arg->type() == type())
{
if (binary_cmp)
return !stringcmp(&str_value, &arg->str_value);
return !sortcmp(&str_value, &arg->str_value, collation.collation);
}
return FALSE;
}
/* /*
bin item. bin item.
In string context this is a binary string. In string context this is a binary string.
......
...@@ -434,7 +434,7 @@ public: ...@@ -434,7 +434,7 @@ public:
virtual table_map not_null_tables() const { return used_tables(); } virtual table_map not_null_tables() const { return used_tables(); }
/* /*
Returns true if this is a simple constant item like an integer, not Returns true if this is a simple constant item like an integer, not
a constant expression a constant expression. Used in the optimizer to propagate basic constants.
*/ */
virtual bool basic_const_item() const { return 0; } virtual bool basic_const_item() const { return 0; }
/* cloning of constant items (0 if it is not const) */ /* cloning of constant items (0 if it is not const) */
...@@ -914,7 +914,6 @@ public: ...@@ -914,7 +914,6 @@ public:
bool convert_str_value(THD *thd); bool convert_str_value(THD *thd);
Item *new_item() { return new Item_param(pos_in_query); }
/* /*
If value for parameter was not set we treat it as non-const If value for parameter was not set we treat it as non-const
so noone will use parameters value in fix_fields still so noone will use parameters value in fix_fields still
...@@ -923,12 +922,29 @@ public: ...@@ -923,12 +922,29 @@ public:
virtual table_map used_tables() const virtual table_map used_tables() const
{ return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; }
void print(String *str); void print(String *str);
/* parameter never equal to other parameter of other item */
bool eq(const Item *item, bool binary_cmp) const { return 0; }
bool is_null() bool is_null()
{ DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
bool basic_const_item() const;
/*
This method is used to make a copy of a basic constant item when
propagating constants in the optimizer. The reason to create a new
item and not use the existing one is not precisely known (2005/04/16).
Probably we are trying to preserve tree structure of items, in other
words, avoid pointing at one item from two different nodes of the tree.
Return a new basic constant item if parameter value is a basic
constant, assert otherwise. This method is called only if
basic_const_item returned TRUE.
*/
Item *new_item();
/*
Implement by-value equality evaluation if parameter value
is set and is a basic constant (integer, real or string).
Otherwise return FALSE.
*/
bool eq(const Item *item, bool binary_cmp) const;
}; };
class Item_int :public Item_num class Item_int :public Item_num
{ {
public: public:
...@@ -956,6 +972,7 @@ public: ...@@ -956,6 +972,7 @@ public:
void cleanup() {} void cleanup() {}
void print(String *str); void print(String *str);
Item_num *neg() { value= -value; return this; } Item_num *neg() { value= -value; return this; }
bool eq(const Item *, bool binary_cmp) const;
}; };
...@@ -1022,8 +1039,10 @@ public: ...@@ -1022,8 +1039,10 @@ public:
unsigned_flag= !decimal_value.sign(); unsigned_flag= !decimal_value.sign();
return this; return this;
} }
bool eq(const Item *, bool binary_cmp) const;
}; };
class Item_float :public Item_num class Item_float :public Item_num
{ {
char *presentation; char *presentation;
...@@ -1059,6 +1078,7 @@ public: ...@@ -1059,6 +1078,7 @@ public:
{ return new Item_float(name, value, decimals, max_length); } { return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; } Item_num *neg() { value= -value; return this; }
void print(String *str); void print(String *str);
bool eq(const Item *, bool binary_cmp) const;
}; };
...@@ -1198,6 +1218,7 @@ public: ...@@ -1198,6 +1218,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
// to prevent drop fixed flag (no need parent cleanup call) // to prevent drop fixed flag (no need parent cleanup call)
void cleanup() {} void cleanup() {}
bool eq(const Item *item, bool binary_cmp) const;
}; };
......
...@@ -1395,11 +1395,12 @@ void Item_func_neg::fix_length_and_dec() ...@@ -1395,11 +1395,12 @@ void Item_func_neg::fix_length_and_dec()
/* /*
If this is in integer context keep the context as integer if possible If this is in integer context keep the context as integer if possible
(This is how multiplication and other integer functions works) (This is how multiplication and other integer functions works)
Use val() to get value as arg_type doesn't mean that item is
Item_int or Item_real due to existence of Item_param.
*/ */
if (hybrid_type == INT_RESULT && if (hybrid_type == INT_RESULT &&
args[0]->type() == INT_ITEM && args[0]->type() == INT_ITEM &&
((ulonglong) ((Item_uint*) args[0])->value >= ((ulonglong) args[0]->val_int() >= (ulonglong) LONGLONG_MIN))
(ulonglong) LONGLONG_MIN))
{ {
/* /*
Ensure that result is converted to DECIMAL, as longlong can't hold Ensure that result is converted to DECIMAL, as longlong can't hold
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# started and shut down when the systems goes down. # started and shut down when the systems goes down.
# Comments to support chkconfig on RedHat Linux # Comments to support chkconfig on RedHat Linux
# chkconfig: 2345 90 20 # chkconfig: 2345 64 36
# description: A very fast and reliable SQL database engine. # description: A very fast and reliable SQL database engine.
# Comments to support LSB init script conventions # Comments to support LSB init script conventions
......
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