A fix: bug#6931: Date Type column problem when using UNION-Table
bug#7833: Wrong datatype of aggregate column is returned mysql-test/r/func_group.result: Test case for bug 7833: Wrong datatype of aggregate column is returned mysql-test/r/union.result: Test case for bug 6931: Date Type column problem when using UNION-Table. mysql-test/t/func_group.test: Test case for bug 7833: Wrong datatype of aggregate column is returned mysql-test/t/union.test: Test case for bug 6931: Date Type column problem when using UNION-Table.
This commit is contained in:
parent
7116beb95d
commit
66eb71f3fc
@ -733,3 +733,15 @@ one 2
|
|||||||
two 2
|
two 2
|
||||||
three 1
|
three 1
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
create table t1(f1 datetime);
|
||||||
|
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
|
||||||
|
drop table t2;
|
||||||
|
create table t2 select f2 from (select now() f2 from t1) a;
|
||||||
|
show columns from t2;
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
f2 datetime 0000-00-00 00:00:00
|
||||||
|
drop table t2, t1;
|
||||||
|
@ -1137,3 +1137,39 @@ t1 CREATE TABLE `t1` (
|
|||||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
drop table t1;
|
drop table t1;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
create table t1(a1 int, f1 char(10));
|
||||||
|
create table t2
|
||||||
|
select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a
|
||||||
|
union
|
||||||
|
select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a
|
||||||
|
order by f2, a1;
|
||||||
|
show columns from t2;
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
f2 date YES NULL
|
||||||
|
a1 int(11) YES NULL
|
||||||
|
drop table t1, t2;
|
||||||
|
create table t1 (f1 int);
|
||||||
|
create table t2 (f1 int, f2 int ,f3 date);
|
||||||
|
create table t3 (f1 int, f2 char(10));
|
||||||
|
create table t4
|
||||||
|
(
|
||||||
|
select t2.f3 as sdate
|
||||||
|
from t1
|
||||||
|
left outer join t2 on (t1.f1 = t2.f1)
|
||||||
|
inner join t3 on (t2.f2 = t3.f1)
|
||||||
|
order by t1.f1, t3.f1, t2.f3
|
||||||
|
)
|
||||||
|
union
|
||||||
|
(
|
||||||
|
select cast('2004-12-31' as date) as sdate
|
||||||
|
from t1
|
||||||
|
left outer join t2 on (t1.f1 = t2.f1)
|
||||||
|
inner join t3 on (t2.f2 = t3.f1)
|
||||||
|
group by t1.f1
|
||||||
|
order by t1.f1, t3.f1, t2.f3
|
||||||
|
)
|
||||||
|
order by sdate;
|
||||||
|
show columns from t4;
|
||||||
|
Field Type Null Key Default Extra
|
||||||
|
sdate date YES NULL
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
|
@ -473,3 +473,17 @@ INSERT INTO t1 VALUES
|
|||||||
|
|
||||||
select val, count(*) from t1 group by val;
|
select val, count(*) from t1 group by val;
|
||||||
drop table t1;
|
drop table t1;
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug 7833: Wrong datatype of aggregate column is returned
|
||||||
|
#
|
||||||
|
|
||||||
|
create table t1(f1 datetime);
|
||||||
|
insert into t1 values (now());
|
||||||
|
create table t2 select f2 from (select max(now()) f2 from t1) a;
|
||||||
|
show columns from t2;
|
||||||
|
drop table t2;
|
||||||
|
create table t2 select f2 from (select now() f2 from t1) a;
|
||||||
|
show columns from t2;
|
||||||
|
drop table t2, t1;
|
||||||
|
@ -664,3 +664,38 @@ show create table t1;
|
|||||||
drop table t1;
|
drop table t1;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug 6931: Date Type column problem when using UNION-Table.
|
||||||
|
#
|
||||||
|
create table t1(a1 int, f1 char(10));
|
||||||
|
create table t2
|
||||||
|
select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a
|
||||||
|
union
|
||||||
|
select f2,a1 from (select a1, CAST('2004-12-31' AS DATE) f2 from t1) a
|
||||||
|
order by f2, a1;
|
||||||
|
show columns from t2;
|
||||||
|
drop table t1, t2;
|
||||||
|
|
||||||
|
create table t1 (f1 int);
|
||||||
|
create table t2 (f1 int, f2 int ,f3 date);
|
||||||
|
create table t3 (f1 int, f2 char(10));
|
||||||
|
create table t4
|
||||||
|
(
|
||||||
|
select t2.f3 as sdate
|
||||||
|
from t1
|
||||||
|
left outer join t2 on (t1.f1 = t2.f1)
|
||||||
|
inner join t3 on (t2.f2 = t3.f1)
|
||||||
|
order by t1.f1, t3.f1, t2.f3
|
||||||
|
)
|
||||||
|
union
|
||||||
|
(
|
||||||
|
select cast('2004-12-31' as date) as sdate
|
||||||
|
from t1
|
||||||
|
left outer join t2 on (t1.f1 = t2.f1)
|
||||||
|
inner join t3 on (t2.f2 = t3.f1)
|
||||||
|
group by t1.f1
|
||||||
|
order by t1.f1, t3.f1, t2.f3
|
||||||
|
)
|
||||||
|
order by sdate;
|
||||||
|
show columns from t4;
|
||||||
|
drop table t1, t2, t3, t4;
|
||||||
|
35
sql/field.cc
35
sql/field.cc
@ -245,6 +245,7 @@ static Field::field_cast_enum field_cast_date[]=
|
|||||||
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
|
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
|
||||||
static Field::field_cast_enum field_cast_newdate[]=
|
static Field::field_cast_enum field_cast_newdate[]=
|
||||||
{Field::FIELD_CAST_NEWDATE,
|
{Field::FIELD_CAST_NEWDATE,
|
||||||
|
Field::FIELD_CAST_DATE,
|
||||||
Field::FIELD_CAST_DATETIME,
|
Field::FIELD_CAST_DATETIME,
|
||||||
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
|
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
|
||||||
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
|
Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP};
|
||||||
@ -6024,6 +6025,40 @@ Field *make_field(char *ptr, uint32 field_length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check if field_type is appropriate field type
|
||||||
|
to create field for tmp table using
|
||||||
|
item->tmp_table_field() method
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
field_types_to_be_kept()
|
||||||
|
field_type - field type
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
it is used in function get_holder_example_field()
|
||||||
|
from item.cc
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
1 - can use item->tmp_table_field() method
|
||||||
|
0 - can not use item->tmp_table_field() method
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool field_types_to_be_kept(enum_field_types field_type)
|
||||||
|
{
|
||||||
|
switch (field_type)
|
||||||
|
{
|
||||||
|
case FIELD_TYPE_DATE:
|
||||||
|
case FIELD_TYPE_NEWDATE:
|
||||||
|
case FIELD_TYPE_TIME:
|
||||||
|
case FIELD_TYPE_DATETIME:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Create a field suitable for create of table */
|
/* Create a field suitable for create of table */
|
||||||
|
|
||||||
create_field::create_field(Field *old_field,Field *orig_field)
|
create_field::create_field(Field *old_field,Field *orig_field)
|
||||||
|
@ -1265,6 +1265,7 @@ int set_field_to_null(Field *field);
|
|||||||
int set_field_to_null_with_conversions(Field *field, bool no_conversions);
|
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,
|
bool test_if_int(const char *str, int length, const char *int_end,
|
||||||
CHARSET_INFO *cs);
|
CHARSET_INFO *cs);
|
||||||
|
bool field_types_to_be_kept(enum_field_types field_type);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following are for the interface with the .frm file
|
The following are for the interface with the .frm file
|
||||||
|
65
sql/item.cc
65
sql/item.cc
@ -2639,7 +2639,53 @@ void Item_cache_row::bring_value()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Item_type_holder::Item_type_holder(THD *thd, Item *item)
|
/*
|
||||||
|
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()),
|
:Item(thd, item), item_type(item->result_type()),
|
||||||
orig_type(item_type)
|
orig_type(item_type)
|
||||||
{
|
{
|
||||||
@ -2649,10 +2695,7 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item)
|
|||||||
It is safe assign pointer on field, because it will be used just after
|
It is safe assign pointer on field, because it will be used just after
|
||||||
all JOIN::prepare calls and before any SELECT execution
|
all JOIN::prepare calls and before any SELECT execution
|
||||||
*/
|
*/
|
||||||
if (item->type() == Item::FIELD_ITEM)
|
field_example= get_holder_example_field(thd, item, table);
|
||||||
field_example= ((Item_field*) item)->field;
|
|
||||||
else
|
|
||||||
field_example= 0;
|
|
||||||
max_length= real_length(item);
|
max_length= real_length(item);
|
||||||
maybe_null= item->maybe_null;
|
maybe_null= item->maybe_null;
|
||||||
collation.set(item->collation);
|
collation.set(item->collation);
|
||||||
@ -2692,25 +2735,23 @@ inline bool is_attr_compatible(Item *from, Item *to)
|
|||||||
(to->maybe_null || !from->maybe_null) &&
|
(to->maybe_null || !from->maybe_null) &&
|
||||||
(to->result_type() != STRING_RESULT ||
|
(to->result_type() != STRING_RESULT ||
|
||||||
from->result_type() != STRING_RESULT ||
|
from->result_type() != STRING_RESULT ||
|
||||||
my_charset_same(from->collation.collation,
|
(from->collation.collation == to->collation.collation)));
|
||||||
to->collation.collation)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_type_holder::join_types(THD *thd, Item *item)
|
bool Item_type_holder::join_types(THD *thd, Item *item, TABLE *table)
|
||||||
{
|
{
|
||||||
uint32 new_length= real_length(item);
|
uint32 new_length= real_length(item);
|
||||||
bool use_new_field= 0, use_expression_type= 0;
|
bool use_new_field= 0, use_expression_type= 0;
|
||||||
Item_result new_result_type= type_convertor[item_type][item->result_type()];
|
Item_result new_result_type= type_convertor[item_type][item->result_type()];
|
||||||
bool item_is_a_field= item->type() == Item::FIELD_ITEM;
|
Field *field= get_holder_example_field(thd, item, table);
|
||||||
|
bool item_is_a_field= field;
|
||||||
/*
|
/*
|
||||||
Check if both items point to fields: in this case we
|
Check if both items point to fields: in this case we
|
||||||
can adjust column types of result table in the union smartly.
|
can adjust column types of result table in the union smartly.
|
||||||
*/
|
*/
|
||||||
if (field_example && item_is_a_field)
|
if (field_example && item_is_a_field)
|
||||||
{
|
{
|
||||||
Field *field= ((Item_field *)item)->field;
|
|
||||||
/* Can 'field_example' field store data of the column? */
|
/* Can 'field_example' field store data of the column? */
|
||||||
if ((use_new_field=
|
if ((use_new_field=
|
||||||
(!field->field_cast_compatible(field_example->field_cast_type()) ||
|
(!field->field_cast_compatible(field_example->field_cast_type()) ||
|
||||||
@ -2751,7 +2792,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
|
|||||||
It is safe to assign a pointer to field here, because it will be used
|
It is safe to assign a pointer to field here, because it will be used
|
||||||
before any table is closed.
|
before any table is closed.
|
||||||
*/
|
*/
|
||||||
field_example= ((Item_field*) item)->field;
|
field_example= field;
|
||||||
}
|
}
|
||||||
|
|
||||||
old_cs= collation.collation->name;
|
old_cs= collation.collation->name;
|
||||||
|
@ -1321,14 +1321,14 @@ protected:
|
|||||||
Item_result orig_type;
|
Item_result orig_type;
|
||||||
Field *field_example;
|
Field *field_example;
|
||||||
public:
|
public:
|
||||||
Item_type_holder(THD*, Item*);
|
Item_type_holder(THD*, Item*, TABLE *);
|
||||||
|
|
||||||
Item_result result_type () const { return item_type; }
|
Item_result result_type () const { return item_type; }
|
||||||
enum Type type() const { return TYPE_HOLDER; }
|
enum Type type() const { return TYPE_HOLDER; }
|
||||||
double val();
|
double val();
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
String *val_str(String*);
|
String *val_str(String*);
|
||||||
bool join_types(THD *thd, Item *);
|
bool join_types(THD *thd, Item *, TABLE *);
|
||||||
Field *example() { return field_example; }
|
Field *example() { return field_example; }
|
||||||
static uint32 real_length(Item *item);
|
static uint32 real_length(Item *item);
|
||||||
void cleanup()
|
void cleanup()
|
||||||
|
@ -148,6 +148,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||||||
SELECT_LEX *sl, *first_select;
|
SELECT_LEX *sl, *first_select;
|
||||||
select_result *tmp_result;
|
select_result *tmp_result;
|
||||||
bool is_union;
|
bool is_union;
|
||||||
|
TABLE *empty_table= 0;
|
||||||
DBUG_ENTER("st_select_lex_unit::prepare");
|
DBUG_ENTER("st_select_lex_unit::prepare");
|
||||||
|
|
||||||
describe= test(additional_options & SELECT_DESCRIBE);
|
describe= test(additional_options & SELECT_DESCRIBE);
|
||||||
@ -239,13 +240,21 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||||||
goto err;
|
goto err;
|
||||||
if (sl == first_select)
|
if (sl == first_select)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
We need to create an empty table object. It is used
|
||||||
|
to create tmp_table fields in Item_type_holder.
|
||||||
|
The main reason of this is that we can't create
|
||||||
|
field object without table.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(!empty_table);
|
||||||
|
empty_table= (TABLE*) thd->calloc(sizeof(TABLE));
|
||||||
types.empty();
|
types.empty();
|
||||||
List_iterator_fast<Item> it(sl->item_list);
|
List_iterator_fast<Item> it(sl->item_list);
|
||||||
Item *item_tmp;
|
Item *item_tmp;
|
||||||
while ((item_tmp= it++))
|
while ((item_tmp= it++))
|
||||||
{
|
{
|
||||||
/* Error's in 'new' will be detected after loop */
|
/* Error's in 'new' will be detected after loop */
|
||||||
types.push_back(new Item_type_holder(thd_arg, item_tmp));
|
types.push_back(new Item_type_holder(thd_arg, item_tmp, empty_table));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thd_arg->is_fatal_error)
|
if (thd_arg->is_fatal_error)
|
||||||
@ -264,7 +273,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
|
|||||||
Item *type, *item_tmp;
|
Item *type, *item_tmp;
|
||||||
while ((type= tp++, item_tmp= it++))
|
while ((type= tp++, item_tmp= it++))
|
||||||
{
|
{
|
||||||
if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp))
|
if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp,
|
||||||
|
empty_table))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user