Commit b1fe1d37 authored by acurtis@xiphis.org's avatar acurtis@xiphis.org

Merge xiphis.org:/anubis/bk/mysql-5.0

into  xiphis.org:/home/antony/work2/p4-bug12096.1
parents 894092be d00441e3
......@@ -85,6 +85,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
if (!my_binary_compare(keyinfo->seg[j].charset))
keyinfo->flag|= HA_END_SPACE_KEY;
keyinfo->flag|= HA_VAR_LENGTH_KEY;
length+= 2;
/* Save number of bytes used to store length */
keyinfo->seg[j].bit_start= 1;
break;
......@@ -95,6 +96,7 @@ int heap_create(const char *name, uint keys, HP_KEYDEF *keydef,
if (!my_binary_compare(keyinfo->seg[j].charset))
keyinfo->flag|= HA_END_SPACE_KEY;
keyinfo->flag|= HA_VAR_LENGTH_KEY;
length+= 2;
/* Save number of bytes used to store length */
keyinfo->seg[j].bit_start= 2;
/*
......
......@@ -718,3 +718,16 @@ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length I
t1 MEMORY 10 Fixed 0 11 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL
t2 MEMORY 10 Fixed 0 12 0 # 0 0 NULL NULL NULL NULL latin1_swedish_ci NULL
drop table t1, t2;
CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256),
KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY;
INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256));
SELECT COUNT(*) FROM t1 WHERE a='a';
COUNT(*)
2
SELECT COUNT(*) FROM t1 WHERE b='aa';
COUNT(*)
2
SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256);
COUNT(*)
2
DROP TABLE t1;
......@@ -43,3 +43,11 @@ Field Type Null Key Default Extra
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
......@@ -458,4 +458,16 @@ create table t2 (c varchar(10)) engine=memory;
show table status like 't_';
drop table t1, t2;
#
# BUG#18233 - Memory tables INDEX USING HASH (a,b) returns 1 row on
# SELECT WHERE a= AND b=
#
CREATE TABLE t1(a VARCHAR(1), b VARCHAR(2), c VARCHAR(256),
KEY(a), KEY(b), KEY(c)) ENGINE=MEMORY;
INSERT INTO t1 VALUES('a','aa',REPEAT('a', 256)),('a','aa',REPEAT('a',256));
SELECT COUNT(*) FROM t1 WHERE a='a';
SELECT COUNT(*) FROM t1 WHERE b='aa';
SELECT COUNT(*) FROM t1 WHERE c=REPEAT('a',256);
DROP TABLE t1;
# End of 5.0 tests
......@@ -107,3 +107,38 @@ show columns from t1;
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;
......@@ -425,15 +425,26 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
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 */
strxmov(path, mysql_data_home, "/", db, NullS);
path_len= unpack_dirname(path,path); // Convert if not unix
......@@ -537,9 +548,9 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
}
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);
}
......@@ -553,12 +564,23 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
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));
/* Check directory */
strxmov(path, mysql_data_home, "/", db, "/", MY_DB_OPT_FILE, NullS);
fn_format(path, path, "", "", MYF(MY_UNPACK_FILENAME));
......@@ -596,9 +618,9 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
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);
}
......@@ -630,15 +652,26 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
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));
(void) sprintf(path,"%s/%s",mysql_data_home,db);
length= unpack_dirname(path,path); // Convert if not unix
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
......@@ -747,7 +780,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
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()
......@@ -776,9 +808,9 @@ exit:
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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment