summaryrefslogtreecommitdiff
path: root/sql/item_sum.cc
diff options
context:
space:
mode:
authorAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-08-27 13:44:35 +0400
committerAlexey Kopytov <Alexey.Kopytov@Sun.com>2010-08-27 13:44:35 +0400
commitb409a2218e7fe7371ce81f71f7beb2716da8a05b (patch)
tree6fb2439f226113dcbabc50c14f731cd8e71a2994 /sql/item_sum.cc
parent2df3a61c3febba980e955158c8e46f575c1a03c4 (diff)
downloadmariadb-git-b409a2218e7fe7371ce81f71f7beb2716da8a05b.tar.gz
Bug #54465: assert: field_types == 0 || field_types[field_pos]
== MYSQL_TYPE_LONGLONG A MIN/MAX() function with a subquery as its argument could lead to a debug assertion on debug builds or wrong data on release ones. The problem was a combination of the following factors: - Item_sum_hybrid::fix_fields() might use the argument (args[0]) to calculate 'hybrid_field_type' which was later used to decide how the data should be sent to the client. - Item_sum::make_field() might use the argument again to calculate the field's type when sending result set metadata to the client. - The argument could be changed in between these two calls via Item::set_arg() leading to inconsistent metadata being reported. Here is what was happening for the bug's test case: 1. Item_sum_hybrid::fix_fields() calculates hybrid_field_type as MYSQL_TYPE_LONGLONG based on args[0] which is an Item::SUBSELECT_ITEM at that time. 2. A temporary table is created to execute the query. create_tmp_field_from_item() creates a Field_long object according to the subselect's max_length. 3. The subselect item in Item_sum_hybrid is replaced by the Item_field object referencing the newly created Field_long. 4. Item_sum::make_field() rightfully returns the MYSQL_TYPE_LONG type when calculating the result set metadata. 5. When sending the actual data, Item::send() relies on the virtual field_type() function which in our case returns previously calculated hybrid_field_type == MYSQL_TYPE_LONGLONG. It looks like the only solution is to never refer to the argument's metadata after the result metadata has been calculated in fix_fields(), since the argument itself may be different by then. In this sense, Item_sum::make_field() should never be used, because it may rely on the argument's metadata and is only called after fix_fields(). The "default" implementation in Item::make_field() should be used instead as it relies only on field_type(), but not on the argument's type. Fixed by removing Item_sum::make_field() so that the superclass implementation Item::make_field() is always used.
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r--sql/item_sum.cc20
1 files changed, 0 insertions, 20 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 25b3bd5d91d..ae9e46e2abf 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -417,26 +417,6 @@ void Item_sum::mark_as_sum_func()
}
-void Item_sum::make_field(Send_field *tmp_field)
-{
- if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
- {
- ((Item_field*) args[0])->field->make_field(tmp_field);
- /* For expressions only col_name should be non-empty string. */
- char *empty_string= (char*)"";
- tmp_field->db_name= empty_string;
- tmp_field->org_table_name= empty_string;
- tmp_field->table_name= empty_string;
- tmp_field->org_col_name= empty_string;
- tmp_field->col_name= name;
- if (maybe_null)
- tmp_field->flags&= ~NOT_NULL_FLAG;
- }
- else
- init_make_field(tmp_field, field_type());
-}
-
-
void Item_sum::print(String *str, enum_query_type query_type)
{
/* orig_args is not filled with valid values until fix_fields() */