• Gleb Shchepa's avatar
    Bug #11827369: ASSERTION FAILED: !THD->LEX->CONTEXT_ANALYSIS_ONLY · 7ebfe30b
    Gleb Shchepa authored
    Some queries with the "SELECT ... FROM DUAL" nested subqueries
    failed with an assertion on debug builds.
    Non-debug builds were not affected.
    
    There were a few different issues with similar assertion
    failures on different queries:
    
    1. The first problem was related to the incomplete propagation
    of the "non-constant" item status from underlying subquery
    items to the outer item tree: in some cases non-constants were
    interpreted as constants and evaluated at the preparation stage
    (val_int() calls withing fix_fields() etc).
    
    Thus, the default implementation of Item_ref::const_item() from
    the Item parent class didn't take into account the "const_item"
    status of the referenced item tree -- it used the insufficient
    "used_tables() == 0" check instead. This worked in most cases
    since our "non-constant" functions like RAND() and SLEEP() set
    the RAND_TABLE_BIT in the used table map, so they aren't
    non-constant from Item_ref's "point of view". However, the
    "SELECT ... FROM DUAL" subquery may have an empty map of used
    tables, but at the same time subqueries are never "constant" at
    the context analysis stage (preparation, view creation etc).
    So, the non-contantness of such subqueries was missed.
    
    Fix: the Item_ref::const_item() function has been overloaded to
    take into account both (*ref)->const_item() status and tricky
    Item_ref::used_tables() return values, since the only
    (*ref)->const_item() call is not enough there.
    
    2. In some cases instead of the const_item() call we check a
    value of the Item::with_subselect field to recognize items
    with nested subqueries. However, the Item_ref class didn't
    propagate this value from the referenced item tree.
    
    Fix: Item::has_subquery() and Item_ref::has_subquery()
    functions have been backported from 5.6. All direct
    references to the with_subselect fields of nested items have
    been replaced with the has_subquery() function call.
    
    3. The Item_func_regex class didn't propagate with_subselect
    as well, since it overloads the Item_func::fix_fields()
    function with insufficient fix_fields() implementation.
    
    Fix: the Item_func_regex::fix_fields() function has been
    modified to gather "constant" statuses from inner items.
    
    4. The Item_func_isnull::update_used_tables() function has
    a special branch for the underlying item where the maybe_null
    value is false: in this case it marks the Item_func_isnull
    as a "const_item" and sets the cached_value to false.
    However, the Item_func_isnull::val_int() was not in sync with
    update_used_tables(): it didn't take into account neither
    const_item_cache nor cached_value for the case of
    "args[0]->maybe_null == false optimization".
    As far as such an Item_func_isnull has "const_item() == true",
    it's ok to call Item_func_isnull::val_int() etc from outer
    items on preparation stage. In this case the server tried to
    call Item_func_isnull::args[0]->isnull(), and if the args[0]
    item contained a nested not-nullable subquery, it failed
    with an assertion.
    
    Fix: take the value of Item_func_isnull::const_item_cache into
    account in the val_int() function.
    
    5. The auxiliary Item_is_not_null_test class has a similar
    optimization in the update_used_tables() function as the
    Item_func_isnull class has, and the same issue in the val_int()
    function.
    In addition to that the Item_is_not_null_test::update_used_tables()
    doesn't update the const_item_cache value, so the "maybe_null"
    optimization is useless there. Thus, we missed some optimizations
    of cases like these (before and after the fix):
      <  <is_not_null_test>(a),
      ---
      >  <cache>(<is_not_null_test>(a)),
    or
      < having (<is_not_null_test>(a) and <is_not_null_test>(a))
      ---
      > having 1
    etc.
    
    Fix: update Item_is_not_null_test::const_item_cache in
    update_used_tables() and take in into account in val_int().
    7ebfe30b
item_func.cc 153 KB