Commit 1748234b authored by Jon Olav Hauglid's avatar Jon Olav Hauglid

Merge from mysql-5.5-bugfixing to mysql-5.5-runtime.

parents 42d5298b 5d873f58
......@@ -93,6 +93,7 @@ extern "C" {
#else
#include <readline/readline.h>
#define HAVE_READLINE
#define USE_POPEN
#endif
//int vidattr(long unsigned int attrs); // Was missing in sun curses
}
......@@ -108,10 +109,6 @@ extern "C" {
#define cmp_database(cs,A,B) strcmp((A),(B))
#endif
#if !defined(__WIN__) && !defined(THREAD)
#define USE_POPEN
#endif
#include "completion_hash.h"
#define PROMPT_CHAR '\\'
......
......@@ -16,6 +16,7 @@
INSTALL(
DIRECTORY .
DESTINATION ${INSTALL_MYSQLTESTDIR}
USE_SOURCE_PERMISSIONS
COMPONENT Test
PATTERN "var/" EXCLUDE
PATTERN "lib/My/SafeProcess" EXCLUDE
......
......@@ -1100,5 +1100,19 @@ my_col
00
DROP TABLE t1;
#
# Bug#55912 FORMAT with locale set fails for numbers < 1000
#
SET collation_connection=utf32_general_ci;
CREATE TABLE t1 AS SELECT format(123,2,'no_NO');
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`format(123,2,'no_NO')` varchar(37) CHARACTER SET utf32 NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT * FROM t1;
format(123,2,'no_NO')
123,00
DROP TABLE t1;
#
# End of 5.5 tests
#
......@@ -345,3 +345,78 @@ CREATE TABLE t1 LIKE t2;
ERROR 42S01: Table 't1' already exists
DROP TABLE t2;
DROP TABLE t1;
#
# Bug#54332 Deadlock with two connections doing LOCK TABLE+INSERT DELAYED
#
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (a INT);
CREATE TABLE t3 (a INT);
# Test 1: Using LOCK TABLE
# Connection con1
LOCK TABLE t1 WRITE;
# Connection default
LOCK TABLE t2 WRITE;
# Sending:
INSERT DELAYED INTO t1 VALUES (1);
# Connection con1
# Wait until INSERT DELAYED is blocked on table 't1'.
INSERT DELAYED INTO t2 VALUES (1);
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
UNLOCK TABLES;
# Connection default
# Reaping: INSERT DELAYED INTO t1 VALUES (1)
UNLOCK TABLES;
# Test 2: Using ALTER TABLE
START TRANSACTION;
SELECT * FROM t1 WHERE a=0;
a
# Connection con1
# Sending:
ALTER TABLE t1 COMMENT 'test';
# Connection default
# Wait until ALTER TABLE is blocked on table 't1'.
INSERT DELAYED INTO t1 VALUES (3);
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
# Connection con1
# Reaping: ALTER TABLE t1 COMMENT 'test'
# Test 3: Using RENAME TABLE
# Connection default
START TRANSACTION;
INSERT INTO t2 VALUES (1);
# Connection con1
# Sending:
RENAME TABLE t1 to t5, t2 to t4;
# Connection default
# Wait until RENAME TABLE is blocked on table 't1'.
INSERT DELAYED INTO t1 VALUES (4);
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
# Connection con1
# Reaping: RENAME TABLE t1 to t5, t2 to t4
# Connection default
# Reverting the renames
RENAME TABLE t5 to t1, t4 to t2;
# Test 4: Two INSERT DELAYED on the same table
START TRANSACTION;
INSERT INTO t2 VALUES (1);
# Connection con2
LOCK TABLE t1 WRITE, t2 WRITE;
# Connection con1
# Wait until LOCK TABLE is blocked on table 't2'.
INSERT DELAYED INTO t1 VALUES (5);
# Connection default
# Wait until INSERT DELAYED is blocked on table 't1'.
INSERT DELAYED INTO t1 VALUES (6);
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
COMMIT;
# Connection con2
# Reaping: LOCK TABLE t1 WRITE, t2 WRITE
UNLOCK TABLES;
# Connection con1
# Reaping: INSERT DELAYED INTO t1 VALUES (5)
# Connection con2
# Connection con1
# Connection default
DROP TABLE t1, t2, t3;
......@@ -2734,3 +2734,28 @@ format(123, 1, 'Non-existent-locale')
Warnings:
Warning 1649 Unknown locale: 'Non-existent-locale'
End of 5.4 tests
#
# Start of 5.5 tests
#
#
# Bug#55912 FORMAT with locale set fails for numbers < 1000
#
SELECT FORMAT(123.33, 2, 'no_NO'), FORMAT(1123.33, 2, 'no_NO');
FORMAT(123.33, 2, 'no_NO') FORMAT(1123.33, 2, 'no_NO')
123,33 1.123,33
SELECT FORMAT(12333e-2, 2, 'no_NO'), FORMAT(112333e-2, 2, 'no_NO');
FORMAT(12333e-2, 2, 'no_NO') FORMAT(112333e-2, 2, 'no_NO')
123,33 1.123,33
CREATE TABLE t1 AS SELECT format(123,2,'no_NO');
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`format(123,2,'no_NO')` varchar(37) NOT NULL DEFAULT ''
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT * FROM t1;
format(123,2,'no_NO')
123,00
DROP TABLE t1;
#
# End of 5.5 tests
#
......@@ -44,7 +44,7 @@ a abmon mon
2006-12-01 Δεκ Δεκέμβριος
SELECT format(123456.789, 3, 'el_GR');
format(123456.789, 3, 'el_GR')
123456.789
123456,789
DROP TABLE t1;
#
# Bug#46633 Obsolete Serbian locale name
......
......@@ -432,5 +432,8 @@ Bug #47147: mysql client option --skip-column-names does not apply to vertical o
*************************** 1. row ***************************
1
Bug #54466 client 5.5 built from source lacks "pager" support
a
1
End of tests
drop table if exists t1, t2;
#
# Bug#54747: Deadlock between REORGANIZE PARTITION and
# SELECT is not detected
#
SET @old_innodb_thread_concurrency:= @@innodb_thread_concurrency;
SET GLOBAL innodb_thread_concurrency = 1;
CREATE TABLE t1
(user_num BIGINT,
hours SMALLINT,
KEY user_num (user_num))
ENGINE = InnoDB
PARTITION BY RANGE COLUMNS (hours)
(PARTITION hour_003 VALUES LESS THAN (3),
PARTITION hour_004 VALUES LESS THAN (4),
PARTITION hour_005 VALUES LESS THAN (5),
PARTITION hour_last VALUES LESS THAN (MAXVALUE));
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
BEGIN;
SELECT COUNT(*) FROM t1;
COUNT(*)
5
# con1
# SEND a ALTER PARTITION which waits on the ongoing transaction.
ALTER TABLE t1
REORGANIZE PARTITION hour_003, hour_004 INTO
(PARTITION oldest VALUES LESS THAN (4));
# Connection default wait until the ALTER is in 'waiting for table...'
# state and then continue the transaction by trying a SELECT
SELECT COUNT(*) FROM t1;
COUNT(*)
5
COMMIT;
# con1, reaping ALTER.
# Disconnecting con1 and switching to default. Cleaning up.
SET GLOBAL innodb_thread_concurrency = @old_innodb_thread_concurrency;
DROP TABLE t1;
#
# Bug#50418: DROP PARTITION does not interact with transactions
#
CREATE TABLE t1 (
......
#
# Bug#52121 partition by key on utf32 enum field cause debug assertion: (length % 4) == 0
#
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
CREATE TABLE t1 (
a enum('a') CHARACTER SET utf32 COLLATE utf32_spanish2_ci
) ENGINE=MYISAM PARTITION BY KEY(a) PARTITIONS 2;
INSERT INTO t1 VALUES ('a');
SELECT * FROM t1;
a
a
DROP TABLE t1;
################################################################################
# t/partition_ctype_utf32.test #
# #
# Purpose: #
# Tests for partitions + UTF32 #
# #
#------------------------------------------------------------------------------#
# Original Author: Alexander Barkov #
# Original Date: 2010-08-05 #
# Change Author: #
# Change Date: #
# Change: #
################################################################################
--source include/have_partition.inc
--source include/have_utf32.inc
--echo #
--echo # Bug#52121 partition by key on utf32 enum field cause debug assertion: (length % 4) == 0
--echo #
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (
a enum('a') CHARACTER SET utf32 COLLATE utf32_spanish2_ci
) ENGINE=MYISAM PARTITION BY KEY(a) PARTITIONS 2;
INSERT INTO t1 VALUES ('a');
SELECT * FROM t1;
DROP TABLE t1;
......@@ -809,6 +809,15 @@ CREATE TABLE t1 AS SELECT HEX(0x00) AS my_col;
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # Bug#55912 FORMAT with locale set fails for numbers < 1000
--echo #
SET collation_connection=utf32_general_ci;
CREATE TABLE t1 AS SELECT format(123,2,'no_NO');
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # End of 5.5 tests
--echo #
......@@ -388,3 +388,162 @@ CREATE TABLE t1 LIKE t2;
DROP TABLE t2;
DROP TABLE t1;
--echo #
--echo # Bug#54332 Deadlock with two connections doing LOCK TABLE+INSERT DELAYED
--echo #
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (a INT);
CREATE TABLE t3 (a INT);
--echo # Test 1: Using LOCK TABLE
--echo # Connection con1
connect (con1, localhost, root);
LOCK TABLE t1 WRITE;
--echo # Connection default
connection default;
LOCK TABLE t2 WRITE;
--echo # Sending:
--send INSERT DELAYED INTO t1 VALUES (1)
--echo # Connection con1
connection con1;
--echo # Wait until INSERT DELAYED is blocked on table 't1'.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table metadata lock"
AND info = "INSERT DELAYED INTO t1 VALUES (1)";
--source include/wait_condition.inc
--error ER_LOCK_DEADLOCK
INSERT DELAYED INTO t2 VALUES (1);
UNLOCK TABLES;
--echo # Connection default
connection default;
--echo # Reaping: INSERT DELAYED INTO t1 VALUES (1)
--reap
UNLOCK TABLES;
--echo # Test 2: Using ALTER TABLE
START TRANSACTION;
SELECT * FROM t1 WHERE a=0;
--echo # Connection con1
connection con1;
--echo # Sending:
--send ALTER TABLE t1 COMMENT 'test'
--echo # Connection default
connection default;
--echo # Wait until ALTER TABLE is blocked on table 't1'.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table metadata lock"
AND info = "ALTER TABLE t1 COMMENT 'test'";
--source include/wait_condition.inc
--error ER_LOCK_DEADLOCK
INSERT DELAYED INTO t1 VALUES (3);
COMMIT;
--echo # Connection con1
connection con1;
--echo # Reaping: ALTER TABLE t1 COMMENT 'test'
--reap
--echo # Test 3: Using RENAME TABLE
--echo # Connection default
connection default;
START TRANSACTION;
INSERT INTO t2 VALUES (1);
--echo # Connection con1
connection con1;
--echo # Sending:
--send RENAME TABLE t1 to t5, t2 to t4
--echo # Connection default
connection default;
--echo # Wait until RENAME TABLE is blocked on table 't1'.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table metadata lock"
AND info = "RENAME TABLE t1 to t5, t2 to t4";
--source include/wait_condition.inc
--error ER_LOCK_DEADLOCK
INSERT DELAYED INTO t1 VALUES (4);
COMMIT;
--echo # Connection con1
connection con1;
--echo # Reaping: RENAME TABLE t1 to t5, t2 to t4
--reap
--echo # Connection default
connection default;
--echo # Reverting the renames
RENAME TABLE t5 to t1, t4 to t2;
--echo # Test 4: Two INSERT DELAYED on the same table
START TRANSACTION;
INSERT INTO t2 VALUES (1);
--echo # Connection con2
connect (con2, localhost, root);
--send LOCK TABLE t1 WRITE, t2 WRITE
--echo # Connection con1
connection con1;
--echo # Wait until LOCK TABLE is blocked on table 't2'.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table metadata lock"
AND info = "LOCK TABLE t1 WRITE, t2 WRITE";
--source include/wait_condition.inc
--send INSERT DELAYED INTO t1 VALUES (5)
--echo # Connection default
connection default;
--echo # Wait until INSERT DELAYED is blocked on table 't1'.
let $wait_condition=
SELECT COUNT(*) = 1 FROM information_schema.processlist
WHERE state = "Waiting for table metadata lock"
AND info = "INSERT DELAYED INTO t1 VALUES (5)";
--source include/wait_condition.inc
--error ER_LOCK_DEADLOCK
INSERT DELAYED INTO t1 VALUES (6);
COMMIT;
--echo # Connection con2
connection con2;
--echo # Reaping: LOCK TABLE t1 WRITE, t2 WRITE
--reap
UNLOCK TABLES;
--echo # Connection con1
connection con1;
--echo # Reaping: INSERT DELAYED INTO t1 VALUES (5)
--reap
--echo # Connection con2
connection con2;
disconnect con2;
--source include/wait_until_disconnected.inc
--echo # Connection con1
connection con1;
disconnect con1;
--source include/wait_until_disconnected.inc
--echo # Connection default
connection default;
DROP TABLE t1, t2, t3;
......@@ -11,8 +11,6 @@
##############################################################################
kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild.
lowercase_table3 : Bug#54845 2010-06-30 alik main.lowercase_table3 on Mac OSX
mysqlhotcopy_myisam : bug#54129 2010-06-04 Horst
mysqlhotcopy_archive : bug#54129 2010-06-04 Horst
partition_innodb_plugin : Bug#53307 2010-04-30 VasilDimov valgrind warnings
plugin : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
plugin_load : Bug#55966 2010-08-13 alik "plugin" tests fail in 5.5
......
......@@ -1404,3 +1404,20 @@ SELECT format(123, 1, 'Non-existent-locale');
--echo End of 5.4 tests
--echo #
--echo # Start of 5.5 tests
--echo #
--echo #
--echo # Bug#55912 FORMAT with locale set fails for numbers < 1000
--echo #
SELECT FORMAT(123.33, 2, 'no_NO'), FORMAT(1123.33, 2, 'no_NO');
SELECT FORMAT(12333e-2, 2, 'no_NO'), FORMAT(112333e-2, 2, 'no_NO');
CREATE TABLE t1 AS SELECT format(123,2,'no_NO');
SHOW CREATE TABLE t1;
SELECT * FROM t1;
DROP TABLE t1;
--echo #
--echo # End of 5.5 tests
--echo #
......@@ -425,5 +425,11 @@ drop table t1;
--echo
--exec $MYSQL --skip-column-names --vertical test -e "select 1 as a"
#
# Bug #54466 client 5.5 built from source lacks "pager" support
#
--echo Bug #54466 client 5.5 built from source lacks "pager" support
--exec $MYSQL --pager test -e "select 1 as a"
--echo
--echo End of tests
......@@ -8,6 +8,63 @@ drop table if exists t1, t2;
let $MYSQLD_DATADIR= `SELECT @@datadir`;
--echo #
--echo # Bug#54747: Deadlock between REORGANIZE PARTITION and
--echo # SELECT is not detected
--echo #
SET @old_innodb_thread_concurrency:= @@innodb_thread_concurrency;
SET GLOBAL innodb_thread_concurrency = 1;
CREATE TABLE t1
(user_num BIGINT,
hours SMALLINT,
KEY user_num (user_num))
ENGINE = InnoDB
PARTITION BY RANGE COLUMNS (hours)
(PARTITION hour_003 VALUES LESS THAN (3),
PARTITION hour_004 VALUES LESS THAN (4),
PARTITION hour_005 VALUES LESS THAN (5),
PARTITION hour_last VALUES LESS THAN (MAXVALUE));
INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
BEGIN;
SELECT COUNT(*) FROM t1;
--echo # con1
--connect (con1,localhost,root,,)
--echo # SEND a ALTER PARTITION which waits on the ongoing transaction.
--send
ALTER TABLE t1
REORGANIZE PARTITION hour_003, hour_004 INTO
(PARTITION oldest VALUES LESS THAN (4));
--echo # Connection default wait until the ALTER is in 'waiting for table...'
--echo # state and then continue the transaction by trying a SELECT
--connection default
let $wait_condition =
SELECT COUNT(*) = 1
FROM information_schema.processlist
WHERE INFO like 'ALTER TABLE t1%REORGANIZE PARTITION hour_003, hour_004%'
AND STATE = 'Waiting for table metadata lock';
--source include/wait_condition.inc
SELECT COUNT(*) FROM t1;
COMMIT;
--echo # con1, reaping ALTER.
--connection con1
--reap
--echo # Disconnecting con1 and switching to default. Cleaning up.
--disconnect con1
--connection default
SET GLOBAL innodb_thread_concurrency = @old_innodb_thread_concurrency;
DROP TABLE t1;
--echo #
--echo # Bug#50418: DROP PARTITION does not interact with transactions
--echo #
......
......@@ -302,6 +302,8 @@ void my_thread_global_end(void)
#ifndef HAVE_GETHOSTBYNAME_R
mysql_mutex_destroy(&LOCK_gethostbyname_r);
#endif
my_thread_basic_global_init_done= 0;
}
static my_thread_id thread_id= 0;
......
......@@ -344,6 +344,7 @@ ELSE()
MESSAGE(FATAL_ERROR "Can not find ${file}.sh or ${file} in "
"${CMAKE_CURRENT_SOURCE_DIR}" )
ENDIF()
EXECUTE_PROCESS(COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/${file})
IF(NOT ${file}_COMPONENT)
SET(${file}_COMPONENT Server)
ENDIF()
......
File mode changed from 100644 to 100755
......@@ -1329,7 +1329,7 @@ void Field::hash(ulong *nr, ulong *nr2)
else
{
uint len= pack_length();
CHARSET_INFO *cs= charset();
CHARSET_INFO *cs= sort_charset();
cs->coll->hash_sort(cs, ptr, len, nr, nr2);
}
}
......
......@@ -2217,7 +2217,7 @@ const int FORMAT_MAX_DECIMALS= 30;
MY_LOCALE *Item_func_format::get_locale(Item *item)
{
DBUG_ASSERT(arg_count == 3);
String tmp, *locale_name= args[2]->val_str(&tmp);
String tmp, *locale_name= args[2]->val_str_ascii(&tmp);
MY_LOCALE *lc;
if (!locale_name ||
!(lc= my_locale_by_name(locale_name->c_ptr_safe())))
......@@ -2250,7 +2250,7 @@ void Item_func_format::fix_length_and_dec()
are stored in more than one byte
*/
String *Item_func_format::val_str(String *str)
String *Item_func_format::val_str_ascii(String *str)
{
uint32 str_length;
/* Number of decimal digits */
......@@ -2290,8 +2290,7 @@ String *Item_func_format::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
nr= my_double_round(nr, (longlong) dec, FALSE, FALSE);
/* Here default_charset() is right as this is not an automatic conversion */
str->set_real(nr, dec, default_charset());
str->set_real(nr, dec, &my_charset_numeric);
if (isnan(nr))
return str;
str_length=str->length();
......@@ -2341,6 +2340,14 @@ String *Item_func_format::val_str(String *str)
/* Put the rest of the integer part without grouping */
str->copy(dst, buf + sizeof(buf) - dst, &my_charset_latin1);
}
else if (dec_length && lc->decimal_point != '.')
{
/*
For short values without thousands (<1000)
replace decimal point to localized value.
*/
((char*) str->ptr())[str_length - dec_length]= lc->decimal_point;
}
return str;
}
......
......@@ -539,17 +539,17 @@ public:
};
class Item_func_format :public Item_str_func
class Item_func_format :public Item_str_ascii_func
{
String tmp_str;
MY_LOCALE *locale;
public:
Item_func_format(Item *org, Item *dec): Item_str_func(org, dec) {}
Item_func_format(Item *org, Item *dec): Item_str_ascii_func(org, dec) {}
Item_func_format(Item *org, Item *dec, Item *lang):
Item_str_func(org, dec, lang) {}
Item_str_ascii_func(org, dec, lang) {}
MY_LOCALE *get_locale(Item *item);
String *val_str(String *);
String *val_str_ascii(String *);
void fix_length_and_dec();
const char *func_name() const { return "format"; }
virtual void print(String *str, enum_query_type query_type);
......
......@@ -137,6 +137,30 @@ static my_bool acquire_plugins(THD *thd, plugin_ref plugin, void *arg)
}
/**
@brief Acquire audit plugins
@param[in] thd MySQL thread handle
@param[in] event_class Audit event class
@details Ensure that audit plugins interested in given event
class are locked by current thread.
*/
void mysql_audit_acquire_plugins(THD *thd, uint event_class)
{
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
DBUG_ENTER("mysql_audit_acquire_plugins");
set_audit_mask(event_class_mask, event_class);
if (thd && !check_audit_mask(mysql_global_audit_mask, event_class_mask) &&
check_audit_mask(thd->audit_class_mask, event_class_mask))
{
plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN, &event_class);
add_audit_mask(thd->audit_class_mask, event_class_mask);
}
DBUG_VOID_RETURN;
}
/**
Notify the audit system of an event
......@@ -151,21 +175,8 @@ void mysql_audit_notify(THD *thd, uint event_class, uint event_subtype, ...)
{
va_list ap;
audit_handler_t *handlers= audit_handlers + event_class;
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
DBUG_ASSERT(event_class < audit_handlers_count);
set_audit_mask(event_class_mask, event_class);
/*
Check to see if we have acquired the audit plugins for the
required audit event classes.
*/
if (thd && check_audit_mask(thd->audit_class_mask, event_class_mask))
{
plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN, &event_class);
add_audit_mask(thd->audit_class_mask, event_class_mask);
}
mysql_audit_acquire_plugins(thd, event_class);
va_start(ap, event_subtype);
(*handlers)(thd, event_subtype, ap);
va_end(ap);
......@@ -448,6 +459,11 @@ static void event_class_dispatch(THD *thd, const struct mysql_event *event)
#else /* EMBEDDED_LIBRARY */
void mysql_audit_acquire_plugins(THD *thd, uint event_class)
{
}
void mysql_audit_initialize()
{
}
......
......@@ -29,6 +29,7 @@ extern void mysql_audit_finalize();
extern void mysql_audit_init_thd(THD *thd);
extern void mysql_audit_free_thd(THD *thd);
extern void mysql_audit_acquire_plugins(THD *thd, uint event_class);
extern void mysql_audit_notify(THD *thd, uint event_class,
......
......@@ -548,10 +548,34 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(TRUE);
}
if (delayed_get_table(thd, table_list))
/*
In order for the deadlock detector to be able to find any deadlocks
caused by the handler thread locking this table, we take the metadata
lock inside the connection thread. If this goes ok, the ticket is cloned
and added to the list of granted locks held by the handler thread.
*/
MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint();
if (thd->mdl_context.acquire_lock(&table_list->mdl_request,
thd->variables.lock_wait_timeout))
/*
If a lock can't be acquired, it makes no sense to try normal insert.
Therefore we just abort the statement.
*/
DBUG_RETURN(TRUE);
if (table_list->table)
/*
If a lock was acquired above, we should release it after delayed_get_table()
has cloned the ticket for the handler thread. Note that acquire_lock() can
succeed because of a lock already held by the connection. In this case we
should not release it here.
*/
MDL_ticket *table_ticket = mdl_savepoint == thd->mdl_context.mdl_savepoint() ?
NULL: thd->mdl_context.mdl_savepoint();
bool error= FALSE;
if (delayed_get_table(thd, table_list))
error= TRUE;
else if (table_list->table)
{
/*
Open tables used for sub-selects or in stored functions, will also
......@@ -560,16 +584,30 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
if (open_and_lock_tables(thd, table_list->next_global, TRUE, 0))
{
end_delayed_insert(thd);
DBUG_RETURN(TRUE);
error= TRUE;
}
else
{
/*
First table was not processed by open_and_lock_tables(),
we need to set updatability flag "by hand".
*/
if (!table_list->derived && !table_list->view)
table_list->updatable= 1; // usual table
}
/*
First table was not processed by open_and_lock_tables(),
we need to set updatability flag "by hand".
*/
if (!table_list->derived && !table_list->view)
table_list->updatable= 1; // usual table
DBUG_RETURN(FALSE);
}
if (table_ticket)
thd->mdl_context.release_lock(table_ticket);
/*
Clone_ticket() in delayed_get_table() causes TABLE_LIST::MDL_REQUEST::ticket
to be overwritten with the cloned ticket. Reset the ticket here in case
we end up having to use normal insert.
*/
table_list->mdl_request.ticket= NULL;
if (error || table_list->table)
DBUG_RETURN(error);
#endif
/*
* This is embedded library and we don't have auxiliary
......@@ -2025,6 +2063,20 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
/* Replace volatile strings with local copies */
di->table_list.alias= di->table_list.table_name= di->thd.query();
di->table_list.db= di->thd.db;
/*
Clone the ticket representing the lock on the target table for
the insert and add it to the list of granted metadata locks held by
the handler thread. This is safe since the handler thread is
not holding nor waiting on any metadata locks.
*/
if (di->thd.mdl_context.clone_ticket(&table_list->mdl_request))
{
delete di;
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
goto end_create;
}
di->lock();
mysql_mutex_lock(&di->mutex);
if ((error= mysql_thread_create(key_thread_delayed_insert,
......@@ -2036,6 +2088,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
error));
mysql_mutex_unlock(&di->mutex);
di->unlock();
di->thd.mdl_context.release_lock(table_list->mdl_request.ticket);
delete di;
my_error(ER_CANT_CREATE_THREAD, MYF(ME_FATALERROR), error);
goto end_create;
......
......@@ -63,6 +63,7 @@
#include "sql_table.h" // build_table_filename,
// build_table_shadow_filename,
// table_to_filename
// mysql_*_alter_copy_data
#include "opt_range.h" // store_key_image_to_rec
#include "sql_analyse.h" // append_escaped
......@@ -4377,7 +4378,6 @@ static int fast_end_partition(THD *thd, ulonglong copied,
ALTER_PARTITION_PARAM_TYPE *lpt,
bool written_bin_log)
{
int error;
char tmp_name[80];
DBUG_ENTER("fast_end_partition");
......@@ -4386,13 +4386,6 @@ static int fast_end_partition(THD *thd, ulonglong copied,
if (!is_empty)
query_cache_invalidate3(thd, table_list, 0);
error= trans_commit_stmt(thd);
if (trans_commit_implicit(thd))
error= 1;
if (error)
DBUG_RETURN(TRUE); /* The error has been reported */
if ((!is_empty) && (!written_bin_log) &&
(!thd->lex->no_write_to_binlog) &&
write_bin_log(thd, FALSE, thd->query(), thd->query_length()))
......@@ -5535,17 +5528,25 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
char path[FN_REFLEN+1];
int error;
handler *file= lpt->table->file;
THD *thd= lpt->thd;
DBUG_ENTER("mysql_change_partitions");
build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
if(mysql_trans_prepare_alter_copy_data(thd))
DBUG_RETURN(TRUE);
if ((error= file->ha_change_partitions(lpt->create_info, path, &lpt->copied,
&lpt->deleted, lpt->pack_frm_data,
lpt->pack_frm_len)))
{
file->print_error(error, MYF(error != ER_OUTOFMEMORY ? 0 : ME_FATALERROR));
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
if (mysql_trans_commit_alter_copy_data(thd))
DBUG_RETURN(TRUE); /* The error has been reported */
DBUG_RETURN(test(error));
}
......
......@@ -29,7 +29,7 @@
#include "records.h" // init_read_record, end_read_record
#include <my_pthread.h>
#include <my_getopt.h>
#include <mysql/plugin_audit.h>
#include "sql_audit.h"
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#define REPORT_TO_LOG 1
#define REPORT_TO_USER 2
......@@ -1709,6 +1709,27 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
/*
Pre-acquire audit plugins for events that may potentially occur
during [UN]INSTALL PLUGIN.
When audit event is triggered, audit subsystem acquires interested
plugins by walking through plugin list. Evidently plugin list
iterator protects plugin list by acquiring LOCK_plugin, see
plugin_foreach_with_mask().
On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
rather for a long time.
When audit event is triggered during [UN]INSTALL PLUGIN, plugin
list iterator acquires the same lock (within the same thread)
second time.
This hack should be removed when LOCK_plugin is fixed so it
protects only what it supposed to protect.
*/
mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
mysql_mutex_lock(&LOCK_plugin);
mysql_rwlock_wrlock(&LOCK_system_variables_hash);
......@@ -1789,6 +1810,27 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
/*
Pre-acquire audit plugins for events that may potentially occur
during [UN]INSTALL PLUGIN.
When audit event is triggered, audit subsystem acquires interested
plugins by walking through plugin list. Evidently plugin list
iterator protects plugin list by acquiring LOCK_plugin, see
plugin_foreach_with_mask().
On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
rather for a long time.
When audit event is triggered during [UN]INSTALL PLUGIN, plugin
list iterator acquires the same lock (within the same thread)
second time.
This hack should be removed when LOCK_plugin is fixed so it
protects only what it supposed to protect.
*/
mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
mysql_mutex_lock(&LOCK_plugin);
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
{
......
......@@ -6740,6 +6740,54 @@ err_with_mdl:
}
/* mysql_alter_table */
/**
Prepare the transaction for the alter table's copy phase.
*/
bool mysql_trans_prepare_alter_copy_data(THD *thd)
{
DBUG_ENTER("mysql_prepare_alter_copy_data");
/*
Turn off recovery logging since rollback of an alter table is to
delete the new table so there is no need to log the changes to it.
This needs to be done before external_lock.
*/
if (ha_enable_transaction(thd, FALSE))
DBUG_RETURN(TRUE);
DBUG_RETURN(FALSE);
}
/**
Commit the copy phase of the alter table.
*/
bool mysql_trans_commit_alter_copy_data(THD *thd)
{
bool error= FALSE;
DBUG_ENTER("mysql_commit_alter_copy_data");
if (ha_enable_transaction(thd, TRUE))
DBUG_RETURN(TRUE);
/*
Ensure that the new table is saved properly to disk before installing
the new .frm.
And that InnoDB's internal latches are released, to avoid deadlock
when waiting on other instances of the table before rename (Bug#54747).
*/
if (trans_commit_stmt(thd))
error= TRUE;
if (trans_commit_implicit(thd))
error= TRUE;
DBUG_RETURN(error);
}
static int
copy_data_between_tables(TABLE *from,TABLE *to,
List<Create_field> &create,
......@@ -6766,14 +6814,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
ulonglong prev_insert_id;
DBUG_ENTER("copy_data_between_tables");
/*
Turn off recovery logging since rollback of an alter table is to
delete the new table so there is no need to log the changes to it.
This needs to be done before external_lock
*/
error= ha_enable_transaction(thd, FALSE);
if (error)
if (mysql_trans_prepare_alter_copy_data(thd))
DBUG_RETURN(-1);
if (!(copy= new Copy_field[to->s->fields]))
......@@ -6932,20 +6973,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
}
to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (ha_enable_transaction(thd, TRUE))
{
if (mysql_trans_commit_alter_copy_data(thd))
error= 1;
goto err;
}
/*
Ensure that the new table is saved properly to disk so that we
can do a rename
*/
if (trans_commit_stmt(thd))
error=1;
if (trans_commit_implicit(thd))
error=1;
err:
thd->variables.sql_mode= save_sql_mode;
......
......@@ -143,6 +143,8 @@ bool mysql_create_table_no_lock(THD *thd, const char *db,
bool mysql_prepare_alter_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
Alter_info *alter_info);
bool mysql_trans_prepare_alter_copy_data(THD *thd);
bool mysql_trans_commit_alter_copy_data(THD *thd);
bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
......
......@@ -1625,7 +1625,7 @@ static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
if (flag_events_waits_history_long)
insert_events_waits_history_long(wait);
if (rc == 0)
if (rc == 0 && wait->m_timer_state == TIMER_STATE_TIMED)
{
/* Thread safe: we are protected by the instrumented mutex */
PFS_single_stat_chain *stat;
......@@ -1635,9 +1635,8 @@ static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&mutex->m_wait_stat, wait_time);
stat= find_per_thread_mutex_class_wait_stat(wait->m_thread,
mutex->m_class);
aggregate_single_stat_chain(stat, wait_time);
stat= find_per_thread_mutex_class_wait_stat(wait->m_thread, mutex->m_class);
aggregate_single_stat_chain(stat, wait_time);
}
wait->m_thread->m_wait_locker_count--;
}
......@@ -1690,11 +1689,13 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
rwlock->m_writer= NULL;
rwlock->m_readers++;
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time);
stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread,
rwlock->m_class);
aggregate_single_stat_chain(stat, wait_time);
if (wait->m_timer_state == TIMER_STATE_TIMED)
{
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time);
stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread, rwlock->m_class);
aggregate_single_stat_chain(stat, wait_time);
}
}
wait->m_thread->m_wait_locker_count--;
}
......@@ -1742,11 +1743,13 @@ static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
rwlock->m_readers= 0;
rwlock->m_last_read= 0;
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time);
stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread,
rwlock->m_class);
aggregate_single_stat_chain(stat, wait_time);
if (wait->m_timer_state == TIMER_STATE_TIMED)
{
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&rwlock->m_wait_stat, wait_time);
stat= find_per_thread_rwlock_class_wait_stat(wait->m_thread, rwlock->m_class);
aggregate_single_stat_chain(stat, wait_time);
}
}
wait->m_thread->m_wait_locker_count--;
}
......@@ -1803,11 +1806,13 @@ static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
PFS_single_stat_chain *stat;
PFS_cond *cond= pfs_locker->m_target.m_cond;
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&cond->m_wait_stat, wait_time);
stat= find_per_thread_cond_class_wait_stat(wait->m_thread,
cond->m_class);
aggregate_single_stat_chain(stat, wait_time);
if (wait->m_timer_state == TIMER_STATE_TIMED)
{
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&cond->m_wait_stat, wait_time);
stat= find_per_thread_cond_class_wait_stat(wait->m_thread, cond->m_class);
aggregate_single_stat_chain(stat, wait_time);
}
}
wait->m_thread->m_wait_locker_count--;
}
......@@ -1850,9 +1855,12 @@ static void end_table_wait_v1(PSI_table_locker* locker)
if (flag_events_waits_history_long)
insert_events_waits_history_long(wait);
PFS_table *table= pfs_locker->m_target.m_table;
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&table->m_wait_stat, wait_time);
if (wait->m_timer_state == TIMER_STATE_TIMED)
{
PFS_table *table= pfs_locker->m_target.m_table;
ulonglong wait_time= wait->m_timer_end - wait->m_timer_start;
aggregate_single_stat_chain(&table->m_wait_stat, wait_time);
}
/*
There is currently no per table and per thread aggregation.
......
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