summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <gluh@gluh.mysql.r18.ru>2005-02-04 16:24:00 +0300
committerunknown <gluh@gluh.mysql.r18.ru>2005-02-04 16:24:00 +0300
commit1a3a4ee3e64c6418300d9afa0ba0e402407917c8 (patch)
tree0a061e2e09da762cc5988602be849c8915d2c496
parentd3694db695be338cd157c2e1566acb7a3bf80fd9 (diff)
parentd716cb9440f5078379e040d2b4fe4ca4f98f24fb (diff)
downloadmariadb-git-1a3a4ee3e64c6418300d9afa0ba0e402407917c8.tar.gz
Merge sgluhov@bk-internal.mysql.com:/home/bk/mysql-4.1
into gluh.mysql.r18.ru:/home/gluh/MySQL/mysql-4.1
-rw-r--r--mysql-test/r/func_group.result12
-rw-r--r--mysql-test/r/union.result36
-rw-r--r--mysql-test/t/func_group.test14
-rw-r--r--mysql-test/t/union.test35
-rw-r--r--sql/field.cc35
-rw-r--r--sql/field.h1
-rw-r--r--sql/item.cc65
-rw-r--r--sql/item.h4
-rw-r--r--sql/sql_union.cc14
9 files changed, 200 insertions, 16 deletions
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index 4bb79a1cb41..fa645700875 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -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;
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index f07bdad9021..115ef6a47f9 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -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;
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 79d6112e6de..465611a5ebb 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -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;
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index 8682808f3f3..90b2197603b 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -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;
diff --git a/sql/field.cc b/sql/field.cc
index 7357bc06f11..9965cb792be 100644
--- a/sql/field.cc
+++ b/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)
diff --git a/sql/field.h b/sql/field.h
index 27a01a69273..fd0f2f9c2f1 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -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
diff --git a/sql/item.cc b/sql/item.cc
index ab29c147dfb..d61d628e8fa 100644
--- a/sql/item.cc
+++ b/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;
diff --git a/sql/item.h b/sql/item.h
index 237a8f7efac..e0de7452eec 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -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()
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 027a21db7ac..882316d57d7 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -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);
}
}