From c095f98ff7d18e2e5de1adf629147f2b199fbfaf Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Nov 2006 18:48:16 +0200 Subject: Bug #22457: Column alias in ORDER BY works, but not if in an expression The parser is allocating Item_field for references by name in ORDER BY expressions. Such expressions however may point not only to Item_field in the select list (or to a table column) but also to an arbitrary Item. This causes Item_field::fix_fields to throw an error about missing column. The fix substitutes Item_field for the reference with an Item_ref when not pointing to Item_field. mysql-test/r/order_by.result: Bug #22457: Column alias in ORDER BY works, but not if in an expression - test case mysql-test/t/order_by.test: Bug #22457: Column alias in ORDER BY works, but not if in an expression - test case sql/item.cc: Bug #22457: Column alias in ORDER BY works, but not if in an expression - transform the Item_field made by the parser into Item_ref if it doesn't point to Item_field and it is in allowed context --- sql/item.cc | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'sql/item.cc') diff --git a/sql/item.cc b/sql/item.cc index 94f0a24fcc3..45d7856b2c1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1761,10 +1761,37 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) 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(db_name,table_name,field_name); + if (!rf) + return 1; + thd->change_item_tree(ref, 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, tables, ref) || rf->check_cols(1); + } } } -- cgit v1.2.1