• Alexey Kopytov's avatar
    Bug #54465: assert: field_types == 0 || field_types[field_pos] · d7d0f639
    Alexey Kopytov authored
                == 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.
    
    mysql-test/r/func_group.result:
      Added a test case for bug #54465.
    mysql-test/t/func_group.test:
      Added a test case for bug #54465.
    sql/item_sum.cc:
      Removed Item_sum::make_field() so that the superclass
      implementation Item::make_field() is always used.
    sql/item_sum.h:
      Removed Item_sum::make_field() so that the superclass
      implementation Item::make_field() is always used.
    d7d0f639
item_sum.cc 85.7 KB