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
|
||||
three 1
|
||||
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
|
||||
drop table t1;
|
||||
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;
|
||||
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 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};
|
||||
static Field::field_cast_enum field_cast_newdate[]=
|
||||
{Field::FIELD_CAST_NEWDATE,
|
||||
Field::FIELD_CAST_DATE,
|
||||
Field::FIELD_CAST_DATETIME,
|
||||
Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING,
|
||||
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_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);
|
||||
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
|
||||
|
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()),
|
||||
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
|
||||
all JOIN::prepare calls and before any SELECT execution
|
||||
*/
|
||||
if (item->type() == Item::FIELD_ITEM)
|
||||
field_example= ((Item_field*) item)->field;
|
||||
else
|
||||
field_example= 0;
|
||||
field_example= get_holder_example_field(thd, item, table);
|
||||
max_length= real_length(item);
|
||||
maybe_null= item->maybe_null;
|
||||
collation.set(item->collation);
|
||||
@ -2692,25 +2735,23 @@ inline bool is_attr_compatible(Item *from, Item *to)
|
||||
(to->maybe_null || !from->maybe_null) &&
|
||||
(to->result_type() != STRING_RESULT ||
|
||||
from->result_type() != STRING_RESULT ||
|
||||
my_charset_same(from->collation.collation,
|
||||
to->collation.collation)));
|
||||
(from->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);
|
||||
bool use_new_field= 0, use_expression_type= 0;
|
||||
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
|
||||
can adjust column types of result table in the union smartly.
|
||||
*/
|
||||
if (field_example && item_is_a_field)
|
||||
{
|
||||
Field *field= ((Item_field *)item)->field;
|
||||
/* Can 'field_example' field store data of the column? */
|
||||
if ((use_new_field=
|
||||
(!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
|
||||
before any table is closed.
|
||||
*/
|
||||
field_example= ((Item_field*) item)->field;
|
||||
field_example= field;
|
||||
}
|
||||
|
||||
old_cs= collation.collation->name;
|
||||
|
@ -1321,14 +1321,14 @@ protected:
|
||||
Item_result orig_type;
|
||||
Field *field_example;
|
||||
public:
|
||||
Item_type_holder(THD*, Item*);
|
||||
Item_type_holder(THD*, Item*, TABLE *);
|
||||
|
||||
Item_result result_type () const { return item_type; }
|
||||
enum Type type() const { return TYPE_HOLDER; }
|
||||
double val();
|
||||
longlong val_int();
|
||||
String *val_str(String*);
|
||||
bool join_types(THD *thd, Item *);
|
||||
bool join_types(THD *thd, Item *, TABLE *);
|
||||
Field *example() { return field_example; }
|
||||
static uint32 real_length(Item *item);
|
||||
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_result *tmp_result;
|
||||
bool is_union;
|
||||
TABLE *empty_table= 0;
|
||||
DBUG_ENTER("st_select_lex_unit::prepare");
|
||||
|
||||
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;
|
||||
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();
|
||||
List_iterator_fast<Item> it(sl->item_list);
|
||||
Item *item_tmp;
|
||||
while ((item_tmp= it++))
|
||||
{
|
||||
/* 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)
|
||||
@ -264,7 +273,8 @@ 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))
|
||||
if (((Item_type_holder*)type)->join_types(thd_arg, item_tmp,
|
||||
empty_table))
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user