Commit 8830eb4a authored by monty@hundin.mysql.fi's avatar monty@hundin.mysql.fi

Change of internal key_field=NULL handling to avoid error messages.

Optimized SELECT DISTINCT ... ORDER BY ... LIMIT
Fixed reference to uninitalized variable
parent ce56f927
......@@ -198,6 +198,30 @@ a
select distinct 1 from t1,t3 where t1.a=t3.a;
1
1
explain SELECT distinct t1.a from t1;
table type possible_keys key key_len ref rows Extra
t1 index NULL PRIMARY 4 NULL 2 Using index
explain SELECT distinct t1.a from t1 order by a desc;
table type possible_keys key key_len ref rows Extra
t1 index NULL PRIMARY 4 NULL 2 Using index
explain SELECT t1.a from t1 group by a order by a desc;
table type possible_keys key key_len ref rows Extra
t1 index NULL PRIMARY 4 NULL 2 Using index
explain SELECT distinct t1.a from t1 order by a desc limit 1;
table type possible_keys key key_len ref rows Extra
t1 index NULL PRIMARY 4 NULL 2 Using index
explain SELECT distinct a from t3 order by a desc limit 2;
table type possible_keys key key_len ref rows Extra
t3 index NULL a 5 NULL 204 Using index
explain SELECT distinct a,b from t3 order by a+1;
table type possible_keys key key_len ref rows Extra
t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort
explain SELECT distinct a,b from t3 order by a limit 10;
table type possible_keys key key_len ref rows Extra
t3 index NULL a 5 NULL 204 Using temporary
explain SELECT a,b from t3 group by a,b order by a+1;
table type possible_keys key key_len ref rows Extra
t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort
drop table t1,t2,t3,t4;
CREATE TABLE t1 (name varchar(255));
INSERT INTO t1 VALUES ('aa'),('ab'),('ac'),('ad'),('ae');
......
......@@ -31,9 +31,10 @@ log10(100) log10(18) log10(-4) log10(0) log10(NULL)
select pow(10,log10(10)),power(2,4);
pow(10,log10(10)) power(2,4)
10.000000 16.000000
set @@rand_seed1=10000000,@@rand_seed2=1000000;
select rand(999999),rand();
rand(999999) rand()
0.014231365187309 0.8078568166195
0.014231365187309 0.028870999839968
select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1);
PI() sin(pi()/2) cos(pi()/2) abs(tan(pi())) cot(1) asin(1) acos(0) atan(1)
3.141593 1.000000 0.000000 0.000000 0.64209262 1.570796 1.570796 0.785398
......
......@@ -1036,3 +1036,25 @@ n d
1 30
2 20
drop table t1,t2;
create table t1 (a int, b int) type=innodb;
insert into t1 values(20,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a;
b ifnull(t2.b,"this is null")
NULL this is null
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
b ifnull(t2.b,"this is null")
NULL this is null
insert into t1 values(10,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
b ifnull(t2.b,"this is null")
NULL this is null
NULL this is null
drop table t1;
create table t1 (a varchar(10) not null) type=myisam;
create table t2 (b varchar(10) not null unique) type=innodb;
select t1.a from t1,t2 where t1.a=t2.b;
a
drop table t1,t2;
......@@ -6,7 +6,7 @@ select 1 | NULL,1 & NULL,1+NULL,1-NULL;
NULL NULL NULL NULL
select NULL=NULL,NULL<>NULL,IFNULL(NULL,1.1)+0,IFNULL(NULL,1) | 0;
NULL=NULL NULL<>NULL IFNULL(NULL,1.1)+0 IFNULL(NULL,1) | 0
NULL NULL 1.1 1
NULL NULL 1 1
select strcmp("a",NULL),(1<NULL)+0.0,NULL regexp "a",null like "a%","a%" like null;
strcmp("a",NULL) (1<NULL)+0.0 NULL regexp "a" null like "a%" "a%" like null
NULL NULL NULL NULL NULL
......@@ -56,3 +56,20 @@ indexed_field
NULL
NULL
DROP TABLE t1;
create table t1 (a int, b int) type=myisam;
insert into t1 values(20,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a;
b ifnull(t2.b,"this is null")
NULL this is null
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
b ifnull(t2.b,"this is null")
NULL this is null
insert into t1 values(10,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
b ifnull(t2.b,"this is null")
NULL this is null
NULL this is null
drop table t1;
......@@ -88,6 +88,16 @@ select distinct t1.a from t1,t3 where t1.a=t3.a;
#flush status;
select distinct 1 from t1,t3 where t1.a=t3.a;
#show status like 'Handler%';
explain SELECT distinct t1.a from t1;
explain SELECT distinct t1.a from t1 order by a desc;
explain SELECT t1.a from t1 group by a order by a desc;
explain SELECT distinct t1.a from t1 order by a desc limit 1;
explain SELECT distinct a from t3 order by a desc limit 2;
explain SELECT distinct a,b from t3 order by a+1;
explain SELECT distinct a,b from t3 order by a limit 10;
explain SELECT a,b from t3 group by a,b order by a+1;
drop table t1,t2,t3,t4;
CREATE TABLE t1 (name varchar(255));
......
......@@ -13,6 +13,7 @@ select ln(exp(10)),exp(ln(sqrt(10))*2),ln(-1),ln(0),ln(NULL);
select log2(8),log2(15),log2(-2),log2(0),log2(NULL);
select log10(100),log10(18),log10(-4),log10(0),log10(NULL);
select pow(10,log10(10)),power(2,4);
set @@rand_seed1=10000000,@@rand_seed2=1000000;
select rand(999999),rand();
select pi(),sin(pi()/2),cos(pi()/2),abs(tan(pi())),cot(1),asin(1),acos(0),atan(1);
select degrees(pi()),radians(360);
......@@ -673,3 +673,26 @@ UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n;
select * from t1;
select * from t2;
drop table t1,t2;
#
# Testing of IFNULL
#
create table t1 (a int, b int) type=innodb;
insert into t1 values(20,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a;
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
insert into t1 values(10,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
drop table t1;
#
# Test of read_through not existing const_table
#
create table t1 (a varchar(10) not null) type=myisam;
create table t2 (b varchar(10) not null unique) type=innodb;
select t1.a from t1,t2 where t1.a=t2.b;
drop table t1,t2;
......@@ -34,3 +34,17 @@ SELECT * FROM t1 WHERE indexed_field=NULL;
SELECT * FROM t1 WHERE indexed_field IS NULL;
SELECT * FROM t1 WHERE indexed_field<=>NULL;
DROP TABLE t1;
#
# Testing of IFNULL
#
create table t1 (a int, b int) type=myisam;
insert into t1 values(20,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a;
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
insert into t1 values(10,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
t2.b=t3.a order by 1;
drop table t1;
......@@ -1058,7 +1058,7 @@ Field *make_field(char *ptr, uint32 field_length,
uint pack_length_to_packflag(uint type);
uint32 calc_pack_length(enum_field_types type,uint32 length);
bool set_field_to_null(Field *field);
bool set_field_to_null_with_conversions(Field *field);
bool set_field_to_null_with_conversions(Field *field, bool no_conversions);
uint find_enum(TYPELIB *typelib,const char *x, uint length);
ulonglong find_set(TYPELIB *typelib,const char *x, uint length);
bool test_if_int(const char *str,int length);
......
......@@ -122,8 +122,26 @@ set_field_to_null(Field *field)
}
/*
Set field to NULL or TIMESTAMP or to next auto_increment number
SYNOPSIS
set_field_to_null_with_conversions()
field Field to update
no_conversion Set to 1 if we should return 1 if field can't
take null values.
If set to 0 we will do store the 'default value'
if the field is a special field. If not we will
give an error.
RETURN VALUES
0 Field could take 0 or an automatic conversion was used
1 Field could not take NULL and no conversion was used.
If no_conversion was not set, an error message is printed
*/
bool
set_field_to_null_with_conversions(Field *field)
set_field_to_null_with_conversions(Field *field, bool no_conversions)
{
if (field->real_maybe_null())
{
......@@ -131,6 +149,8 @@ set_field_to_null_with_conversions(Field *field)
field->reset();
return 0;
}
if (no_conversions)
return 1;
/*
Check if this is a special type, which will get a special walue
......@@ -156,8 +176,6 @@ set_field_to_null_with_conversions(Field *field)
}
static void do_skip(Copy_field *copy __attribute__((unused)))
{
}
......
......@@ -419,7 +419,7 @@ void Item_field::save_org_in_field(Field *to)
if (field->is_null())
{
null_value=1;
set_field_to_null_with_conversions(to);
set_field_to_null_with_conversions(to, 1);
}
else
{
......@@ -429,12 +429,12 @@ void Item_field::save_org_in_field(Field *to)
}
}
bool Item_field::save_in_field(Field *to)
bool Item_field::save_in_field(Field *to, bool no_conversions)
{
if (result_field->is_null())
{
null_value=1;
return set_field_to_null_with_conversions(to);
return set_field_to_null_with_conversions(to, no_conversions);
}
else
{
......@@ -461,9 +461,9 @@ bool Item_field::save_in_field(Field *to)
1 Field doesn't support NULL values and can't handle 'field = NULL'
*/
bool Item_null::save_in_field(Field *field)
bool Item_null::save_in_field(Field *field, bool no_conversions)
{
return set_field_to_null_with_conversions(field);
return set_field_to_null_with_conversions(field, no_conversions);
}
......@@ -485,7 +485,7 @@ bool Item_null::save_safe_in_field(Field *field)
}
bool Item::save_in_field(Field *field)
bool Item::save_in_field(Field *field, bool no_conversions)
{
if (result_type() == STRING_RESULT ||
result_type() == REAL_RESULT &&
......@@ -496,7 +496,7 @@ bool Item::save_in_field(Field *field)
str_value.set_quick(buff,sizeof(buff));
result=val_str(&str_value);
if (null_value)
return set_field_to_null_with_conversions(field);
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
field->store(result->ptr(),result->length());
str_value.set_quick(0, 0);
......@@ -513,7 +513,7 @@ bool Item::save_in_field(Field *field)
{
longlong nr=val_int();
if (null_value)
return set_field_to_null_with_conversions(field);
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
field->store(nr);
}
......@@ -521,7 +521,7 @@ bool Item::save_in_field(Field *field)
}
bool Item_string::save_in_field(Field *field)
bool Item_string::save_in_field(Field *field, bool no_conversions)
{
String *result;
result=val_str(&str_value);
......@@ -532,7 +532,7 @@ bool Item_string::save_in_field(Field *field)
return 0;
}
bool Item_int::save_in_field(Field *field)
bool Item_int::save_in_field(Field *field, bool no_conversions)
{
longlong nr=val_int();
if (null_value)
......@@ -542,7 +542,7 @@ bool Item_int::save_in_field(Field *field)
return 0;
}
bool Item_real::save_in_field(Field *field)
bool Item_real::save_in_field(Field *field, bool no_conversions)
{
double nr=val();
if (null_value)
......@@ -597,7 +597,7 @@ longlong Item_varbinary::val_int()
}
bool Item_varbinary::save_in_field(Field *field)
bool Item_varbinary::save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
if (field->result_type() == STRING_RESULT)
......@@ -658,9 +658,10 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables)
return 0;
}
/*
** If item is a const function, calculate it and return a const item
** The original item is freed if not returned
If item is a const function, calculate it and return a const item
The original item is freed if not returned
*/
Item_result item_cmp_type(Item_result a,Item_result b)
......
......@@ -53,11 +53,11 @@ public:
void set_name(char* str,uint length=0);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual bool fix_fields(THD *,struct st_table_list *);
virtual bool save_in_field(Field *field);
virtual bool save_in_field(Field *field, bool no_conversions);
virtual void save_org_in_field(Field *field)
{ (void) save_in_field(field); }
{ (void) save_in_field(field, 1); }
virtual bool save_safe_in_field(Field *field)
{ return save_in_field(field); }
{ return save_in_field(field, 1); }
virtual bool send(THD *thd, String *str);
virtual bool eq(const Item *, bool binary_cmp) const;
virtual Item_result result_type () const { return REAL_RESULT; }
......@@ -130,7 +130,7 @@ public:
}
void make_field(Send_field *field);
bool fix_fields(THD *,struct st_table_list *);
bool save_in_field(Field *field);
bool save_in_field(Field *field,bool no_conversions);
void save_org_in_field(Field *field);
table_map used_tables() const;
enum Item_result result_type () const
......@@ -156,7 +156,7 @@ public:
longlong val_int();
String *val_str(String *str);
void make_field(Send_field *field);
bool save_in_field(Field *field);
bool save_in_field(Field *field, bool no_conversions);
bool save_safe_in_field(Field *field);
enum Item_result result_type () const
{ return STRING_RESULT; }
......@@ -190,7 +190,7 @@ public:
double val() { return (double) value; }
String *val_str(String*);
void make_field(Send_field *field);
bool save_in_field(Field *field);
bool save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_int(name,value,max_length); }
void print(String *str);
......@@ -232,7 +232,7 @@ public:
max_length=length;
}
Item_real(double value_par) :value(value_par) {}
bool save_in_field(Field *field);
bool save_in_field(Field *field, bool no_conversions);
enum Type type() const { return REAL_ITEM; }
double val() { return value; }
longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));}
......@@ -277,7 +277,7 @@ public:
double val() { return atof(str_value.ptr()); }
longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); }
String *val_str(String*) { return (String*) &str_value; }
bool save_in_field(Field *field);
bool save_in_field(Field *field, bool no_conversions);
void make_field(Send_field *field);
enum Item_result result_type () const { return STRING_RESULT; }
bool basic_const_item() const { return 1; }
......@@ -298,7 +298,7 @@ public:
Item_default() { name= (char*) "DEFAULT"; }
enum Type type() const { return DEFAULT_ITEM; }
void make_field(Send_field *field) {}
bool save_in_field(Field *field)
bool save_in_field(Field *field, bool no_conversions)
{
field->set_default();
return 0;
......@@ -339,7 +339,7 @@ public:
double val() { return (double) Item_varbinary::val_int(); }
longlong val_int();
String *val_str(String*) { return &str_value; }
bool save_in_field(Field *field);
bool save_in_field(Field *field, bool no_conversions);
void make_field(Send_field *field);
enum Item_result result_type () const { return INT_RESULT; }
unsigned int size_of() { return sizeof(*this);}
......@@ -401,7 +401,8 @@ public:
bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); }
void make_field(Send_field *field) { (*ref)->make_field(field); }
bool fix_fields(THD *,struct st_table_list *);
bool save_in_field(Field *field) { return (*ref)->save_in_field(field); }
bool save_in_field(Field *field, bool no_conversions)
{ return (*ref)->save_in_field(field, no_conversions); }
void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
enum Item_result result_type () const { return (*ref)->result_type(); }
table_map used_tables() const { return (*ref)->used_tables(); }
......@@ -421,9 +422,9 @@ class Item_int_with_ref :public Item_int
public:
Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg)
{}
bool save_in_field(Field *field)
bool save_in_field(Field *field, bool no_conversions)
{
return ref->save_in_field(field);
return ref->save_in_field(field, no_conversions);
}
unsigned int size_of() { return sizeof(*this);}
};
......
......@@ -48,7 +48,7 @@ static bool convert_constant_item(Field *field, Item **item)
{
if ((*item)->const_item() && (*item)->type() != Item::INT_ITEM)
{
if (!(*item)->save_in_field(field) &&
if (!(*item)->save_in_field(field, 1) &&
!((*item)->null_value))
{
Item *tmp=new Item_int_with_ref(field->val_int(), *item);
......@@ -444,15 +444,29 @@ longlong Item_func_between::val_int()
return 0;
}
static Item_result item_store_type(Item_result a,Item_result b)
{
if (a == STRING_RESULT || b == STRING_RESULT)
return STRING_RESULT;
else if (a == REAL_RESULT || b == REAL_RESULT)
return REAL_RESULT;
else
return INT_RESULT;
}
void
Item_func_ifnull::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null;
max_length=max(args[0]->max_length,args[1]->max_length);
decimals=max(args[0]->decimals,args[1]->decimals);
cached_result_type=args[0]->result_type();
if ((cached_result_type=item_store_type(args[0]->result_type(),
args[1]->result_type())) !=
REAL_RESULT)
decimals= 0;
}
double
Item_func_ifnull::val()
{
......
......@@ -696,21 +696,20 @@ double Item_func_round::val()
}
double Item_func_rand::val()
void Item_func_rand::fix_length_and_dec()
{
THD* thd = current_thd;
decimals=NOT_FIXED_DEC;
max_length=float_length(decimals);
if (arg_count)
{ // Only use argument once in query
uint32 tmp= (uint32) (args[0]->val_int());
randominit(&thd->rand,(uint32) (tmp*0x10001L+55555555L),
(uint32) (tmp*0x10000001L));
#ifdef DELETE_ITEMS
delete args[0];
#endif
arg_count=0;
if ((rand= (struct rand_struct*) sql_alloc(sizeof(*rand))))
randominit(rand,(uint32) (tmp*0x10001L+55555555L),
(uint32) (tmp*0x10000001L));
}
else if (!thd->rand_used)
else
{
THD *thd= current_thd;
/*
No need to send a Rand log event if seed was given eg: RAND(seed),
as it will be replicated in the query as such.
......@@ -722,8 +721,14 @@ double Item_func_rand::val()
thd->rand_used=1;
thd->rand_saved_seed1=thd->rand.seed1;
thd->rand_saved_seed2=thd->rand.seed2;
rand= &thd->rand;
}
return rnd(&thd->rand);
}
double Item_func_rand::val()
{
return rnd(rand);
}
longlong Item_func_sign::val_int()
......
......@@ -459,20 +459,20 @@ public:
const char *func_name() const { return truncate ? "truncate" : "round"; }
double val();
void fix_length_and_dec();
unsigned int size_of() { return sizeof(*this);}
};
class Item_func_rand :public Item_real_func
{
struct rand_struct *rand;
public:
Item_func_rand(Item *a) :Item_real_func(a) {}
Item_func_rand() :Item_real_func() {}
double val();
const char *func_name() const { return "rand"; }
void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
bool const_item() const { return 0; }
table_map used_tables() const { return RAND_TABLE_BIT; }
void fix_length_and_dec();
};
......
......@@ -403,7 +403,7 @@ String *Item_date::val_str(String *str)
}
bool Item_date::save_in_field(Field *field)
bool Item_date::save_in_field(Field *field, bool no_conversions)
{
TIME ltime;
timestamp_type t_type=TIMESTAMP_FULL;
......@@ -518,7 +518,7 @@ bool Item_func_now::get_date(TIME *res,
}
bool Item_func_now::save_in_field(Field *to)
bool Item_func_now::save_in_field(Field *to, bool no_conversions)
{
to->set_notnull();
to->store_time(&ltime,TIMESTAMP_FULL);
......
......@@ -231,7 +231,7 @@ public:
double val() { return (double) val_int(); }
const char *func_name() const { return "date"; }
void fix_length_and_dec() { decimals=0; max_length=10; }
bool save_in_field(Field *to);
bool save_in_field(Field *to, bool no_conversions);
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,FIELD_TYPE_DATE);
......@@ -316,7 +316,7 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
double val() { return (double) value; }
longlong val_int() { return value; }
bool save_in_field(Field *to);
bool save_in_field(Field *to, bool no_conversions);
String *val_str(String *str)
{ str_value.set(buff,buff_length); return &str_value; }
const char *func_name() const { return "now"; }
......
......@@ -1029,7 +1029,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
field->cmp_type() != value->result_type())
DBUG_RETURN(0);
if (value->save_in_field(field))
if (value->save_in_field(field, 1))
{
/* This happens when we try to insert a NULL field in a not null column */
// TODO; Check if we can we remove the following block.
......@@ -1038,9 +1038,9 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
/* convert column_name <=> NULL -> column_name IS NULL */
// Get local copy of key
char *str= (char*) alloc_root(param->mem_root,1);
if (!*str)
if (!str)
DBUG_RETURN(0);
*str = 1;
*str= 1;
DBUG_RETURN(new SEL_ARG(field,str,str));
}
DBUG_RETURN(&null_element); // cmp with NULL is never true
......
......@@ -43,7 +43,7 @@
void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
{ /* For mysql 3.21.# */
#ifdef HAVE_purify
bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
#endif
rand_st->max_value= 0x3FFFFFFFL;
rand_st->max_value_dbl=(double) rand_st->max_value;
......
......@@ -2098,7 +2098,7 @@ fill_record(List<Item> &fields,List<Item> &values)
while ((field=(Item_field*) f++))
{
value=v++;
if (value->save_in_field(field->field))
if (value->save_in_field(field->field, 0))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
......@@ -2116,7 +2116,7 @@ fill_record(Field **ptr,List<Item> &values)
while ((field = *ptr++))
{
value=v++;
if (value->save_in_field(field))
if (value->save_in_field(field, 0))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
......
......@@ -158,9 +158,8 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
{
pthread_mutex_lock(&LOCK_thread_count);
ulong tmp=(ulong) (rnd(&sql_rand) * 3000000);
randominit(&rand, tmp + (ulong) start_time,
tmp + (ulong) thread_id);
pthread_mutex_unlock(&LOCK_thread_count);
randominit(&rand, tmp + (ulong) start_time, tmp + (ulong) thread_id);
}
}
......@@ -171,16 +170,16 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
void THD::init(void)
{
pthread_mutex_lock(&LOCK_global_system_variables);
variables= global_system_variables;
pthread_mutex_unlock(&LOCK_global_system_variables);
server_status= SERVER_STATUS_AUTOCOMMIT;
update_lock_default= (variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY :
TL_WRITE);
options= thd_startup_options;
sql_mode=(uint) opt_sql_mode;
open_options=ha_open_options;
pthread_mutex_lock(&LOCK_global_system_variables);
variables= global_system_variables;
pthread_mutex_unlock(&LOCK_global_system_variables);
update_lock_default= (variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY :
TL_WRITE);
session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
}
......
......@@ -180,10 +180,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
item->save_in_field(key_part->field);
item->save_in_field(key_part->field, 1);
key_len+=key_part->store_length;
}
if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len))))
if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
{
send_error(&thd->net,ER_OUTOFMEMORY);
goto err;
......
......@@ -130,7 +130,9 @@ static int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &all_fields, ORDER *order, bool *hidden);
static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &all_fields,ORDER *new_order);
static ORDER *create_distinct_group(ORDER *order, List<Item> &fields);
static ORDER *create_distinct_group(THD *thd, ORDER *order,
List<Item> &fields,
bool *all_order_by_fields_used);
static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
......@@ -228,6 +230,10 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
bzero((char*) &keyuse,sizeof(keyuse));
thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
/* select_limit is used to decide if we are likely to scan the whole table */
select_limit= thd->select_limit;
if (having || (select_options & OPTION_FOUND_ROWS))
select_limit= HA_POS_ERROR;
if (setup_tables(tables) ||
setup_fields(thd,tables,fields,1,&all_fields,1) ||
......@@ -436,6 +442,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
thd->proc_info="statistics";
if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
goto err;
thd->proc_info="preparing";
if (result->initialize_tables(&join))
goto err;
......@@ -444,7 +451,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{
error=return_zero_rows(&join,result,tables,fields,
join.tmp_table_param.sum_func_count != 0 &&
!group,0,"",having,procedure);
!group,0,"no matching row in const table",having,
procedure);
goto err;
}
if (!(thd->options & OPTION_BIG_SELECTS) &&
......@@ -504,21 +512,47 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
if (! hidden_group_fields)
select_distinct=0;
}
else if (select_distinct && join.tables - join.const_tables == 1 &&
(thd->select_limit == HA_POS_ERROR ||
(join.select_options & OPTION_FOUND_ROWS) ||
order &&
!(skip_sort_order=
test_if_skip_sort_order(&join.join_tab[join.const_tables],
order, thd->select_limit,1))))
else if (select_distinct && join.tables - join.const_tables == 1)
{
if ((group=create_distinct_group(order,fields)))
{
select_distinct=0;
no_order= !order;
join.group=1; // For end_write_group
}
else if (thd->fatal_error) // End of memory
/*
We are only using one table. In this case we change DISTINCT to a
GROUP BY query if:
- The GROUP BY can be done through indexes (no sort) and the ORDER
BY only uses selected fields.
(In this case we can later optimize away GROUP BY and ORDER BY)
- We are scanning the whole table without LIMIT
This can happen if:
- We are using CALC_FOUND_ROWS
- We are using an ORDER BY that can't be optimized away.
We don't want to use this optimization when we are using LIMIT
because in this case we can just create a temporary table that
holds LIMIT rows and stop when this table is full.
*/
JOIN_TAB *tab= &join.join_tab[join.const_tables];
bool all_order_fields_used;
if (order)
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
if ((group=create_distinct_group(thd, order, fields,
&all_order_fields_used)))
{
bool skip_group= (skip_sort_order &&
test_if_skip_sort_order(tab, group, select_limit,
1) != 0);
if ((skip_group && all_order_fields_used) ||
select_limit == HA_POS_ERROR ||
(order && !skip_sort_order))
{
/* Change DISTINCT to GROUP BY */
select_distinct= 0;
no_order= !order;
if (all_order_fields_used)
order=0;
join.group=1; // For end_write_group
}
else
group= 0;
} else if (thd->fatal_error) // End of memory
goto err;
}
group=remove_const(&join,group,conds,&simple_group);
......@@ -622,10 +656,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
order=group;
if (order &&
(join.const_tables == join.tables ||
(simple_order &&
((simple_order || skip_sort_order) &&
test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
(join.select_options & OPTION_FOUND_ROWS) ?
HA_POS_ERROR : thd->select_limit,0))))
select_limit, 0))))
order=0;
select_describe(&join,need_tmp,
order != 0 && !skip_sort_order,
......@@ -653,7 +686,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
group ? 0 : select_distinct,
group && simple_group,
(order == 0 || skip_sort_order) &&
!(join.select_options & OPTION_FOUND_ROWS),
select_limit != HA_POS_ERROR,
join.select_options)))
goto err; /* purecov: inspected */
......@@ -706,9 +739,10 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
/* Optimize "select distinct b from t1 order by key_part_1 limit #" */
if (order && skip_sort_order)
{
(void) test_if_skip_sort_order(&join.join_tab[join.const_tables],
order, thd->select_limit,0);
order=0;
/* Should always succeed */
if (test_if_skip_sort_order(&join.join_tab[join.const_tables],
order, thd->select_limit,0))
order=0;
}
}
......@@ -877,8 +911,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
DBUG_EXECUTE("where",print_where(conds,"having after sort"););
}
}
select_limit= thd->select_limit;
if (having || group || (join.select_options & OPTION_FOUND_ROWS))
if (group)
select_limit= HA_POS_ERROR;
else
{
......@@ -953,13 +986,21 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
}
/*
Calculate the best possible join and initialize the join structure
RETURN VALUES
0 ok
1 Fatal error
*/
static bool
make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse_array)
{
int error;
uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part;
table_map const_table_map,found_const_table_map,all_table_map;
table_map found_const_table_map,all_table_map;
TABLE **table_vector;
JOIN_TAB *stat,*stat_end,*s,**stat_ref;
SQL_SELECT *select;
......@@ -979,7 +1020,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->best_ref=stat_vector;
stat_end=stat+table_count;
const_table_map=found_const_table_map=all_table_map=0;
found_const_table_map=all_table_map=0;
const_count=0;
for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++)
......@@ -1070,7 +1111,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DBUG_RETURN(1);
/* Read tables with 0 or 1 rows (system tables) */
join->const_table_map=const_table_map;
join->const_table_map= 0;
for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
p_pos < p_end ;
......@@ -1107,16 +1148,16 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->dependent) // If dependent on some table
{
// All dep. must be constants
if (s->dependent & ~(join->const_table_map))
if (s->dependent & ~(found_const_table_map))
continue;
if (table->file->records <= 1L &&
!(table->file->table_flags() & HA_NOT_EXACT_COUNT))
{ // system table
int tmp;
int tmp= 0;
s->type=JT_SYSTEM;
join->const_table_map|=table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
if ((tmp=join_read_const_table(s,join->positions+const_count-1)))
if ((tmp= join_read_const_table(s,join->positions+const_count-1)))
{
if (tmp > 0)
DBUG_RETURN(1); // Fatal error
......@@ -1141,7 +1182,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
if (keyuse->val->type() != Item::NULL_ITEM)
{
if (!((~join->const_table_map) & keyuse->used_tables))
if (!((~found_const_table_map) & keyuse->used_tables))
const_ref|= (key_map) 1 << keyuse->keypart;
else
refs|=keyuse->used_tables;
......@@ -1162,7 +1203,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->const_table_map|=table->map;
set_position(join,const_count++,s,start_keyuse);
if (create_ref_for_key(join, s, start_keyuse,
join->const_table_map))
found_const_table_map))
DBUG_RETURN(1);
if ((tmp=join_read_const_table(s,
join->positions+const_count-1)))
......@@ -1210,8 +1251,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
ha_rows records;
if (!select)
select=make_select(s->table, join->const_table_map,
join->const_table_map,
select=make_select(s->table, found_const_table_map,
found_const_table_map,
and_conds(conds,s->on_expr),&error);
records=get_quick_record_count(select,s->table, s->const_keys,
join->row_limit);
......@@ -2373,12 +2414,13 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
bool
store_val_in_field(Field *field,Item *item)
{
bool error;
THD *thd=current_thd;
ha_rows cuted_fields=thd->cuted_fields;
thd->count_cuted_fields=1;
item->save_in_field(field);
error= item->save_in_field(field, 1);
thd->count_cuted_fields=0;
return cuted_fields != thd->cuted_fields;
return error || cuted_fields != thd->cuted_fields;
}
......@@ -6577,12 +6619,14 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
*/
static ORDER *
create_distinct_group(ORDER *order_list,List<Item> &fields)
create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields,
bool *all_order_by_fields_used)
{
List_iterator<Item> li(fields);
Item *item;
ORDER *order,*group,**prev;
*all_order_by_fields_used= 1;
while ((item=li++))
item->marker=0; /* Marker that field is not used */
......@@ -6591,13 +6635,15 @@ create_distinct_group(ORDER *order_list,List<Item> &fields)
{
if (order->in_field_list)
{
ORDER *ord=(ORDER*) sql_memdup(order,sizeof(ORDER));
ORDER *ord=(ORDER*) thd->memdup((char*) order,sizeof(ORDER));
if (!ord)
return 0;
*prev=ord;
prev= &ord->next;
(*ord->item)->marker=1;
}
else
*all_order_by_fields_used= 0;
}
li.rewind();
......@@ -6607,7 +6653,7 @@ create_distinct_group(ORDER *order_list,List<Item> &fields)
continue;
if (!item->marker)
{
ORDER *ord=(ORDER*) sql_calloc(sizeof(ORDER));
ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
if (!ord)
return 0;
ord->item=li.ref();
......@@ -7059,7 +7105,7 @@ copy_sum_funcs(Item_sum **func_ptr)
{
Item_sum *func;
for (; (func = *func_ptr) ; func_ptr++)
(void) func->save_in_field(func->result_field);
(void) func->save_in_field(func->result_field, 1);
return;
}
......@@ -7090,7 +7136,7 @@ copy_funcs(Item_result_field **func_ptr)
{
Item_result_field *func;
for (; (func = *func_ptr) ; func_ptr++)
(void) func->save_in_field(func->result_field);
(void) func->save_in_field(func->result_field, 1);
return;
}
......
......@@ -247,12 +247,12 @@ class store_key_field: public store_key
copy_field.set(to_field,from_field,0);
}
}
bool copy()
{
copy_field.do_copy(&copy_field);
return err != 0;
}
const char *name() const { return field_name; }
bool copy()
{
copy_field.do_copy(&copy_field);
return err != 0;
}
const char *name() const { return field_name; }
};
......@@ -269,8 +269,7 @@ public:
{}
bool copy()
{
item->save_in_field(to_field);
return err != 0;
return item->save_in_field(to_field, 1) || err != 0;
}
const char *name() const { return "func"; }
};
......@@ -293,7 +292,8 @@ public:
if (!inited)
{
inited=1;
item->save_in_field(to_field);
if (item->save_in_field(to_field, 1))
err= 1;
}
return err != 0;
}
......
......@@ -574,7 +574,7 @@ static bool make_empty_rec(File file,enum db_type table_type,
if (field->def &&
(regfield->real_type() != FIELD_TYPE_YEAR ||
field->def->val_int() != 0))
field->def->save_in_field(regfield);
field->def->save_in_field(regfield, 1);
else if (regfield->real_type() == FIELD_TYPE_ENUM &&
(field->flags & NOT_NULL_FLAG))
{
......
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