diff options
author | unknown <bell@sanja.is.com.ua> | 2003-11-23 02:01:15 +0200 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2003-11-23 02:01:15 +0200 |
commit | 3e21b667bcf164779674e0c08d8c1b9044acc2b5 (patch) | |
tree | e4fd5f08fab614b6e2c048191bd9451abd45131d | |
parent | 920c30b43a3be8955db4e03cc393dd56ac8f5239 (diff) | |
download | mariadb-git-3e21b667bcf164779674e0c08d8c1b9044acc2b5.tar.gz |
Fixed UNION fields type/length detecting
mysql-test/r/union.result:
new results with max union field length detecting
type conversion tests
mysql-test/t/union.test:
type conversion tests
sql/field.h:
field converion support
sql/item.cc:
fixed printing field of internal temporary table of SELECT (reference from HAVING clause)
layout fix
new item for storing field type
sql/item.h:
new item for storing field type
sql/item_subselect.cc:
new subquery item length/dec detecting
sql/mysql_priv.h:
we do not need pre-inited tables and fields
sql/sql_base.cc:
we do not need double fix_fielding
sql/sql_class.h:
we do not need double fix_fielding
sql/sql_derived.cc:
preparing moved before temporary table creation
sql/sql_lex.h:
we do not need pre-inited tables and fields
new lists to store fields types and fields of temporary table
sql/sql_parse.cc:
we do not need pre-inited tables and fields
sql/sql_prepare.cc:
we do not need pre-inited tables and fields
sql/sql_select.cc:
we do not need pre-inited tables and fields
support mysql_select call from derived tables after it preparing (in derived table routing)
support of crreating temporary table fields from Item_type_holder
sql/sql_select.h:
we do not need pre-inited tables and fields
sql/sql_union.cc:
we do not need pre-inited tables and fields
check of columns number in union moved to prepare()
prepering of SELECTS moved before temporary table creation, fixed union columns type/length detecting
sql/sql_update.cc:
we do not need pre-inited tables and fields
-rw-r--r-- | mysql-test/r/union.result | 209 | ||||
-rw-r--r-- | mysql-test/t/union.test | 82 | ||||
-rw-r--r-- | sql/field.h | 48 | ||||
-rw-r--r-- | sql/item.cc | 121 | ||||
-rw-r--r-- | sql/item.h | 32 | ||||
-rw-r--r-- | sql/item_subselect.cc | 49 | ||||
-rw-r--r-- | sql/mysql_priv.h | 5 | ||||
-rw-r--r-- | sql/sql_base.cc | 14 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_derived.cc | 152 | ||||
-rw-r--r-- | sql/sql_lex.h | 11 | ||||
-rw-r--r-- | sql/sql_parse.cc | 2 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 222 | ||||
-rw-r--r-- | sql/sql_select.h | 2 | ||||
-rw-r--r-- | sql/sql_union.cc | 154 | ||||
-rw-r--r-- | sql/sql_update.cc | 2 |
17 files changed, 795 insertions, 313 deletions
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 00eddd596cf..cf5920481b2 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -53,7 +53,7 @@ select 0,'#' union select a,b from t1 union all select a,b from t2 union select 4 d 5 f 6 e -7 g +7 gg select a,b from t1 union select a,b from t1; a b 1 a @@ -449,10 +449,10 @@ INSERT INTO t2 (id, id_master, text1, text2) VALUES("4", "1", SELECT 1 AS id_master, 1 AS id, NULL AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; id_master id text1 text2 1 1 NULL ABCDE -1 1 bar1 -1 2 bar2 +1 1 foo1 bar1 +1 2 foo2 bar2 1 3 NULL bar3 -1 4 bar4 +1 4 foo4 bar4 SELECT 1 AS id_master, 1 AS id, 'ABCDE' AS text1, 'ABCDE' AS text2 UNION SELECT id_master, t2.id, text1, text2 FROM t1 LEFT JOIN t2 ON t1.id = t2.id_master; id_master id text1 text2 1 1 ABCDE ABCDE @@ -523,3 +523,204 @@ pla_id matintnum 105 c 0 0 drop table t1, t2; +create table t1 SELECT "a" as a UNION select "aa" as a; +select * from t1; +a +a +aa +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(2) NOT NULL default '' +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT 12 as a UNION select "aa" as a; +select * from t1; +a +12 +aa +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(2) NOT NULL default '' +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT 12 as a UNION select 12.2 as a; +select * from t1; +a +12.0 +12.2 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` double(4,1) NOT NULL default '0.0' +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob); +insert into t2 values (NULL, 1, 3, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'testc', 'testv', 'tetetetetest'); +create table t1 SELECT it2 from t2 UNION select it1 from t2; +select * from t1; +it2 +1 +NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `it2` tinyint(4) default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT it2 from t2 UNION select i from t2; +select * from t1; +it2 +1 +3 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `it2` int(11) NOT NULL default '0' +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT i from t2 UNION select f from t2; +select * from t1; +i +3 +1.5 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` float default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT f from t2 UNION select d from t2; +select * from t1; +f +1.5 +2.5 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` double default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT f from t2 UNION select y from t2; +select * from t1; +f +1.5 +1972 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` double default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT f from t2 UNION select da from t2; +select * from t1; +f +1.5 +1972-10-22 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f` char(12) binary default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT y from t2 UNION select da from t2; +select * from t1; +y +1972 +1972-10-22 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `y` char(10) binary default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT y from t2 UNION select dt from t2; +select * from t1; +y +1972 +1972-10-22 11:50:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `y` char(19) binary default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT da from t2 UNION select dt from t2; +select * from t1; +da +1972-10-22 00:00:00 +1972-10-22 11:50:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `da` datetime default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT dt from t2 UNION select sc from t2; +select * from t1; +dt +1972-10-22 11:50:00 +testc +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `dt` char(19) default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT dt from t2 UNION select sv from t2; +select * from t1; +dt +1972-10-22 11:50:00 +testv +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `dt` char(19) default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT sc from t2 UNION select sv from t2; +select * from t1; +sc +testc +testv +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sc` varchar(10) default NULL +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT dt from t2 UNION select b from t2; +select * from t1; +dt +1972-10-22 11:50:00 +tetetetetest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `dt` blob +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT sv from t2 UNION select b from t2; +select * from t1; +sv +testv +tetetetetest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `sv` blob +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2; +select * from t1; +i +3 +2.5 +tetetetetest +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `i` blob +) TYPE=MyISAM DEFAULT CHARSET=latin1 +drop table t1,t2; diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 3cfdc14b0b8..af511d18ecc 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -302,3 +302,85 @@ insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd' insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id union SELECT 0, 0; drop table t1, t2; + +# +# types conversions +# + + +create table t1 SELECT "a" as a UNION select "aa" as a; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT 12 as a UNION select "aa" as a; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT 12 as a UNION select 12.2 as a; +select * from t1; +show create table t1; +drop table t1; + +create table t2 (it1 tinyint, it2 tinyint not null, i int not null, f float, d double, y year, da date, dt datetime, sc char(10), sv varchar(10), b blob); +insert into t2 values (NULL, 1, 3, 1.5, 2.5, 1972, '1972-10-22', '1972-10-22 11:50', 'testc', 'testv', 'tetetetetest'); + +create table t1 SELECT it2 from t2 UNION select it1 from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT it2 from t2 UNION select i from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT i from t2 UNION select f from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT f from t2 UNION select d from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT f from t2 UNION select y from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT f from t2 UNION select da from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT y from t2 UNION select da from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT y from t2 UNION select dt from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT da from t2 UNION select dt from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT dt from t2 UNION select sc from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT dt from t2 UNION select sv from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT sc from t2 UNION select sv from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT dt from t2 UNION select b from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT sv from t2 UNION select b from t2; +select * from t1; +show create table t1; +drop table t1; +create table t1 SELECT i from t2 UNION select d from t2 UNION select b from t2; +select * from t1; +show create table t1; +drop table t1,t2; diff --git a/sql/field.h b/sql/field.h index 692e64d1146..ef6920f4d89 100644 --- a/sql/field.h +++ b/sql/field.h @@ -230,6 +230,24 @@ public: virtual bool has_charset(void) const { return FALSE; } virtual void set_charset(CHARSET_INFO *charset) { } void set_warning(const unsigned int level, const unsigned int code); + /* + number which describe preferences of field type converion, + for example, if we have int and float, float is prefered as more general + + ennumiration begins from: + 100 for int types + 300 for float point + 500 time/date + 700 string + */ + virtual uint convert_order()= 0; + /* + Is this type is compatible with given + (given can be stored in it) + Should take care only of types 'less' then current + */ + virtual bool convert_order_compatible(uint order) { return 0; } + friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -334,6 +352,7 @@ public: void overflow(bool negative); bool zero_pack() const { return 0; } void sql_type(String &str) const; + uint convert_order() { return 130; } }; @@ -369,6 +388,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 1; } void sql_type(String &str) const; + uint convert_order() { return 100; } }; @@ -404,6 +424,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 2; } void sql_type(String &str) const; + uint convert_order() { return 101; } }; @@ -434,6 +455,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 3; } void sql_type(String &str) const; + uint convert_order() { return 102; } }; @@ -469,6 +491,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return 4; } void sql_type(String &str) const; + uint convert_order() { return 103; } }; @@ -507,6 +530,7 @@ public: uint32 pack_length() const { return 8; } void sql_type(String &str) const; bool store_for_compare() { return 1; } + uint convert_order() { return 104; } }; #endif @@ -540,6 +564,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(float); } void sql_type(String &str) const; + uint convert_order() { return 300; } }; @@ -573,6 +598,7 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return sizeof(double); } void sql_type(String &str) const; + uint convert_order() { return 301; } }; @@ -606,6 +632,7 @@ public: uint32 pack_length() const { return 0; } void sql_type(String &str) const; uint size_of() const { return sizeof(*this); } + uint convert_order() { return 0; } }; @@ -649,6 +676,8 @@ public: } bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); + uint convert_order() { return 520; } + bool convert_order_compatible(uint ord) { return ord<520; } }; @@ -674,6 +703,8 @@ public: String *val_str(String*,String *); bool send_binary(Protocol *protocol); void sql_type(String &str) const; + uint convert_order() { return 501; } + bool convert_order_compatible(uint ord) { return ord<520; } }; @@ -706,6 +737,8 @@ public: void sql_type(String &str) const; bool store_for_compare() { return 1; } bool zero_pack() const { return 1; } + uint convert_order() { return 502; } + bool convert_order_compatible(uint ord) { return ord<520; } }; class Field_newdate :public Field_str { @@ -737,6 +770,8 @@ public: bool zero_pack() const { return 1; } bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); + uint convert_order() { return 503; } + bool convert_order_compatible(uint ord) { return ord<520; } }; @@ -770,6 +805,8 @@ public: void sql_type(String &str) const; bool store_for_compare() { return 1; } bool zero_pack() const { return 1; } + uint convert_order() { return 504; } + bool convert_order_compatible(uint ord) { return ord<520; } }; @@ -807,6 +844,8 @@ public: bool zero_pack() const { return 1; } bool get_date(TIME *ltime,uint fuzzydate); bool get_time(TIME *ltime); + uint convert_order() { return 530; } + bool convert_order_compatible(uint ord) { return ord<=501; } }; @@ -851,6 +890,7 @@ public: uint size_of() const { return sizeof(*this); } enum_field_types real_type() const { return FIELD_TYPE_STRING; } bool has_charset(void) const { return TRUE; } + uint convert_order() { return 700; } }; @@ -894,6 +934,7 @@ public: uint size_of() const { return sizeof(*this); } enum_field_types real_type() const { return FIELD_TYPE_VAR_STRING; } bool has_charset(void) const { return TRUE; } + uint convert_order() { return 701; } }; @@ -983,6 +1024,7 @@ public: uint size_of() const { return sizeof(*this); } bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } + uint convert_order() { return 701; } }; @@ -1011,6 +1053,8 @@ public: void get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type); void set_key_image(char *buff,uint length, CHARSET_INFO *cs); + uint convert_order() { return 750; } + bool convert_order_compatible(uint ord) { return ord < 750; }; }; @@ -1052,6 +1096,8 @@ public: bool optimize_range(uint idx) { return 0; } bool eq_def(Field *field); bool has_charset(void) const { return TRUE; } + uint convert_order() { return 30; } + bool convert_order_compatible(uint ord) { return ord < 30; }; }; @@ -1077,6 +1123,8 @@ public: void sql_type(String &str) const; enum_field_types real_type() const { return FIELD_TYPE_SET; } bool has_charset(void) const { return TRUE; } + uint convert_order() { return 40; } + bool convert_order_compatible(uint ord) { return ord < 40; }; }; diff --git a/sql/item.cc b/sql/item.cc index 9684fd3e518..4e88dad5a06 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -312,7 +312,7 @@ void Item_field::set_field(Field *field_par) const char *Item_ident::full_name() const { char *tmp; - if (!table_name) + if (!table_name || !field_name) return field_name ? field_name : name ? name : "tmp_field"; if (db_name && db_name[0]) { @@ -1876,6 +1876,8 @@ void Item_cache_str::store(Item *item) } collation.set(item->collation); } + + double Item_cache_str::val() { int err; @@ -1885,6 +1887,8 @@ double Item_cache_str::val() else return (double)0; } + + longlong Item_cache_str::val_int() { int err; @@ -1895,6 +1899,7 @@ longlong Item_cache_str::val_int() return (longlong)0; } + bool Item_cache_row::allocate(uint num) { item_count= num; @@ -1903,6 +1908,7 @@ bool Item_cache_row::allocate(uint num) (Item_cache **) thd->calloc(sizeof(Item_cache *)*item_count))); } + bool Item_cache_row::setup(Item * item) { example= item; @@ -1919,6 +1925,7 @@ bool Item_cache_row::setup(Item * item) return 0; } + void Item_cache_row::store(Item * item) { null_value= 0; @@ -1930,6 +1937,7 @@ void Item_cache_row::store(Item * item) } } + void Item_cache_row::illegal_method_call(const char *method) { DBUG_ENTER("Item_cache_row::illegal_method_call"); @@ -1939,6 +1947,7 @@ void Item_cache_row::illegal_method_call(const char *method) DBUG_VOID_RETURN; } + bool Item_cache_row::check_cols(uint c) { if (c != item_count) @@ -1949,6 +1958,7 @@ bool Item_cache_row::check_cols(uint c) return 0; } + bool Item_cache_row::null_inside() { for (uint i= 0; i < item_count; i++) @@ -1968,6 +1978,7 @@ bool Item_cache_row::null_inside() return 0; } + void Item_cache_row::bring_value() { for (uint i= 0; i < item_count; i++) @@ -1975,6 +1986,114 @@ void Item_cache_row::bring_value() return; } + +Item_type_holder::Item_type_holder(THD *thd, Item *item) + :Item(thd, *item), item_type(item->result_type()) +{ + DBUG_ASSERT(item->fixed); + if (item->type() == Item::FIELD_ITEM) + { + Item_field *fitem= (Item_field*) item; + field_example= (Field*) thd->memdup((const char*)fitem->field, + fitem->field->size_of()); + } + else + field_example= 0; +} + + +// STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT +static Item_result type_convertor[4][4]= +{{STRING_RESULT, STRING_RESULT, STRING_RESULT, ROW_RESULT}, + {STRING_RESULT, REAL_RESULT, REAL_RESULT, ROW_RESULT}, + {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}, + {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}}; + +void Item_type_holder::join_types(THD *thd, Item *item) +{ + bool change_field= 0, skip_store_field= 0; + Item_result new_type= type_convertor[item_type][item->result_type()]; + + // we have both fields + if (field_example && item->type() == Item::FIELD_ITEM) + { + Field *field= ((Item_field *)item)->field; + + // is new field better + if ((change_field= + field_example->convert_order() < field->convert_order())) + { + // is it compatible? + if (field->convert_order_compatible(field_example->convert_order())) + skip_store_field= 1; + } + else + { + /* + if old field can't store value of 'worse' new field we will make + decision about result field tipe based only on Item result type + */ + if (field_example->convert_order_compatible(field->convert_order())) + skip_store_field= 1; + } + } + + // size/type should be changed + if (change_field || + (new_type != item_type) || + (max_length < item->max_length) || + ((new_type == INT_RESULT) && + (decimals < item->decimals)) || + (!maybe_null && item->maybe_null)) + { + // new field has some parameters worse then current + skip_store_field|= (change_field && + (max_length > item->max_length) || + ((new_type == INT_RESULT) && + (decimals > item->decimals)) || + (maybe_null && !item->maybe_null)); + if (skip_store_field || item->type() != Item::FIELD_ITEM) + field_example= 0; + else + { + /* + we do not need following, because we use mem_root + if (field_example) + thd->free(field_example) + */ + Item_field *fitem= (Item_field*) item; + field_example= (Field*) thd->memdup((const char*)fitem->field, + fitem->field->size_of()); + } + max_length= max(max_length, item->max_length); + decimals= max(decimals, item->decimals); + maybe_null|= item->maybe_null; + item_type= new_type; + } + DBUG_ASSERT(item_type != ROW_RESULT); +} + + +double Item_type_holder::val() +{ + DBUG_ASSERT(0); // should never be called + return 0.0; +} + + +longlong Item_type_holder::val_int() +{ + DBUG_ASSERT(0); // should never be called + return 0; +} + + +String *Item_type_holder::val_str(String*) +{ + DBUG_ASSERT(0); // should never be called + return 0; +} + /***************************************************************************** ** Instantiate templates *****************************************************************************/ diff --git a/sql/item.h b/sql/item.h index 907b9ea5ad4..ceeb2158155 100644 --- a/sql/item.h +++ b/sql/item.h @@ -98,7 +98,7 @@ public: COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, - SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM}; + SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -371,17 +371,17 @@ class Item_int :public Item public: const longlong value; Item_int(int32 i,uint length=11) :value((longlong) i) - { max_length=length;} + { max_length=length; fixed= 1; } #ifdef HAVE_LONG_LONG Item_int(longlong i,uint length=21) :value(i) - { max_length=length;} + { max_length=length; fixed= 1;} #endif Item_int(const char *str_arg,longlong i,uint length) :value(i) - { max_length=length; name=(char*) str_arg;} + { max_length=length; name=(char*) str_arg; fixed= 1; } Item_int(const char *str_arg) : value(str_arg[0] == '-' ? strtoll(str_arg,(char**) 0,10) : (longlong) strtoull(str_arg,(char**) 0,10)) - { max_length= (uint) strlen(str_arg); name=(char*) str_arg;} + { max_length= (uint) strlen(str_arg); name=(char*) str_arg; fixed= 1; } enum Type type() const { return INT_ITEM; } enum Item_result result_type () const { return INT_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } @@ -969,6 +969,28 @@ public: void bring_value(); }; + +/* + Used to store type. name, length of Item for UNIONS & derived table +*/ +class Item_type_holder: public Item +{ +protected: + Item_result item_type; + Field *field_example; +public: + Item_type_holder(THD*, Item*); + + Item_result result_type () const { return item_type; } + enum Type type() const { return TYPE_HOLDER; } + double val(); + longlong val_int(); + String *val_str(String*); + void join_types(THD *thd, Item *); + Field *example() { return field_example; } +}; + + extern Item_buff *new_Item_buff(Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern Item *resolve_const_item(Item *item,Item *cmp_item); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a60a35aac6b..367400d6b0b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -924,7 +924,7 @@ int subselect_single_select_engine::prepare() (ORDER*) select_lex->group_list.first, select_lex->having, (ORDER*) 0, select_lex, - select_lex->master_unit(), 0)) + select_lex->master_unit())) return 1; thd->lex.current_select= save_select; return 0; @@ -932,7 +932,7 @@ int subselect_single_select_engine::prepare() int subselect_union_engine::prepare() { - return unit->prepare(thd, result, 0); + return unit->prepare(thd, result); } int subselect_uniquesubquery_engine::prepare() @@ -942,12 +942,12 @@ int subselect_uniquesubquery_engine::prepare() return 1; } -static Item_result set_row(SELECT_LEX *select_lex, Item * item, +static Item_result set_row(List<Item> &item_list, Item *item, Item_cache **row, bool *maybe_null) { Item_result res_type= STRING_RESULT; Item *sel_item; - List_iterator_fast<Item> li(select_lex->item_list); + List_iterator_fast<Item> li(item_list); for (uint i= 0; (sel_item= li++); i++) { item->max_length= sel_item->max_length; @@ -962,7 +962,7 @@ static Item_result set_row(SELECT_LEX *select_lex, Item * item, row[i]->collation.set(sel_item->collation); } } - if (select_lex->item_list.elements > 1) + if (item_list.elements > 1) res_type= ROW_RESULT; return res_type; } @@ -970,7 +970,7 @@ static Item_result set_row(SELECT_LEX *select_lex, Item * item, void subselect_single_select_engine::fix_length_and_dec(Item_cache **row) { DBUG_ASSERT(row || select_lex->item_list.elements==1); - res_type= set_row(select_lex, item, row, &maybe_null); + res_type= set_row(select_lex->item_list, item, row, &maybe_null); item->collation.set(row[0]->collation); if (cols() != 1) maybe_null= 0; @@ -981,44 +981,11 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) DBUG_ASSERT(row || unit->first_select()->item_list.elements==1); if (unit->first_select()->item_list.elements == 1) - { - uint32 mlen= 0, len; - Item *sel_item= 0; - for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) - { - List_iterator_fast<Item> li(sl->item_list); - Item *s_item= li++; - if ((len= s_item->max_length) > mlen) - mlen= len; - if (!sel_item) - sel_item= s_item; - maybe_null= s_item->maybe_null; - } - item->max_length= mlen; - res_type= sel_item->result_type(); - item->decimals= sel_item->decimals; - if (row) - { - if (!(row[0]= Item_cache::get_cache(res_type))) - return; - row[0]->set_len_n_dec(mlen, sel_item->decimals); - } - } + res_type= set_row(unit->types, item, row, &maybe_null); else { - SELECT_LEX *sl= unit->first_select(); bool fake= 0; - res_type= set_row(sl, item, row, &fake); - for (sl= sl->next_select(); sl; sl= sl->next_select()) - { - List_iterator_fast<Item> li(sl->item_list); - Item *sel_item; - for (uint i= 0; (sel_item= li++); i++) - { - if (sel_item->max_length > row[i]->max_length) - row[i]->max_length= sel_item->max_length; - } - } + res_type= set_row(unit->types, item, row, &fake); } } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index b9032381c45..5cf352aff99 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -482,7 +482,7 @@ int mysql_select(THD *thd, Item ***rref_pointer_array, COND *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulong select_type, select_result *result, SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex, bool tables_and_fields_initied); + SELECT_LEX *select_lex); void free_underlaid_joins(THD *thd, SELECT_LEX *select); void fix_tables_pointers(SELECT_LEX *select_lex); void fix_tables_pointers(SELECT_LEX_UNIT *select_lex); @@ -491,7 +491,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type, select_result *result); int mysql_union(THD *thd, LEX *lex, select_result *result, - SELECT_LEX_UNIT *unit, bool tables_and_fields_initied); + SELECT_LEX_UNIT *unit); int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t); Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item ***copy_func, Field **from_field, @@ -675,7 +675,6 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, List<Item> &item, bool set_query_id, List<Item> *sum_func_list, bool allow_sum_func); -void unfix_item_list(List<Item> item_list); int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); int setup_ftfuncs(SELECT_LEX* select); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7a657841845..775aa1cd43f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2023,20 +2023,6 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, DBUG_RETURN(test(thd->net.report_error)); } -/* - Mark all items in list as not fixed (0 assigned to 'fixed' field) - - SYNOPSYS - unfix_item_list() - item_list - list of items -*/ -void unfix_item_list(List<Item> item_list) -{ - Item *item; - List_iterator_fast<Item> it(item_list); - while ((item= it++)) - item->walk(&Item::remove_fixed, 0); -} /* Remap table numbers if INSERT ... SELECT diff --git a/sql/sql_class.h b/sql/sql_class.h index b19caf057e6..36faeae8f57 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -946,6 +946,7 @@ class select_union :public select_result { bool send_data(List<Item> &items); bool send_eof(); bool flush(); + void set_table(TABLE *tbl) { table= tbl; } }; /* Base subselect interface class */ diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 719686a56c3..591c6579a46 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -62,16 +62,15 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *org_table_list) { - SELECT_LEX *select_cursor= unit->first_select(); - List<Item> item_list; + SELECT_LEX *first_select= unit->first_select(); TABLE *table; int res; select_union *derived_result; - TABLE_LIST *tables= (TABLE_LIST *)select_cursor->table_list.first; + TABLE_LIST *tables= (TABLE_LIST *)first_select->table_list.first; TMP_TABLE_PARAM tmp_table_param; - bool is_union= select_cursor->next_select() && - select_cursor->next_select()->linkage == UNION_TYPE; - bool is_subsel= select_cursor->first_inner_unit() ? 1: 0; + bool is_union= first_select->next_select() && + first_select->next_select()->linkage == UNION_TYPE; + bool is_subsel= first_select->first_inner_unit() ? 1: 0; SELECT_LEX *save_current_select= lex->current_select; DBUG_ENTER("mysql_derived"); @@ -112,16 +111,12 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, fix_tables_pointers(unit); } - lex->current_select= select_cursor; - TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first; - /* Setting up. A must if a join or IGNORE, USE or similar are utilised */ - if (setup_tables(first_table) || - setup_wild(thd, first_table, select_cursor->item_list, 0, - select_cursor->with_wild)) - { - res= -1; + if(!(derived_result= new select_union(0))) + DBUG_RETURN(1); // out of memory + + // st_select_lex_unit::prepare coppectly work for single select + if ((res= unit->prepare(thd, derived_result))) goto exit; - } /* This is done in order to redo all field optimisations when any of the @@ -133,30 +128,16 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, cursor->table->clear_query_id= 1; } - item_list= select_cursor->item_list; - select_cursor->with_wild= 0; - if (select_cursor->setup_ref_array(thd, - select_cursor->order_list.elements + - select_cursor->group_list.elements) || - setup_fields(thd, select_cursor->ref_pointer_array, first_table, - item_list, 0, 0, 1)) - { - res= -1; - goto exit; - } - // Item list should be fix_fielded yet another time in JOIN::prepare - unfix_item_list(item_list); - bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); - tmp_table_param.field_count= item_list.elements; + tmp_table_param.field_count= unit->types.elements; /* Temp table is created so that it hounours if UNION without ALL is to be processed */ - if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, + if (!(table= create_tmp_table(thd, &tmp_table_param, unit->types, (ORDER*) 0, is_union && !unit->union_option, 1, - (select_cursor->options | thd->options | + (first_select->options | thd->options | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, org_table_list->alias))) @@ -164,70 +145,69 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, res= -1; goto exit; } - - if ((derived_result=new select_union(table))) + derived_result->set_table(table); + derived_result->tmp_table_param=tmp_table_param; + + unit->offset_limit_cnt= first_select->offset_limit; + unit->select_limit_cnt= first_select->select_limit+ + first_select->offset_limit; + if (unit->select_limit_cnt < first_select->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; + if (unit->select_limit_cnt == HA_POS_ERROR) + first_select->options&= ~OPTION_FOUND_ROWS; + + if (is_union) + res= mysql_union(thd, lex, derived_result, unit); + else + res= mysql_select(thd, &first_select->ref_pointer_array, + (TABLE_LIST*) first_select->table_list.first, + first_select->with_wild, + first_select->item_list, first_select->where, + (first_select->order_list.elements+ + first_select->group_list.elements), + (ORDER *) first_select->order_list.first, + (ORDER *) first_select->group_list.first, + first_select->having, (ORDER*) NULL, + (first_select->options | thd->options | + SELECT_NO_UNLOCK), + derived_result, unit, first_select); + + if (!res) { - derived_result->tmp_table_param=tmp_table_param; - unit->offset_limit_cnt= select_cursor->offset_limit; - unit->select_limit_cnt= select_cursor->select_limit+ - select_cursor->offset_limit; - if (unit->select_limit_cnt < select_cursor->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; - if (unit->select_limit_cnt == HA_POS_ERROR) - select_cursor->options&= ~OPTION_FOUND_ROWS; - - if (is_union) - res= mysql_union(thd, lex, derived_result, unit, 1); + /* + Here we entirely fix both TABLE_LIST and list of SELECT's as + there were no derived tables + */ + if (derived_result->flush()) + res= 1; else - res= mysql_select(thd, &select_cursor->ref_pointer_array, - (TABLE_LIST*) select_cursor->table_list.first, - select_cursor->with_wild, - select_cursor->item_list, select_cursor->where, - (select_cursor->order_list.elements+ - select_cursor->group_list.elements), - (ORDER *) select_cursor->order_list.first, - (ORDER *) select_cursor->group_list.first, - select_cursor->having, (ORDER*) NULL, - (select_cursor->options | thd->options | - SELECT_NO_UNLOCK), - derived_result, unit, select_cursor, 1); - - if (!res) { - /* - Here we entirely fix both TABLE_LIST and list of SELECT's as - there were no derived tables - */ - if (derived_result->flush()) - res= 1; - else - { - org_table_list->real_name=table->real_name; - org_table_list->table=table; - table->derived_select_number= select_cursor->select_number; - table->tmp_table= TMP_TABLE; + org_table_list->real_name=table->real_name; + org_table_list->table=table; + table->derived_select_number= first_select->select_number; + table->tmp_table= TMP_TABLE; #ifndef NO_EMBEDDED_ACCESS_CHECKS - org_table_list->grant.privilege= SELECT_ACL; + org_table_list->grant.privilege= SELECT_ACL; #endif - if (lex->describe) + if (lex->describe) + { + // to fix a problem in EXPLAIN + if (tables) { - // to fix a problem in EXPLAIN - if (tables) - { - for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next) - if (cursor->table_list) - cursor->table_list->table=cursor->table; - } + for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next) + if (cursor->table_list) + cursor->table_list->table=cursor->table; } - else - unit->exclude_tree(); - org_table_list->db= (char *)""; - // Force read of table stats in the optimizer - table->file->info(HA_STATUS_VARIABLE); } + else + unit->exclude_tree(); + org_table_list->db= (char *)""; + // Force read of table stats in the optimizer + table->file->info(HA_STATUS_VARIABLE); } - delete derived_result; } + delete derived_result; + if (res) free_tmp_table(thd, table); else diff --git a/sql/sql_lex.h b/sql/sql_lex.h index d2345165eb9..29301053c59 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -295,7 +295,6 @@ class JOIN; class select_union; class st_select_lex_unit: public st_select_lex_node { protected: - List<Item> item_list; TABLE_LIST result_table_list; select_union *union_result; TABLE *table; /* temporary table using for appending UNION results */ @@ -305,9 +304,13 @@ protected: ulong found_rows_for_union; bool prepared, // prepare phase already performed for UNION (unit) optimized, // optimize phase already performed for UNION (unit) - executed, // already executed - t_and_f; // used for transferring tables_and_fields_initied UNIT:: methods + executed; // already executed + public: + // list of fields which points to temporary table for union + List<Item> item_list; + // list of types of items inside union (used for union & derived tables) + List<Item> types; /* Pointer to 'last' select or pointer to unit where stored global parameters for union @@ -342,7 +345,7 @@ public: void exclude_tree(); /* UNION methods */ - int prepare(THD *thd, select_result *result, bool tables_and_fields_initied); + int prepare(THD *thd, select_result *result); int exec(); int cleanup(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 9f4b10682ba..d5a15de422d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2716,7 +2716,7 @@ mysql_execute_command(THD *thd) (ORDER *)NULL, select_lex->options | thd->options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK, - result, unit, select_lex, 0); + result, unit, select_lex); if (thd->net.report_error) res= -1; delete result; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 354214a4da5..69517b171cb 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -682,7 +682,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, if (join->prepare(&select_lex->ref_pointer_array, tables, wild_num, conds, og_num, order, group, having, proc, - select_lex, unit, 0)) + select_lex, unit)) DBUG_RETURN(1); if (send_prep_stmt(stmt, fields.elements) || thd->protocol_simple.send_fields(&fields, 0) || diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 44b403c0bb1..ba4dd9f856e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -177,7 +177,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result) fix_tables_pointers(lex->all_selects_list); if (select_lex->next_select()) - res=mysql_union(thd, lex, result, &lex->unit, 0); + res=mysql_union(thd, lex, result, &lex->unit); else res= mysql_select(thd, &select_lex->ref_pointer_array, (TABLE_LIST*) select_lex->table_list.first, @@ -190,7 +190,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result) select_lex->having, (ORDER*) lex->proc_list.first, select_lex->options | thd->options, - result, &(lex->unit), &(lex->select_lex), 0); + result, &(lex->unit), &(lex->select_lex)); /* Don't set res if it's -1 as we may want this later */ DBUG_PRINT("info",("res: %d report_error: %d", res, @@ -285,8 +285,7 @@ JOIN::prepare(Item ***rref_pointer_array, ORDER *order_init, ORDER *group_init, Item *having_init, ORDER *proc_param_init, SELECT_LEX *select, - SELECT_LEX_UNIT *unit, - bool tables_and_fields_initied) + SELECT_LEX_UNIT *unit) { DBUG_ENTER("JOIN::prepare"); @@ -302,10 +301,8 @@ JOIN::prepare(Item ***rref_pointer_array, /* Check that all tables, fields, conds and order are ok */ - if ((tables_and_fields_initied ? 0 : (setup_tables(tables_list) || - setup_wild(thd, tables_list, - fields_list, - &all_fields, wild_num))) || + if (setup_tables(tables_list) || + setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || select_lex->setup_ref_array(thd, og_num) || setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, &all_fields, 1) || @@ -1536,7 +1533,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, COND *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulong select_options, select_result *result, SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex, bool tables_and_fields_initied) + SELECT_LEX *select_lex) { int err; bool free_join= 1; @@ -1546,26 +1543,31 @@ mysql_select(THD *thd, Item ***rref_pointer_array, if (select_lex->join != 0) { join= select_lex->join; - if (select_lex->linkage != GLOBAL_OPTIONS_TYPE) + // is it single SELECT in derived table, called in derived table creation + if (select_lex->linkage != DERIVED_TABLE_TYPE || + (select_options & SELECT_DESCRIBE)) { - //here is EXPLAIN of subselect or derived table - join->result= result; - if (!join->procedure && result->prepare(join->fields_list, unit)) + if (select_lex->linkage != GLOBAL_OPTIONS_TYPE) { - DBUG_RETURN(-1); + //here is EXPLAIN of subselect or derived table + join->result= result; + if (!join->procedure && result->prepare(join->fields_list, unit)) + { + DBUG_RETURN(-1); + } } - } - else - { - if (join->prepare(rref_pointer_array, tables, wild_num, - conds, og_num, order, group, having, proc_param, - select_lex, unit, tables_and_fields_initied)) + else { - goto err; + if (join->prepare(rref_pointer_array, tables, wild_num, + conds, og_num, order, group, having, proc_param, + select_lex, unit)) + { + goto err; + } } + free_join= 0; } join->select_options= select_options; - free_join= 0; } else { @@ -1574,7 +1576,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array, thd->used_tables=0; // Updated by setup_fields if (join->prepare(rref_pointer_array, tables, wild_num, conds, og_num, order, group, having, proc_param, - select_lex, unit, tables_and_fields_initied)) + select_lex, unit)) { goto err; } @@ -4546,6 +4548,115 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) ****************************************************************************/ /* + Create field for temporary table from given field + + SYNOPSIS + create_tmp_field_from_field() + thd Thread handler + org_field field from which new field will be created + item Item to create a field for + table Temporary table + modify_item 1 if item->result_field should point to new item. + This is relevent for how fill_record() is going to + work: + If modify_item is 1 then fill_record() will update + the record in the original table. + If modify_item is 0 then fill_record() will update + the temporary table + + RETURN + 0 on error + new_created field +*/ +static Field* create_tmp_field_from_field(THD *thd, + Field* org_field, + Item *item, + TABLE *table, + bool modify_item) +{ + Field *new_field; + + // The following should always be true + if ((new_field= org_field->new_field(&thd->mem_root,table))) + { + if (modify_item) + ((Item_field *)item)->result_field= new_field; + else + new_field->field_name= item->name; + if (org_field->maybe_null()) + new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join + if (org_field->type() == FIELD_TYPE_VAR_STRING) + table->db_create_options|= HA_OPTION_PACK_RECORD; + } + return new_field; +} + +/* + Create field for temporary table using type of given item + + SYNOPSIS + create_tmp_field_from_item() + thd Thread handler + item Item to create a field for + table Temporary table + copy_func If set and item is a function, store copy of item + in this array + modify_item 1 if item->result_field should point to new item. + This is relevent for how fill_record() is going to + work: + If modify_item is 1 then fill_record() will update + the record in the original table. + If modify_item is 0 then fill_record() will update + the temporary table + + RETURN + 0 on error + new_created field +*/ +static Field* create_tmp_field_from_item(THD *thd, + Item *item, + TABLE *table, + Item ***copy_func, + bool modify_item) +{ + bool maybe_null=item->maybe_null; + Field *new_field; + LINT_INIT(new_field); + + switch (item->result_type()) { + case REAL_RESULT: + new_field=new Field_double(item->max_length, maybe_null, + item->name, table, item->decimals); + break; + case INT_RESULT: + new_field=new Field_longlong(item->max_length, maybe_null, + item->name, table, item->unsigned_flag); + break; + case STRING_RESULT: + if (item->max_length > 255) + new_field= new Field_blob(item->max_length, maybe_null, + item->name, table, + item->collation.collation); + else + new_field= new Field_string(item->max_length, maybe_null, + item->name, table, + item->collation.collation); + break; + case ROW_RESULT: + default: + // This case should never be choosen + DBUG_ASSERT(0); + new_field= 0; // to satisfy compiler (uninitialized variable) + break; + } + if (copy_func && item->is_result_field()) + *((*copy_func)++) = item; // Save for copy_funcs + if (modify_item) + item->set_result_field(new_field); + return new_field; +} + +/* Create field for temporary table SYNOPSIS @@ -4556,6 +4667,8 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item) type Type of item (normally item->type) copy_func If set and item is a function, store copy of item in this array + from_field if field will be created using other field as example, + pointer example field will be written here group 1 if we are going to do a relative group by on result modify_item 1 if item->result_field should point to new item. This is relevent for how fill_record() is going to @@ -4622,24 +4735,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, return 0; // Error } case Item::FIELD_ITEM: - { - Field *org_field=((Item_field*) item)->field,*new_field; - - *from_field=org_field; - // The following should always be true - if ((new_field= org_field->new_field(&thd->mem_root,table))) - { - if (modify_item) - ((Item_field*) item)->result_field= new_field; - else - new_field->field_name=item->name; - if (org_field->maybe_null()) - new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join - if (org_field->type()==FIELD_TYPE_VAR_STRING) - table->db_create_options|= HA_OPTION_PACK_RECORD; - } - return new_field; - } + return create_tmp_field_from_field(thd, (*from_field= + ((Item_field*) item)->field), + item, table, modify_item); case Item::FUNC_ITEM: case Item::COND_ITEM: case Item::FIELD_AVG_ITEM: @@ -4653,40 +4751,14 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::REF_ITEM: case Item::NULL_ITEM: case Item::VARBIN_ITEM: + return create_tmp_field_from_item(thd, item, table, + copy_func, modify_item); + case Item::TYPE_HOLDER: { - bool maybe_null=item->maybe_null; - Field *new_field; - LINT_INIT(new_field); - - switch (item->result_type()) { - case REAL_RESULT: - new_field=new Field_double(item->max_length,maybe_null, - item->name,table,item->decimals); - break; - case INT_RESULT: - new_field=new Field_longlong(item->max_length,maybe_null, - item->name,table, item->unsigned_flag); - break; - case STRING_RESULT: - if (item->max_length > 255) - new_field= new Field_blob(item->max_length,maybe_null, - item->name,table,item->collation.collation); - else - new_field= new Field_string(item->max_length,maybe_null, - item->name,table,item->collation.collation); - break; - case ROW_RESULT: - default: - // This case should never be choosen - DBUG_ASSERT(0); - new_field= 0; // to satisfy compiler (uninitialized variable) - break; - } - if (copy_func && item->is_result_field()) - *((*copy_func)++) = item; // Save for copy_funcs - if (modify_item) - item->set_result_field(new_field); - return new_field; + Field *example= ((Item_type_holder *)item)->example(); + if (example) + return create_tmp_field_from_field(thd, example, item, table, 0); + return create_tmp_field_from_item(thd, item, table, copy_func, 0); } default: // Dosen't have to be stored return 0; @@ -9077,7 +9149,7 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, select_lex->having, (ORDER*) thd->lex.proc_list.first, select_lex->options | thd->options | SELECT_DESCRIBE, - result, unit, select_lex, 0); + result, unit, select_lex); DBUG_RETURN(res); } diff --git a/sql/sql_select.h b/sql/sql_select.h index 5f0370a5a32..2e101c78613 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -266,7 +266,7 @@ class JOIN :public Sql_alloc int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, COND *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, SELECT_LEX *select, - SELECT_LEX_UNIT *unit, bool tables_and_fields_initied); + SELECT_LEX_UNIT *unit); int optimize(); int reinit(); void exec(); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 5292299f928..e2c90e4ff4c 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -25,11 +25,11 @@ #include "sql_select.h" int mysql_union(THD *thd, LEX *lex, select_result *result, - SELECT_LEX_UNIT *unit, bool tables_and_fields_initied) + SELECT_LEX_UNIT *unit) { DBUG_ENTER("mysql_union"); int res= 0; - if (!(res= unit->prepare(thd, result, tables_and_fields_initied))) + if (!(res= unit->prepare(thd, result))) res= unit->exec(); res|= unit->cleanup(); DBUG_RETURN(res); @@ -59,12 +59,6 @@ select_union::~select_union() int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) { unit= u; - if (not_describe && list.elements != table->fields) - { - my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, - ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); - return -1; - } return 0; } @@ -112,11 +106,11 @@ bool select_union::flush() } -int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, - bool tables_and_fields_initied) +int st_select_lex_unit::prepare(THD *thd, select_result *sel_result) { SELECT_LEX *lex_select_save= thd->lex.current_select; - SELECT_LEX *select_cursor,*sl; + SELECT_LEX *sl, *first_select; + select_result *tmp_result; DBUG_ENTER("st_select_lex_unit::prepare"); /* @@ -129,74 +123,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, DBUG_RETURN(0); prepared= 1; res= 0; - found_rows_for_union= first_select_in_union()->options & OPTION_FOUND_ROWS; TMP_TABLE_PARAM tmp_table_param; - t_and_f= tables_and_fields_initied; bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM)); - thd->lex.current_select= sl= select_cursor= first_select_in_union(); + thd->lex.current_select= sl= first_select= first_select_in_union(); + found_rows_for_union= first_select->options & OPTION_FOUND_ROWS; + /* Global option */ - if (t_and_f) + + if (first_select->next_select()) { - // Item list and tables will be initialized by mysql_derived - item_list= select_cursor->item_list; + if (!(tmp_result= union_result= new select_union(0))) + goto err; + union_result->not_describe= 1; + union_result->tmp_table_param= tmp_table_param; } else { - item_list.empty(); - TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first; - - if (setup_tables(first_table) || - setup_wild(thd, first_table, select_cursor->item_list, 0, - select_cursor->with_wild)) - goto err; - List_iterator<Item> it(select_cursor->item_list); - Item *item; - item_list= select_cursor->item_list; - select_cursor->with_wild= 0; - if (select_cursor->setup_ref_array(thd, - select_cursor->order_list.elements + - select_cursor->group_list.elements) || - setup_fields(thd, select_cursor->ref_pointer_array, first_table, - item_list, 0, 0, 1)) - goto err; - // Item list should be fix_fielded yet another time in JOIN::prepare - unfix_item_list(item_list); - - t_and_f= 1; - while((item=it++)) - { - item->maybe_null=1; - if (item->type() == Item::FIELD_ITEM) - ((class Item_field *)item)->field->table->maybe_null=1; - } + tmp_result= sel_result; + // single select should be processed like select in p[arantses + first_select->braces= 1; } - tmp_table_param.field_count=item_list.elements; - if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, - (ORDER*) 0, !union_option, - 1, (select_cursor->options | thd->options | - TMP_TABLE_ALL_COLUMNS), - HA_POS_ERROR, (char*) ""))) - goto err; - table->file->extra(HA_EXTRA_WRITE_CACHE); - table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - bzero((char*) &result_table_list,sizeof(result_table_list)); - result_table_list.db= (char*) ""; - result_table_list.real_name=result_table_list.alias= (char*) "union"; - result_table_list.table=table; - - if (!(union_result=new select_union(table))) - goto err; - - union_result->not_describe=1; - union_result->tmp_table_param=tmp_table_param; - for (;sl; sl= sl->next_select()) { JOIN *join= new JOIN(thd, sl->item_list, sl->options | thd->options | SELECT_NO_UNLOCK, - union_result); + tmp_result); thd->lex.current_select= sl; offset_limit_cnt= sl->offset_limit; select_limit_cnt= sl->select_limit+sl->offset_limit; @@ -215,27 +168,76 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, (ORDER*) sl->group_list.first, sl->having, (ORDER*) NULL, - sl, this, t_and_f); - t_and_f= 0; + sl, this); if (res || thd->is_fatal_error) goto err; + if (sl == first_select) + { + types.empty(); + List_iterator_fast<Item> it(sl->item_list); + Item *item; + while((item= it++)) + { + types.push_back(new Item_type_holder(thd, item)); + } + + if (thd->is_fatal_error) + goto err; // out of memory + } + else + { + if (types.elements != sl->item_list.elements) + { + my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, + ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); + goto err; + } + List_iterator_fast<Item> it(sl->item_list); + List_iterator_fast<Item> tp(types); + Item *type, *item; + while((type= tp++, item= it++)) + { + ((Item_type_holder*)type)->join_types(thd, item); + } + } } - item_list.empty(); - thd->lex.current_select= lex_select_save; + if (first_select->next_select()) { - List_iterator<Item> it(select_cursor->item_list); - Field **field; + tmp_table_param.field_count= types.elements; + if (!(table= create_tmp_table(thd, &tmp_table_param, types, + (ORDER*) 0, !union_option, 1, + (first_select_in_union()->options | + thd->options | + TMP_TABLE_ALL_COLUMNS), + HA_POS_ERROR, (char*) ""))) + goto err; + table->file->extra(HA_EXTRA_WRITE_CACHE); + table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + bzero((char*) &result_table_list, sizeof(result_table_list)); + result_table_list.db= (char*) ""; + result_table_list.real_name= result_table_list.alias= (char*) "union"; + result_table_list.table= table; + union_result->set_table(table); - for (field= table->field; *field; field++) + item_list.empty(); + thd->lex.current_select= lex_select_save; { - (void) it++; - if (item_list.push_back(new Item_field(*field))) - DBUG_RETURN(-1); + Field **field; + for (field= table->field; *field; field++) + { + if (item_list.push_back(new Item_field(*field))) + DBUG_RETURN(-1); + } } } + else + first_select->braces= 0; // remove our changes + + thd->lex.current_select= lex_select_save; DBUG_RETURN(res || thd->is_fatal_error ? 1 : 0); + err: thd->lex.current_select= lex_select_save; DBUG_RETURN(-1); @@ -419,7 +421,7 @@ int st_select_lex_unit::exec() (ORDER*)global_parameters->order_list.first, (ORDER*) NULL, NULL, (ORDER*) NULL, options | SELECT_NO_UNLOCK, - result, this, fake_select_lex, 0); + result, this, fake_select_lex); if (!res) thd->limit_found_rows = (ulonglong)table->file->records + add_rows; /* diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 9214894e214..8b77f6958d0 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -461,7 +461,7 @@ int mysql_multi_update(THD *thd, conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, (ORDER *)NULL, options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK, - result, unit, select_lex, 0); + result, unit, select_lex); delete result; DBUG_RETURN(res); } |