• Gleb Shchepa's avatar
    Bug #45640: optimizer bug produces wrong results · 994c0f83
    Gleb Shchepa authored
    Grouping by a subquery in a query with a distinct aggregate
    function lead to a wrong result (wrong and unordered
    grouping values).
    
    There are two related problems:
    
    1) The query like this:
    
       SELECT (SELECT t1.a) aa, COUNT(DISTINCT b) c
       FROM t1 GROUP BY aa
    
    returned wrong result, because the outer reference "t1.a"
    in the subquery was substituted with the Item_ref item.
    
    The Item_ref item obtains data from the result_field object
    that refreshes once after the end of each group. This data
    is not applicable to filesort since filesort() doesn't care
    about groups (and doesn't update result_field objects with
    copy_fields() and so on). Also that data is not applicable
    to group separation algorithm: end_send_group() checks every
    record with test_if_group_changed() that evaluates Item_ref
    items, but it refreshes those Item_ref-s only after the end
    of group, that is a vicious circle and the grouped column
    values in the output are shifted.
    
    Fix: if
           a) we grouping by a subquery and
           b) that subquery has outer references to FROM list
              of the grouping query,
         then we substitute these outer references with
         Item_direct_ref like references under aggregate
         functions: Item_direct_ref obtains data directly
         from the current record.
    
    2) The query with a non-trivial grouping expression like:
    
       SELECT (SELECT t1.a) aa, COUNT(DISTINCT b) c
       FROM t1 GROUP BY aa+0
    
    also returned wrong result, since JOIN::exec() substitutes
    references to top-level aliases in SELECT list with Item_copy
    caching items. Item_copy items have same refreshing policy
    as Item_ref items, so the whole groping expression with
    Item_copy inside returns wrong result in filesort() and
    end_send_group().
    
    Fix: include aliased items into GROUP BY item tree instead
         of Item_ref references to them.
    
    
    
    mysql-test/r/group_by.result:
      Test case for bug #45640
    mysql-test/t/group_by.test:
      Test case for bug #45640
    sql/item.cc:
      Bug #45640: optimizer bug produces wrong results
      
      Item_field::fix_fields() has been modified to resolve
      aliases in GROUP BY item trees into aliased items instead
      of Item_ref items.
    sql/item.h:
      Bug #45640: optimizer bug produces wrong results
      
      - Item::find_item_processor() has been introduced.
      - Item_ref::walk() has been modified to apply processors
        to itself too (not only to referenced item).
    sql/mysql_priv.h:
      Bug #45640: optimizer bug produces wrong results
      
      fix_inner_refs() has been modified to accept group_list
      parameter.
    sql/sql_lex.cc:
      Bug #45640: optimizer bug produces wrong results
      
      Initialization of st_select_lex::group_fix_field has
      been added.
    sql/sql_lex.h:
      Bug #45640: optimizer bug produces wrong results
      
      The st_select_lex::group_fix_field field has been introduced
      to control alias resolution in Itef_fied::fix_fields.
    sql/sql_select.cc:
      Bug #45640: optimizer bug produces wrong results
      
      - The fix_inner_refs function has been modified to treat
        subquery outer references like outer fields under aggregate
        functions, if they are included in GROUP BY item tree.
      
      - The find_order_in_list function has been modified to
        fix Item_field alias fields included in the GROUP BY item
        trees in a special manner.
    994c0f83
sql_select.cc 542 KB