• Dmitry Shulga's avatar
    MDEV-24860: Incorrect behaviour of SET STATEMENT in case it is executed as a prepared statement · 259e5243
    Dmitry Shulga authored
    Running statements with SET STATEMENT FOR clause is handled incorrectly in
    case the whole statement is executed in prepared statement mode.
    For example, running of the following statement
      SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR CREATE TABLE t1 AS SELECT CONCAT('abc') AS c1;
    results in different definition of the table t1 depending on whether
    the statement is executed as a prepared or as a regular statement.
    
    In first case the column c1 is defined as
      `c1` varchar(3) DEFAULT NULL
    in the last case the column c1 is defined as
      `c1` varchar(3) NOT NULL
    
    Different definition for the column c1 arise due to the fact that
    a value of the data memeber Item_func_concat::maybe_null depends on
    whether strict mode is on or off. Below is definition of the method
    fix_fields() of the class Item_str_func that is base class for the
    class Item_func_concat that is created on parsing the
    SET STATEMENT FOR clause.
    
    bool Item_str_func::fix_fields(THD *thd, Item **ref)
    {
      bool res= Item_func::fix_fields(thd, ref);
      /*
        In Item_str_func::check_well_formed_result() we may set null_value
        flag on the same condition as in test() below.
      */
      maybe_null= maybe_null || thd->is_strict_mode();
      return res;
    }
    
    Although the clause SET STATEMENT sql_mode = 'NO_ENGINE_SUBSTITUTION' FOR
    is parsed on PREPARE phase during processing of the prepared statement,
    real setting of the sql_mode system variable is done on EXECUTION phase.
    On the other hand, the method Item_str_func::fix_fields is called on PREPARE
    phase. In result, thd->is_strict_mode() returns true during calling the method
    Item_str_func::fix_fields(), the data member maybe_null is assigned the value
    true and column c1 is defined as DEFAULT NULL.
    
    To fix the issue the system variables listed in the SET STATEMENT FOR clause
    are set at the beginning of handling the PREPARE phase just right before
    calling  the function check_prepared_statement() and their original values
    restored immediate after return from this function.
    
    Additionally, to avoid code duplication the source code used in the function
    mysql_execute_command for setting variables, specified by SET STATEMENT
    clause, were extracted to the standalone functions
    run_set_statement_if_requested(). This new function is called from
    the function  mysql_execute_command() and the method
    Prepared_statement::prepare().
    259e5243
sql_parse.cc 318 KB