diff options
author | monty@hundin.mysql.fi <> | 2002-12-03 13:08:25 +0200 |
---|---|---|
committer | monty@hundin.mysql.fi <> | 2002-12-03 13:08:25 +0200 |
commit | 8830eb4aa9fcfd4467407a8c1236d24c2af6bdfb (patch) | |
tree | 4cad7c11d248679cf59fce6e92c37d2d7dc6e486 | |
parent | ce56f927fa2a059f02654b30537f9da2afdd1d33 (diff) | |
download | mariadb-git-8830eb4aa9fcfd4467407a8c1236d24c2af6bdfb.tar.gz |
Change of internal key_field=NULL handling to avoid error messages.
Optimized SELECT DISTINCT ... ORDER BY ... LIMIT
Fixed reference to uninitalized variable
-rw-r--r-- | mysql-test/r/distinct.result | 24 | ||||
-rw-r--r-- | mysql-test/r/func_math.result | 3 | ||||
-rw-r--r-- | mysql-test/r/innodb.result | 22 | ||||
-rw-r--r-- | mysql-test/r/null.result | 19 | ||||
-rw-r--r-- | mysql-test/t/distinct.test | 10 | ||||
-rw-r--r-- | mysql-test/t/func_math.test | 1 | ||||
-rw-r--r-- | mysql-test/t/innodb.test | 23 | ||||
-rw-r--r-- | mysql-test/t/null.test | 14 | ||||
-rw-r--r-- | sql/field.h | 2 | ||||
-rw-r--r-- | sql/field_conv.cc | 24 | ||||
-rw-r--r-- | sql/item.cc | 29 | ||||
-rw-r--r-- | sql/item.h | 27 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 18 | ||||
-rw-r--r-- | sql/item_func.cc | 25 | ||||
-rw-r--r-- | sql/item_func.h | 4 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 4 | ||||
-rw-r--r-- | sql/item_timefunc.h | 4 | ||||
-rw-r--r-- | sql/opt_range.cc | 6 | ||||
-rw-r--r-- | sql/password.c | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.cc | 15 | ||||
-rw-r--r-- | sql/sql_handler.cc | 4 | ||||
-rw-r--r-- | sql/sql_select.cc | 130 | ||||
-rw-r--r-- | sql/sql_select.h | 18 | ||||
-rw-r--r-- | sql/unireg.cc | 2 |
25 files changed, 315 insertions, 119 deletions
diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 10a00995c9e..020d6c6534f 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -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'); diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index f1c0de2f88a..811a16fff6c 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -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 diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 1e136acb21d..9d50a6a86e9 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -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; diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 07724a56025..cdea66cbf58 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -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; diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index aaffea3c5a5..7f75b6b1687 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -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)); diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 74e8a5ce092..bd125dafd53 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -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); diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 8edde83507a..eb5b0c9efd2 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -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; diff --git a/mysql-test/t/null.test b/mysql-test/t/null.test index 8bd9e806118..ad32e0be6ff 100644 --- a/mysql-test/t/null.test +++ b/mysql-test/t/null.test @@ -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; diff --git a/sql/field.h b/sql/field.h index ba28a6a872e..f064724f6a2 100644 --- a/sql/field.h +++ b/sql/field.h @@ -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); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 53b26920c14..ffc93f3e871 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -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))) { } diff --git a/sql/item.cc b/sql/item.cc index b3b4e99e28a..ec9b07c443c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -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) diff --git a/sql/item.h b/sql/item.h index 563db2291fb..ad68287a92c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -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);} }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index b5f21c8772e..0dc1e91d372 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -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() { diff --git a/sql/item_func.cc b/sql/item_func.cc index 5721a2f5e8c..c3b1190a4b6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -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() diff --git a/sql/item_func.h b/sql/item_func.h index b7e0cee540a..501dcdadc3f 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -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(); }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ccbba3777c4..6a95c15a226 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -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(<ime,TIMESTAMP_FULL); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index c0255e71d27..0ca2a36609d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -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"; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index d1f99604959..a18c0178b5d 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -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 diff --git a/sql/password.c b/sql/password.c index 48181ea18e6..318c8e84db3 100644 --- a/sql/password.c +++ b/sql/password.c @@ -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; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 043ce44c140..7b7c8c01aab 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -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); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a5f14a507f7..8b276cf0d9b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -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; } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index ea02c46c0f4..289d2434225 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -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; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 89f0ac1885a..eaa291f4d90 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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; } diff --git a/sql/sql_select.h b/sql/sql_select.h index a90b2fe3582..d0e10f75727 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -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(©_field); - return err != 0; - } - const char *name() const { return field_name; } + bool copy() + { + copy_field.do_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; } diff --git a/sql/unireg.cc b/sql/unireg.cc index cc8440da1e4..5183f471fa2 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -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)) { |