#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, ¬_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#3726 | Dmitry Lenev | 27 May |