Commit 046ced26 authored by unknown's avatar unknown
Browse files

Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.

Manual merge from 4.1.


mysql-test/r/create.result:
  Auto merged
mysql-test/t/create.test:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/sql_handler.cc:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_yacc.yy:
  Auto merged
parents abbdab6a 10481cd0
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -579,3 +579,21 @@ select * from t2;
b
1
drop table t1,t2;
use test;
create table t1 (a int);
create table t1 select * from t1;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
create table t2 union = (t1) select * from t1;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
flush tables with read lock;
unlock tables;
drop table t1;
create table t1(column.name int);
ERROR 42000: Incorrect table name 'column'
create table t1(test.column.name int);
ERROR 42000: Incorrect table name 'column'
create table t1(xyz.t1.name int);
ERROR 42000: Incorrect database name 'xyz'
create table t1(t1.name int);
create table t2(test.t2.name int);
drop table t1,t2;
+30 −0
Original line number Diff line number Diff line
@@ -471,3 +471,33 @@ insert into t2 values ();
select * from t1;
select * from t2;
drop table t1,t2;

#
# Bug#10224 - ANALYZE TABLE crashing with simultaneous
# CREATE ... SELECT statement.
# This tests two additional possible errors and a hang if 
# an improper fix is present.
#
connection default;
use test;
create table t1 (a int);
--error 1093
create table t1 select * from t1;
--error 1093
create table t2 union = (t1) select * from t1;
flush tables with read lock;
unlock tables;
drop table t1;

#
# Bug#10413: Invalid column name is not rejected
#
--error 1103
create table t1(column.name int);
--error 1103
create table t1(test.column.name int);
--error 1102
create table t1(xyz.t1.name int);
create table t1(t1.name int);
create table t2(test.t2.name int);
drop table t1,t2;
+21 −49
Original line number Diff line number Diff line
@@ -82,8 +82,24 @@ static int unlock_external(THD *thd, TABLE **table,uint count);
static void print_lock_error(int error, const char *);


MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
                              bool ignore_global_read_lock)
/*
  Lock tables.

  SYNOPSIS
    mysql_lock_tables()
    thd                         The current thread.
    tables                      An array of pointers to the tables to lock.
    count                       The number of tables to lock.
    flags                       Options:
      MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK      Ignore a global read lock
      MYSQL_LOCK_IGNORE_FLUSH                 Ignore a flush tables.

  RETURN
    A lock structure pointer on success.
    NULL on error.
*/

MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
{
  MYSQL_LOCK *sql_lock;
  TABLE *write_lock_used;
@@ -94,7 +110,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
    if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used)))
      break;

    if (global_read_lock && write_lock_used && ! ignore_global_read_lock)
    if (global_read_lock && write_lock_used &&
        ! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
    {
      /*
	Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
@@ -128,7 +145,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
      thd->some_tables_deleted=1;		// Try again
      sql_lock->lock_count=0;			// Locks are alread freed
    }
    else if (!thd->some_tables_deleted)
    else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
    {
      thd->locked=0;
      break;
@@ -951,48 +968,3 @@ bool make_global_read_lock_block_commit(THD *thd)
}


/*
  Set protection against global read lock.

  SYNOPSIS
    set_protect_against_global_read_lock()
    void

  RETURN
    FALSE       OK, no global read lock exists.
    TRUE        Error, global read lock exists already.
*/

bool set_protect_against_global_read_lock(void)
{
  bool       global_read_lock_exists;

  pthread_mutex_lock(&LOCK_open);
  if (! (global_read_lock_exists= test(global_read_lock)))
    protect_against_global_read_lock++;
  pthread_mutex_unlock(&LOCK_open);
  return global_read_lock_exists;
}


/*
  Unset protection against global read lock.

  SYNOPSIS
    unset_protect_against_global_read_lock()
    void

  RETURN
    void
*/

void unset_protect_against_global_read_lock(void)
{
  pthread_mutex_lock(&LOCK_open);
  protect_against_global_read_lock--;
  pthread_mutex_unlock(&LOCK_open);
  pthread_cond_broadcast(&COND_refresh);
}

+5 −2
Original line number Diff line number Diff line
@@ -1166,8 +1166,11 @@ extern pthread_t signal_thread;
extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */

MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
                              bool ignore_global_read_lock= FALSE);
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags);
/* mysql_lock_tables() flags bits */
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK      0x0001
#define MYSQL_LOCK_IGNORE_FLUSH                 0x0002

void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
+3 −3
Original line number Diff line number Diff line
@@ -1384,7 +1384,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
    MYSQL_LOCK *lock;
    /* We should always get these locks */
    thd->some_tables_deleted=0;
    if ((lock=mysql_lock_tables(thd,tables,(uint) (tables_ptr-tables))))
    if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr-tables), 0)))
    {
      thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock);
    }
@@ -2022,7 +2022,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
    {
      DBUG_ASSERT(thd->lock == 0);	// You must lock everything at once
      if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
	if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
	if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0)))
	  table= 0;
    }
  }
@@ -2237,7 +2237,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
      thd->options|= OPTION_TABLE_LOCK;
    }

    if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start))))
    if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), 0)))
    {
      if (thd->lex->requires_prelocking())
      {
Loading