[prev in list] [next in list] [prev in thread] [next in thread] 

List:       mysql-internals
Subject:    bk commit into 5.0 tree (ingo:1.1934) BUG#10224
From:       ingo () mysql ! com
Date:       2005-05-31 20:15:54
Message-ID: E1DdD9U-0005eA-00 () chilla ! local
[Download RAW message or body]

Below is the list of changes that have just been committed into a local
5.0 repository of mydev. When mydev does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1934 05/05/31 22:15:43 ingo@mysql.com +9 -0
  Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
  NOT TO BE PUSHED.
  This is to show, how the requred changes for 5.0 look like,
  in case that someone needs to do an urgent merge.
  Especially sql_parse.cc will need manual attention.

  sql/sql_table.cc
    1.247 05/05/31 22:15:37 ingo@mysql.com +1 -1
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  sql/sql_parse.cc
    1.438 05/05/31 22:15:37 ingo@mysql.com +35 -3
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  sql/sql_insert.cc
    1.154 05/05/31 22:15:37 ingo@mysql.com +18 -6
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  sql/sql_handler.cc
    1.67 05/05/31 22:15:37 ingo@mysql.com +1 -1
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  sql/sql_base.cc
    1.247 05/05/31 22:15:37 ingo@mysql.com +3 -3
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  sql/mysql_priv.h
    1.302 05/05/31 22:15:37 ingo@mysql.com +5 -2
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  sql/lock.cc
    1.67 05/05/31 22:15:37 ingo@mysql.com +21 -49
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  mysql-test/t/create.test
    1.53 05/05/31 22:15:37 ingo@mysql.com +17 -0
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

  mysql-test/r/create.result
    1.90 05/05/31 22:15:37 ingo@mysql.com +9 -0
    Bug#10224 - ANALYZE TABLE crashing with simultaneous CREATE ... SELECT statement.
    NOT TO BE PUSHED.
    This is to show, how the requred changes for 5.0 look like,
    in case that someone needs to do an urgent merge.
    Especially sql_parse.cc will need manual attention.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	ingo
# Host:	chilla.local
# Root:	/home/mydev/mysql-5.0-5000

--- 1.66/sql/lock.cc	Wed Apr 27 22:58:05 2005
+++ 1.67/sql/lock.cc	Tue May 31 22:15:37 2005
@@ -82,8 +82,24 @@
 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 @@
     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 @@
       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;
@@ -948,51 +965,6 @@
     thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
   thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
   DBUG_RETURN(error);
-}
-
-
-
-/*
-  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);
 }
 
 

--- 1.301/sql/mysql_priv.h	Fri May 27 17:22:15 2005
+++ 1.302/sql/mysql_priv.h	Tue May 31 22:15:37 2005
@@ -1167,8 +1167,11 @@
 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);

--- 1.246/sql/sql_base.cc	Wed May 25 17:38:28 2005
+++ 1.247/sql/sql_base.cc	Tue May 31 22:15:37 2005
@@ -1384,7 +1384,7 @@
     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 @@
     {
       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 @@
       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())
       {

--- 1.153/sql/sql_insert.cc	Wed May 25 17:38:28 2005
+++ 1.154/sql/sql_insert.cc	Tue May 31 22:15:37 2005
@@ -1211,10 +1211,13 @@
         Avoid that a global read lock steps in while we are creating the
         new thread. It would block trying to open the table. Hence, the
         DI thread and this thread would wait until after the global
-        readlock is gone. If the read lock exists already, we leave with
-        no table and then switch to non-delayed insert.
+        readlock is gone. Since the insert thread needs to wait for a
+        global read lock anyway, we do it right now. Note that
+        wait_if_global_read_lock() sets a protection against a new
+        global read lock when it succeeds. This needs to be released by
+        start_waiting_global_read_lock().
       */
-      if (set_protect_against_global_read_lock())
+      if (wait_if_global_read_lock(thd, 0, 1))
         goto err;
       if (!(tmp=new delayed_insert()))
       {
@@ -1256,7 +1259,11 @@
 	pthread_cond_wait(&tmp->cond_client,&tmp->mutex);
       }
       pthread_mutex_unlock(&tmp->mutex);
-      unset_protect_against_global_read_lock();
+      /*
+        Release the protection against the global read lock and wake
+        everyone, who might want to set a global read lock.
+      */
+      start_waiting_global_read_lock(thd);
       thd->proc_info="got old table";
       if (tmp->thd.killed)
       {
@@ -1292,7 +1299,11 @@
 
  err1:
   thd->fatal_error();
-  unset_protect_against_global_read_lock();
+  /*
+    Release the protection against the global read lock and wake
+    everyone, who might want to set a global read lock.
+  */
+  start_waiting_global_read_lock(thd);
  err:
   pthread_mutex_unlock(&LOCK_delayed_create);
   DBUG_RETURN(0); // Continue with normal insert
@@ -1650,7 +1661,8 @@
         handler will close the table and finish when the outstanding
         inserts are done.
       */
-      if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, TRUE)))
+      if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1,
+                                          MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK)))
       {
 	/* Fatal error */
 	di->dead= 1;

--- 1.437/sql/sql_parse.cc	Fri May 27 18:30:33 2005
+++ 1.438/sql/sql_parse.cc	Tue May 31 22:15:37 2005
@@ -2773,6 +2773,24 @@
       lex->create_info.default_table_charset= lex->create_info.table_charset;
       lex->create_info.table_charset= 0;
     }
+    /*
+      The create-select command will open and read-lock the select table
+      and then create, open and write-lock the new table. If a global
+      read lock steps in, we get a deadlock. The write lock waits for
+      the global read lock, while the global read lock waits for the
+      select table to be closed. So we wait until the global readlock is
+      gone before starting both steps. Note that
+      wait_if_global_read_lock() sets a protection against a new global
+      read lock when it succeeds. This needs to be released by
+      start_waiting_global_read_lock(). We protect the normal CREATE
+      TABLE in the same way. That way we avoid that a new table is
+      created during a gobal read lock.
+    */
+    if (wait_if_global_read_lock(thd, 0, 1))
+    {
+      res= -1;
+      goto unsent_create_error;
+    }
     if (select_lex->item_list.elements)		// With select
     {
       select_result *result;
@@ -2790,7 +2808,7 @@
             unique_table(create_table, select_tables))
         {
           my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->table_name);
-          goto unsent_create_error;
+          goto unsent_create_error1;
         }
         /* If we create merge table, we have to test tables in merge, too */
         if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
@@ -2803,7 +2821,7 @@
             if (unique_table(tab, select_tables))
             {
               my_error(ER_UPDATE_TABLE_USED, MYF(0), tab->table_name);
-              goto unsent_create_error;
+              goto unsent_create_error1;
             }
           }
         }
@@ -2846,9 +2864,21 @@
       if (!res)
 	send_ok(thd);
     }
+    /*
+      Release the protection against the global read lock and wake
+      everyone, who might want to set a global read lock.
+    */
+    start_waiting_global_read_lock(thd);
     lex->link_first_table_back(create_table, link_to_local);
     break;
 
+unsent_create_error1:
+    /*
+      Release the protection against the global read lock and wake
+      everyone, who might want to set a global read lock.
+    */
+    start_waiting_global_read_lock(thd);
+
     /* put tables back for PS rexecuting */
 unsent_create_error:
     lex->link_first_table_back(create_table, link_to_local);
@@ -6922,7 +6952,8 @@
   if (select_lex->item_list.elements)
   {
     /* Check permissions for used tables in CREATE TABLE ... SELECT */
-
+#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
+    /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
     /*
       Only do the check for PS, becasue we on execute we have to check that
       against the opened tables to ensure we don't use a table that is part
@@ -6941,6 +6972,7 @@
         goto err;
       }
     }
+#endif
     if (tables && check_table_access(thd, SELECT_ACL, tables,0))
       goto err;
   }

--- 1.246/sql/sql_table.cc	Wed May 25 17:33:31 2005
+++ 1.247/sql/sql_table.cc	Tue May 31 22:15:37 2005
@@ -1756,7 +1756,7 @@
   }
 
   table->reginfo.lock_type=TL_WRITE;
-  if (!((*lock)= mysql_lock_tables(thd, &table,1)))
+  if (! ((*lock)= mysql_lock_tables(thd, &table, 1, 0)))
   {
     VOID(pthread_mutex_lock(&LOCK_open));
     hash_delete(&open_cache,(byte*) table);

--- 1.89/mysql-test/r/create.result	Sat May  7 17:34:52 2005
+++ 1.90/mysql-test/r/create.result	Tue May 31 22:15:37 2005
@@ -579,3 +579,12 @@
 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;

--- 1.52/mysql-test/t/create.test	Sat May  7 17:35:37 2005
+++ 1.53/mysql-test/t/create.test	Tue May 31 22:15:37 2005
@@ -471,3 +471,20 @@
 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;

--- 1.66/sql/sql_handler.cc	Fri Mar  4 14:34:54 2005
+++ 1.67/sql/sql_handler.cc	Tue May 31 22:15:37 2005
@@ -433,7 +433,7 @@
   protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
 
   HANDLER_TABLES_HACK(thd);
-  lock= mysql_lock_tables(thd, &tables->table, 1);
+  lock= mysql_lock_tables(thd, &tables->table, 1, 0);
   HANDLER_TABLES_HACK(thd);
 
   if (!lock)

-- 
MySQL Internals Mailing List
For list archives: http://lists.mysql.com/internals
To unsubscribe:    http://lists.mysql.com/internals?unsub=mysql-internals@progressive-comp.com

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic