fixed union types merging and table related metadata (BUG#8824)

This commit is contained in:
bell@sanja.is.com.ua 2005-03-23 08:36:48 +02:00
parent 80d9cafa8f
commit 4554b1f263
17 changed files with 1171 additions and 424 deletions

View File

@ -747,7 +747,7 @@ insert into t1 values (now());
create table t2 select f2 from (select max(now()) f2 from t1) a;
show columns from t2;
Field Type Null Key Default Extra
f2 datetime 0000-00-00 00:00:00
f2 datetime YES NULL
drop table t2;
create table t2 select f2 from (select now() f2 from t1) a;
show columns from t2;

View File

@ -55,8 +55,33 @@ id data data
2 female no
select t1.id from t1 union select t2.id from t2;
Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr
def test t1 t1 id id 1 3 1 Y 32768 0 63
def id id 1 4 1 Y 32768 0 63
id
1
2
drop table t1,t2;
create table t1 ( a int, b varchar(30), primary key(a));
insert into t1 values (1,'one');
insert into t1 values (2,'two');
set @arg00=1 ;
select @arg00 FROM t1 where a=1 union distinct select 1 FROM t1 where a=1;
Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr
def @arg00 @arg00 8 20 1 Y 32768 0 63
@arg00
1
select * from (select @arg00) aaa;
Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr
def aaa @arg00 @arg00 8 20 1 Y 32768 0 63
@arg00
1
select 1 union select 1;
Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr
def 1 1 8 20 1 N 32769 0 63
1
1
select * from (select 1 union select 1) aaa;
Catalog Database Table Table_alias Column Column_alias Name Type Length Max length Is_null Flags Decimals Charsetnr
def aaa 1 1 8 20 1 N 32769 0 63
1
1
drop table t1;

View File

@ -655,7 +655,7 @@ f
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f` binary(24) default NULL
`f` varbinary(24) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT y from t2 UNION select da from t2;
@ -666,7 +666,7 @@ y
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`y` binary(10) default NULL
`y` varbinary(10) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT y from t2 UNION select dt from t2;
@ -677,7 +677,7 @@ y
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`y` binary(19) default NULL
`y` varbinary(19) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT da from t2 UNION select dt from t2;
@ -699,7 +699,7 @@ testc
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` binary(19) default NULL
`dt` varbinary(19) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT dt from t2 UNION select sv from t2;
@ -710,7 +710,7 @@ testv
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` binary(19) default NULL
`dt` varbinary(19) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT sc from t2 UNION select sv from t2;
@ -732,7 +732,7 @@ tetetetetest
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`dt` blob
`dt` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT sv from t2 UNION select b from t2;
@ -755,7 +755,7 @@ tetetetetest
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`i` blob
`i` longblob
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT sv from t2 UNION select tx from t2;
@ -766,7 +766,7 @@ teeeeeeeeeeeest
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`sv` text
`sv` longtext
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 SELECT b from t2 UNION select tx from t2;
@ -1069,7 +1069,7 @@ create table t1 as
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`_latin1'test' collate latin1_bin` char(4) character set latin1 collate latin1_bin NOT NULL default ''
`_latin1'test' collate latin1_bin` varchar(4) character set latin1 collate latin1_bin NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
@ -1082,7 +1082,7 @@ create table t1 as
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`test` char(4) character set latin1 collate latin1_bin NOT NULL default ''
`test` varchar(4) character set latin1 collate latin1_bin NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
@ -1095,7 +1095,7 @@ create table t1 as
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`test` char(4) character set latin1 collate latin1_bin NOT NULL default ''
`test` varchar(4) character set latin1 collate latin1_bin NOT NULL default ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
select count(*) from t1;
count(*)
@ -1195,3 +1195,38 @@ a b
2 b
3 c
drop table t1;
CREATE TABLE t1 (
a ENUM('ä','ö','ü') character set utf8 not null default 'ü',
b ENUM("one", "two") character set utf8,
c ENUM("one", "two")
);
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` enum('ä','ö','ü') character set utf8 NOT NULL default 'ü',
`b` enum('one','two') character set utf8 default NULL,
`c` enum('one','two') default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
insert into t1 values ('ä', 'one', 'one'), ('ö', 'two', 'one'), ('ü', NULL, NULL);
create table t2 select NULL union select a from t1;
show columns from t2;
Field Type Null Key Default Extra
NULL enum('ä','ö','ü') YES NULL
drop table t2;
create table t2 select a from t1 union select NULL;
show columns from t2;
Field Type Null Key Default Extra
a enum('ä','ö','ü') YES NULL
drop table t2;
create table t2 select a from t1 union select a from t1;
show columns from t2;
Field Type Null Key Default Extra
a char(1)
drop table t2;
create table t2 select a from t1 union select c from t1;
ERROR HY000: Illegal mix of collations (utf8_general_ci,IMPLICIT) and (latin1_swedish_ci,IMPLICIT) for operation 'UNION'
create table t2 select a from t1 union select b from t1;
show columns from t2;
Field Type Null Key Default Extra
a varchar(3) YES NULL
drop table t2, t1;

View File

@ -34,4 +34,17 @@ select t1.id, t1.data, t2.data from t1, t2 where t1.id = t2.id order by t1.id;
select t1.id from t1 union select t2.id from t2;
drop table t1,t2;
#
# variables union and derived tables metadata test
#
create table t1 ( a int, b varchar(30), primary key(a));
insert into t1 values (1,'one');
insert into t1 values (2,'two');
set @arg00=1 ;
select @arg00 FROM t1 where a=1 union distinct select 1 FROM t1 where a=1;
select * from (select @arg00) aaa;
select 1 union select 1;
select * from (select 1 union select 1) aaa;
drop table t1;
--disable_metadata

View File

@ -711,3 +711,28 @@ select * from ((select * from t1 limit 1) union (select * from t1 limit 1) union
select * from ((((select * from t1))) union (select * from t1) union (select * from t1)) a;
select * from ((select * from t1) union (((select * from t1))) union (select * from t1)) a;
drop table t1;
#
# Enum merging test
#
CREATE TABLE t1 (
a ENUM('ä','ö','ü') character set utf8 not null default 'ü',
b ENUM("one", "two") character set utf8,
c ENUM("one", "two")
);
show create table t1;
insert into t1 values ('ä', 'one', 'one'), ('ö', 'two', 'one'), ('ü', NULL, NULL);
create table t2 select NULL union select a from t1;
show columns from t2;
drop table t2;
create table t2 select a from t1 union select NULL;
show columns from t2;
drop table t2;
create table t2 select a from t1 union select a from t1;
show columns from t2;
drop table t2;
-- error 1267
create table t2 select a from t1 union select c from t1;
create table t2 select a from t1 union select b from t1;
show columns from t2;
drop table t2, t1;

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,17 @@ class Protocol;
struct st_cache_field;
void field_conv(Field *to,Field *from);
inline uint get_enum_pack_length(int elements)
{
return elements < 256 ? 1 : 2;
}
inline uint get_set_pack_length(int elements)
{
uint len= (elements + 7) / 8;
return len > 4 ? 8 : len;
}
class Field
{
Field(const Item &); /* Prevent use of these */
@ -75,17 +86,6 @@ public:
GEOM_GEOMETRYCOLLECTION = 7
};
enum imagetype { itRAW, itMBR};
enum field_cast_enum
{
FIELD_CAST_STOP, FIELD_CAST_DECIMAL, FIELD_CAST_TINY, FIELD_CAST_SHORT,
FIELD_CAST_MEDIUM, FIELD_CAST_LONG, FIELD_CAST_LONGLONG,
FIELD_CAST_FLOAT, FIELD_CAST_DOUBLE,
FIELD_CAST_NULL,
FIELD_CAST_TIMESTAMP, FIELD_CAST_YEAR, FIELD_CAST_DATE, FIELD_CAST_NEWDATE,
FIELD_CAST_TIME, FIELD_CAST_DATETIME,
FIELD_CAST_STRING, FIELD_CAST_VARSTRING, FIELD_CAST_BLOB,
FIELD_CAST_GEOM, FIELD_CAST_ENUM, FIELD_CAST_SET
};
utype unireg_check;
uint32 field_length; // Length of field
@ -119,6 +119,8 @@ public:
virtual String *val_str(String*,String *)=0;
virtual Item_result result_type () const=0;
virtual Item_result cmp_type () const { return result_type(); }
static enum_field_types field_type_merge(enum_field_types, enum_field_types);
static Item_result result_merge_type(enum_field_types);
bool eq(Field *field) { return ptr == field->ptr && null_ptr == field->null_ptr; }
virtual bool eq_def(Field *field);
virtual uint32 pack_length() const { return (uint32) field_length; }
@ -290,8 +292,6 @@ public:
int cuted_increment);
void set_datetime_warning(const uint level, const uint code,
double nr, timestamp_type ts_type);
virtual field_cast_enum field_cast_type()= 0;
bool field_cast_compatible(field_cast_enum type);
/* maximum possible display length */
virtual uint32 max_length()= 0;
friend bool reopen_table(THD *,struct st_table *,bool);
@ -398,7 +398,6 @@ public:
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
uint32 max_length() { return field_length; }
field_cast_enum field_cast_type() { return FIELD_CAST_DECIMAL; }
};
@ -430,7 +429,6 @@ public:
uint32 pack_length() const { return 1; }
void sql_type(String &str) const;
uint32 max_length() { return 4; }
field_cast_enum field_cast_type() { return FIELD_CAST_TINY; }
};
@ -467,7 +465,6 @@ public:
uint32 pack_length() const { return 2; }
void sql_type(String &str) const;
uint32 max_length() { return 6; }
field_cast_enum field_cast_type() { return FIELD_CAST_SHORT; }
};
@ -499,7 +496,6 @@ public:
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
uint32 max_length() { return 8; }
field_cast_enum field_cast_type() { return FIELD_CAST_MEDIUM; }
};
@ -536,7 +532,6 @@ public:
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
uint32 max_length() { return 11; }
field_cast_enum field_cast_type() { return FIELD_CAST_LONG; }
};
@ -576,7 +571,6 @@ public:
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
uint32 max_length() { return 20; }
field_cast_enum field_cast_type() { return FIELD_CAST_LONGLONG; }
};
#endif
@ -611,7 +605,6 @@ public:
uint32 pack_length() const { return sizeof(float); }
void sql_type(String &str) const;
uint32 max_length() { return 24; }
field_cast_enum field_cast_type() { return FIELD_CAST_FLOAT; }
};
@ -646,7 +639,6 @@ public:
uint32 pack_length() const { return sizeof(double); }
void sql_type(String &str) const;
uint32 max_length() { return 53; }
field_cast_enum field_cast_type() { return FIELD_CAST_DOUBLE; }
};
@ -677,7 +669,6 @@ public:
void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); }
uint32 max_length() { return 4; }
field_cast_enum field_cast_type() { return FIELD_CAST_NULL; }
};
@ -729,7 +720,6 @@ public:
}
bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime);
field_cast_enum field_cast_type() { return FIELD_CAST_TIMESTAMP; }
timestamp_auto_set_type get_auto_set_type() const;
};
@ -753,7 +743,6 @@ public:
bool send_binary(Protocol *protocol);
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_YEAR; }
};
@ -786,7 +775,6 @@ public:
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
field_cast_enum field_cast_type() { return FIELD_CAST_DATE; }
};
class Field_newdate :public Field_str {
@ -818,7 +806,6 @@ public:
bool zero_pack() const { return 1; }
bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime);
field_cast_enum field_cast_type() { return FIELD_CAST_NEWDATE; }
};
@ -853,7 +840,6 @@ public:
void sql_type(String &str) const;
bool can_be_compared_as_longlong() const { return TRUE; }
bool zero_pack() const { return 1; }
field_cast_enum field_cast_type() { return FIELD_CAST_TIME; }
};
@ -891,7 +877,6 @@ public:
bool zero_pack() const { return 1; }
bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime);
field_cast_enum field_cast_type() { return FIELD_CAST_DATETIME; }
};
@ -937,7 +922,6 @@ public:
enum_field_types real_type() const { return FIELD_TYPE_STRING; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_STRING; }
};
@ -986,7 +970,6 @@ public:
enum_field_types real_type() const { return FIELD_TYPE_VAR_STRING; }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_VARSTRING; }
};
@ -1081,7 +1064,6 @@ public:
uint size_of() const { return sizeof(*this); }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_BLOB; }
uint32 max_length();
};
@ -1111,7 +1093,6 @@ 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);
field_cast_enum field_cast_type() { return FIELD_CAST_GEOM; }
};
#endif /*HAVE_SPATIAL*/
@ -1155,7 +1136,6 @@ public:
bool has_charset(void) const { return TRUE; }
/* enum and set are sorted as integers */
CHARSET_INFO *sort_charset(void) const { return &my_charset_bin; }
field_cast_enum field_cast_type() { return FIELD_CAST_ENUM; }
};
@ -1181,7 +1161,6 @@ public:
void sql_type(String &str) const;
enum_field_types real_type() const { return FIELD_TYPE_SET; }
bool has_charset(void) const { return TRUE; }
field_cast_enum field_cast_type() { return FIELD_CAST_SET; }
};
@ -1268,7 +1247,6 @@ int set_field_to_null(Field *field);
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
bool test_if_int(const char *str, int length, const char *int_end,
CHARSET_INFO *cs);
bool field_types_to_be_kept(enum_field_types field_type);
/*
The following are for the interface with the .frm file

View File

@ -1700,10 +1700,10 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table)
case MYSQL_TYPE_NULL:
return new Field_null((char*) 0, max_length, Field::NONE,
name, table, &my_charset_bin);
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_INT24:
return new Field_medium((char*) 0, max_length, null_ptr, 0, Field::NONE,
name, table, 0, unsigned_flag);
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_DATE:
return new Field_date(maybe_null, name, table, &my_charset_bin);
case MYSQL_TYPE_TIME:
@ -2701,204 +2701,268 @@ void Item_cache_row::bring_value()
}
/*
Returns field for temporary table dependind on item type
SYNOPSIS
get_holder_example_field()
thd - thread handler
item - pointer to item
table - empty table object
NOTE
It is possible to return field for Item_func
items only if field type of this item is
date or time or datetime type.
also see function field_types_to_be_kept() from
field.cc
RETURN
# - field
0 - no field
*/
Field *get_holder_example_field(THD *thd, Item *item, TABLE *table)
{
DBUG_ASSERT(table);
Item_func *tmp_item= 0;
if (item->type() == Item::FIELD_ITEM)
return (((Item_field*) item)->field);
if (item->type() == Item::FUNC_ITEM)
tmp_item= (Item_func *) item;
else if (item->type() == Item::SUM_FUNC_ITEM)
{
Item_sum *item_sum= (Item_sum *) item;
if (item_sum->keep_field_type())
{
if (item_sum->args[0]->type() == Item::FIELD_ITEM)
return (((Item_field*) item_sum->args[0])->field);
if (item_sum->args[0]->type() == Item::FUNC_ITEM)
tmp_item= (Item_func *) item_sum->args[0];
}
}
return (tmp_item && field_types_to_be_kept(tmp_item->field_type()) ?
tmp_item->tmp_table_field(table) : 0);
}
Item_type_holder::Item_type_holder(THD *thd, Item *item, TABLE *table)
:Item(thd, item), item_type(item->result_type()),
orig_type(item_type)
Item_type_holder::Item_type_holder(THD *thd, Item *item)
:Item(thd, item), enum_set_typelib(0), fld_type(get_real_type(item))
{
DBUG_ASSERT(item->fixed);
/*
It is safe assign pointer on field, because it will be used just after
all JOIN::prepare calls and before any SELECT execution
*/
field_example= get_holder_example_field(thd, item, table);
max_length= real_length(item);
max_length= display_length(item);
maybe_null= item->maybe_null;
collation.set(item->collation);
get_full_info(item);
}
/*
STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT
ROW_RESULT should never appear in Item_type_holder::join_types,
but it is included in following table just to make table full
(there DBUG_ASSERT in function to catch 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}};
/*
Values of 'from' field can be stored in 'to' field.
Return expression type of Item_type_holder
SYNOPSIS
is_attr_compatible()
from Item which values should be saved
to Item where values should be saved
Item_type_holder::result_type()
RETURN
1 can be saved
0 can not be saved
Item_result (type of internal MySQL expression result)
*/
inline bool is_attr_compatible(Item *from, Item *to)
Item_result Item_type_holder::result_type() const
{
return ((to->max_length >= from->max_length) &&
(to->maybe_null || !from->maybe_null) &&
(to->result_type() != STRING_RESULT ||
from->result_type() != STRING_RESULT ||
(from->collation.collation == to->collation.collation)));
return Field::result_merge_type(fld_type);
}
bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table)
/*
Find real field type of item
SYNOPSIS
Item_type_holder::get_real_type()
RETURN
type of field which should be created to store item value
*/
enum_field_types Item_type_holder::get_real_type(Item *item)
{
uint32 new_length= real_length(item);
bool use_new_field= 0, use_expression_type= 0;
Item_result new_result_type= type_convertor[item_type][item->result_type()];
Field *field= get_holder_example_field(thd, item, table);
bool item_is_a_field= (field != NULL);
/*
Check if both items point to fields: in this case we
can adjust column types of result table in the union smartly.
*/
if (field_example && item_is_a_field)
switch(item->type())
{
/* Can 'field_example' field store data of the column? */
if ((use_new_field=
(!field->field_cast_compatible(field_example->field_cast_type()) ||
!is_attr_compatible(item, this))))
{
/*
The old field can't store value of the new field.
Check if the new field can store value of the old one.
*/
use_expression_type|=
(!field_example->field_cast_compatible(field->field_cast_type()) ||
!is_attr_compatible(this, item));
}
}
else if (field_example || item_is_a_field)
case FIELD_ITEM:
{
/*
Expression types can't be mixed with field types, we have to use
expression types.
Item_fields::field_type ask Field_type() but sometimes field return
a different type, like for enum/set, so we need to ask real type.
*/
use_new_field= 1; // make next if test easier
use_expression_type= 1;
Field *field= ((Item_field *) item)->field;
enum_field_types type= field->real_type();
/* work around about varchar type field detection */
if (type == MYSQL_TYPE_STRING && field->type() == MYSQL_TYPE_VAR_STRING)
return MYSQL_TYPE_VAR_STRING;
return type;
}
/* Check whether size/type of the result item should be changed */
if (use_new_field ||
(new_result_type != item_type) || (new_length > max_length) ||
(!maybe_null && item->maybe_null) ||
(item_type == STRING_RESULT &&
collation.collation != item->collation.collation))
case SUM_FUNC_ITEM:
{
const char *old_cs,*old_derivation;
if (use_expression_type || !item_is_a_field)
field_example= 0;
else
/*
Argument of aggregate function sometimes should be asked about field
type
*/
Item_sum *item_sum= (Item_sum *) item;
if (item_sum->keep_field_type())
return get_real_type(item_sum->args[0]);
break;
}
case FUNC_ITEM:
if (((Item_func *) item)->functype() == Item_func::VAR_VALUE_FUNC)
{
/*
It is safe to assign a pointer to field here, because it will be used
before any table is closed.
There are work around of problem with changing variable type on the
fly and variable always report "string" as field type to get
acceptable information for client in send_field, so we make field
type from expression type.
*/
field_example= field;
switch (item->result_type())
{
case STRING_RESULT:
return MYSQL_TYPE_VAR_STRING;
case INT_RESULT:
return MYSQL_TYPE_LONGLONG;
case REAL_RESULT:
return MYSQL_TYPE_DOUBLE;
case ROW_RESULT:
default:
DBUG_ASSERT(0);
return MYSQL_TYPE_VAR_STRING;
}
}
break;
default:
break;
}
return item->field_type();
}
/*
Find field type which can carry current Item_type_holder type and
type of given Item.
SYNOPSIS
Item_type_holder::join_types()
thd thread handler
item given item to join its parameters with this item ones
RETURN
TRUE error - types are incompatible
FALSE OK
*/
bool Item_type_holder::join_types(THD *thd, Item *item)
{
max_length= max(max_length, display_length(item));
fld_type= Field::field_type_merge(fld_type, get_real_type(item));
if (Field::result_merge_type(fld_type) == STRING_RESULT)
{
const char *old_cs, *old_derivation;
old_cs= collation.collation->name;
old_derivation= collation.derivation_name();
if (item_type == STRING_RESULT && collation.aggregate(item->collation))
if (collation.aggregate(item->collation))
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0),
old_cs, old_derivation,
item->collation.collation->name,
item->collation.derivation_name(),
"UNION");
return 1;
return TRUE;
}
max_length= max(max_length, new_length);
decimals= max(decimals, item->decimals);
maybe_null|= item->maybe_null;
item_type= new_result_type;
}
DBUG_ASSERT(item_type != ROW_RESULT);
return 0;
decimals= max(decimals, item->decimals);
maybe_null|= item->maybe_null;
get_full_info(item);
return FALSE;
}
/*
Calculate lenth for merging result for given Item type
uint32 Item_type_holder::real_length(Item *item)
SYNOPSIS
Item_type_holder::real_length()
item Item for lrngth detection
RETURN
length
*/
uint32 Item_type_holder::display_length(Item *item)
{
if (item->type() == Item::FIELD_ITEM)
return ((Item_field *)item)->max_disp_length();
switch (item->result_type())
switch (item->field_type())
{
case STRING_RESULT:
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_NEWDATE:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_SET:
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
case MYSQL_TYPE_VAR_STRING:
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_GEOMETRY:
return item->max_length;
case REAL_RESULT:
case MYSQL_TYPE_TINY:
return 4;
case MYSQL_TYPE_SHORT:
return 6;
case MYSQL_TYPE_LONG:
return 11;
case MYSQL_TYPE_FLOAT:
return 25;
case MYSQL_TYPE_DOUBLE:
return 53;
case INT_RESULT:
case MYSQL_TYPE_NULL:
return 4;
case MYSQL_TYPE_LONGLONG:
return 20;
case ROW_RESULT:
case MYSQL_TYPE_INT24:
return 8;
default:
DBUG_ASSERT(0); // we should never go there
return 0;
}
}
/*
Make temporary table field according collected information about type
of UNION result
SYNOPSIS
Item_type_holder::make_field_by_type()
table temporary table for which we create fields
RETURN
created field
*/
Field *Item_type_holder::make_field_by_type(TABLE *table)
{
if (fld_type == MYSQL_TYPE_ENUM || fld_type == MYSQL_TYPE_SET)
{
DBUG_ASSERT(enum_set_typelib);
/*
The field functions defines a field to be not null if null_ptr is not 0
*/
uchar *null_ptr= maybe_null ? (uchar*) "" : 0;
if (fld_type == MYSQL_TYPE_ENUM)
return new Field_enum((char *) 0, max_length, null_ptr, 0,
Field::NONE, name,
table, get_enum_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
else
return new Field_set((char *) 0, max_length, null_ptr, 0,
Field::NONE, name,
table, get_set_pack_length(enum_set_typelib->count),
enum_set_typelib, collation.collation);
}
return tmp_table_field_from_field_type(table);
}
/*
Get full information from Item about enum/set fields to be able to create
them later
SYNOPSIS
Item_type_holder::get_full_info
item Item for information collection
*/
void Item_type_holder::get_full_info(Item *item)
{
if (fld_type == MYSQL_TYPE_ENUM ||
fld_type == MYSQL_TYPE_SET)
{
/*
We can have enum/set type after merging only if we have one enum/set
field and number of NULL fields
*/
DBUG_ASSERT((enum_set_typelib &&
get_real_type(item) == MYSQL_TYPE_NULL) ||
(!enum_set_typelib &&
item->type() == Item::FIELD_ITEM &&
(get_real_type(item) == MYSQL_TYPE_ENUM ||
get_real_type(item) == MYSQL_TYPE_SET) &&
((Field_enum*)((Item_field *) item)->field)->typelib));
if (!enum_set_typelib)
{
enum_set_typelib= ((Field_enum*)((Item_field *) item)->field)->typelib;
}
}
}
double Item_type_holder::val()
{
DBUG_ASSERT(0); // should never be called

View File

@ -1321,32 +1321,32 @@ public:
/*
Used to store type. name, length of Item for UNIONS & derived table
Item_type_holder used to store type. name, length of Item for UNIONS &
derived tables.
Item_type_holder do not need cleanup() because its time of live limited by
single SP/PS execution.
*/
class Item_type_holder: public Item
{
protected:
Item_result item_type;
Item_result orig_type;
Field *field_example;
public:
Item_type_holder(THD*, Item*, TABLE *);
TYPELIB *enum_set_typelib;
enum_field_types fld_type;
Item_result result_type () const { return item_type; }
void get_full_info(Item *item);
public:
Item_type_holder(THD*, Item*);
Item_result result_type() const;
virtual enum_field_types field_type() const { return fld_type; };
enum Type type() const { return TYPE_HOLDER; }
double val();
longlong val_int();
String *val_str(String*);
bool join_types(THD *thd, Item *, TABLE *);
Field *example() { return field_example; }
static uint32 real_length(Item *item);
void cleanup()
{
DBUG_ENTER("Item_type_holder::cleanup");
Item::cleanup();
item_type= orig_type;
DBUG_VOID_RETURN;
}
bool join_types(THD *thd, Item *);
Field *make_field_by_type(TABLE *table);
static uint32 display_length(Item *item);
static enum_field_types get_real_type(Item *);
};

View File

@ -51,7 +51,7 @@ public:
SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC};
NOT_FUNC, NOT_ALL_FUNC, NOW_FUNC, VAR_VALUE_FUNC};
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
@ -980,6 +980,7 @@ public:
select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b)
*/
enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
enum Functype functype() const { return VAR_VALUE_FUNC; }
const char *func_name() const { return "get_user_var"; }
bool const_item() const;
table_map used_tables() const

View File

@ -1235,7 +1235,7 @@ int subselect_single_select_engine::prepare()
int subselect_union_engine::prepare()
{
return unit->prepare(thd, result, SELECT_NO_UNLOCK);
return unit->prepare(thd, result, SELECT_NO_UNLOCK, "");
}
int subselect_uniquesubquery_engine::prepare()

View File

@ -123,7 +123,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
DBUG_RETURN(1); // out of memory
// st_select_lex_unit::prepare correctly work for single select
if ((res= unit->prepare(thd, derived_result, 0)))
if ((res= unit->prepare(thd, derived_result, 0, org_table_list->alias)))
goto exit;
@ -161,7 +161,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if (is_union)
{
// execute union without clean up
if (!(res= unit->prepare(thd, derived_result, SELECT_NO_UNLOCK)))
if (!(res= unit->prepare(thd, derived_result, SELECT_NO_UNLOCK, "")))
res= unit->exec();
}
else

View File

@ -389,7 +389,8 @@ public:
void exclude_tree();
/* UNION methods */
int prepare(THD *thd, select_result *result, ulong additional_options);
int prepare(THD *thd, select_result *result, ulong additional_options,
const char *tmp_table_alias);
int exec();
int cleanup();
inline void unclean() { cleaned= 0; }

View File

@ -4539,9 +4539,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
new_field->pack_length= (interval_list->elements + 7) / 8;
if (new_field->pack_length > 4)
new_field->pack_length=8;
new_field->pack_length= get_set_pack_length(interval_list->elements);
List_iterator<String> it(*interval_list);
String *tmp;
@ -4558,7 +4556,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
case FIELD_TYPE_ENUM:
{
// Should be safe
new_field->pack_length= interval_list->elements < 256 ? 1 : 2;
new_field->pack_length= get_enum_pack_length(interval_list->elements);
List_iterator<String> it(*interval_list);
String *tmp;

View File

@ -1079,7 +1079,7 @@ static int mysql_test_select(Prepared_statement *stmt,
thd->used_tables= 0; // Updated by setup_fields
// JOIN::prepare calls
if (unit->prepare(thd, 0, 0))
if (unit->prepare(thd, 0, 0, ""))
{
send_error(thd);
goto err_prep;
@ -1228,7 +1228,7 @@ static int select_like_statement_test(Prepared_statement *stmt,
thd->used_tables= 0; // Updated by setup_fields
// JOIN::prepare calls
if (lex->unit.prepare(thd, 0, 0))
if (lex->unit.prepare(thd, 0, 0, ""))
{
res= thd->net.report_error ? -1 : 1;
}

View File

@ -4836,14 +4836,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
return create_tmp_field_from_item(thd, item, table, copy_func, modify_item,
convert_blob_length);
case Item::TYPE_HOLDER:
{
Field *example= ((Item_type_holder *)item)->example();
if (example)
return create_tmp_field_from_field(thd, example, item, table, 0,
convert_blob_length);
return create_tmp_field_from_item(thd, item, table, copy_func, 0,
convert_blob_length);
}
return ((Item_type_holder *)item)->make_field_by_type(table);
default: // Dosen't have to be stored
return 0;
}
@ -5340,8 +5333,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
if (create_myisam_tmp_table(table,param,select_options))
goto err;
}
/* Set table_name for easier debugging */
table->table_name= base_name(tmpname);
if (!open_tmp_table(table))
DBUG_RETURN(table);
@ -9525,7 +9516,8 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
unit->fake_select_lex->select_number= UINT_MAX; // jost for initialization
unit->fake_select_lex->type= "UNION RESULT";
unit->fake_select_lex->options|= SELECT_DESCRIBE;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE,
"")))
res= unit->exec();
res|= unit->cleanup();
}

View File

@ -29,7 +29,7 @@ int mysql_union(THD *thd, LEX *lex, select_result *result,
{
DBUG_ENTER("mysql_union");
int res= 0;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK)))
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK, "")))
res= unit->exec();
res|= unit->cleanup();
DBUG_RETURN(res);
@ -142,7 +142,8 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd)
int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
ulong additional_options)
ulong additional_options,
const char *tmp_table_alias)
{
SELECT_LEX *lex_select_save= thd_arg->lex->current_select;
SELECT_LEX *sl, *first_select;
@ -252,7 +253,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
while ((item_tmp= it++))
{
/* Error's in 'new' will be detected after loop */
types.push_back(new Item_type_holder(thd_arg, item_tmp, empty_table));
types.push_back(new Item_type_holder(thd_arg, item_tmp));
}
if (thd_arg->is_fatal_error)
@ -271,8 +272,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
Item *type, *item_tmp;
while ((type= tp++, item_tmp= it++))
{
if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp,
empty_table))
if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp))
DBUG_RETURN(-1);
}
}
@ -304,7 +304,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
(first_select_in_union()->options |
thd_arg->options |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR, (char*) "")))
HA_POS_ERROR, (char *) tmp_table_alias)))
goto err;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);