summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <holyfoot/hf@mysql.com/deer.(none)>2006-11-09 16:08:31 +0400
committerunknown <holyfoot/hf@mysql.com/deer.(none)>2006-11-09 16:08:31 +0400
commit27aa4489ad698b7a2cd822f5c03072c2a5a28fd0 (patch)
treec5f4c418d6686b9c2f0743626e878a0546f07468 /sql
parentc13142f556713e3cf173c6c2ce82e1d25f7d7755 (diff)
parentf399d6566187d1b41b3308893730cc70e64062c8 (diff)
downloadmariadb-git-27aa4489ad698b7a2cd822f5c03072c2a5a28fd0.tar.gz
Merge bk@192.168.21.1:mysql-5.0-opt
into mysql.com:/home/hf/work/8663/my50-8663
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc2
-rw-r--r--sql/item.cc33
-rw-r--r--sql/item_subselect.cc34
-rw-r--r--sql/item_subselect.h7
-rw-r--r--sql/sql_select.cc4
5 files changed, 65 insertions, 15 deletions
diff --git a/sql/field.cc b/sql/field.cc
index a09c97fb356..61bbea5e615 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5639,7 +5639,7 @@ int Field_datetime::store_time(TIME *ltime,timestamp_type type)
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES))), &error))
{
- char buff[12];
+ char buff[19];
String str(buff, sizeof(buff), &my_charset_latin1);
make_datetime((DATE_TIME_FORMAT *) 0, ltime, &str);
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
diff --git a/sql/item.cc b/sql/item.cc
index b26f65ead69..dc92edd651d 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3707,10 +3707,37 @@ bool Item_field::fix_fields(THD *thd, Item **reference)
Item** res= find_item_in_list(this, thd->lex->current_select->item_list,
&counter, REPORT_EXCEPT_NOT_FOUND,
&not_used);
- if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM)
+ if (res != (Item **)not_found_item)
{
- set_field((*((Item_field**)res))->field);
- return 0;
+ if ((*res)->type() == Item::FIELD_ITEM)
+ {
+ /*
+ It's an Item_field referencing another Item_field in the select
+ list.
+ use the field from the Item_field in the select list and leave
+ the Item_field instance in place.
+ */
+ set_field((*((Item_field**)res))->field);
+ return 0;
+ }
+ else
+ {
+ /*
+ It's not an Item_field in the select list so we must make a new
+ Item_ref to point to the Item in the select list and replace the
+ Item_field created by the parser with the new Item_ref.
+ */
+ Item_ref *rf= new Item_ref(context, db_name,table_name,field_name);
+ if (!rf)
+ return 1;
+ thd->change_item_tree(reference, rf);
+ /*
+ Because Item_ref never substitutes itself with other items
+ in Item_ref::fix_fields(), we can safely use the original
+ pointer to it even after fix_fields()
+ */
+ return rf->fix_fields(thd, reference) || rf->check_cols(1);
+ }
}
}
if ((ret= fix_outer_field(thd, &from_field, reference)) < 0)
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 432a8882f5f..551795acd53 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -391,6 +391,15 @@ enum Item_result Item_singlerow_subselect::result_type() const
return engine->type();
}
+/*
+ Don't rely on the result type to calculate field type.
+ Ask the engine instead.
+*/
+enum_field_types Item_singlerow_subselect::field_type() const
+{
+ return engine->field_type();
+}
+
void Item_singlerow_subselect::fix_length_and_dec()
{
if ((max_columns= engine->cols()) == 1)
@@ -1613,32 +1622,36 @@ bool subselect_single_select_engine::no_rows()
}
-static Item_result set_row(List<Item> &item_list, Item *item,
- Item_cache **row, bool *maybe_null)
+/*
+ makes storage for the output values for the subquery and calcuates
+ their data and column types and their nullability.
+*/
+void subselect_engine::set_row(List<Item> &item_list, Item_cache **row)
{
- Item_result res_type= STRING_RESULT;
Item *sel_item;
List_iterator_fast<Item> li(item_list);
+ res_type= STRING_RESULT;
+ res_field_type= FIELD_TYPE_VAR_STRING;
for (uint i= 0; (sel_item= li++); i++)
{
item->max_length= sel_item->max_length;
res_type= sel_item->result_type();
+ res_field_type= sel_item->field_type();
item->decimals= sel_item->decimals;
item->unsigned_flag= sel_item->unsigned_flag;
- *maybe_null= sel_item->maybe_null;
+ maybe_null= sel_item->maybe_null;
if (!(row[i]= Item_cache::get_cache(res_type)))
- return STRING_RESULT; // we should return something
+ return;
row[i]->setup(sel_item);
}
if (item_list.elements > 1)
res_type= ROW_RESULT;
- return res_type;
}
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_list, item, row, &maybe_null);
+ set_row(select_lex->item_list, row);
item->collation.set(row[0]->collation);
if (cols() != 1)
maybe_null= 0;
@@ -1650,13 +1663,14 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row)
if (unit->first_select()->item_list.elements == 1)
{
- res_type= set_row(unit->types, item, row, &maybe_null);
+ set_row(unit->types, row);
item->collation.set(row[0]->collation);
}
else
{
- bool fake= 0;
- res_type= set_row(unit->types, item, row, &fake);
+ bool maybe_null_saved= maybe_null;
+ set_row(unit->types, row);
+ maybe_null= maybe_null_saved;
}
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 0c6ba055096..f1be99353cc 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -159,6 +159,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
enum Item_result result_type() const;
+ enum_field_types field_type() const;
void fix_length_and_dec();
uint cols();
@@ -311,6 +312,7 @@ protected:
THD *thd; /* pointer to current THD */
Item_subselect *item; /* item, that use this engine */
enum Item_result res_type; /* type of results */
+ enum_field_types res_field_type; /* column type of the results */
bool maybe_null; /* may be null (first item in select) */
public:
@@ -320,6 +322,7 @@ public:
result= res;
item= si;
res_type= STRING_RESULT;
+ res_field_type= FIELD_TYPE_VAR_STRING;
maybe_null= 0;
}
virtual ~subselect_engine() {}; // to satisfy compiler
@@ -358,6 +361,7 @@ public:
virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */
enum Item_result type() { return res_type; }
+ enum_field_types field_type() { return res_field_type; }
virtual void exclude()= 0;
bool may_be_null() { return maybe_null; };
virtual table_map upper_select_const_tables()= 0;
@@ -368,6 +372,9 @@ public:
virtual bool is_executed() const { return FALSE; }
/* Check if subquery produced any rows during last query execution */
virtual bool no_rows() = 0;
+
+protected:
+ void set_row(List<Item> &item_list, Item_cache **row);
};
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f92217302f8..cfc068cec86 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2951,10 +2951,12 @@ add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
join->unit->item->substype() == Item_subselect::IN_SUBS &&
!join->unit->first_select()->next_select())
{
+ KEY_FIELD *save= *key_fields;
add_key_fields(join, key_fields, and_level, cond, usable_tables,
sargables);
// Indicate that this ref access candidate is for subquery lookup:
- (*key_fields)[-1].outer_ref= TRUE;
+ for (; save != *key_fields; save++)
+ save->outer_ref= TRUE;
}
return;
}