Merge tulin@bk-internal.mysql.com:/home/bk/mysql-5.0

into poseidon.ndb.mysql.com:/home/tomas/mysql-5.0-ndb
This commit is contained in:
unknown 2005-03-03 16:52:03 +01:00
commit be63bf616b
33 changed files with 603 additions and 128 deletions

View file

@ -206,11 +206,13 @@ void __CDECL hfree(void *ptr);
#endif
#endif /* MSDOS */
#ifndef errno /* did we already get it? */
#ifdef HAVE_ERRNO_AS_DEFINE
#include <errno.h> /* errno is a define */
#else
extern int errno; /* declare errno */
#endif
#endif /* #ifndef errno */
extern char NEAR errbuff[NRERRBUFFS][ERRMSGSIZE];
extern char *home_dir; /* Home directory for user */
extern char *my_progname; /* program-name (printed in errors) */

View file

@ -18,5 +18,4 @@ master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table
master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table `table:name` (a int)
master-bin.000001 # Query 1 # use `drop-temp+table-test`; create temporary table shortn2 (a int)
master-bin.000001 # Query 1 # use `drop-temp+table-test`; DROP /*!40005 TEMPORARY */ TABLE IF EXISTS `drop-temp+table-test`.`shortn2`,`drop-temp+table-test`.`table:name`,`drop-temp+table-test`.`shortn1`
master-bin.000001 # Query 1 # use `drop-temp+table-test`; DO RELEASE_LOCK("a")
drop database `drop-temp+table-test`;

View file

@ -93,7 +93,6 @@ master-bin.000001 96 Query 1 # use `test`; BEGIN
master-bin.000001 165 Query 1 # use `test`; insert into t1 values(8)
master-bin.000001 253 Query 1 # use `test`; insert into t2 select * from t1
master-bin.000001 348 Query 1 # use `test`; ROLLBACK
master-bin.000001 420 Query 1 # use `test`; DO RELEASE_LOCK("a")
delete from t1;
delete from t2;
reset master;

View file

@ -487,3 +487,40 @@ insert into t1 values ('foo');
prepare stmt FROM 'SELECT char_length (a) FROM t1';
ERROR 42000: FUNCTION test.char_length does not exist
drop table t1;
prepare stmt from "SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0";
execute stmt;
foo
SELECT FOUND_ROWS();
FOUND_ROWS()
2
execute stmt;
foo
SELECT FOUND_ROWS();
FOUND_ROWS()
2
deallocate prepare stmt;
create table t1 (a char(3) not null, b char(3) not null,
c char(3) not null, primary key (a, b, c));
create table t2 like t1;
prepare stmt from
"select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
where t1.a=1";
execute stmt;
a
execute stmt;
a
execute stmt;
a
prepare stmt from
"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
left outer join t2 t3 on t3.a=? where t1.a=?";
set @a:=1, @b:=1, @c:=1;
execute stmt using @a, @b, @c;
a b c a b c
execute stmt using @a, @b, @c;
a b c a b c
execute stmt using @a, @b, @c;
a b c a b c
deallocate prepare stmt;
drop table t1,t2;

View file

@ -33,27 +33,12 @@ select sum(length(word)) from t1;
sum(length(word))
1022
drop table t1,t3;
create table t1 (n int) engine=myisam;
reset master;
stop slave;
reset slave;
create table t1(n int);
select get_lock("hold_slave",10);
get_lock("hold_slave",10)
1
explain extended select get_lock("hold_slave",10);
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select sql_no_cache get_lock(_latin1'hold_slave',10) AS `get_lock("hold_slave",10)`
lock tables t1 read;
start slave;
select release_lock("hold_slave");
release_lock("hold_slave")
1
explain extended select release_lock("hold_slave");
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select sql_no_cache release_lock(_latin1'hold_slave') AS `release_lock("hold_slave")`
unlock tables;
create table t2(id int);
insert into t2 values(connection_id());

View file

@ -4,26 +4,20 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
select get_lock("a",5);
get_lock("a",5)
1
create table t1(n int);
insert into t1 values(1+get_lock("a",15)*0);
insert into t1 values(2);
stop slave;
select * from t1;
n
1
stop slave sql_thread;
insert into t1 values(1);
insert into t1 values(2);
stop slave;
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 377 # # master-bin.000001 No No 0 0 289 # None 0 No #
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 358 # # master-bin.000001 No No 0 0 182 # None 0 No #
change master to master_user='root';
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 289 # # master-bin.000001 No No 0 0 289 # None 0 No #
select release_lock("a");
release_lock("a")
1
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 182 # # master-bin.000001 No No 0 0 182 # None 0 No #
start slave;
select * from t1;
n

View file

@ -0,0 +1,81 @@
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 not null, key(a)) engine=innodb;
create table t2 (a int not null, key(a)) engine=innodb;
create table t3 (a int) engine=innodb;
create table t4 (a int) engine=innodb;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL,
KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) NOT NULL,
KEY `a` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
stop slave;
begin;
insert into t3 select * from t2 for update;
insert into t1 values(1);
commit;
begin;
select * from t1 for update;
a
start slave;
insert into t2 values(22);
commit;
select * from t1;
a
1
select * from t2;
a
22
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 19116 # # master-bin.000001 Yes Yes 0 0 19116 # None 0 No #
stop slave;
change master to master_log_pos=534;
begin;
select * from t2 for update;
a
22
start slave;
commit;
select * from t1;
a
1
1
select * from t2;
a
22
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 19116 # # master-bin.000001 Yes Yes 0 0 19116 # None 0 No #
set global max_relay_log_size=0;
stop slave;
change master to master_log_pos=534;
begin;
select * from t2 for update;
a
22
start slave;
commit;
select * from t1;
a
1
1
1
select * from t2;
a
22
show slave status;
Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master
# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 19116 # # master-bin.000001 Yes Yes 0 0 19116 # None 0 No #
drop table t1,t2;

View file

@ -2204,6 +2204,10 @@ call bug8757()|
delete from t1|
delete from t2|
drop procedure bug8757|
drop procedure if exists bug8762|
drop procedure if exists bug8762; create procedure bug8762() begin end|
drop procedure if exists bug8762; create procedure bug8762() begin end|
drop procedure bug8762|
drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)|
drop procedure if exists ifac|
@ -2538,3 +2542,41 @@ drop procedure bug7992|
drop table t3|
drop table t1;
drop table t2;
CREATE TABLE t1 (
lpitnumber int(11) default NULL,
lrecordtype int(11) default NULL
);
CREATE TABLE t2 (
lbsiid int(11) NOT NULL default '0',
ltradingmodeid int(11) NOT NULL default '0',
ltradingareaid int(11) NOT NULL default '0',
csellingprice decimal(19,4) default NULL,
PRIMARY KEY (lbsiid,ltradingmodeid,ltradingareaid)
);
CREATE TABLE t3 (
lbsiid int(11) NOT NULL default '0',
ltradingareaid int(11) NOT NULL default '0',
PRIMARY KEY (lbsiid,ltradingareaid)
);
CREATE PROCEDURE bug8849()
begin
insert into t3
(
t3.lbsiid,
t3.ltradingareaid
)
select distinct t1.lpitnumber, t2.ltradingareaid
from
t2 join t1 on
t1.lpitnumber = t2.lbsiid
and t1.lrecordtype = 1
left join t2 as price01 on
price01.lbsiid = t2.lbsiid and
price01.ltradingmodeid = 1 and
t2.ltradingareaid = price01.ltradingareaid;
end|
call bug8849();
call bug8849();
call bug8849();
drop procedure bug8849;
drop tables t1,t2,t3;

View file

@ -497,3 +497,46 @@ insert into t1 values ('foo');
prepare stmt FROM 'SELECT char_length (a) FROM t1';
drop table t1;
#
# Bug #6089: FOUND_ROWS returns wrong values when no table/view is used
#
prepare stmt from "SELECT SQL_CALC_FOUND_ROWS 'foo' UNION SELECT 'bar' LIMIT 0";
execute stmt;
SELECT FOUND_ROWS();
execute stmt;
SELECT FOUND_ROWS();
deallocate prepare stmt;
#
# Bug#8115: equality propagation and prepared statements
#
create table t1 (a char(3) not null, b char(3) not null,
c char(3) not null, primary key (a, b, c));
create table t2 like t1;
# reduced query
prepare stmt from
"select t1.a from (t1 left outer join t2 on t2.a=1 and t1.b=t2.b)
where t1.a=1";
execute stmt;
execute stmt;
execute stmt;
# original query
prepare stmt from
"select t1.a, t1.b, t1.c, t2.a, t2.b, t2.c from
(t1 left outer join t2 on t2.a=? and t1.b=t2.b)
left outer join t2 t3 on t3.a=? where t1.a=?";
set @a:=1, @b:=1, @c:=1;
execute stmt using @a, @b, @c;
execute stmt using @a, @b, @c;
execute stmt using @a, @b, @c;
deallocate prepare stmt;
drop table t1,t2;

View file

@ -39,7 +39,13 @@ save_master_pos;
connection slave;
sync_with_master;
#test handling of aborted connection in the middle of update
# Test if the slave SQL thread can be more than 16K behind the slave
# I/O thread (> IO_SIZE)
connection master;
# we'll use table-level locking to delay slave SQL thread
create table t1 (n int) engine=myisam;
sync_slave_with_master;
connection master;
reset master;
connection slave;
@ -47,29 +53,26 @@ stop slave;
reset slave;
connection master;
create table t1(n int);
#we want the log to exceed 16K to test deal with the log that is bigger than
#IO_SIZE
let $1=5000;
# Generate 16K of relay log
disable_query_log;
while ($1)
{
eval insert into t1 values($1+get_lock("hold_slave",10)*0);
eval insert into t1 values($1);
dec $1;
}
enable_query_log;
# Try to cause a large relay log lag on the slave
# Try to cause a large relay log lag on the slave by locking t1
connection slave;
select get_lock("hold_slave",10);
explain extended select get_lock("hold_slave",10);
lock tables t1 read;
start slave;
#hope this is long enough for I/O thread to fetch over 16K relay log data
sleep 3;
select release_lock("hold_slave");
explain extended select release_lock("hold_slave");
unlock tables;
#test handling of aborted connection in the middle of update
connection master;
create table t2(id int);
insert into t2 values(connection_id());

View file

@ -1,16 +1,23 @@
# Verify that after CHANGE MASTER, replication (I/O thread and SQL
# thread) restart from where SQL thread left, not from where
# I/O thread left (some old bug fixed in 4.0.17)
source include/master-slave.inc;
connection slave;
select get_lock("a",5);
connection master;
# Make SQL slave thread advance a bit
create table t1(n int);
insert into t1 values(1+get_lock("a",15)*0);
sync_slave_with_master;
select * from t1;
# Now stop it and make I/O slave thread be ahead
stop slave sql_thread;
connection master;
insert into t1 values(1);
insert into t1 values(2);
save_master_pos;
connection slave;
--real_sleep 3; # can't sync_with_master as we should be blocked
--real_sleep 3; # wait for I/O thread to have read updates
stop slave;
select * from t1;
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
@ -18,8 +25,6 @@ change master to master_user='root';
--replace_result $MASTER_MYPORT MASTER_MYPORT
--replace_column 1 # 8 # 9 # 23 # 33 #
show slave status;
# Will restart from after the values(2), which is bug
select release_lock("a");
start slave;
sync_with_master;
select * from t1;

View file

@ -0,0 +1 @@
--innodb --loose-innodb_lock_wait_timeout=4 --slave-transaction-retries=2 --max-relay-log-size=4096

View file

@ -0,0 +1,107 @@
# See if slave restarts the transaction after failing on an InnoDB deadlock error.
# Note: testing what happens when too many retries is possible, but
# needs large waits when running with --debug, so we don't do it.
# The same way, this test may not test what is expected when run
# under Valgrind, timings are too short then (with --valgrind I
# (Guilhem) have seen the test manage to provoke lock wait timeout
# error but not deadlock error; that is ok as code deals with the two
# errors in exactly the same way.
source include/have_innodb.inc;
source include/master-slave.inc;
connection master;
create table t1 (a int not null, key(a)) engine=innodb;
create table t2 (a int not null, key(a)) engine=innodb;
create table t3 (a int) engine=innodb;
create table t4 (a int) engine=innodb;
sync_slave_with_master;
show create table t1;
show create table t2;
stop slave;
# 1) Test deadlock
connection master;
begin;
# Let's keep BEGIN and the locked statement in two different relay logs.
let $1=200;
disable_query_log;
while ($1)
{
eval insert into t3 values( $1 );
dec $1;
}
enable_query_log;
insert into t3 select * from t2 for update;
insert into t1 values(1);
commit;
save_master_pos;
connection slave;
begin;
# Let's make our transaction large so that it's slave who is chosen as
# victim
let $1=1000;
disable_query_log;
while ($1)
{
eval insert into t4 values( $1 );
dec $1;
}
enable_query_log;
select * from t1 for update;
start slave;
--sleep 3; # hope that slave is blocked now
insert into t2 values(22); # provoke deadlock, slave should be victim
commit;
sync_with_master;
select * from t1; # check that slave succeeded finally
select * from t2;
# check that no error is reported
--replace_column 1 # 8 # 9 # 23 # 33 #
--replace_result $MASTER_MYPORT MASTER_MYPORT
show slave status;
# 2) Test lock wait timeout
stop slave;
change master to master_log_pos=534; # the BEGIN log event
begin;
select * from t2 for update; # hold lock
start slave;
--sleep 10; # slave should have blocked, and be retrying
commit;
sync_with_master;
select * from t1; # check that slave succeeded finally
select * from t2;
# check that no error is reported
--replace_column 1 # 8 # 9 # 23 # 33 #
--replace_result $MASTER_MYPORT MASTER_MYPORT
show slave status;
# Now we repeat 2), but with BEGIN in the same relay log as
# COMMIT (to see if seeking into hot log is ok).
set global max_relay_log_size=0;
# This is really copy-paste of 2) of above
stop slave;
change master to master_log_pos=534;
begin;
select * from t2 for update;
start slave;
--sleep 10;
commit;
sync_with_master;
select * from t1;
select * from t2;
--replace_column 1 # 8 # 9 # 23 # 33 #
--replace_result $MASTER_MYPORT MASTER_MYPORT
show slave status;
connection master;
drop table t1,t2;
sync_slave_with_master;

View file

@ -22,6 +22,13 @@ connection slave;
sync_with_master;
select get_lock("lock",3);
select * from t1;
# There is no point in testing REPLICATIION of the IS_*_LOCK
# functions; slave does not run with the same concurrency context as
# master (generally in slave we can't know that on master this lock
# was already held by another connection and so that the the
# get_lock() we're replicating timed out on master hence returned 0,
# or that the is_free_lock() we're playing returned 0 etc.
# But here all we do is test these functions outside of replication.
select is_free_lock("lock"), is_used_lock("lock") = connection_id();
explain extended select is_free_lock("lock"), is_used_lock("lock");
# Check lock functions

View file

@ -2714,6 +2714,19 @@ delete from t2|
drop procedure bug8757|
#
# BUG#8762: Stored Procedures: Inconsistent behavior
# of DROP PROCEDURE IF EXISTS statement.
--disable_warnings
drop procedure if exists bug8762|
--enable_warnings
# Doesn't exist
drop procedure if exists bug8762; create procedure bug8762() begin end|
# Does exist
drop procedure if exists bug8762; create procedure bug8762() begin end|
drop procedure bug8762|
#
# Some "real" examples
#
@ -3073,3 +3086,52 @@ delimiter ;|
drop table t1;
drop table t2;
#
# Bug#8849: rolling back changes to AND/OR structure of ON and WHERE clauses
# in SP
#
CREATE TABLE t1 (
lpitnumber int(11) default NULL,
lrecordtype int(11) default NULL
);
CREATE TABLE t2 (
lbsiid int(11) NOT NULL default '0',
ltradingmodeid int(11) NOT NULL default '0',
ltradingareaid int(11) NOT NULL default '0',
csellingprice decimal(19,4) default NULL,
PRIMARY KEY (lbsiid,ltradingmodeid,ltradingareaid)
);
CREATE TABLE t3 (
lbsiid int(11) NOT NULL default '0',
ltradingareaid int(11) NOT NULL default '0',
PRIMARY KEY (lbsiid,ltradingareaid)
);
delimiter |;
CREATE PROCEDURE bug8849()
begin
insert into t3
(
t3.lbsiid,
t3.ltradingareaid
)
select distinct t1.lpitnumber, t2.ltradingareaid
from
t2 join t1 on
t1.lpitnumber = t2.lbsiid
and t1.lrecordtype = 1
left join t2 as price01 on
price01.lbsiid = t2.lbsiid and
price01.ltradingmodeid = 1 and
t2.ltradingareaid = price01.ltradingareaid;
end|
delimiter ;|
call bug8849();
call bug8849();
call bug8849();
drop procedure bug8849;
drop tables t1,t2,t3;

View file

@ -2289,6 +2289,21 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (check_stack_overrun(thd, buff))
return TRUE; // Fatal error flag is set!
/*
The following optimization reduces the depth of an AND-OR tree.
E.g. a WHERE clause like
F1 AND (F2 AND (F2 AND F4))
is parsed into a tree with the same nested structure as defined
by braces. This optimization will transform such tree into
AND (F1, F2, F3, F4).
Trees of OR items are flattened as well:
((F1 OR F2) OR (F3 OR F4)) => OR (F1, F2, F3, F4)
Items for removed AND/OR levels will dangle until the death of the
entire statement.
The optimization is currently prepared statements and stored procedures
friendly as it doesn't allocate any memory and its effects are durable
(i.e. do not depend on PS/SP arguments).
*/
while ((item=li++))
{
table_map tmp_table_map;
@ -3265,6 +3280,7 @@ Item_equal::Item_equal(Item *c, Item_field *f)
const_item= c;
}
Item_equal::Item_equal(Item_equal *item_equal)
: Item_bool_func(), eval_item(0), cond_false(0)
{
@ -3301,12 +3317,7 @@ void Item_equal::add(Item_field *f)
uint Item_equal::members()
{
uint count= 0;
List_iterator_fast<Item_field> li(fields);
Item_field *item;
while ((item= li++))
count++;
return count;
return fields.elements;
}

View file

@ -1095,6 +1095,12 @@ public:
predicates that can not be used to access tables in the investigated
plan for those, obtained by substitution of some fields for equal fields,
that can be used.
Prepared Statements/Stored Procedures note: instances of class
Item_equal are created only at the time a PS/SP is executed and
are deleted in the end of execution. All changes made to these
objects need not be registered in the list of changes of the parse
tree and do not harm PS/SP re-execution.
*/
class Item_equal: public Item_bool_func

View file

@ -2856,18 +2856,6 @@ void item_user_lock_free(void)
void item_user_lock_release(User_level_lock *ull)
{
ull->locked=0;
if (mysql_bin_log.is_open())
{
char buf[256];
const char *command="DO RELEASE_LOCK(\"";
String tmp(buf,sizeof(buf), system_charset_info);
tmp.copy(command, strlen(command), tmp.charset());
tmp.append(ull->key,ull->key_length);
tmp.append("\")", 2);
Query_log_event qev(current_thd, tmp.ptr(), tmp.length(), 0, FALSE);
qev.error_code=0; // this query is always safe to run on slave
mysql_bin_log.write(&qev);
}
if (--ull->count)
pthread_cond_signal(&ull->cond);
else
@ -2991,6 +2979,16 @@ longlong Item_func_get_lock::val_int()
User_level_lock *ull;
int error=0;
/*
In slave thread no need to get locks, everything is serialized. Anyway
there is no way to make GET_LOCK() work on slave like it did on master
(i.e. make it return exactly the same value) because we don't have the
same other concurrent threads environment. No matter what we return here,
it's not guaranteed to be same as on master.
*/
if (thd->slave_thread)
return 1;
pthread_mutex_lock(&LOCK_user_locks);
if (!res || !res->length())

View file

@ -2457,7 +2457,7 @@ void sql_print_information(const char *format, ...)
static const char tc_log_magic[]={(char) 254, 0x23, 0x05, 0x74};
uint opt_tc_log_size=TC_LOG_MIN_SIZE;
ulong opt_tc_log_size= TC_LOG_MIN_SIZE;
ulong tc_log_max_pages_used=0, tc_log_page_size=0,
tc_log_page_waits=0, tc_log_cur_pages_used=0;

View file

@ -1616,9 +1616,9 @@ end:
probably, so data_buf will be freed, so the thd->... listed above will be
pointers to freed memory.
So we must set them to 0, so that those bad pointers values are not later
used. Note that "cleanup" queries (automatic DO RELEASE_LOCK() and DROP
TEMPORARY TABLE don't suffer from these assignments to 0 as DROP TEMPORARY
TABLE uses the db.table syntax).
used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE
don't suffer from these assignments to 0 as DROP TEMPORARY
TABLE uses the db.table syntax.
*/
thd->db= thd->catalog= 0; // prevent db from being freed
thd->query= 0; // just to be sure
@ -3666,8 +3666,8 @@ void Stop_log_event::print(FILE* file, bool short_form, LAST_EVENT_INFO* last_ev
The master stopped.
We used to clean up all temporary tables but this is useless as, as the
master has shut down properly, it has written all DROP TEMPORARY TABLE and DO
RELEASE_LOCK (prepared statements' deletion is TODO).
master has shut down properly, it has written all DROP TEMPORARY TABLE
(prepared statements' deletion is TODO only when we binlog prep stmts).
We used to clean up slave_load_tmpdir, but this is useless as it has been
cleared at the end of LOAD DATA INFILE.
So we have nothing to do here.

View file

@ -805,6 +805,7 @@ void mysql_stmt_free(THD *thd, char *packet);
void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
void reset_stmt_for_execute(THD *thd, LEX *lex);
void init_stmt_after_parse(THD*, LEX*);
/* sql_error.cc */
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
@ -1037,7 +1038,7 @@ extern ulong query_cache_size, query_cache_min_res_unit;
extern ulong thd_startup_options, slow_launch_threads, slow_launch_time;
extern ulong table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong slave_net_timeout;
extern ulong slave_net_timeout, slave_trans_retries;
extern uint max_user_connections;
extern ulong what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;

View file

@ -334,7 +334,7 @@ ulong server_id, thd_startup_options;
ulong table_cache_size, thread_stack, thread_stack_min, what_to_log;
ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
ulong open_files_limit, max_binlog_size, max_relay_log_size;
ulong slave_net_timeout;
ulong slave_net_timeout, slave_trans_retries;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
ulong refresh_version, flush_version; /* Increments on each reload */
@ -4192,7 +4192,7 @@ enum options_mysqld
OPT_QUERY_CACHE_TYPE, OPT_QUERY_CACHE_WLOCK_INVALIDATE, OPT_RECORD_BUFFER,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE,
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
OPT_READONLY, OPT_DEBUGGING,
OPT_SLAVE_TRANS_RETRIES, OPT_READONLY, OPT_DEBUGGING,
OPT_SORT_BUFFER, OPT_TABLE_CACHE,
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK,
@ -4566,7 +4566,7 @@ Disable with --skip-isam.",
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"log-tc-size", OPT_LOG_TC_SIZE, "Size of transaction coordinator log.",
(gptr*) &opt_tc_log_size, (gptr*) &opt_tc_log_size, 0, GET_ULONG,
REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0, 0, TC_LOG_PAGE_SIZE, 0},
REQUIRED_ARG, TC_LOG_MIN_SIZE, TC_LOG_MIN_SIZE, ~0L, 0, TC_LOG_PAGE_SIZE, 0},
{"log-update", OPT_UPDATE_LOG,
"The update log is deprecated since version 5.0, is replaced by the binary \
log and this option justs turns on --log-bin instead.",
@ -5222,7 +5222,7 @@ The minimum value for this variable is 4096.",
(gptr*) &max_system_variables.max_length_for_sort_data, 0, GET_ULONG,
REQUIRED_ARG, 1024, 4, 8192*1024L, 0, 1, 0},
{"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE,
"If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 expected, the minimum value for this variable is 4096.",
"If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 excepted, the minimum value for this variable is 4096.",
(gptr*) &max_relay_log_size, (gptr*) &max_relay_log_size, 0, GET_ULONG,
REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0},
{ "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY,
@ -5408,6 +5408,12 @@ The minimum value for this variable is 4096.",
"Number of seconds to wait for more data from a master/slave connection before aborting the read.",
(gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0,
GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{"slave_transaction_retries", OPT_SLAVE_TRANS_RETRIES,
"Number of times the slave SQL thread will retry a transaction in case "
"it failed with a deadlock or elapsed lock wait timeout, "
"before giving up and stopping.",
(gptr*) &slave_trans_retries, (gptr*) &slave_trans_retries, 0,
GET_ULONG, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0},
#endif /* HAVE_REPLICATION */
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
"If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.",
@ -5793,7 +5799,7 @@ static void mysql_init_variables(void)
opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
opt_disable_networking= opt_skip_show_db=0;
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname= 0;
opt_tc_log_file= "tc.log"; // no hostname in tc_log file name !
opt_tc_log_file= (char *)"tc.log"; // no hostname in tc_log file name !
opt_secure_auth= 0;
opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;

View file

@ -340,6 +340,8 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
#ifdef HAVE_REPLICATION
sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout",
&slave_net_timeout);
sys_var_long_ptr sys_slave_trans_retries("slave_transaction_retries",
&slave_trans_retries);
#endif
sys_var_long_ptr sys_slow_launch_time("slow_launch_time",
&slow_launch_time);
@ -652,6 +654,7 @@ sys_var *sys_variables[]=
#ifdef HAVE_REPLICATION
&sys_slave_compressed_protocol,
&sys_slave_net_timeout,
&sys_slave_trans_retries,
&sys_slave_skip_counter,
#endif
&sys_slow_launch_time,
@ -931,6 +934,7 @@ struct show_var_st init_vars[]= {
{"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL},
#ifdef HAVE_REPLICATION
{sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS},
{sys_slave_trans_retries.name,(char*) &sys_slave_trans_retries, SHOW_SYS},
#endif
{sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS},
#ifdef HAVE_SYS_UN_H

View file

@ -3228,6 +3228,53 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
DBUG_PRINT("info", ("Deleting the event after it has been executed"));
delete ev;
}
if (slave_trans_retries)
{
if (exec_res &&
(thd->net.last_errno == ER_LOCK_DEADLOCK ||
thd->net.last_errno == ER_LOCK_WAIT_TIMEOUT) &&
!thd->is_fatal_error)
{
const char *errmsg;
/*
We were in a transaction which has been rolled back because of a
deadlock (currently, InnoDB deadlock detected by InnoDB) or lock
wait timeout (innodb_lock_wait_timeout exceeded); let's seek back to
BEGIN log event and retry it all again.
We have to not only seek but also
a) init_master_info(), to seek back to hot relay log's start for later
(for when we will come back to this hot log after re-processing the
possibly existing old logs where BEGIN is: check_binlog_magic() will
then need the cache to be at position 0 (see comments at beginning of
init_master_info()).
b) init_relay_log_pos(), because the BEGIN may be an older relay log.
*/
if (rli->trans_retries--)
{
sql_print_information("Slave SQL thread retries transaction");
if (init_master_info(rli->mi, 0, 0, 0, SLAVE_SQL))
sql_print_error("Failed to initialize the master info structure");
else if (init_relay_log_pos(rli,
rli->group_relay_log_name,
rli->group_relay_log_pos,
1, &errmsg, 1))
sql_print_error("Error initializing relay log position: %s",
errmsg);
else
{
exec_res= 0;
sleep(2); // chance for concurrent connection to get more locks
}
}
else
sql_print_error("Slave SQL thread retried transaction %lu time(s) "
"in vain, giving up. Consider raising the value of "
"the slave_transaction_retries variable.",
slave_trans_retries);
}
if (!((thd->options & OPTION_BEGIN) && opt_using_transactions))
rli->trans_retries= slave_trans_retries; // restart from fresh
}
return exec_res;
}
else
@ -3642,6 +3689,7 @@ slave_begin:
pthread_mutex_lock(&rli->log_space_lock);
rli->ignore_log_space_limit= 0;
pthread_mutex_unlock(&rli->log_space_lock);
rli->trans_retries= slave_trans_retries; // start from "no error"
if (init_relay_log_pos(rli,
rli->group_relay_log_name,
@ -4188,7 +4236,7 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
master server shutdown. The only thing this does is cleaning. But
cleaning is already done on a per-master-thread basis (as the master
server is shutting down cleanly, it has written all DROP TEMPORARY TABLE
and DO RELEASE_LOCK; prepared statements' deletion are TODO).
prepared statements' deletion are TODO only when we binlog prep stmts).
We don't even increment mi->master_log_pos, because we may be just after
a Rotate event. Btw, in a few milliseconds we are going to have a Start

View file

@ -293,7 +293,8 @@ typedef struct st_relay_log_info
} until_log_names_cmp_result;
char cached_charset[6];
ulong trans_retries;
st_relay_log_info();
~st_relay_log_info();

View file

@ -288,12 +288,14 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
* in thd->lex (the unit and master stuff), and the easiest way to
* do it is, is to call mysql_init_query(), but this unfortunately
* resets teh value_list where we keep the CALL parameters. So we
* copy the list and then restore it.
* copy the list and then restore it. (... and found_semicolon too).
*/
List<Item> vals= thd->lex->value_list;
List<Item> tmpvals= thd->lex->value_list;
char *tmpfsc= thd->lex->found_semicolon;
lex_start(thd, (uchar*)defstr.c_ptr(), defstr.length());
thd->lex->value_list= vals;
thd->lex->value_list= tmpvals;
thd->lex->found_semicolon= tmpfsc;
}
if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)

View file

@ -819,6 +819,7 @@ sp_head::restore_lex(THD *thd)
LEX *sublex= thd->lex;
LEX *oldlex= (LEX *)m_lex.pop();
init_stmt_after_parse(thd, sublex);
if (! oldlex)
return; // Nothing to restore

View file

@ -45,7 +45,7 @@ extern const char **errmesg;
#define TC_LOG_PAGE_SIZE 8192
#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
extern uint opt_tc_log_size;
extern ulong opt_tc_log_size;
extern ulong tc_log_max_pages_used;
extern ulong tc_log_page_size;
extern ulong tc_log_page_waits;

View file

@ -1837,8 +1837,6 @@ void st_select_lex_unit::set_limit(SELECT_LEX *values,
select_limit_cnt= values->select_limit+values->offset_limit;
if (select_limit_cnt < values->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
}

View file

@ -1809,20 +1809,33 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
else
{
stmt->setup_set_params();
SELECT_LEX *sl= stmt->lex->all_selects_list;
/*
Save WHERE clause pointers, because they may be changed during query
optimisation.
*/
for (; sl; sl= sl->next_select_in_list())
sl->prep_where= sl->where;
init_stmt_after_parse(thd, stmt->lex);
stmt->state= Item_arena::PREPARED;
}
DBUG_RETURN(!stmt);
}
/* Reinit statement before execution */
/*
Init PS/SP specific parse tree members.
*/
void init_stmt_after_parse(THD *thd, LEX *lex)
{
SELECT_LEX *sl= lex->all_selects_list;
/*
Save WHERE clause pointers, because they may be changed during query
optimisation.
*/
for (; sl; sl= sl->next_select_in_list())
sl->prep_where= sl->where;
for (TABLE_LIST *table= lex->query_tables; table; table= table->next_global)
table->prep_on_expr= table->on_expr;
}
/* Reinit prepared statement/stored procedure before execution */
void reset_stmt_for_execute(THD *thd, LEX *lex)
{
@ -1883,6 +1896,12 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
tables->table= 0;
if (tables->nested_join)
tables->nested_join->counter= 0;
if (tables->prep_on_expr)
{
tables->on_expr= tables->prep_on_expr->copy_andor_structure(thd);
tables->on_expr->cleanup();
}
}
lex->current_select= &lex->select_lex;

View file

@ -6192,9 +6192,9 @@ finish:
For b=c it will be called with *cond_equal=(0,[Item_equal(a,b)])
and will transform *cond_equal into CE=(0,[Item_equal(a,b,c)]).
For b=2 it will be called with *cond_equal=(ptr(CE),[])
and will transform *cond_equal into (ptr(CE,[Item_equal(2,a,b,c)]).
and will transform *cond_equal into (ptr(CE),[Item_equal(2,a,b,c)]).
For f=e it will be called with *cond_equal=(ptr(CE), [])
and will transform *cond_equal into (ptr(CE,[Item_equal(f,e)]).
and will transform *cond_equal into (ptr(CE),[Item_equal(f,e)]).
NOTES
Now only fields that have the same type defintions (verified by
@ -6463,6 +6463,11 @@ static COND *build_equal_items_for_cond(COND *cond,
*/
while ((item= li++))
{
/*
PS/SP note: we can safely remove a node from AND-OR
structure here because it's restored before each
re-execution of any prepared statement/stored procedure.
*/
if (check_equality(item, &cond_equal))
li.remove();
}
@ -6501,6 +6506,11 @@ static COND *build_equal_items_for_cond(COND *cond,
if ((new_item = build_equal_items_for_cond(item, inherited))!= item)
{
/* This replacement happens only for standalone equalities */
/*
This is ok with PS/SP as the replacement is done for
arguments of an AND/OR item, which are restored for each
execution of PS/SP.
*/
li.replace(new_item);
}
}
@ -6636,10 +6646,12 @@ static COND *build_equal_items(THD *thd, COND *cond,
Item *expr;
List<TABLE_LIST> *join_list= table->nested_join ?
&table->nested_join->join_list : NULL;
expr= build_equal_items(thd, table->on_expr, inherited, join_list,
&table->cond_equal);
if (expr != table->on_expr)
thd->change_item_tree(&table->on_expr, expr);
/*
We can modify table->on_expr because its old value will
be restored before re-execution of PS/SP.
*/
table->on_expr= build_equal_items(thd, table->on_expr, inherited,
join_list, &table->cond_equal);
}
}
}
@ -6866,10 +6878,14 @@ static COND* substitute_for_best_equal_field(COND *cond,
while ((item= li++))
{
Item *new_item =substitute_for_best_equal_field(item, cond_equal,
table_join_idx);
table_join_idx);
/*
This works OK with PS/SP re-execution as changes are made to
the arguments of AND/OR items only
*/
if (new_item != item)
li.replace(new_item);
}
}
if (and_level)
{
@ -7198,7 +7214,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
*/
expr= simplify_joins(join, &nested_join->join_list,
table->on_expr, FALSE);
table->on_expr= expr;
table->prep_on_expr= table->on_expr= expr;
}
nested_join->used_tables= (table_map) 0;
nested_join->not_null_tables=(table_map) 0;
@ -7238,7 +7254,7 @@ simplify_joins(JOIN *join, List<TABLE_LIST> *join_list, COND *conds, bool top)
}
else
conds= table->on_expr;
table->on_expr= 0;
table->prep_on_expr= table->on_expr= 0;
}
}
@ -7319,10 +7335,7 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
DBUG_ENTER("optimize_cond");
if (!conds)
{
*cond_value= Item::COND_TRUE;
select->prep_where= 0;
}
else
{
/*

View file

@ -217,8 +217,6 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
thd_arg->lex->current_select= sl;
set_limit(sl, sl);
if (sl->braces)
sl->options&= ~OPTION_FOUND_ROWS;
can_skip_order_by= is_union &&
(!sl->braces || select_limit_cnt == HA_POS_ERROR);
@ -342,10 +340,9 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
if (arena->is_stmt_prepare())
{
/* prepare fake select to initialize it correctly */
ulong options_tmp= init_prepare_fake_select_lex(thd);
(void) init_prepare_fake_select_lex(thd);
/*
it should be done only once (because item_list builds only onece
per statement)
Should be done only once (the only item_list per statement).
*/
DBUG_ASSERT(fake_select_lex->join == 0);
if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->options,
@ -452,21 +449,14 @@ bool st_select_lex_unit::exec()
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
/*
When using braces, SQL_CALC_FOUND_ROWS affects the whole query.
We don't calculate found_rows() per union part
*/
if (select_limit_cnt == HA_POS_ERROR || sl->braces)
sl->options&= ~OPTION_FOUND_ROWS;
else
{
/*
We are doing an union without braces. In this case
SQL_CALC_FOUND_ROWS should be done on all sub parts
*/
sl->options|= found_rows_for_union;
}
sl->join->select_options=sl->options;
/*
When using braces, SQL_CALC_FOUND_ROWS affects the whole query:
we don't calculate found_rows() per union part.
Otherwise, SQL_CALC_FOUND_ROWS should be done on all sub parts.
*/
sl->join->select_options=
(select_limit_cnt == HA_POS_ERROR || sl->braces) ?
sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union;
res= sl->join->optimize();
}
if (!res)
@ -498,7 +488,8 @@ bool st_select_lex_unit::exec()
}
/* Needed for the following test and for records_at_start in next loop */
table->file->info(HA_STATUS_VARIABLE);
if (found_rows_for_union & sl->options)
if (found_rows_for_union && !sl->braces &&
select_limit_cnt != HA_POS_ERROR)
{
/*
This is a union without braces. Remember the number of rows that

View file

@ -339,6 +339,15 @@ typedef struct st_table_list
char *db, *alias, *table_name, *schema_table_name;
char *option; /* Used by cache index */
Item *on_expr; /* Used with outer join */
/*
The scturcture of ON expression presented in the member above
can be changed during certain optimizations. This member
contains a snapshot of AND-OR structure of the ON expression
made after permanent transformations of the parse tree, and is
used to restore ON clause before every reexecution of a prepared
statement or stored procedure.
*/
Item *prep_on_expr;
COND_EQUAL *cond_equal; /* Used with outer join */
struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */