• Monty's avatar
    MDEV-6768 Wrong result with aggregate with join with no result set · 16258677
    Monty authored
    When a query does implicit grouping and join operation produces an empty
    result set, a NULL-complemented row combination is generated.
    However, constant table fields still show non-NULL values.
    
    What happens in the is that end_send_group() is called with a
    const row but without any rows matching the WHERE clause.
    This last part is shown by 'join->first_record' not being set.
    
    This causes item->no_rows_in_result() to be called for all items to reset
    all sum functions to their initial state. However fields are not set
    to NULL.
    
    The used fix is to produce NULL-complemented records for constant tables
    as well. Also, reset the constant table's records back in case we're
    in a subquery which may get re-executed.
    An alternative fix would have item->no_rows_in_result() also work
    with Item_field objects.
    
    There is some other issues with the code:
    - join->no_rows_in_result_called is used but never set.
    - Tables that are used with group functions are not properly marked as
      maybe_null, which is required if the table rows should be regarded as
      null-complemented (not existing).
    - The code that tries to detect if mixed_implicit_grouping should be set
      didn't take into account all usage of fields and sum functions.
    - Item_func::restore_to_before_no_rows_in_result() called the wrong
      function.
    - join->clear() does not use a table_map argument to clear_tables(),
      which caused it to ignore constant tables.
    - unclear_tables() does not correctly restore status to what is
      was before clear_tables().
    
    Main bug fix was to always use a table_map argument to clear_tables() and
    always use join->clear() and clear_tables() together with unclear_tables().
    
    Other fixes:
    - Fixed Item_func::restore_to_before_no_rows_in_result()
    - Set 'join->no_rows_in_result_called' when no_rows_in_result_set()
      is called.
    - Removed not used argument from setup_end_select_func().
    - More code comments
    - Ensure that end_send_group() modifies the same fields as are in the
      result set.
    - Changed return_zero_rows() to use pointers instead of references,
      similar to the rest of the code.
    
    Reviewer: Sergei Petrunia <sergey@mariadb.com>
    16258677
sql_select.h 85.8 KB