• Gopal Shankar's avatar
    Bug#14364558 ASSERT `TABLE_LIST->PRELOCKING_PLACEHOLDER==FALSE' · bb8d551f
    Gopal Shankar authored
                 FAILED IN CHECK_LOCK_AND_ST
    
    Problem:
    --------
    lock_tables() is supposed to invoke check_lock_and_start_stmt()
    for TABLE_LIST which are directly used by top level statement.
    TABLE_LIST->prelocking_placeholder is set only for TABLE_LIST
    which are used indirectly by stored programs invoked by top
    level statement. Hence check_lock_and_start_stmt() should have
    TABLE_LIST->prelocking_placeholder==false always, but it is
    observed that this assert fails.
    
    The failure is found during RQG test rqg_signal_resignal.
    
    Analysis:
    ---------
    open_tables() invokes open_and_process_routines() where it
    finds all the TABLE_LIST that belong to the routine and
    adds it to thd->lex->query_tables. During this process if
    the open_and_process_routines() fail for some reason,
    we are supposed to chop-off all the TABLE_LIST found during
    calls to open_and_process_routines(). But, in practice this
    is not happening.
    
    thd->lex->query_tables_own_last is supposed to point to a
    node in thd->lex->query_tables, which would be a first
    TABLE_LIST used indirectly by stored programs invoked by
    top level statement. This is found to be not-set correctly
    when we plan to chop-off TABLE_LIST's, when
    open_and_process_routines() failed.
    
    close_tables_for_reopen() does chop-off all the TABLE_LIST
    added after thd->lex->query_table_own_last. This is invoked
    upon error in open_and_process_routines(). This call would
    not work as expected as thd->lex->query_tables_own_last
    is not set, or is not set to correctly.
    
    Further, when open_tables() restarts the process of finding
    TABLE_LIST belonging to stored programs, and as the
    thd->lex->query_tables_own_last points to in-correct node,
    there is possibility of new iteration setting the
    thd->lex->query_tables_own_last past some old nodes that
    belong to stored programs, added earlier and not removed.
    Later when open_tables() completes, lock_tables() ends up
    invoking check_lock_and_start_stmt() for TABLE_LIST which
    belong to stored programs, which is not expected behavior
    and hence we hit the assert
    TABLE_LIST->prelocking_placeholder==false.
    
    Due to above behavior, if a user application tries to
    execute a SQL statement which invokes some stored function
    and if the lock grant on stored function fails due to a
    deadlock, then mysqld crashes.
    
    Fix:
    ----
    open_tables() remembers save_query_tables_last which points
    to thd-lex->query_tables_last before calls to
    open_and_process_routines(). If there is no known
    thd->lex->query_tables_own_last set, we are now setting
    thd->lex->query_tables_own_last to save_query_tables_last.
    This will make sure that the call to close_tables_for_reopen()
    will chop-off the list correctly, in other words we now
    remove all the nodes added to thd->lex->query_tables, by
    previous calls to open_and_process_routines().
    
    Further, it is found that the problem exists starting
    from 5.5, due to a code refactoring effort related to
    open_tables(). Hence, the fix will be pushed in 5.5, 5.6
    and trunk.
    bb8d551f
sql_base.cc 304 KB