List:Commits« Previous MessageNext Message »
From:ingo Date:May 23 2006 9:29am
Subject:bk commit into 5.1 tree (ingo:1.2174)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 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.2174 06/05/23 11:28:57 ingo@stripped +8 -0
  Merge mysql.com:/home/mydev/mysql-5.0-bug19815
  into  mysql.com:/home/mydev/mysql-5.1-bug19815

  sql/sql_select.cc
    1.405 06/05/23 11:28:51 ingo@stripped +0 -2
    Bug#19815 - CREATE/RENAME/DROP DATABASE can deadlock on a global read lock
    Manual merge.

  sql/sql_db.cc
    1.135 06/05/23 11:28:51 ingo@stripped +0 -0
    Bug#19815 - CREATE/RENAME/DROP DATABASE can deadlock on a global read lock
    Manual merge.

  sql/field.h
    1.184 06/05/23 11:13:15 ingo@stripped +0 -0
    Auto merged

  sql/field.cc
    1.311 06/05/23 11:13:15 ingo@stripped +0 -0
    Auto merged

  mysql-test/t/view.test
    1.148 06/05/23 11:13:15 ingo@stripped +0 -0
    Auto merged

  mysql-test/t/lock_multi.test
    1.15 06/05/23 11:13:15 ingo@stripped +0 -0
    Auto merged

  mysql-test/r/view.result
    1.162 06/05/23 11:13:14 ingo@stripped +0 -0
    Auto merged

  mysql-test/r/lock_multi.result
    1.17 06/05/23 11:13:14 ingo@stripped +0 -0
    Auto merged

# 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.1-bug19815/RESYNC

--- 1.310/sql/field.cc	2006-04-11 14:25:58 +02:00
+++ 1.311/sql/field.cc	2006-05-23 11:13:15 +02:00
@@ -1223,7 +1223,7 @@
    field_name(field_name_arg),
    query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0),
    unireg_check(unireg_check_arg),
-   field_length(length_arg),null_bit(null_bit_arg)
+   field_length(length_arg), null_bit(null_bit_arg), dflt_field(0)
 {
   flags=null_ptr ? 0: NOT_NULL_FLAG;
   comment.str= (char*) "";

--- 1.183/sql/field.h	2006-04-11 05:15:45 +02:00
+++ 1.184/sql/field.h	2006-05-23 11:13:15 +02:00
@@ -55,6 +55,12 @@
   char		*ptr;			// Position to field in record
   uchar		*null_ptr;		// Byte where null_bit is
   /*
+    dflt_field is used only for the fields of temporary tables.
+    It points to the default value of the field in another table
+    from which this field has been created.
+  */ 
+  Field         *dflt_field;            // Field to copy default value from
+  /*
     Note that you can use table->in_use as replacement for current_thd member 
     only inside of val_*() and store() members (e.g. you can't use it in cons)
   */

--- 1.134/sql/sql_db.cc	2006-05-22 20:45:58 +02:00
+++ 1.135/sql/sql_db.cc	2006-05-23 11:28:51 +02:00
@@ -538,16 +538,27 @@
     my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
     DBUG_RETURN(-1);
   }
-  
-  VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
 
-  /* do not create database if another thread is holding read lock */
+  /*
+    Do not create database if another thread is holding read lock.
+    Wait for global read lock before acquiring LOCK_mysql_create_db.
+    After wait_if_global_read_lock() we have protection against another
+    global read lock. If we would acquire LOCK_mysql_create_db first,
+    another thread could step in and get the global read lock before we
+    reach wait_if_global_read_lock(). If this thread tries the same as we
+    (admin a db), it would then go and wait on LOCK_mysql_create_db...
+    Furthermore wait_if_global_read_lock() checks if the current thread
+    has the global read lock and refuses the operation with
+    ER_CANT_UPDATE_WITH_READLOCK if applicable.
+  */
   if (wait_if_global_read_lock(thd, 0, 1))
   {
     error= -1;
     goto exit2;
   }
 
+  VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
   /* Check directory */
   path_len= build_table_filename(path, sizeof(path), db, "", "");
   path[path_len-1]= 0;                    // Remove last '/' from path
@@ -655,9 +666,9 @@
   }
 
 exit:
+  VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
   start_waiting_global_read_lock(thd);
 exit2:
-  VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
   DBUG_RETURN(error);
 }
 
@@ -671,12 +682,23 @@
   int error= 0;
   DBUG_ENTER("mysql_alter_db");
 
-  VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
-
-  /* do not alter database if another thread is holding read lock */
+  /*
+    Do not alter database if another thread is holding read lock.
+    Wait for global read lock before acquiring LOCK_mysql_create_db.
+    After wait_if_global_read_lock() we have protection against another
+    global read lock. If we would acquire LOCK_mysql_create_db first,
+    another thread could step in and get the global read lock before we
+    reach wait_if_global_read_lock(). If this thread tries the same as we
+    (admin a db), it would then go and wait on LOCK_mysql_create_db...
+    Furthermore wait_if_global_read_lock() checks if the current thread
+    has the global read lock and refuses the operation with
+    ER_CANT_UPDATE_WITH_READLOCK if applicable.
+  */
   if ((error=wait_if_global_read_lock(thd,0,1)))
     goto exit2;
 
+  VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
   /* 
      Recreate db options file: /dbpath/.db.opt
      We pass MY_DB_OPT_FILE as "extension" to avoid
@@ -721,9 +743,9 @@
   send_ok(thd, result);
 
 exit:
+  VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
   start_waiting_global_read_lock(thd);
 exit2:
-  VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
   DBUG_RETURN(error);
 }
 
@@ -755,15 +777,26 @@
   TABLE_LIST* dropped_tables= 0;
   DBUG_ENTER("mysql_rm_db");
 
-  VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
-
-  /* do not drop database if another thread is holding read lock */
+  /*
+    Do not drop database if another thread is holding read lock.
+    Wait for global read lock before acquiring LOCK_mysql_create_db.
+    After wait_if_global_read_lock() we have protection against another
+    global read lock. If we would acquire LOCK_mysql_create_db first,
+    another thread could step in and get the global read lock before we
+    reach wait_if_global_read_lock(). If this thread tries the same as we
+    (admin a db), it would then go and wait on LOCK_mysql_create_db...
+    Furthermore wait_if_global_read_lock() checks if the current thread
+    has the global read lock and refuses the operation with
+    ER_CANT_UPDATE_WITH_READLOCK if applicable.
+  */
   if (wait_if_global_read_lock(thd, 0, 1))
   {
     error= -1;
     goto exit2;
   }
 
+  VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
   length= build_table_filename(path, sizeof(path), db, "", "");
   strmov(path+length, MY_DB_OPT_FILE);		// Append db option file name
   del_dbopt(path);				// Remove dboption hash entry
@@ -872,7 +905,6 @@
 exit:
   (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now  */
   error= Events::drop_schema_events(thd, db);
-  start_waiting_global_read_lock(thd);
   /*
     If this database was the client's selected database, we silently change the
     client's selected database to nothing (to have an empty SELECT DATABASE()
@@ -901,9 +933,9 @@
     thd->db= 0;
     thd->db_length= 0;
   }
-exit2:
   VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
-
+  start_waiting_global_read_lock(thd);
+exit2:
   DBUG_RETURN(error);
 }
 

--- 1.404/sql/sql_select.cc	2006-05-15 20:33:38 +02:00
+++ 1.405/sql/sql_select.cc	2006-05-23 11:28:51 +02:00
@@ -8197,6 +8197,7 @@
                         bool make_copy_field,
                         uint convert_blob_length)
 {
+  Field *result;
   Item::Type orig_type= type;
   Item *orig_item= 0;
 
@@ -8214,8 +8215,7 @@
   case Item::SUM_FUNC_ITEM:
   {
     Item_sum *item_sum=(Item_sum*) item;
-    Field *result= item_sum->create_tmp_field(group, table,
-                                              convert_blob_length);
+    result= item_sum->create_tmp_field(group, table, convert_blob_length);
     if (!result)
       thd->fatal_error();
     return result;
@@ -8225,7 +8225,6 @@
   {
     Item_field *field= (Item_field*) item;
     bool orig_modify= modify_item;
-    Field *result;
     if (orig_type == Item::REF_ITEM)
       modify_item= 0;
     /*
@@ -8259,6 +8258,8 @@
                                           convert_blob_length);
     if (orig_type == Item::REF_ITEM && orig_modify)
       ((Item_ref*)orig_item)->set_result_field(result);
+    if (field->field->eq_def(result))
+      result->dflt_field= field->field;
     return result;
   }
   /* Fall through */
@@ -8281,10 +8282,10 @@
       DBUG_ASSERT(((Item_result_field*)item)->result_field);
       *from_field= ((Item_result_field*)item)->result_field;
     }
-    return create_tmp_field_from_item(thd, item, table, (make_copy_field ? 0 :
-                                      copy_func), modify_item,
-                                      convert_blob_length);
-  case Item::TYPE_HOLDER:
+    return create_tmp_field_from_item(thd, item, table,
+                                      (make_copy_field ? 0 : copy_func),
+                                       modify_item, convert_blob_length);
+  case Item::TYPE_HOLDER:  
     return ((Item_type_holder *)item)->make_field_by_type(table);
   default:					// Dosen't have to be stored
     return 0;
@@ -8739,6 +8740,33 @@
       null_count+= (field->field_length & 7);
     }
     field->reset();
+
+    if (field->dflt_field && field->dflt_field->ptr)
+    {
+      /* 
+        field->dflt_field is set only in the cases  when 'field' can
+        inherit the default value that is defined for the field referred
+        by the Item_field object from which 'field' has been created.
+        For a field created not from a Item_field item dflt_field == 0.
+      */
+      my_ptrdiff_t diff;
+      Field *orig_field= field->dflt_field;
+      /* Get the value from default_values */
+      diff= (my_ptrdiff_t) (orig_field->table->s->default_values-
+                            orig_field->table->record[0]);
+      orig_field->move_field(diff);        // Points now at default_values
+      bool is_null= orig_field->is_real_null();
+      char *from= orig_field->ptr;
+      orig_field->move_field(-diff);       // Back to record[0]
+      if (is_null)
+        field->set_null();
+      else
+      {
+        field->set_notnull();
+        memcpy(field->ptr, from, field->pack_length());
+      }
+    } 
+
     if (from_field[i])
     {						/* Not a table Item */
       copy->set(field,from_field[i],save_sum_fields);

--- 1.161/mysql-test/r/view.result	2006-05-20 04:00:54 +02:00
+++ 1.162/mysql-test/r/view.result	2006-05-23 11:13:14 +02:00
@@ -2694,3 +2694,45 @@
 38
 DROP VIEW v1;
 DROP TABLE t1;
+CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx');
+INSERT INTO t1(id) VALUES (1), (2), (3), (4);
+INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy');
+SELECT * FROM t1;
+id	a
+1	xxx
+2	xxx
+3	xxx
+4	xxx
+5	yyy
+6	yyy
+CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a;
+SELECT * FROM v1;
+a	m
+xxx	1
+yyy	5
+CREATE TABLE t2 SELECT * FROM v1;
+INSERT INTO t2(m) VALUES (0);
+SELECT * FROM t2;
+a	m
+xxx	1
+yyy	5
+xxx	0
+DROP VIEW v1;
+DROP TABLE t1,t2;
+CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b');
+INSERT INTO t1(id) VALUES (1), (2), (3);
+INSERT INTO t1 VALUES (4,'a');
+SELECT * FROM t1;
+id	e
+1	b
+2	b
+3	b
+4	a
+CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e;
+CREATE TABLE t2 SELECT * FROM v1;
+SELECT * FROM t2;
+m	e
+4	a
+1	b
+DROP VIEW v1;
+DROP TABLE IF EXISTS t1,t2;

--- 1.147/mysql-test/t/view.test	2006-05-20 04:00:54 +02:00
+++ 1.148/mysql-test/t/view.test	2006-05-23 11:13:15 +02:00
@@ -2571,4 +2571,33 @@
 DROP VIEW v1;
 DROP TABLE t1;
 
+#
+# Bug #19089: wrong inherited dafault values in temp table views
+#
 
+CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx');
+INSERT INTO t1(id) VALUES (1), (2), (3), (4);
+INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy');
+SELECT * FROM t1;
+
+CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a;
+SELECT * FROM v1;
+
+CREATE TABLE t2 SELECT * FROM v1;
+INSERT INTO t2(m) VALUES (0);
+SELECT * FROM t2;
+
+DROP VIEW v1;
+DROP TABLE t1,t2;
+
+CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b');
+INSERT INTO t1(id) VALUES (1), (2), (3);
+INSERT INTO t1 VALUES (4,'a');
+SELECT * FROM t1;
+
+CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e;
+CREATE TABLE t2 SELECT * FROM v1;
+SELECT * FROM t2;
+
+DROP VIEW v1;
+DROP TABLE IF EXISTS t1,t2;

--- 1.16/mysql-test/r/lock_multi.result	2006-03-29 13:27:30 +02:00
+++ 1.17/mysql-test/r/lock_multi.result	2006-05-23 11:13:14 +02:00
@@ -50,3 +50,11 @@
 a	int(11)	YES		NULL	
 unlock tables;
 drop table t1;
+CREATE DATABASE mysqltest_1;
+FLUSH TABLES WITH READ LOCK;
+ DROP DATABASE mysqltest_1;
+DROP DATABASE mysqltest_1;
+ERROR HY000: Can't execute the query because you have a conflicting read lock
+UNLOCK TABLES;
+DROP DATABASE mysqltest_1;
+ERROR HY000: Can't drop database 'mysqltest_1'; database doesn't exist

--- 1.14/mysql-test/t/lock_multi.test	2006-03-29 13:27:30 +02:00
+++ 1.15/mysql-test/t/lock_multi.test	2006-05-23 11:13:15 +02:00
@@ -126,3 +126,38 @@
 connection locker;
 unlock tables;
 drop table t1;
+
+#
+# Bug#19815 - CREATE/RENAME/DROP DATABASE can deadlock on a global read lock
+#
+connect (con1,localhost,root,,);
+connect (con2,localhost,root,,);
+#
+connection con1;
+CREATE DATABASE mysqltest_1;
+FLUSH TABLES WITH READ LOCK;
+#
+# With bug in place: acquire LOCK_mysql_create_table and
+# wait in wait_if_global_read_lock().
+connection con2;
+send DROP DATABASE mysqltest_1;
+--sleep 1
+#
+# With bug in place: try to acquire LOCK_mysql_create_table...
+# When fixed: Reject dropping db because of the read lock.
+connection con1;
+--error ER_CANT_UPDATE_WITH_READLOCK
+DROP DATABASE mysqltest_1;
+UNLOCK TABLES;
+#
+connection con2;
+reap;
+#
+connection default;
+disconnect con1;
+disconnect con2;
+# This must have been dropped by connection 2 already,
+# which waited until the global read lock was released.
+--error ER_DB_DROP_EXISTS
+DROP DATABASE mysqltest_1;
+
Thread
bk commit into 5.1 tree (ingo:1.2174)ingo23 May