Commit 3e21b667 authored by unknown's avatar unknown

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
parent 920c30b4
......@@ -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;
......@@ -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;
......@@ -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; };
};
......
......@@ -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
*****************************************************************************/
......
......@@ -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);
......
......@@ -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);
}
}
......
......@@ -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);
......
......@@ -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
......
......@@ -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 */
......
......@@ -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
......
......@@ -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();
......
......@@ -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;
......
......@@ -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) ||
......
......@@ -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;
}
......@@ -4545,6 +4547,115 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
Create internal temporary table
****************************************************************************/
/*
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
......@@ -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);
}
......
......@@ -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();
......
......@@ -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;
/*
......
......@@ -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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment