diff options
author | unknown <holyfoot/hf@mysql.com/deer.(none)> | 2006-11-09 16:08:31 +0400 |
---|---|---|
committer | unknown <holyfoot/hf@mysql.com/deer.(none)> | 2006-11-09 16:08:31 +0400 |
commit | 27aa4489ad698b7a2cd822f5c03072c2a5a28fd0 (patch) | |
tree | c5f4c418d6686b9c2f0743626e878a0546f07468 /sql | |
parent | c13142f556713e3cf173c6c2ce82e1d25f7d7755 (diff) | |
parent | f399d6566187d1b41b3308893730cc70e64062c8 (diff) | |
download | mariadb-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.cc | 2 | ||||
-rw-r--r-- | sql/item.cc | 33 | ||||
-rw-r--r-- | sql/item_subselect.cc | 34 | ||||
-rw-r--r-- | sql/item_subselect.h | 7 | ||||
-rw-r--r-- | sql/sql_select.cc | 4 |
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, ¬_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; } |