Commit 7aeeb8f6 authored by kostja@bodhi.(none)'s avatar kostja@bodhi.(none)
Browse files

Implement some code review fixes for the fix for Bug#27430

"Crash in subquery code when in PS and table DDL changed after PREPARE"
parent aeb2b9a8
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -90,6 +90,9 @@ extern int NEAR my_errno; /* Last error in mysys */
#define ME_COLOUR1	((1 << ME_HIGHBYTE))	/* Possibly error-colours */
#define ME_COLOUR2	((2 << ME_HIGHBYTE))
#define ME_COLOUR3	((3 << ME_HIGHBYTE))
#define ME_FATALERROR   1024    /* Fatal statement error */
#define ME_NO_WARNING_FOR_ERROR 2048 /* Don't push a warning for error */
#define ME_NO_SP_HANDLER 4096 /* Don't call stored routine error handlers */

	/* Bits in last argument to fn_format */
#define MY_REPLACE_DIR		1	/* replace dir in name with 'dir' */
+8 −4
Original line number Diff line number Diff line
@@ -3165,15 +3165,19 @@ void Item_param::print(String *str, enum_query_type query_type)
  Preserve the original parameter types and values
  when re-preparing a prepared statement.

  Copy parameter type information and conversion function
  pointers from a parameter of the old statement to the
  corresponding parameter of the new one.
  @details Copy parameter type information and conversion
  function pointers from a parameter of the old statement
  to the corresponding parameter of the new one.

  Move parameter values from the old parameters to the new
  one. We simply "exchange" the values, which allows
  to save on allocation and character set conversion in
  case a parameter is a string or a blob/clob.

  The old parameter gets the value of this one, which
  ensures that all memory of this parameter is freed
  correctly.

  @param[in]  src   parameter item of the original
                    prepared statement
*/
@@ -3187,7 +3191,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
  item_type= src->item_type;
  item_result_type= src->item_result_type;

  collation.set(src->collation.collation);
  collation.set(src->collation);
  maybe_null= src->maybe_null;
  null_value= src->null_value;
  max_length= src->max_length;
+3 −1
Original line number Diff line number Diff line
@@ -2843,6 +2843,7 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
      by the stored procedures code.
    */
    if (thd->spcont &&
        ! (MyFlags & ME_NO_SP_HANDLER) &&
        thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
    {
      /*
@@ -2852,7 +2853,8 @@ int my_message_sql(uint error, const char *str, myf MyFlags)
      DBUG_RETURN(0);
    }

    if (!thd->no_warnings_for_error)
    if (!thd->no_warnings_for_error &&
        !(MyFlags & ME_NO_WARNING_FOR_ERROR))
    {
      /*
        Suppress infinite recursion if there a memory allocation error
+14 −9
Original line number Diff line number Diff line
@@ -3722,9 +3722,8 @@ void assign_new_table_id(TABLE_SHARE *share)
  Compare metadata versions of an element obtained from the table
  definition cache and its corresponding node in the parse tree.

  If the new and the old values mismatch, invoke
  @details If the new and the old values mismatch, invoke
  Metadata_version_observer.

  At prepared statement prepare, all TABLE_LIST version values are
  NULL and we always have a mismatch. But there is no observer set
  in THD, and therefore no error is reported. Instead, we update
@@ -3738,8 +3737,8 @@ void assign_new_table_id(TABLE_SHARE *share)

  @sa Execute_observer
  @sa check_prepared_statement() to see cases when an observer is installed
  @sa TABLE_LIST::is_metadata_version_equal()
  @sa TABLE_SHARE::get_metadata_version()
  @sa TABLE_LIST::is_metadata_id_equal()
  @sa TABLE_SHARE::get_metadata_id()

  @param[in]      thd         used to report errors
  @param[in,out]  tables      TABLE_LIST instance created by the parser
@@ -3755,27 +3754,28 @@ bool
check_and_update_table_version(THD *thd,
                               TABLE_LIST *tables, TABLE_SHARE *table_share)
{
  if (! tables->is_metadata_version_equal(table_share))
  if (! tables->is_metadata_id_equal(table_share))
  {
    if (thd->m_metadata_observer &&
        thd->m_metadata_observer->check_metadata_change(thd))
        thd->m_metadata_observer->report_error(thd))
    {
      /*
        Version of the table share is different from the
        previous execution of the prepared statement, and it is
        unacceptable for this SQLCOM. Error has been reported.
      */
      DBUG_ASSERT(thd->is_error());
      return TRUE;
    }
    /* Always maintain the latest version */
    tables->set_metadata_version(table_share);
    /* Always maintain the latest version and type */
    tables->set_metadata_id(table_share);
  }
#if 0
#ifndef DBUG_OFF
  /* Spuriously reprepare each statement. */
  if (thd->m_metadata_observer && thd->stmt_arena->is_reprepared == FALSE)
  {
    thd->m_metadata_observer->check_metadata_change(thd);
    thd->m_metadata_observer->report_error(thd);
    return TRUE;
  }
#endif
@@ -3828,6 +3828,10 @@ static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,

  if (share->is_view)
  {
    /*
      This table is a view. Validate its metadata version: in particular,
      that it was a view when the statement was prepared.
    */
    if (check_and_update_table_version(thd, table_list, share))
      goto err;
    if (table_list->i_s_requested_object &  OPEN_TABLE_ONLY)
@@ -4622,6 +4626,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
    }
    tables->table->grant= tables->grant;

    /* Check and update metadata version of a base table. */
    if (check_and_update_table_version(thd, tables, tables->table->s))
    {
      result= -1;
+15 −3
Original line number Diff line number Diff line
@@ -57,16 +57,15 @@

class Metadata_version_observer
{
protected:
  virtual ~Metadata_version_observer();
public:
  virtual ~Metadata_version_observer();
  /**
    Check if a change of metadata is OK. In future
    the signature of this method may be extended to accept the old
    and the new versions, but since currently the check is very
    simple, we only need the THD to report an error.
  */
  virtual bool check_metadata_change(THD *thd)= 0;
  virtual bool report_error(THD *thd)= 0;
};


@@ -2842,6 +2841,19 @@ class select_dumpvar :public select_result_interceptor {
#define CF_STATUS_COMMAND	4
#define CF_SHOW_TABLE_COMMAND	8
#define CF_WRITE_LOGS_COMMAND  16
/**
  Must be set for SQL statements that may contain
  Item expressions and/or use joins and tables.
  Indicates that the parse tree of such statement may
  contain rule-based optimizations that depend on metadata
  (i.e. number of columns in a table), and consequently
  that the statement must be re-prepared whenever
  referenced metadata changes. Must not be set for
  statements that themselves change metadata, e.g. RENAME,
  ALTER and other DDL, since otherwise will trigger constant
  reprepare. Consequently, complex item expressions and
  joins are currently prohibited in these statements.
*/
#define CF_REEXECUTION_FRAGILE 32

/* Functions in sql_class.cc */
Loading