Commit cae3c58a authored by Satya B's avatar Satya B

merging with mysql-5.1-bugteam branch

parents ba7c6884 6b2c3ff5
This diff is collapsed.
......@@ -833,3 +833,16 @@ Table Op Msg_type Msg_text
test.t2 check status OK
drop table t1,t2;
##################################################################
#
# Bug #46075: Assertion failed: 0, file .\protocol.cc, line 416
#
CREATE TABLE t1(a INT);
SET max_heap_table_size = 16384;
SET @old_myisam_data_pointer_size = @@myisam_data_pointer_size;
SET GLOBAL myisam_data_pointer_size = 2;
INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
INSERT IGNORE INTO t1 SELECT t1.a FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6,t1 t7;
Got one of the listed errors
SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size;
DROP TABLE t1;
End of 5.0 tests
DROP TABLE IF EXISTS t1, t2;
# Bug#30102 test
CREATE TABLE t1 (a INT)
PARTITION BY RANGE (a)
(PARTITION p0 VALUES LESS THAN (6),
PARTITION `p1....................` VALUES LESS THAN (9),
PARTITION p2 VALUES LESS THAN MAXVALUE);
# List of files in database `test`, all original t1-files here
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYD
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYI
t1#P#p2.MYD
t1#P#p2.MYI
t1.frm
t1.par
INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
# Renaming to a file name where the first partition is 250 chars
# and the second partition is 350 chars
RENAME TABLE t1 TO `t2_new..............................................end`;
Got one of the listed errors
# List of files in database `test`, should not be any t2-files here
# List of files in database `test`, should be all t1-files here
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYD
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYI
t1#P#p2.MYD
t1#P#p2.MYI
t1.frm
t1.par
SELECT * FROM t1;
a
1
10
2
3
4
5
6
7
8
9
# Renaming to a file name where the first partition is 155 chars
# and the second partition is 255 chars
RENAME TABLE t1 TO `t2_............................end`;
# List of files in database `test`, should not be any t1-files here
# List of files in database `test`, should be all t2-files here
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend#P#p0.MYD
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend#P#p0.MYI
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYD
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYI
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend#P#p2.MYD
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend#P#p2.MYI
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend.frm
t2_@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002eend.par
SELECT * FROM `t2_............................end`;
a
1
10
2
3
4
5
6
7
8
9
RENAME TABLE `t2_............................end` to t1;
# List of files in database `test`, should be all t1-files here
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYD
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYI
t1#P#p2.MYD
t1#P#p2.MYI
t1.frm
t1.par
# Renaming to a file name where the first partition is 156 chars
# and the second partition is 256 chars
RENAME TABLE t1 TO `t2_............................_end`;
Got one of the listed errors
# List of files in database `test`, should not be any t2-files here
# List of files in database `test`, should be all t1-files here
t1#P#p0.MYD
t1#P#p0.MYI
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYD
t1#P#p1@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e@002e.MYI
t1#P#p2.MYD
t1#P#p2.MYI
t1.frm
t1.par
SELECT * FROM t1;
a
1
10
2
3
4
5
6
7
8
9
DROP TABLE t1;
# Should not be any files left here
# End of bug#30102 test.
......@@ -35,4 +35,11 @@ CREATE DATABASE IF NOT EXISTS init_file;
CREATE TABLE IF NOT EXISTS init_file.startup ( startdate DATETIME );
INSERT INTO init_file.startup VALUES ( NOW() );
#
# Bug#43587 "Putting event_scheduler=1 in init SQL file crashes mysqld"
#
SET GLOBAL event_scheduler = 'ON';
CREATE EVENT ev1 ON SCHEDULE EVERY 1 DAY DISABLE DO SELECT 1;
DROP EVENT ev1;
SET GLOBAL event_scheduler = 'OFF';
......@@ -24,3 +24,48 @@ Slave_open_temp_tables 0
[on master]
DROP TABLE t1;
[on slave]
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
CREATE TABLE t1 (a int);
CREATE TABLE t2 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) );
CREATE TABLE t3 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) );
CREATE TRIGGER tr1 AFTER DELETE ON t2 FOR EACH ROW INSERT INTO t3 () VALUES ();
CREATE TEMPORARY TABLE t1_tmp (i1 int);
ALTER TABLE t1_tmp ADD COLUMN b INT;
DELETE FROM t2;
CREATE TEMPORARY TABLE t2_tmp (a int);
ALTER TABLE t1_tmp ADD COLUMN c INT;
### assertion: assert that there is one open temp table on slave
SHOW STATUS LIKE 'Slave_open_temp_tables';
Variable_name Value
Slave_open_temp_tables 1
DROP TABLE t1_tmp, t2;
INSERT INTO t1 VALUES (1);
DROP TEMPORARY TABLE t2_tmp;
INSERT INTO t1 VALUES (2);
### assertion: assert that slave has no temporary tables opened
SHOW STATUS LIKE 'Slave_open_temp_tables';
Variable_name Value
Slave_open_temp_tables 0
DROP TABLE t3, t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a int)
slave-bin.000001 # Query # # use `test`; CREATE TABLE t2 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) )
slave-bin.000001 # Query # # use `test`; CREATE TABLE t3 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) )
slave-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER DELETE ON t2 FOR EACH ROW INSERT INTO t3 () VALUES ()
slave-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE t1_tmp (i1 int)
slave-bin.000001 # Query # # use `test`; ALTER TABLE t1_tmp ADD COLUMN b INT
slave-bin.000001 # Query # # use `test`; DROP TABLE `t2` /* generated by server */
slave-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `t1_tmp` /* generated by server */
slave-bin.000001 # Query # # BEGIN
slave-bin.000001 # Table_map # # table_id: # (test.t1)
slave-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
slave-bin.000001 # Query # # COMMIT
slave-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `t2_tmp` /* generated by server */
slave-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (2)
slave-bin.000001 # Query # # use `test`; DROP TABLE t3, t1
......@@ -51,3 +51,98 @@ DROP TABLE t1;
--echo [on slave]
sync_slave_with_master;
#
# BUG#43046: mixed mode switch to row format with temp table lead to wrong
# result
#
# NOTES
# =====
#
# 1. Temporary tables cannot be logged using the row-based
# format. Thus, once row-based logging is used, all subsequent
# statements using that table are unsafe, and we approximate this
# condition by treating all statements made by that client as
# unsafe until the client no longer holds any temporary tables.
#
# 2. Two different connections can use the same temporary table
# name without conflicting with each other or with an
# existing non-TEMPORARY table of the same name.
#
# DESCRIPTION
# ===========
#
# The test is implemented as follows:
# 1. create regular tables
# 2. create a temporary table t1_tmp: should be logged as statement
# 3. issue an alter table: should be logged as statement
# 4. issue statement that forces switch to RBR
# 5. create another temporary table t2_tmp: should not be logged
# 6. issue alter table on t1_tmp: should not be logged
# 7. drop t1_tmp and regular table on same statement: should log both in
# statement format (but different statements)
# 8. issue deterministic insert: logged as row (because t2_tmp still
# exists).
# 9. drop t2_tmp and issue deterministic statement: should log drop and
# query in statement format (show switch back to STATEMENT format)
# 10. in the end the slave should not have open temp tables.
#
connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
-- source include/master-slave-reset.inc
-- connection master
# action: setup environment
CREATE TABLE t1 (a int);
CREATE TABLE t2 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) );
CREATE TABLE t3 ( i1 INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (i1) );
CREATE TRIGGER tr1 AFTER DELETE ON t2 FOR EACH ROW INSERT INTO t3 () VALUES ();
# assertion: assert that CREATE is logged as STATEMENT
CREATE TEMPORARY TABLE t1_tmp (i1 int);
# assertion: assert that ALTER TABLE is logged as STATEMENT
ALTER TABLE t1_tmp ADD COLUMN b INT;
# action: force switch to RBR
DELETE FROM t2;
# assertion: assert that t2_tmp will not make into the binlog (RBR logging atm)
CREATE TEMPORARY TABLE t2_tmp (a int);
# assertion: assert that ALTER TABLE on t1_tmp will not make into the binlog
ALTER TABLE t1_tmp ADD COLUMN c INT;
-- echo ### assertion: assert that there is one open temp table on slave
-- sync_slave_with_master
SHOW STATUS LIKE 'Slave_open_temp_tables';
-- connection master
# assertion: assert that both drops are logged
DROP TABLE t1_tmp, t2;
# assertion: assert that statement is logged as row (master still has one
# opened temporary table - t2_tmp.
INSERT INTO t1 VALUES (1);
# assertion: assert that DROP TABLE *is* logged despite CREATE is not.
DROP TEMPORARY TABLE t2_tmp;
# assertion: assert that statement is now logged as STMT (mixed mode switches
# back to STATEMENT).
INSERT INTO t1 VALUES (2);
-- sync_slave_with_master
-- echo ### assertion: assert that slave has no temporary tables opened
SHOW STATUS LIKE 'Slave_open_temp_tables';
-- connection master
# action: drop remaining tables
DROP TABLE t3, t1;
-- sync_slave_with_master
-- source include/show_binlog_events.inc
......@@ -56,3 +56,54 @@ select hex(s1), hex(convert(s1 using utf8)) from t1 order by binary s1;
drop table t1;
--echo End of 5.0 tests
--echo Start of 5.4 tests
--echo #
--echo # WL#3997 New euckr characters
--echo #
SET NAMES utf8;
CREATE TABLE t1 (a varchar(10) character set euckr);
INSERT INTO t1 VALUES (0xA2E6), (0xA2E7);
SELECT hex(a), hex(@utf8:=convert(a using utf8)), hex(convert(@utf8 using euckr)) FROM t1;
DROP TABLE t1;
--echo #
--echo # WL#3332 Korean Enhancements
--echo # euckr valid codes are now [81..FE][41..5A,61..7A,81..FE]
--echo #
CREATE TABLE t1 (a binary(1), key(a));
--disable_query_log
let $1=255;
while($1)
{
eval INSERT INTO t1 VALUES (unhex(hex($1)));
dec $1;
}
--enable_query_log
CREATE TABLE t2 (s VARCHAR(4), a VARCHAR(1) CHARACTER SET euckr);
--disable_warnings
INSERT INTO t2
SELECT hex(concat(t11.a, t12.a)), concat(t11.a, t12.a)
FROM t1 t11, t1 t12
WHERE t11.a >= 0x81 AND t11.a <= 0xFE
AND t12.a >= 0x41 AND t12.a <= 0xFE
ORDER BY t11.a, t12.a;
--enable_warnings
SELECT s as bad_code FROM t2 WHERE a='' ORDER BY s;
DELETE FROM t2 WHERE a='';
ALTER TABLE t2 ADD u VARCHAR(1) CHARACTER SET utf8, ADD a2 VARCHAR(1) CHARACTER SET euckr;
--disable_warnings
UPDATE t2 SET u=a, a2=u;
--enable_warnings
SELECT s as unassigned_code FROM t2 WHERE u='?';
DELETE FROM t2 WHERE u='?';
# Make sure there are no euckr->utf8->euckr roundtrip problems
SELECT count(*) as roundtrip_problem_chars FROM t2 WHERE hex(a) <> hex(a2);
SELECT s, hex(a), hex(u), hex(a2) FROM t2 ORDER BY s;
DROP TABLE t1, t2;
--echo End of 5.4 tests
......@@ -394,3 +394,24 @@ check table t2 extended;
drop table t1,t2;
--echo ##################################################################
--echo #
--echo # Bug #46075: Assertion failed: 0, file .\protocol.cc, line 416
--echo #
CREATE TABLE t1(a INT);
# To force MyISAM temp. table in the following INSERT ... SELECT.
SET max_heap_table_size = 16384;
# To overflow the temp. table.
SET @old_myisam_data_pointer_size = @@myisam_data_pointer_size;
SET GLOBAL myisam_data_pointer_size = 2;
INSERT INTO t1 VALUES (1), (2), (3), (4), (5);
--error ER_RECORD_FILE_FULL,ER_RECORD_FILE_FULL
INSERT IGNORE INTO t1 SELECT t1.a FROM t1,t1 t2,t1 t3,t1 t4,t1 t5,t1 t6,t1 t7;
# Cleanup
SET GLOBAL myisam_data_pointer_size = @old_myisam_data_pointer_size;
DROP TABLE t1;
--echo End of 5.0 tests
-- source include/have_partition.inc
-- source include/not_embedded.inc
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
let $MYSQLD_DATADIR= `SELECT @@datadir`;
#
# Bug#30102: rename table does corrupt tables with partition files on failure
#
--echo # Bug#30102 test
CREATE TABLE t1 (a INT)
PARTITION BY RANGE (a)
(PARTITION p0 VALUES LESS THAN (6),
PARTITION `p1....................` VALUES LESS THAN (9),
PARTITION p2 VALUES LESS THAN MAXVALUE);
# partition p1 is 't1#P#p1' + @002e * 20 = 107 characters + file ending
# total path lenght of './test/t1#P#p1@002e@002e<...>@002e.MY[ID]' is 118 chars
--echo # List of files in database `test`, all original t1-files here
--list_files $MYSQLD_DATADIR/test t1*
INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
--echo # Renaming to a file name where the first partition is 250 chars
--echo # and the second partition is 350 chars
# 7,7 avoids the error message, which is not deterministic.
--error 7,7
RENAME TABLE t1 TO `t2_new..............................................end`;
# 1234567890123456789012345678901234567890123456
--echo # List of files in database `test`, should not be any t2-files here
--list_files $MYSQLD_DATADIR/test t2*
--echo # List of files in database `test`, should be all t1-files here
--list_files $MYSQLD_DATADIR/test t1*
--sorted_result
SELECT * FROM t1;
--echo # Renaming to a file name where the first partition is 155 chars
--echo # and the second partition is 255 chars
RENAME TABLE t1 TO `t2_............................end`;
# 1234567890123456789012345678
# t2_ + end
# .MY[ID] or .frm
# #P#p[012]
# 28 * @002e
# 6 + 4 + 5 + 28 * 5 = 155
--echo # List of files in database `test`, should not be any t1-files here
--list_files $MYSQLD_DATADIR/test t1*
--echo # List of files in database `test`, should be all t2-files here
--list_files $MYSQLD_DATADIR/test t2*
--sorted_result
SELECT * FROM `t2_............................end`;
RENAME TABLE `t2_............................end` to t1;
--echo # List of files in database `test`, should be all t1-files here
--list_files $MYSQLD_DATADIR/test t1*
--echo # Renaming to a file name where the first partition is 156 chars
--echo # and the second partition is 256 chars
# 7,7 avoids the error message, which is not deterministic.
--error 7,7
RENAME TABLE t1 TO `t2_............................_end`;
# 1234567890123456789012345678
# 7 + 4 + 5 + 28 * 5 = 16 + 140 = 156
--echo # List of files in database `test`, should not be any t2-files here
--list_files $MYSQLD_DATADIR/test t2*
--echo # List of files in database `test`, should be all t1-files here
--list_files $MYSQLD_DATADIR/test t1*
--sorted_result
SELECT * FROM t1;
DROP TABLE t1;
--echo # Should not be any files left here
--list_files $MYSQLD_DATADIR/test t1*
--list_files $MYSQLD_DATADIR/test t2*
--echo # End of bug#30102 test.
......@@ -32,11 +32,11 @@
DESCRIPTION
init_dynamic_array() initiates array and allocate space for
init_alloc eilements.
Array is usable even if space allocation failed.
Array is usable even if space allocation failed, hence, the
function never returns TRUE.
Static buffers must begin immediately after the array structure.
RETURN VALUE
TRUE my_malloc_ci() failed
FALSE Ok
*/
......@@ -63,12 +63,12 @@ my_bool init_dynamic_array2(DYNAMIC_ARRAY *array, uint element_size,
array->size_of_element=element_size;
if ((array->buffer= init_buffer))
DBUG_RETURN(FALSE);
if (!(array->buffer=(uchar*) my_malloc_ci(element_size*init_alloc,
MYF(MY_WME))))
{
/*
Since the dynamic array is usable even if allocation fails here malloc
should not throw an error
*/
if (!(array->buffer= (char*) my_malloc_ci(element_size*init_alloc, MYF(0))))
array->max_element=0;
DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
}
......
......@@ -1430,13 +1430,7 @@ Event_job_data::execute(THD *thd, bool drop)
thd->variables.sql_mode= sql_mode;
thd->variables.time_zone= time_zone;
/*
Peculiar initialization order is a crutch to avoid races in SHOW
PROCESSLIST which reads thd->{query/query_length} without a mutex.
*/
thd->query_length= 0;
thd->query= sp_sql.c_ptr_safe();
thd->query_length= sp_sql.length();
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
{
Parser_state parser_state(thd, thd->query, thd->query_length);
......@@ -1497,13 +1491,8 @@ Event_job_data::execute(THD *thd, bool drop)
else
{
ulong saved_master_access;
/*
Peculiar initialization order is a crutch to avoid races in SHOW
PROCESSLIST which reads thd->{query/query_length} without a mutex.
*/
thd->query_length= 0;
thd->query= sp_sql.c_ptr_safe();
thd->query_length= sp_sql.length();
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
/*
NOTE: even if we run in read-only mode, we should be able to lock
......@@ -1528,8 +1517,7 @@ Event_job_data::execute(THD *thd, bool drop)
thd->end_statement();
thd->cleanup_after_query();
/* Avoid races with SHOW PROCESSLIST */
thd->query_length= 0;
thd->query= NULL;
thd->set_query(NULL, 0);
DBUG_PRINT("info", ("EXECUTED %s.%s ret: %d", dbname.str, name.str, ret));
......
......@@ -158,6 +158,7 @@ deinit_event_thread(THD *thd)
thread_count--;
thread_running--;
delete thd;
pthread_cond_broadcast(&COND_thread_count);
pthread_mutex_unlock(&LOCK_thread_count);
}
......@@ -418,6 +419,7 @@ Event_scheduler::start()
thread_count--;
thread_running--;
delete new_thd;
pthread_cond_broadcast(&COND_thread_count);
pthread_mutex_unlock(&LOCK_thread_count);
}
end:
......@@ -550,6 +552,7 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
thread_count--;
thread_running--;
delete new_thd;
pthread_cond_broadcast(&COND_thread_count);
pthread_mutex_unlock(&LOCK_thread_count);
}
delete event_name;
......@@ -625,13 +628,13 @@ Event_scheduler::stop()
DBUG_PRINT("info", ("Scheduler thread has id %lu",
scheduler_thd->thread_id));
/* Lock from delete */
pthread_mutex_lock(&scheduler_thd->LOCK_delete);
pthread_mutex_lock(&scheduler_thd->LOCK_thd_data);
/* This will wake up the thread if it waits on Queue's conditional */
sql_print_information("Event Scheduler: Killing the scheduler thread, "
"thread id %lu",
scheduler_thd->thread_id);
scheduler_thd->awake(THD::KILL_CONNECTION);
pthread_mutex_unlock(&scheduler_thd->LOCK_delete);
pthread_mutex_unlock(&scheduler_thd->LOCK_thd_data);
/* thd could be 0x0, when shutting down */
sql_print_information("Event Scheduler: "
......
......@@ -852,22 +852,23 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
}
/*
Inits the scheduler's structures.
/**
Initializes the scheduler's structures.
SYNOPSIS
Events::init()
@param opt_noacl_or_bootstrap
TRUE if there is --skip-grant-tables or --bootstrap
option. In that case we disable the event scheduler.
NOTES
This function is not synchronized.
@note This function is not synchronized.
RETURN VALUE
FALSE OK
TRUE Error in case the scheduler can't start
@retval FALSE Perhaps there was an error, and the event scheduler
is disabled. But the error is not fatal and the
server start up can continue.
@retval TRUE Fatal error. Startup must terminate (call unireg_abort()).
*/
bool
Events::init(my_bool opt_noacl)
Events::init(my_bool opt_noacl_or_bootstrap)
{
THD *thd;
......@@ -875,11 +876,6 @@ Events::init(my_bool opt_noacl)
DBUG_ENTER("Events::init");
/* Disable the scheduler if running with --skip-grant-tables */
if (opt_noacl)
opt_event_scheduler= EVENTS_DISABLED;
/* We need a temporary THD during boot */
if (!(thd= new THD()))
{
......@@ -908,23 +904,30 @@ Events::init(my_bool opt_noacl)
/*
Since we allow event DDL even if the scheduler is disabled,
check the system tables, as we might need them.
If run with --skip-grant-tables or --bootstrap, don't try to do the
check of system tables and don't complain: in these modes the tables
are most likely not there and we're going to disable the event
scheduler anyway.
*/
if (Event_db_repository::check_system_tables(thd))
if (opt_noacl_or_bootstrap || Event_db_repository::check_system_tables(thd))
{
sql_print_error("Event Scheduler: An error occurred when initializing "
"system tables.%s",
opt_event_scheduler == EVENTS_DISABLED ?
"" : " Disabling the Event Scheduler.");
if (! opt_noacl_or_bootstrap)
{
sql_print_error("Event Scheduler: An error occurred when initializing "
"system tables. Disabling the Event Scheduler.");
check_system_tables_error= TRUE;
}
/* Disable the scheduler since the system tables are not up to date */
opt_event_scheduler= EVENTS_DISABLED;
check_system_tables_error= TRUE;
goto end;
}
/*
Was disabled explicitly from the command line, or because we're running
with --skip-grant-tables, or because we have no system tables.
with --skip-grant-tables, or --bootstrap, or because we have no system
tables.
*/
if (opt_event_scheduler == Events::EVENTS_DISABLED)
goto end;
......@@ -941,7 +944,7 @@ Events::init(my_bool opt_noacl)
}
if (event_queue->init_queue(thd) || load_events_from_db(thd) ||
opt_event_scheduler == EVENTS_ON && scheduler->start())
(opt_event_scheduler == EVENTS_ON && scheduler->start()))
{
sql_print_error("Event Scheduler: Error while loading from disk.");
res= TRUE; /* fatal error: request unireg_abort */
......
......@@ -253,8 +253,7 @@ static void run_query(THD *thd, char *buf, char *end,
const char* found_semicolon= NULL;
bzero((char*) &thd->net, sizeof(NET));
thd->query_length= end - buf;
thd->query= buf;
thd->set_query(buf, (uint) (end - buf));
thd->variables.pseudo_thread_id= thread_id;
thd->transaction.stmt.modified_non_trans_table= FALSE;
if (disable_binlog)
......@@ -297,8 +296,7 @@ static void run_query(THD *thd, char *buf, char *end,
thd->main_da.reset_diagnostics_area();
thd->options= save_thd_options;
thd->query_length= save_thd_query_length;
thd->query= save_thd_query;
thd->set_query(save_thd_query, save_thd_query_length);
thd->variables.pseudo_thread_id= save_thread_id;
thd->status_var= save_thd_status_var;
thd->transaction.all= save_thd_transaction_all;
......
......@@ -423,12 +423,9 @@ bool ha_partition::initialize_partition(MEM_ROOT *mem_root)
int ha_partition::delete_table(const char *name)
{
int error;
DBUG_ENTER("ha_partition::delete_table");
if ((error= del_ren_cre_table(name, NULL, NULL, NULL)))
DBUG_RETURN(error);
DBUG_RETURN(handler::delete_table(name));
DBUG_RETURN(del_ren_cre_table(name, NULL, NULL, NULL));
}
......@@ -456,12 +453,9 @@ int ha_partition::delete_table(const char *name)
int ha_partition::rename_table(const char *from, const char *to)
{
int error;
DBUG_ENTER("ha_partition::rename_table");
if ((error= del_ren_cre_table(from, to, NULL, NULL)))
DBUG_RETURN(error);
DBUG_RETURN(handler::rename_table(from, to));
DBUG_RETURN(del_ren_cre_table(from, to, NULL, NULL));
}
......@@ -1807,6 +1801,15 @@ uint ha_partition::del_ren_cre_table(const char *from,
DBUG_PRINT("enter", ("from: (%s) to: (%s)", from, to));
name_buffer_ptr= m_name_buffer_ptr;
file= m_file;
if (to == NULL && table_arg == NULL)
{
/*
Delete table, start by delete the .par file. If error, break, otherwise
delete as much as possible.
*/
if ((error= handler::delete_table(from)))
DBUG_RETURN(error);
}
/*
Since ha_partition has HA_FILE_BASED, it must alter underlying table names
if they do not have HA_FILE_BASED and lower_case_table_names == 2.
......@@ -1828,6 +1831,8 @@ uint ha_partition::del_ren_cre_table(const char *from,
create_partition_name(to_buff, to_path, name_buffer_ptr,
NORMAL_PART_NAME, FALSE);
error= (*file)->ha_rename_table(from_buff, to_buff);
if (error)
goto rename_error;
}
else if (table_arg == NULL) // delete branch
error= (*file)->ha_delete_table(from_buff);
......@@ -1843,6 +1848,15 @@ uint ha_partition::del_ren_cre_table(const char *from,
save_error= error;
i++;
} while (*(++file));
if (to != NULL)
{
if ((error= handler::rename_table(from, to)))
{
/* Try to revert everything, ignore errors */
(void) handler::rename_table(to, from);
goto rename_error;
}
}
DBUG_RETURN(save_error);
create_error:
name_buffer_ptr= m_name_buffer_ptr;
......@@ -1850,7 +1864,21 @@ uint ha_partition::del_ren_cre_table(const char *from,
{
create_partition_name(from_buff, from_path, name_buffer_ptr, NORMAL_PART_NAME,
FALSE);
VOID((*file)->ha_delete_table((const char*) from_buff));
(void) (*file)->ha_delete_table((const char*) from_buff);
name_buffer_ptr= strend(name_buffer_ptr) + 1;
}
DBUG_RETURN(error);
rename_error:
name_buffer_ptr= m_name_buffer_ptr;
for (abort_file= file, file= m_file; file < abort_file; file++)
{
/* Revert the rename, back from 'to' to the original 'from' */
create_partition_name(from_buff, from_path, name_buffer_ptr,
NORMAL_PART_NAME, FALSE);
create_partition_name(to_buff, to_path, name_buffer_ptr,
NORMAL_PART_NAME, FALSE);
/* Ignore error here */
(void) (*file)->ha_rename_table(to_buff, from_buff);
name_buffer_ptr= strend(name_buffer_ptr) + 1;
}
DBUG_RETURN(error);
......
......@@ -2977,6 +2977,7 @@ uint handler::get_dup_key(int error)
*/
int handler::delete_table(const char *name)
{
int saved_error= 0;
int error= 0;
int enoent_or_zero= ENOENT; // Error if no file was deleted
char buff[FN_REFLEN];
......@@ -2986,21 +2987,31 @@ int handler::delete_table(const char *name)
fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT);
if (my_delete_with_symlink(buff, MYF(0)))
{
if ((error= my_errno) != ENOENT)
break;
if (my_errno != ENOENT)
{
/*
If error on the first existing file, return the error.
Otherwise delete as much as possible.
*/
if (enoent_or_zero)
return my_errno;
saved_error= my_errno;
}
}
else
enoent_or_zero= 0; // No error for ENOENT
error= enoent_or_zero;
}
return error;
return saved_error ? saved_error : error;
}
int handler::rename_table(const char * from, const char * to)
{
int error= 0;
for (const char **ext= bas_ext(); *ext ; ext++)
const char **ext, **start_ext;
start_ext= bas_ext();
for (ext= start_ext; *ext ; ext++)
{
if (rename_file_ext(from, to, *ext))
{
......@@ -3009,6 +3020,12 @@ int handler::rename_table(const char * from, const char * to)
error= 0;
}
}
if (error)
{
/* Try to revert the rename. Ignore errors. */
for (; ext >= start_ext; ext--)
rename_file_ext(to, from, *ext);
}
return error;
}
......
......@@ -3025,8 +3025,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
rpl_filter->db_ok(thd->db))
{
thd->set_time((time_t)when);
thd->query_length= q_len_arg;
thd->query= (char*)query_arg;
thd->set_query((char*)query_arg, q_len_arg);
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id = next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count));
......@@ -3231,7 +3230,6 @@ Default database: '%s'. Query: '%s'",
} /* End of if (db_ok(... */
end:
VOID(pthread_mutex_lock(&LOCK_thread_count));
/*
Probably we have set thd->query, thd->db, thd->catalog to point to places
in the data_buf of this event. Now the event is going to be deleted
......@@ -3244,10 +3242,8 @@ Default database: '%s'. Query: '%s'",
*/
thd->catalog= 0;
thd->set_db(NULL, 0); /* will free the current database */
thd->set_query(NULL, 0);
DBUG_PRINT("info", ("end: query= 0"));
thd->query= 0; // just to be sure
thd->query_length= 0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
close_thread_tables(thd);
/*
As a disk space optimization, future masters will not log an event for
......@@ -4557,8 +4553,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
print_query(FALSE, load_data_query, &end, (char **)&thd->lex->fname_start,
(char **)&thd->lex->fname_end);
*end= 0;
thd->query_length= end - load_data_query;
thd->query= load_data_query;
thd->set_query(load_data_query, (uint) (end - load_data_query));
if (sql_ex.opt_flags & REPLACE_FLAG)
{
......@@ -4664,12 +4659,9 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
error:
thd->net.vio = 0;
const char *remember_db= thd->db;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->catalog= 0;
thd->set_db(NULL, 0); /* will free the current database */
thd->query= 0;
thd->query_length= 0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->set_query(NULL, 0);
close_thread_tables(thd);
DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error",
......
......@@ -1976,6 +1976,7 @@ extern bool opt_disable_networking, opt_skip_show_db;
extern bool opt_ignore_builtin_innodb;
extern my_bool opt_character_set_client_handshake;
extern bool volatile abort_loop, shutdown_in_progress;
extern bool in_bootstrap;
extern uint volatile thread_count, thread_running, global_read_lock;
extern uint connection_count;
extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
......
......@@ -416,6 +416,21 @@ my_bool locked_in_memory;
bool opt_using_transactions;
bool volatile abort_loop;
bool volatile shutdown_in_progress;
/*
True if the bootstrap thread is running. Protected by LOCK_thread_count,
just like thread_count.
Used in bootstrap() function to determine if the bootstrap thread
has completed. Note, that we can't use 'thread_count' instead,
since in 5.1, in presence of the Event Scheduler, there may be
event threads running in parallel, so it's impossible to know
what value of 'thread_count' is a sign of completion of the
bootstrap thread.
At the same time, we can't start the event scheduler after
bootstrap either, since we want to be able to process event-related
SQL commands in the init file and in --bootstrap mode.
*/
bool in_bootstrap= FALSE;
/**
@brief 'grant_option' is used to indicate if privileges needs
to be checked, in which case the lock, LOCK_grant, is used
......@@ -4426,6 +4441,11 @@ we force server id to 2, but this MySQL server will not act as a slave.");
unireg_abort(1);
}
execute_ddl_log_recovery();
if (Events::init(opt_noacl || opt_bootstrap))
unireg_abort(1);
if (opt_bootstrap)
{
select_thread_in_use= 0; // Allow 'kill' to work
......@@ -4437,14 +4457,10 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (read_init_file(opt_init_file))
unireg_abort(1);
}
execute_ddl_log_recovery();
create_shutdown_thread();
start_handle_manager();
if (Events::init(opt_noacl))
unireg_abort(1);
sql_print_information(ER(ER_STARTUP),my_progname,server_version,
((unix_sock == INVALID_SOCKET) ? (char*) ""
: mysqld_unix_port),
......@@ -4726,6 +4742,7 @@ static void bootstrap(FILE *file)
thd->security_ctx->master_access= ~(ulong)0;
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
thread_count++;
in_bootstrap= TRUE;
bootstrap_file=file;
#ifndef EMBEDDED_LIBRARY // TODO: Enable this
......@@ -4738,7 +4755,7 @@ static void bootstrap(FILE *file)
}
/* Wait for thread to die */
(void) pthread_mutex_lock(&LOCK_thread_count);
while (thread_count)
while (in_bootstrap)
{
(void) pthread_cond_wait(&COND_thread_count,&LOCK_thread_count);
DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
......
......@@ -512,7 +512,7 @@ terminate_slave_thread(THD *thd,
int error;
DBUG_PRINT("loop", ("killing slave thread"));
pthread_mutex_lock(&thd->LOCK_delete);
pthread_mutex_lock(&thd->LOCK_thd_data);
#ifndef DONT_USE_THR_ALARM
/*
Error codes from pthread_kill are:
......@@ -523,7 +523,7 @@ terminate_slave_thread(THD *thd,
DBUG_ASSERT(err != EINVAL);
#endif
thd->awake(THD::NOT_KILLED);
pthread_mutex_unlock(&thd->LOCK_delete);
pthread_mutex_unlock(&thd->LOCK_thd_data);
/*
There is a small chance that slave thread might miss the first
......@@ -1250,15 +1250,13 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
DBUG_RETURN(1);
}
thd->command = COM_TABLE_DUMP;
thd->query_length= packet_len;
/* Note that we should not set thd->query until the area is initalized */
if (!(query = thd->strmake((char*) net->read_pos, packet_len)))
{
sql_print_error("create_table_from_dump: out of memory");
my_message(ER_GET_ERRNO, "Out of memory", MYF(0));
DBUG_RETURN(1);
}
thd->query= query;
thd->set_query(query, packet_len);
thd->is_slave_error = 0;
bzero((char*) &tables,sizeof(tables));
......@@ -2755,10 +2753,8 @@ log space");
// print the current replication position
sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query = thd->db = 0; // extra safety
thd->query_length= thd->db_length= 0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->set_query(NULL, 0);
thd->reset_db(NULL, 0);
if (mysql)
{
/*
......@@ -3110,15 +3106,14 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
must "proactively" clear playgrounds:
*/
rli->cleanup_context(thd, 1);
VOID(pthread_mutex_lock(&LOCK_thread_count));
/*
Some extra safety, which should not been needed (normally, event deletion
should already have done these assignments (each event which sets these
variables is supposed to set them to 0 before terminating)).
*/
thd->query= thd->db= thd->catalog= 0;
thd->query_length= thd->db_length= 0;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->catalog= 0;
thd->set_query(NULL, 0);
thd->reset_db(NULL, 0);
thd_proc_info(thd, "Waiting for slave mutex on exit");
pthread_mutex_lock(&rli->run_lock);
/* We need data_lock, at least to wake up any waiting master_pos_wait() */
......
......@@ -1012,8 +1012,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
else
DBUG_RETURN(TRUE);
thd->query= pbuf;
thd->query_length= qbuf.length();
thd->set_query(pbuf, qbuf.length());
DBUG_RETURN(FALSE);
}
......@@ -2858,8 +2857,7 @@ sp_instr_stmt::execute(THD *thd, uint *nextp)
}
else
*nextp= m_ip+1;
thd->query= query;
thd->query_length= query_length;
thd->set_query(query, query_length);
thd->query_name_consts= 0;
if (!thd->is_error())
......
......@@ -627,7 +627,7 @@ THD::THD()
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&LOCK_thd_data, MY_MUTEX_INIT_FAST);
/* Variables with default values */
proc_info="login";
......@@ -911,8 +911,8 @@ THD::~THD()
THD_CHECK_SENTRY(this);
DBUG_ENTER("~THD()");
/* Ensure that no one is using THD */
pthread_mutex_lock(&LOCK_delete);
pthread_mutex_unlock(&LOCK_delete);
pthread_mutex_lock(&LOCK_thd_data);
pthread_mutex_unlock(&LOCK_thd_data);
add_to_status(&global_status_var, &status_var);
/* Close connection */
......@@ -939,7 +939,7 @@ THD::~THD()
free_root(&transaction.mem_root,MYF(0));
#endif
mysys_var=0; // Safety (shouldn't be needed)
pthread_mutex_destroy(&LOCK_delete);
pthread_mutex_destroy(&LOCK_thd_data);
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
#endif
......@@ -1012,7 +1012,7 @@ void THD::awake(THD::killed_state state_to_set)
DBUG_ENTER("THD::awake");
DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
THD_CHECK_SENTRY(this);
safe_mutex_assert_owner(&LOCK_delete);
safe_mutex_assert_owner(&LOCK_thd_data);
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
......@@ -1409,7 +1409,7 @@ int THD::send_explain_fields(select_result *result)
void THD::close_active_vio()
{
DBUG_ENTER("close_active_vio");
safe_mutex_assert_owner(&LOCK_delete);
safe_mutex_assert_owner(&LOCK_thd_data);
#ifndef EMBEDDED_LIBRARY
if (active_vio)
{
......@@ -3055,6 +3055,25 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
}
void THD::set_statement(Statement *stmt)
{
pthread_mutex_lock(&LOCK_thd_data);
Statement::set_statement(stmt);
pthread_mutex_unlock(&LOCK_thd_data);
}
/** Assign a new value to thd->query. */
void THD::set_query(char *query_arg, uint32 query_length_arg)
{
pthread_mutex_lock(&LOCK_thd_data);
query= query_arg;
query_length= query_length_arg;
pthread_mutex_unlock(&LOCK_thd_data);
}
/**
Mark transaction to rollback and mark error as fatal to a sub-statement.
......
......@@ -631,22 +631,16 @@ class Statement: public ilink, public Query_arena
we need to declare it char * because all table handlers are written
in C and need to point to it.
Note that (A) if we set query = NULL, we must at the same time set
query_length = 0, and protect the whole operation with the
LOCK_thread_count mutex. And (B) we are ONLY allowed to set query to a
non-NULL value if its previous value is NULL. We do not need to protect
operation (B) with any mutex. To avoid crashes in races, if we do not
know that thd->query cannot change at the moment, one should print
Note that if we set query = NULL, we must at the same time set
query_length = 0, and protect the whole operation with
LOCK_thd_data mutex. To avoid crashes in races, if we do not
know that thd->query cannot change at the moment, we should print
thd->query like this:
(1) reserve the LOCK_thread_count mutex;
(2) check if thd->query is NULL;
(3) if not NULL, then print at most thd->query_length characters from
it. We will see the query_length field as either 0, or the right value
for it.
Assuming that the write and read of an n-bit memory field in an n-bit
computer is atomic, we can avoid races in the above way.
This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB
STATUS.
(1) reserve the LOCK_thd_data mutex;
(2) print or copy the value of query and query_length
(3) release LOCK_thd_data mutex.
This printing is needed at least in SHOW PROCESSLIST and SHOW
ENGINE INNODB STATUS.
*/
char *query;
uint32 query_length; // current query length
......@@ -678,7 +672,7 @@ class Statement: public ilink, public Query_arena
virtual ~Statement();
/* Assign execution context (note: not all members) of given stmt to self */
void set_statement(Statement *stmt);
virtual void set_statement(Statement *stmt);
void set_n_backup_statement(Statement *stmt, Statement *backup);
void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */
......@@ -1298,7 +1292,15 @@ class THD :public Statement,
THR_LOCK_OWNER main_lock_id; // To use for conventional queries
THR_LOCK_OWNER *lock_id; // If not main_lock_id, points to
// the lock_id of a cursor.
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
/**
Protects THD data accessed from other threads:
- thd->query and thd->query_length (used by SHOW ENGINE
INNODB STATUS and SHOW PROCESSLIST
- thd->mysys_var (used by KILL statement and shutdown).
Is locked when THD is deleted.
*/
pthread_mutex_t LOCK_thd_data;
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
/*
......@@ -1890,15 +1892,15 @@ class THD :public Statement,
#ifdef SIGNAL_WITH_VIO_CLOSE
inline void set_active_vio(Vio* vio)
{
pthread_mutex_lock(&LOCK_delete);
pthread_mutex_lock(&LOCK_thd_data);
active_vio = vio;
pthread_mutex_unlock(&LOCK_delete);
pthread_mutex_unlock(&LOCK_thd_data);
}
inline void clear_active_vio()
{
pthread_mutex_lock(&LOCK_delete);
pthread_mutex_lock(&LOCK_thd_data);
active_vio = 0;
pthread_mutex_unlock(&LOCK_delete);
pthread_mutex_unlock(&LOCK_thd_data);
}
void close_active_vio();
#endif
......@@ -2271,6 +2273,14 @@ class THD :public Statement,
*/
void pop_internal_handler();
/** Overloaded to guard query/query_length fields */
virtual void set_statement(Statement *stmt);
/**
Assign a new value to thd->query.
Protected with LOCK_thd_data mutex.
*/
void set_query(char *query_arg, uint32 query_length_arg);
private:
/** The current internal error handler for this thread, or NULL. */
Internal_error_handler *m_internal_handler;
......
......@@ -1909,7 +1909,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list)
thread_count++;
pthread_mutex_unlock(&LOCK_thread_count);
di->thd.set_db(table_list->db, (uint) strlen(table_list->db));
di->thd.query= my_strdup(table_list->table_name, MYF(MY_WME));
di->thd.set_query(my_strdup(table_list->table_name, MYF(MY_WME)), 0);
if (di->thd.db == NULL || di->thd.query == NULL)
{
/* The error is reported */
......
......@@ -457,6 +457,7 @@ pthread_handler_t handle_bootstrap(void *arg)
thd->init_for_queries();
while (fgets(buff, thd->net.max_packet, file))
{
char *query;
/* strlen() can't be deleted because fgets() doesn't return length */
ulong length= (ulong) strlen(buff);
while (buff[length-1] != '\n' && !feof(file))
......@@ -489,11 +490,10 @@ pthread_handler_t handle_bootstrap(void *arg)
if (strncmp(buff, STRING_WITH_LEN("delimiter")) == 0)
continue;
thd->query_length=length;
thd->query= (char*) thd->memdup_w_gap(buff, length+1,
thd->db_length+1+
QUERY_CACHE_FLAGS_SIZE);
thd->query[length] = '\0';
query= (char *) thd->memdup_w_gap(buff, length + 1,
thd->db_length + 1 +
QUERY_CACHE_FLAGS_SIZE);
thd->set_query(query, length);
DBUG_PRINT("query",("%-.4096s",thd->query));
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
thd->profiling.start_new_query();
......@@ -533,8 +533,9 @@ pthread_handler_t handle_bootstrap(void *arg)
#ifndef EMBEDDED_LIBRARY
(void) pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
(void) pthread_mutex_unlock(&LOCK_thread_count);
in_bootstrap= FALSE;
(void) pthread_cond_broadcast(&COND_thread_count);
(void) pthread_mutex_unlock(&LOCK_thread_count);
my_thread_end();
pthread_exit(0);
#endif
......@@ -658,8 +659,7 @@ int mysql_table_dump(THD *thd, LEX_STRING *db, char *tbl_name)
if (check_one_table_access(thd, SELECT_ACL, table_list))
goto err;
thd->free_list = 0;
thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
thd->set_query(tbl_name, (uint) strlen(tbl_name));
if ((error = mysqld_dump_create_info(thd, table_list, -1)))
{
my_error(ER_GET_ERRNO, MYF(0), my_errno);
......@@ -1239,9 +1239,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->profiling.set_query_source(beginning_of_next_stmt, length);
#endif
thd->set_query(beginning_of_next_stmt, length);
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_length= length;
thd->query= beginning_of_next_stmt;
/*
Count each statement from the client.
*/
......@@ -1294,9 +1293,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
table_list.schema_table= schema_table;
}
thd->query_length= (uint) (packet_end - packet); // Don't count end \0
if (!(thd->query=fields= (char*) thd->memdup(packet,thd->query_length+1)))
uint query_length= (uint) (packet_end - packet); // Don't count end \0
if (!(fields= (char *) thd->memdup(packet, query_length + 1)))
break;
thd->set_query(fields, query_length);
general_log_print(thd, command, "%s %s", table_list.table_name, fields);
if (lower_case_table_names)
my_casedn_str(files_charset_info, table_list.table_name);
......@@ -1589,13 +1589,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
log_slow_statement(thd);
thd_proc_info(thd, "cleaning up");
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
thd_proc_info(thd, 0);
thd->set_query(NULL, 0);
thd->command=COM_SLEEP;
thd->query=0;
thd->query_length=0;
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
thread_running--;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd_proc_info(thd, 0);
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_RETURN(error);
......@@ -1788,6 +1787,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
bool alloc_query(THD *thd, const char *packet, uint packet_length)
{
char *query;
/* Remove garbage at start and end of query */
while (packet_length > 0 && my_isspace(thd->charset(), packet[0]))
{
......@@ -1802,14 +1802,13 @@ bool alloc_query(THD *thd, const char *packet, uint packet_length)
packet_length--;
}
/* We must allocate some extra memory for query cache */
thd->query_length= 0; // Extra safety: Avoid races
if (!(thd->query= (char*) thd->memdup_w_gap((uchar*) (packet),
packet_length,
thd->db_length+ 1 +
QUERY_CACHE_FLAGS_SIZE)))
return TRUE;
thd->query[packet_length]=0;
thd->query_length= packet_length;
if (! (query= (char*) thd->memdup_w_gap(packet,
packet_length,
1 + thd->db_length +
QUERY_CACHE_FLAGS_SIZE)))
return TRUE;
query[packet_length]= '\0';
thd->set_query(query, packet_length);
/* Reclaim some memory */
thd->packet.shrink(thd->variables.net_buffer_length);
......@@ -6950,7 +6949,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
continue;
if (tmp->thread_id == id)
{
pthread_mutex_lock(&tmp->LOCK_delete); // Lock from delete
pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
break;
}
}
......@@ -6983,7 +6982,7 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
}
else
error=ER_KILL_DENIED_ERROR;
pthread_mutex_unlock(&tmp->LOCK_delete);
pthread_mutex_unlock(&tmp->LOCK_thd_data);
}
DBUG_PRINT("exit", ("%d", error));
DBUG_RETURN(error);
......
......@@ -1102,7 +1102,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
if (tmp->command == COM_BINLOG_DUMP &&
tmp->server_id == slave_server_id)
{
pthread_mutex_lock(&tmp->LOCK_delete); // Lock from delete
pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
break;
}
}
......@@ -1115,7 +1115,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
again. We just to do kill the thread ourselves.
*/
tmp->awake(THD::KILL_QUERY);
pthread_mutex_unlock(&tmp->LOCK_delete);
pthread_mutex_unlock(&tmp->LOCK_thd_data);
}
}
......
......@@ -10662,6 +10662,11 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
if (table->s->db_type() != heap_hton ||
error != HA_ERR_RECORD_FILE_FULL)
{
/*
We don't want this error to be converted to a warning, e.g. in case of
INSERT IGNORE ... SELECT.
*/
thd->fatal_error();
table->file->print_error(error,MYF(0));
DBUG_RETURN(1);
}
......
......@@ -1768,16 +1768,14 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thd_info->start_time= tmp->start_time;
thd_info->query=0;
/* Lock THD mutex that protects its data when looking at it. */
pthread_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->query)
{
/*
query_length is always set to 0 when we set query = NULL; see
the comment in sql_class.h why this prevents crashes in possible
races with query_length
*/
uint length= min(max_query_length, tmp->query_length);
thd_info->query=(char*) thd->strmake(tmp->query,length);
}
pthread_mutex_unlock(&tmp->LOCK_thd_data);
thread_infos.append(thd_info);
}
}
......
......@@ -1799,6 +1799,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
int non_temp_tables_count= 0;
bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0;
String built_query;
String built_tmp_query;
DBUG_ENTER("mysql_rm_table_part2");
LINT_INIT(alias);
......@@ -1866,6 +1867,25 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
case 0:
// removed temporary table
tmp_table_deleted= 1;
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
thd->current_stmt_binlog_row_based)
{
if (built_tmp_query.is_empty())
{
built_tmp_query.set_charset(system_charset_info);
built_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
}
built_tmp_query.append("`");
if (thd->db == NULL || strcmp(db,thd->db) != 0)
{
built_tmp_query.append(db);
built_tmp_query.append("`.`");
}
built_tmp_query.append(table->table_name);
built_tmp_query.append("`,");
}
continue;
case -1:
DBUG_ASSERT(thd->in_sub_stmt);
......@@ -2023,29 +2043,52 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
write_bin_log(thd, !error, thd->query, thd->query_length);
}
else if (thd->current_stmt_binlog_row_based &&
non_temp_tables_count > 0 &&
tmp_table_deleted)
{
if (non_temp_tables_count > 0)
{
/*
In this case we have deleted both temporary and
non-temporary tables, so:
- since we have deleted a non-temporary table we have to
binlog the statement, but
- since we have deleted a temporary table we cannot binlog
the statement (since the table may have not been created on the
slave - check "if" branch below, this might cause the slave to
stop).
Instead, we write a built statement, only containing the
non-temporary tables, to the binary log
*/
built_query.chop(); // Chop of the last comma
built_query.append(" /* generated by server */");
write_bin_log(thd, !error, built_query.ptr(), built_query.length());
}
/*
In this case we have deleted both temporary and
non-temporary tables, so:
- since we have deleted a non-temporary table we have to
binlog the statement, but
- since we have deleted a temporary table we cannot binlog
the statement (since the table has not been created on the
slave, this might cause the slave to stop).
Instead, we write a built statement, only containing the
non-temporary tables, to the binary log
One needs to always log any temporary table drop, if:
1. thread logging format is mixed mode; AND
2. current statement logging format is set to row.
*/
built_query.chop(); // Chop of the last comma
built_query.append(" /* generated by server */");
write_bin_log(thd, !error, built_query.ptr(), built_query.length());
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED)
{
/*
In this case we have deleted some temporary tables but we are using
row based logging for the statement. However, thread uses mixed mode
format, thence we need to log the dropping as we cannot tell for
sure whether the create was logged as statement previously or not, ie,
before switching to row mode.
*/
built_tmp_query.chop(); // Chop of the last comma
built_tmp_query.append(" /* generated by server */");
write_bin_log(thd, !error, built_tmp_query.ptr(), built_tmp_query.length());
}
}
/*
The remaining cases are:
- no tables where deleted and
- only temporary tables where deleted and row-based
- no tables were deleted and
- only temporary tables were deleted and row-based
replication is used.
In both these cases, nothing should be written to the binary
log.
......
......@@ -1612,10 +1612,8 @@ bool ha_myisam::check_and_repair(THD *thd)
old_query= thd->query;
old_query_length= thd->query_length;
pthread_mutex_lock(&LOCK_thread_count);
thd->query= table->s->table_name.str;
thd->query_length= (uint) table->s->table_name.length;
pthread_mutex_unlock(&LOCK_thread_count);
thd->set_query(table->s->table_name.str,
(uint) table->s->table_name.length);
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
{
......@@ -1628,10 +1626,7 @@ bool ha_myisam::check_and_repair(THD *thd)
if (repair(thd, &check_opt))
error=1;
}
pthread_mutex_lock(&LOCK_thread_count);
thd->query= old_query;
thd->query_length= old_query_length;
pthread_mutex_unlock(&LOCK_thread_count);
thd->set_query(old_query, old_query_length);
DBUG_RETURN(error);
}
......
......@@ -185,13 +185,13 @@ static uchar NEAR sort_order_euc_kr[]=
Valid multi-byte characters:
[A1..FE][41..5A,61..7A,81..FE]
[81..FE][41..5A,61..7A,81..FE]
Note, 0x5C is not a valid MB tail,
so escape_with_backslash_is_dangerous is not set.
*/
#define iseuc_kr_head(c) ((0xa1<=(uchar)(c) && (uchar)(c)<=0xfe))
#define iseuc_kr_head(c) ((0x81<=(uchar)(c) && (uchar)(c)<=0xfe))
#define iseuc_kr_tail1(c) ((uchar) (c) >= 0x41 && (uchar) (c) <= 0x5A)
#define iseuc_kr_tail2(c) ((uchar) (c) >= 0x61 && (uchar) (c) <= 0x7A)
......@@ -1294,7 +1294,7 @@ static uint16 tab_ksc5601_uni0[]={
0x25A8,0x25A7,0x25A6,0x25A9,0x2668,0x260F,0x260E,0x261C,
0x261E,0x00B6,0x2020,0x2021,0x2195,0x2197,0x2199,0x2196,
0x2198,0x266D,0x2669,0x266A,0x266C,0x327F,0x321C,0x2116,
0x33C7,0x2122,0x33C2,0x33D8,0x2121, 0, 0, 0,
0x33C7,0x2122,0x33C2,0x33D8,0x2121,0x20AC,0x00AE, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
......@@ -4172,7 +4172,7 @@ static int func_ksc5601_uni_onechar(int code){
/* page 0 0x00A1-0x0167 */
static uint16 tab_uni_ksc56010[]={
0xA2AE, 0, 0,0xA2B4, 0, 0,0xA1D7,0xA1A7,
0,0xA8A3, 0, 0,0xA1A9, 0, 0,0xA1C6,
0,0xA8A3, 0, 0,0xA1A9,0xA2E7, 0,0xA1C6,
0xA1BE,0xA9F7,0xA9F8,0xA2A5, 0,0xA2D2,0xA1A4,0xA2AC,
0xA9F6,0xA8AC, 0,0xA8F9,0xA8F6,0xA8FA,0xA2AF, 0,
0, 0, 0, 0, 0,0xA8A1, 0, 0,
......@@ -4270,7 +4270,7 @@ static uint16 tab_uni_ksc56012[]={
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,0xA2E6,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
......
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