List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:May 27 2008 7:50pm
Subject:commit into mysql-6.0 branch (dlenev:2650) WL#3726
View as plain text  
#At file:///home/dlenev/src/bzr/mysql-6.0-3726-w/

 2650 Dmitry Lenev	2008-05-27 [merge]
      Commit after merging changes from two branches with after review
      fixes for WL#3726 "DDL locking for all metadata objects".
modified:
  mysql-test/include/query_cache_sql_prepare.inc
  mysql-test/r/query_cache_ps_no_prot.result
  mysql-test/r/query_cache_ps_ps_prot.result
  mysql-test/t/disabled.def
  sql/ha_partition.cc
  sql/ha_partition.h
  sql/handler.cc
  sql/mysql_priv.h
  sql/sql_base.cc
  sql/sql_plist.h
  sql/sql_show.cc
  sql/sql_table.cc
  sql/sql_view.cc
  sql/table.cc
  sql/table.h
  storage/myisam/ha_myisam.cc
  tests/mysql_client_test.c


=== modified file 'mysql-test/include/query_cache_sql_prepare.inc'
--- a/mysql-test/include/query_cache_sql_prepare.inc	2007-08-31 16:42:14 +0000
+++ b/mysql-test/include/query_cache_sql_prepare.inc	2008-05-26 12:12:28 +0000
@@ -1,11 +1,13 @@
 ############### include/query_cache_sql_prepare.inc ################
 #
 # This is to see how statements prepared via the PREPARE SQL command
-# go into the query cache: if using parameters they cannot; if not
-# using parameters they can.
+# go into the query cache.
 # Query cache is abbreviated as "QC"
 #
 # Last update:
+# 2008-05-26 Kostja
+#               - Add test coverage for automatic statement reprepare
+#
 # 2007-05-03 ML - Move t/query_cache_sql_prepare.test
 #                 to   include/query_cache_sql_prepare.inc
 #               - Create two toplevel tests sourcing this routine
@@ -490,6 +492,37 @@
 
 --echo
 --echo ########################################################################
+--echo #
+--echo # Bug#27430 Crash in subquery code when in PS and table DDL changed
+--echo # after PREPARE
+--echo # Check the effect of automatic reprepare on query cache
+--echo #
+--echo ########################################################################
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a varchar(255));
+insert into t1 (a) values ("Pack my box with five dozen liquor jugs.");
+flush status;
+prepare stmt from "select a from t1";
+execute stmt;
+set @@global.query_cache_size=0;
+alter table t1 add column b int;
+execute stmt;
+set @@global.query_cache_size=100000;
+execute stmt;
+execute stmt;
+--echo #
+--echo # Sic: ALTER TABLE caused an automatic reprepare 
+--echo # of the prepared statement. Since the query cache was disabled
+--echo # at the time of reprepare, the new prepared statement doesn't
+--echo # work with it.
+--echo # 
+show status like 'Qcache_hits';
+show status like 'Qcache_queries_in_cache';
+--echo # Cleanup
+deallocate prepare stmt;
+drop table t1;
 
 ###############################################################################
 

=== modified file 'mysql-test/r/query_cache_ps_no_prot.result'
--- a/mysql-test/r/query_cache_ps_no_prot.result	2007-08-31 16:42:14 +0000
+++ b/mysql-test/r/query_cache_ps_no_prot.result	2008-05-26 12:12:28 +0000
@@ -529,5 +529,46 @@
 use test;
 
 ########################################################################
+#
+# Bug#27430 Crash in subquery code when in PS and table DDL changed
+# after PREPARE
+# Check the effect of automatic reprepare on query cache
+#
+########################################################################
+drop table if exists t1;
+create table t1 (a varchar(255));
+insert into t1 (a) values ("Pack my box with five dozen liquor jugs.");
+flush status;
+prepare stmt from "select a from t1";
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+set @@global.query_cache_size=0;
+alter table t1 add column b int;
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+set @@global.query_cache_size=100000;
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+#
+# Sic: ALTER TABLE caused an automatic reprepare 
+# of the prepared statement. Since the query cache was disabled
+# at the time of reprepare, the new prepared statement doesn't
+# work with it.
+# 
+show status like 'Qcache_hits';
+Variable_name	Value
+Qcache_hits	0
+show status like 'Qcache_queries_in_cache';
+Variable_name	Value
+Qcache_queries_in_cache	0
+# Cleanup
+deallocate prepare stmt;
+drop table t1;
 set @@global.query_cache_size=@initial_query_cache_size;
 flush status;

=== modified file 'mysql-test/r/query_cache_ps_ps_prot.result'
--- a/mysql-test/r/query_cache_ps_ps_prot.result	2007-08-31 16:42:14 +0000
+++ b/mysql-test/r/query_cache_ps_ps_prot.result	2008-05-26 12:12:28 +0000
@@ -529,5 +529,46 @@
 use test;
 
 ########################################################################
+#
+# Bug#27430 Crash in subquery code when in PS and table DDL changed
+# after PREPARE
+# Check the effect of automatic reprepare on query cache
+#
+########################################################################
+drop table if exists t1;
+create table t1 (a varchar(255));
+insert into t1 (a) values ("Pack my box with five dozen liquor jugs.");
+flush status;
+prepare stmt from "select a from t1";
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+set @@global.query_cache_size=0;
+alter table t1 add column b int;
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+set @@global.query_cache_size=100000;
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+execute stmt;
+a
+Pack my box with five dozen liquor jugs.
+#
+# Sic: ALTER TABLE caused an automatic reprepare 
+# of the prepared statement. Since the query cache was disabled
+# at the time of reprepare, the new prepared statement doesn't
+# work with it.
+# 
+show status like 'Qcache_hits';
+Variable_name	Value
+Qcache_hits	0
+show status like 'Qcache_queries_in_cache';
+Variable_name	Value
+Qcache_queries_in_cache	0
+# Cleanup
+deallocate prepare stmt;
+drop table t1;
 set @@global.query_cache_size=@initial_query_cache_size;
 flush status;

=== modified file 'mysql-test/t/disabled.def'
--- a/mysql-test/t/disabled.def	2008-05-22 06:54:47 +0000
+++ b/mysql-test/t/disabled.def	2008-05-27 10:46:20 +0000
@@ -47,3 +47,4 @@
 key_buffer_size_basic_32    : Bug#36876 main.key_buffer_size_basic_32 fails on some
systems
 max_heap_table_size_basic_32 : Bug#36877 main.max_heap_table_size_basic_32 fails on some
systems
 tmp_table_size_basic_32     : Bug#36878 main.tmp_table_size_basic_32 fails on some
systems
+merge                       : Temporarily broken by WL#3726

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2008-05-14 13:49:41 +0000
+++ b/sql/ha_partition.cc	2008-05-27 12:15:44 +0000
@@ -2402,7 +2402,7 @@
     for the same table.
   */
   if (is_not_tmp_table)
-    pthread_mutex_lock(&table_share->mutex);
+    pthread_mutex_lock(&table_share->LOCK_ha_data);
   if (!table_share->ha_data)
   {
     HA_DATA_PARTITION *ha_data;
@@ -2416,7 +2416,7 @@
     bzero(ha_data, sizeof(HA_DATA_PARTITION));
   }
   if (is_not_tmp_table)
-    pthread_mutex_unlock(&table_share->mutex);
+    pthread_mutex_unlock(&table_share->LOCK_ha_data);
   /*
     Some handlers update statistics as part of the open call. This will in
     some cases corrupt the statistics of the partition handler and thus

=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h	2008-05-08 13:01:30 +0000
+++ b/sql/ha_partition.h	2008-05-27 12:15:44 +0000
@@ -861,7 +861,7 @@
     if(table_share->tmp_table == NO_TMP_TABLE)
     {
       auto_increment_lock= TRUE;
-      pthread_mutex_lock(&table_share->mutex);
+      pthread_mutex_lock(&table_share->LOCK_ha_data);
     }
   }
   virtual void unlock_auto_increment()
@@ -874,7 +874,7 @@
     */
     if(auto_increment_lock && !auto_increment_safe_stmt_log_lock)
     {
-      pthread_mutex_unlock(&table_share->mutex);
+      pthread_mutex_unlock(&table_share->LOCK_ha_data);
       auto_increment_lock= FALSE;
     }
   }

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	2008-05-23 13:54:03 +0000
+++ b/sql/handler.cc	2008-05-27 10:44:38 +0000
@@ -3253,8 +3253,8 @@
 int
 handler::ha_change_partitions(HA_CREATE_INFO *create_info,
                      const char *path,
-                     ulonglong *copied,
-                     ulonglong *deleted,
+                     ulonglong * const copied,
+                     ulonglong * const deleted,
                      const uchar *pack_frm_data,
                      size_t pack_frm_len)
 {

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2008-05-27 17:31:53 +0000
+++ b/sql/mysql_priv.h	2008-05-27 17:50:29 +0000
@@ -1314,7 +1314,7 @@
                           bool tmp_table);
 TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
                              uint key_length, uint db_flags, int *error);
-void release_table_share(TABLE_SHARE *share, enum release_type type);
+void release_table_share(TABLE_SHARE *share);
 TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name);
 TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update,
                    uint lock_flags);

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2008-05-27 17:31:53 +0000
+++ b/sql/sql_base.cc	2008-05-27 17:50:29 +0000
@@ -103,7 +103,6 @@
 TABLE *unused_tables;
 HASH table_def_cache;
 static TABLE_SHARE *oldest_unused_share, end_of_unused_share;
-static pthread_mutex_t LOCK_table_share;
 static bool table_def_inited= 0;
 
 static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables,
@@ -240,13 +239,12 @@
 static void table_def_free_entry(TABLE_SHARE *share)
 {
   DBUG_ENTER("table_def_free_entry");
+  safe_mutex_assert_owner(&LOCK_open);
   if (share->prev)
   {
     /* remove from old_unused_share list */
-    pthread_mutex_lock(&LOCK_table_share);
     *share->prev= share->next;
     share->next->prev= share->prev;
-    pthread_mutex_unlock(&LOCK_table_share);
   }
   free_table_share(share);
   DBUG_VOID_RETURN;
@@ -256,7 +254,6 @@
 bool table_def_init(void)
 {
   table_def_inited= 1;
-  pthread_mutex_init(&LOCK_table_share, MY_MUTEX_INIT_FAST);
   oldest_unused_share= &end_of_unused_share;
   end_of_unused_share.prev= &oldest_unused_share;
 
@@ -274,7 +271,6 @@
     /* Free all open TABLEs first. */
     close_cached_tables(NULL, NULL, FALSE, FALSE);
     table_def_inited= 0;
-    pthread_mutex_destroy(&LOCK_table_share);
     /* Free table definitions. */
     hash_free(&table_def_cache);
   }
@@ -461,12 +457,6 @@
   }
 
   /*
-    Lock mutex to be able to read table definition from file without
-    conflicts
-  */
-  (void) pthread_mutex_lock(&share->mutex);
-
-  /*
     We assign a new table id under the protection of the LOCK_open and
     the share's own mutex.  We do this insted of creating a new mutex
     and using it for the sole purpose of serializing accesses to a
@@ -495,7 +485,6 @@
   share->ref_count++;				// Mark in use
   DBUG_PRINT("exit", ("share: %p  ref_count: %u",
                       share, share->ref_count));
-  (void) pthread_mutex_unlock(&share->mutex);
   DBUG_RETURN(share);
 
 found:
@@ -503,20 +492,15 @@
      We found an existing table definition. Return it if we didn't get
      an error when reading the table definition from file.
   */
-
-  /* We must do a lock to ensure that the structure is initialized */
-  (void) pthread_mutex_lock(&share->mutex);
   if (share->error)
   {
     /* Table definition contained an error */
     open_table_error(share, share->error, share->open_errno, share->errarg);
-    (void) pthread_mutex_unlock(&share->mutex);
     DBUG_RETURN(0);
   }
   if (share->is_view && !(db_flags & OPEN_VIEW))
   {
     open_table_error(share, 1, ENOENT, 0);
-    (void) pthread_mutex_unlock(&share->mutex);
     DBUG_RETURN(0);
   }
 
@@ -527,22 +511,16 @@
       Unlink share from this list
     */
     DBUG_PRINT("info", ("Unlinking from not used list"));
-    pthread_mutex_lock(&LOCK_table_share);
     *share->prev= share->next;
     share->next->prev= share->prev;
     share->next= 0;
     share->prev= 0;
-    pthread_mutex_unlock(&LOCK_table_share);
   }
-  (void) pthread_mutex_unlock(&share->mutex);
 
    /* Free cache if too big */
   while (table_def_cache.records > table_def_size &&
          oldest_unused_share->next)
-  {
-    pthread_mutex_lock(&oldest_unused_share->mutex);
     hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
-  }
 
   DBUG_PRINT("exit", ("share: %p  ref_count: %u",
                       share, share->ref_count));
@@ -629,29 +607,17 @@
                               db_flags, error));
 }
 
-
-/* 
-   Mark that we are not using table share anymore.
-
-   SYNOPSIS
-     release_table_share()
-     share		Table share
-     release_type	How the release should be done:
-     			RELEASE_NORMAL
-                         - Release without checking
-                        RELEASE_WAIT_FOR_DROP
-                         - Don't return until we get a signal that the
-                           table is deleted or the thread is killed.
-
-   IMPLEMENTATION
-     If ref_count goes to zero and (we have done a refresh or if we have
-     already too many open table shares) then delete the definition.
-
-     If type == RELEASE_WAIT_FOR_DROP then don't return until we get a signal
-     that the table is deleted or the thread is killed.
+/**
+  Mark that we are not using table share anymore.
+
+  @param  share   Table share
+
+  If the share has no open tables and (we have done a refresh or
+  if we have already too many open table shares) then delete the
+  definition.
 */
 
-void release_table_share(TABLE_SHARE *share, enum release_type type)
+void release_table_share(TABLE_SHARE *share)
 {
   bool to_be_deleted= 0;
   DBUG_ENTER("release_table_share");
@@ -662,7 +628,6 @@
 
   safe_mutex_assert_owner(&LOCK_open);
 
-  pthread_mutex_lock(&share->mutex);
   if (!--share->ref_count)
   {
     if (share->version != refresh_version)
@@ -673,12 +638,10 @@
       DBUG_PRINT("info",("moving share to unused list"));
 
       DBUG_ASSERT(share->next == 0);
-      pthread_mutex_lock(&LOCK_table_share);
       share->prev= end_of_unused_share.prev;
       *end_of_unused_share.prev= share;
       end_of_unused_share.prev= &share->next;
       share->next= &end_of_unused_share;
-      pthread_mutex_unlock(&LOCK_table_share);
 
       to_be_deleted= (table_def_cache.records > table_def_size);
     }
@@ -688,9 +651,7 @@
   {
     DBUG_PRINT("info", ("Deleting share"));
     hash_delete(&table_def_cache, (uchar*) share);
-    DBUG_VOID_RETURN;
   }
-  pthread_mutex_unlock(&share->mutex);
   DBUG_VOID_RETURN;
 }
 
@@ -733,9 +694,8 @@
 {
   DBUG_ENTER("reference_table_share");
   DBUG_ASSERT(share->ref_count);
-  pthread_mutex_lock(&share->mutex);
+  safe_mutex_assert_owner(&LOCK_open);
   share->ref_count++;
-  pthread_mutex_unlock(&share->mutex);
   DBUG_PRINT("exit", ("share: 0x%lx  ref_count: %u",
                      (ulong) share, share->ref_count));
   DBUG_VOID_RETURN;
@@ -794,7 +754,7 @@
   table->file->close();
   table->db_stat= 0;                            // Mark file closed
   table_def_change_share(table, share);
-  release_table_share(table->s, RELEASE_NORMAL);
+  release_table_share(table->s);
   table->s= share;
   table->file->change_table_ptr(table, table->s);
 
@@ -1031,10 +991,7 @@
     free_cache_entry(unused_tables);
   /* Free table shares */
   while (oldest_unused_share->next)
-  {
-    pthread_mutex_lock(&oldest_unused_share->mutex);
     (void) hash_delete(&table_def_cache, (uchar*) oldest_unused_share);
-  }
 
   if (!wait_for_refresh)
   {
@@ -2508,7 +2465,7 @@
 void table_share_release_hook(void *share)
 {
   pthread_mutex_lock(&LOCK_open);
-  release_table_share((TABLE_SHARE*)share, RELEASE_NORMAL);
+  release_table_share((TABLE_SHARE*) share);
   broadcast_refresh();
   pthread_mutex_unlock(&LOCK_open);
 }
@@ -2858,7 +2815,7 @@
         goto err_unlock;
 
       /* TODO: Don't free this */
-      release_table_share(share, RELEASE_NORMAL);
+      release_table_share(share);
 
       if (flags & OPEN_VIEW_NO_PARSE)
       {
@@ -2934,7 +2891,7 @@
     {
       if (action)
         *action= OT_BACK_OFF_AND_RETRY;
-      release_table_share(share, RELEASE_NORMAL);
+      release_table_share(share);
       pthread_mutex_unlock(&LOCK_open);
       DBUG_RETURN(0);
     }
@@ -2947,7 +2904,7 @@
     table= share->free_tables.head();
     table_def_use_table(thd, table);
     /* We need to release share as we have EXTRA reference to it in our hands. */
-    release_table_share(share, RELEASE_NORMAL);
+    release_table_share(share);
   }
   else
   {
@@ -3049,7 +3006,7 @@
   DBUG_RETURN(table);
 
 err_unlock:
-  release_table_share(share, RELEASE_NORMAL);
+  release_table_share(share);
 err_unlock2:
   pthread_mutex_unlock(&LOCK_open);
   mdl_release_lock(&thd->mdl_context, mdl_lock);
@@ -3703,13 +3660,13 @@
                     flags, thd->open_options, &not_used, table_list,
                     mem_root))
   {
-    release_table_share(share, RELEASE_NORMAL);
+    release_table_share(share);
     pthread_mutex_unlock(&LOCK_open);
     return FALSE;
   }
 
   my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str, "VIEW");
-  release_table_share(share, RELEASE_NORMAL);
+  release_table_share(share);
 err:
   pthread_mutex_unlock(&LOCK_open);
   return TRUE;
@@ -3773,7 +3730,7 @@
     if (table_list->i_s_requested_object &  OPEN_TABLE_ONLY)
       goto err;
     /* Attempt to reopen view will bring havoc to upper layers anyway. */
-    release_table_share(share, RELEASE_NORMAL);
+    release_table_share(share);
     my_error(ER_WRONG_OBJECT, MYF(0), share->db.str, share->table_name.str,
              "BASE TABLE");
     DBUG_RETURN(1);
@@ -3806,7 +3763,7 @@
       if (share->ref_count != 1)
         goto err;
 
-      release_table_share(share, RELEASE_NORMAL);
+      release_table_share(share);
 
       if (ha_create_table_from_engine(thd, table_list->db,
                                       table_list->table_name))
@@ -3823,7 +3780,7 @@
     entry->s->version= 0;
 
     /* TODO: We don't need to release share here. */
-    release_table_share(share, RELEASE_NORMAL);
+    release_table_share(share);
     pthread_mutex_unlock(&LOCK_open);
     error= (int)auto_repair_table(thd, table_list);
     pthread_mutex_lock(&LOCK_open);
@@ -3843,7 +3800,7 @@
   DBUG_RETURN(0);
 
 err:
-  release_table_share(share, RELEASE_NORMAL);
+  release_table_share(share);
   DBUG_RETURN(1);
 }
 
@@ -3965,7 +3922,7 @@
   pthread_mutex_lock(&LOCK_open);
 
 end_with_lock_open:
-  release_table_share(share, RELEASE_NORMAL);
+  release_table_share(share);
   pthread_mutex_unlock(&LOCK_open);
   return result;
 }
@@ -8376,10 +8333,7 @@
       DBUG_PRINT("info", ("share version: %lu  ref_count: %u",
                           share->version, share->ref_count));
       if (share->ref_count == 0)
-      {
-        pthread_mutex_lock(&share->mutex);
         hash_delete(&table_def_cache, (uchar*) share);
-      }
     }
 
     if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG))
@@ -8517,10 +8471,7 @@
   {
     DBUG_ASSERT(leave_thd || share->ref_count == 0);
     if (share->ref_count == 0)
-    {
-      pthread_mutex_lock(&share->mutex);
       hash_delete(&table_def_cache, (uchar*) share);
-    }
   }
 }
 

=== modified file 'sql/sql_plist.h'
--- a/sql/sql_plist.h	2008-05-24 10:03:45 +0000
+++ b/sql/sql_plist.h	2008-05-27 09:45:34 +0000
@@ -62,7 +62,7 @@
 public:
   I_P_List() : first(NULL) { };
   inline void empty()      { first= NULL; }
-  inline bool is_empty()   { return (first == NULL); }
+  inline bool is_empty() const { return (first == NULL); }
   inline void push_front(T* a)
   {
     *B::next_ptr(a)= first;

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2008-05-23 13:54:03 +0000
+++ b/sql/sql_show.cc	2008-05-27 09:45:34 +0000
@@ -3205,7 +3205,7 @@
   }
 
 err_share:
-  release_table_share(share, RELEASE_NORMAL);
+  release_table_share(share);
 
 err_unlock:
   pthread_mutex_unlock(&LOCK_open);

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2008-05-24 20:33:22 +0000
+++ b/sql/sql_table.cc	2008-05-27 09:45:34 +0000
@@ -4007,7 +4007,7 @@
 
     if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, OTM_OPEN))
     {
-      release_table_share(share, RELEASE_NORMAL);
+      release_table_share(share);
       pthread_mutex_unlock(&LOCK_open);
       DBUG_RETURN(0);                           // Out of memory
     }

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2008-05-23 13:54:03 +0000
+++ b/sql/sql_view.cc	2008-05-27 12:15:44 +0000
@@ -1633,11 +1633,9 @@
     if ((share= get_cached_table_share(view->db, view->table_name)))
     {
       DBUG_ASSERT(share->ref_count == 0);
-      pthread_mutex_lock(&share->mutex);
       share->ref_count++;
       share->version= 0;
-      pthread_mutex_unlock(&share->mutex);
-      release_table_share(share, RELEASE_WAIT_FOR_DROP);
+      release_table_share(share);
     }
     query_cache_invalidate3(thd, view, 0);
     sp_cache_invalidate();

=== modified file 'sql/table.cc'
--- a/sql/table.cc	2008-05-24 10:03:45 +0000
+++ b/sql/table.cc	2008-05-27 12:15:44 +0000
@@ -346,8 +346,7 @@
     share->free_tables.empty();
 
     memcpy((char*) &share->mem_root, (char*) &mem_root, sizeof(mem_root));
-    pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
-    pthread_cond_init(&share->cond, NULL);
+    pthread_mutex_init(&share->LOCK_ha_data, MY_MUTEX_INIT_FAST);
   }
   DBUG_RETURN(share);
 }
@@ -436,25 +435,11 @@
   DBUG_PRINT("enter", ("table: %s.%s", share->db.str, share->table_name.str));
   DBUG_ASSERT(share->ref_count == 0);
 
-  /*
-    If someone is waiting for this to be deleted, inform it about this.
-    Don't do a delete until we know that no one is refering to this anymore.
-  */
+  /* The mutex is initialized only for shares that are part of the TDC */
   if (share->tmp_table == NO_TMP_TABLE)
-  {
-    /* share->mutex is locked in release_table_share() */
-    while (share->waiting_on_cond)
-    {
-      pthread_cond_broadcast(&share->cond);
-      pthread_cond_wait(&share->cond, &share->mutex);
-    }
-    /* No thread refers to this anymore */
-    pthread_mutex_unlock(&share->mutex);
-    pthread_mutex_destroy(&share->mutex);
-    pthread_cond_destroy(&share->cond);
-  }
+    pthread_mutex_destroy(&share->LOCK_ha_data);
   hash_free(&share->name_hash);
-  
+
   plugin_unlock(NULL, share->db_plugin);
   share->db_plugin= NULL;
 
@@ -2117,7 +2102,7 @@
   if (free_share)
   {
     if (table->s->tmp_table == NO_TMP_TABLE)
-      release_table_share(table->s, RELEASE_NORMAL);
+      release_table_share(table->s);
     else
       free_table_share(table->s);
   }

=== modified file 'sql/table.h'
--- a/sql/table.h	2008-05-24 10:03:45 +0000
+++ b/sql/table.h	2008-05-27 12:15:44 +0000
@@ -258,8 +258,7 @@
   TYPELIB keynames;			/* Pointers to keynames */
   TYPELIB fieldnames;			/* Pointer to fieldnames */
   TYPELIB *intervals;			/* pointer to interval info */
-  pthread_mutex_t mutex;                /* For locking the share  */
-  pthread_cond_t cond;			/* To signal that share is ready */
+  pthread_mutex_t LOCK_ha_data;         /* To protect access to ha_data */
   struct st_table_share *next,		/* Link to unused shares */
     **prev;
 
@@ -359,7 +358,6 @@
   bool crashed;
   bool is_view;
   bool name_lock, replace_with_name_lock;
-  bool waiting_on_cond;                 /* Protection against free */
   ulong table_map_id;                   /* for row-based replication */
   ulonglong table_map_version;
 

=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc	2008-05-08 16:01:15 +0000
+++ b/storage/myisam/ha_myisam.cc	2008-05-27 12:15:44 +0000
@@ -1669,7 +1669,7 @@
 
     /* Update share */
     if (share->tmp_table == NO_TMP_TABLE)
-      pthread_mutex_lock(&share->mutex);
+      pthread_mutex_lock(&share->LOCK_ha_data);
     share->keys_in_use.set_prefix(share->keys);
     share->keys_in_use.intersect_extended(misam_info.key_map);
     share->keys_for_keyread.intersect(share->keys_in_use);
@@ -1679,7 +1679,7 @@
 	     (char*) misam_info.rec_per_key,
 	     sizeof(table->key_info[0].rec_per_key)*share->key_parts);
     if (share->tmp_table == NO_TMP_TABLE)
-      pthread_mutex_unlock(&share->mutex);
+      pthread_mutex_unlock(&share->LOCK_ha_data);
 
    /*
      Set data_file_name and index_file_name to point at the symlink value

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2008-05-21 10:17:29 +0000
+++ b/tests/mysql_client_test.c	2008-05-26 12:12:28 +0000
@@ -664,6 +664,29 @@
   return row_count;
 }
 
+/* Print the total number of warnings and the warnings themselves.  */
+
+void my_process_warnings(MYSQL *conn, unsigned expected_warning_count)
+{
+  MYSQL_RES *result;
+  int rc;
+
+  if (!opt_silent)
+    fprintf(stdout, "\n total warnings: %u (expected: %u)\n",
+            mysql_warning_count(conn), expected_warning_count);
+
+  DIE_UNLESS(mysql_warning_count(mysql) == expected_warning_count);
+
+  rc= mysql_query(conn, "SHOW WARNINGS");
+  DIE_UNLESS(rc == 0);
+
+  result= mysql_store_result(conn);
+  mytest(result);
+
+  rc= my_process_result_set(result);
+  mysql_free_result(result);
+}
+
 
 /* Utility function to verify a particular column data */
 
@@ -12491,7 +12514,7 @@
 
   rc= mysql_stmt_execute(stmt);
   check_execute(stmt, rc);
-  DIE_UNLESS(mysql_warning_count(mysql) != 6);
+  my_process_warnings(mysql, 12);
 
   verify_col_data("t1", "year", "0000-00-00 00:00:00");
   verify_col_data("t1", "month", "0000-00-00 00:00:00");
@@ -12522,7 +12545,7 @@
 
   rc= mysql_stmt_execute(stmt);
   check_execute(stmt, rc);
-  DIE_UNLESS(mysql_warning_count(mysql) != 3);
+  my_process_warnings(mysql, 6);
 
   verify_col_data("t1", "year", "0000-00-00 00:00:00");
   verify_col_data("t1", "month", "0000-00-00 00:00:00");
@@ -12561,7 +12584,7 @@
 
   rc= mysql_stmt_execute(stmt);
   check_execute(stmt, rc);
-  DIE_UNLESS(mysql_warning_count(mysql) == 2);
+  my_process_warnings(mysql, 2);
 
   verify_col_data("t1", "day_ovfl", "838:59:59");
   verify_col_data("t1", "day", "828:30:30");
@@ -17599,6 +17622,167 @@
 
 }
 
+
+/**
+  Test how warnings generated during assignment of parameters
+  are (currently not) preserve in case of reprepare.
+*/
+
+static void test_wl4166_3()
+{
+  int rc;
+  MYSQL_STMT *stmt;
+  MYSQL_BIND my_bind[1];
+  MYSQL_TIME tm[1];
+
+  myheader("test_wl4166_3");
+
+  rc= mysql_query(mysql, "drop table if exists t1");
+  myquery(rc);
+
+  rc= mysql_query(mysql, "create table t1 (year datetime)");
+  myquery(rc);
+
+  stmt= mysql_simple_prepare(mysql, "insert into t1 (year) values (?)");
+  check_stmt(stmt);
+  verify_param_count(stmt, 1);
+
+  bzero((char*) my_bind, sizeof(my_bind));
+  my_bind[0].buffer_type= MYSQL_TYPE_DATETIME;
+  my_bind[0].buffer= &tm[0];
+
+  rc= mysql_stmt_bind_param(stmt, my_bind);
+  check_execute(stmt, rc);
+
+  tm[0].year= 10000;
+  tm[0].month= 1; tm[0].day= 1;
+  tm[0].hour= 1; tm[0].minute= 1; tm[0].second= 1;
+  tm[0].second_part= 0; tm[0].neg= 0;
+
+  /* Cause a statement reprepare */
+  rc= mysql_query(mysql, "alter table t1 add column c int");
+  myquery(rc);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+  /*
+    Sic: only one warning, instead of two. The warning
+    about data truncation when assigning a parameter is lost.
+    This is a bug.
+  */
+  my_process_warnings(mysql, 1);
+
+  verify_col_data("t1", "year", "0000-00-00 00:00:00");
+
+  mysql_stmt_close(stmt);
+
+  rc= mysql_query(mysql, "drop table t1");
+  myquery(rc);
+}
+
+
+/**
+  Test that long data parameters, as well as parameters
+  that were originally in a different character set, are
+  preserved in case of reprepare.
+*/
+
+static void test_wl4166_4()
+{
+  MYSQL_STMT *stmt;
+  int rc;
+  const char *stmt_text;
+  MYSQL_BIND bind_array[2];
+
+  /* Represented as numbers to keep UTF8 tools from clobbering them. */
+  const char *koi8= "\xee\xd5\x2c\x20\xda\xc1\x20\xd2\xd9\xc2\xc1\xcc\xcb\xd5";
+  const char *cp1251= "\xcd\xf3\x2c\x20\xe7\xe0\x20\xf0\xfb\xe1\xe0\xeb\xea\xf3";
+  char buf1[16], buf2[16];
+  ulong buf1_len, buf2_len;
+
+  myheader("test_wl4166_4");
+
+  rc= mysql_query(mysql, "drop table if exists t1");
+  myquery(rc);
+
+  /*
+    Create table with binary columns, set session character set to cp1251,
+    client character set to koi8, and make sure that there is conversion
+    on insert and no conversion on select
+  */
+  rc= mysql_query(mysql,
+                  "create table t1 (c1 varbinary(255), c2 varbinary(255))");
+  myquery(rc);
+  rc= mysql_query(mysql, "set character_set_client=koi8r, "
+                         "character_set_connection=cp1251, "
+                         "character_set_results=koi8r");
+  myquery(rc);
+
+  bzero((char*) bind_array, sizeof(bind_array));
+
+  bind_array[0].buffer_type= MYSQL_TYPE_STRING;
+
+  bind_array[1].buffer_type= MYSQL_TYPE_STRING;
+  bind_array[1].buffer= (void *) koi8;
+  bind_array[1].buffer_length= strlen(koi8);
+
+  stmt= mysql_stmt_init(mysql);
+  check_stmt(stmt);
+
+  stmt_text= "insert into t1 (c1, c2) values (?, ?)";
+
+  rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+  check_execute(stmt, rc);
+
+  mysql_stmt_bind_param(stmt, bind_array);
+
+  mysql_stmt_send_long_data(stmt, 0, koi8, strlen(koi8));
+
+  /* Cause a reprepare at statement execute */
+  rc= mysql_query(mysql, "alter table t1 add column d int");
+  myquery(rc);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  stmt_text= "select c1, c2 from t1";
+
+  /* c1 and c2 are binary so no conversion will be done on select */
+  rc= mysql_stmt_prepare(stmt, stmt_text, strlen(stmt_text));
+  check_execute(stmt, rc);
+
+  rc= mysql_stmt_execute(stmt);
+  check_execute(stmt, rc);
+
+  bind_array[0].buffer= buf1;
+  bind_array[0].buffer_length= sizeof(buf1);
+  bind_array[0].length= &buf1_len;
+
+  bind_array[1].buffer= buf2;
+  bind_array[1].buffer_length= sizeof(buf2);
+  bind_array[1].length= &buf2_len;
+
+  mysql_stmt_bind_result(stmt, bind_array);
+
+  rc= mysql_stmt_fetch(stmt);
+  check_execute(stmt, rc);
+
+  DIE_UNLESS(buf1_len == strlen(cp1251));
+  DIE_UNLESS(buf2_len == strlen(cp1251));
+  DIE_UNLESS(!memcmp(buf1, cp1251, buf1_len));
+  DIE_UNLESS(!memcmp(buf2, cp1251, buf1_len));
+
+  rc= mysql_stmt_fetch(stmt);
+  DIE_UNLESS(rc == MYSQL_NO_DATA);
+
+  mysql_stmt_close(stmt);
+
+  rc= mysql_query(mysql, "drop table t1");
+  myquery(rc);
+  rc= mysql_query(mysql, "set names default");
+  myquery(rc);
+}
+
 /**
   Bug#36004 mysql_stmt_prepare resets the list of warnings
 */
@@ -17951,6 +18135,8 @@
   { "test_bug28386", test_bug28386 },
   { "test_wl4166_1", test_wl4166_1 },
   { "test_wl4166_2", test_wl4166_2 },
+  { "test_wl4166_3", test_wl4166_3 },
+  { "test_wl4166_4", test_wl4166_4 },
   { "test_bug36004", test_bug36004 },
   { 0, 0 }
 };

Thread
commit into mysql-6.0 branch (dlenev:2650) WL#3726Dmitry Lenev27 May