Added options --auto-increment-increment and --auto-increment-offset.
This allows one to setup a master <-> master replication with non conflicting auto-increment series. Cleaned up binary log code to make it easyer to add new state variables. Added simpler 'upper level' logic for artificial events (events that should not cause cleanups on slave). Simplified binary log handling. Changed how auto_increment works together with to SET INSERT_ID=# to make it more predictable: Now the inserted rows in a multi-row statement are set independent of the existing rows in the table. (Before only InnoDB did this correctly) mysql-test/r/mix_innodb_myisam_binlog.result: Disable End_log_pos column from 'show binlog events' as this is now different from before mysql-test/t/mix_innodb_myisam_binlog.test: Disable End_log_pos column from 'show binlog events' as this is now different from before sql/ha_berkeley.cc: Changed prototype for get_auto_increment() sql/ha_berkeley.h: Changed prototype for get_auto_increment() sql/ha_heap.cc: Changed prototype for get_auto_increment() sql/ha_heap.h: Changed prototype for get_auto_increment() sql/ha_innodb.cc: Change how auto-increment is calculated. Now the auto-increment logic is done in 'update_auto_increment()' to ensure that all handlers has the same auto-increment usage sql/ha_innodb.h: Changed prototype for get_auto_increment() sql/ha_myisam.cc: Changed prototype for get_auto_increment() sql/ha_myisam.h: Changed prototype for get_auto_increment() sql/ha_ndbcluster.cc: Changed prototype for get_auto_increment() sql/ha_ndbcluster.h: Changed prototype for get_auto_increment() sql/handler.cc: Remove some usage of current_thd Changed how auto_increment works with SET INSERT_ID to make it more predictable (Now we should generate same auto-increment serie on a slave, even if the table has rows that was not on the master. Use auto_increment_increment and auto_increment_offset sql/handler.h: Changed prototype for get_auto_increment() sql/log.cc: Remove usage of 'set_log_pos()' to make code simpler. (Now log_pos is set in write_header()) Use 'data_written' instead of 'get_event_len()' to calculate how much data was written in the log sql/log_event.cc: Simple optimizations. Remove cached_event_len (not used variable) Made comments fit into 79 chars Removed Log_event::set_log_pos(). Now we calculate log_pos in write_header(). Renamed write_data() to write() as the original write() function was not needed anymore. Call writing of event header from event::write() functions. This made it easier to calculate the length of an event. Simplified 'write_header' and remove 'switches' from it. Changed all write() functions to return 'bool'. (The previous return values where not consistent) Store auto_increment_increment and auto_increment_offset in binary log Simplified how Query_log_event's where written and read. Now it's much easier to add now status variables for a query event to the binary log. Removed some old MySQL 4.x code to make it easier to grep for functions used in 5.0 sql/log_event.h: Changed return type of write() functions to bool. (Before we returned -1 or 1 for errors) write_data() -> write() Added 'data_written' member to make it easier to get length of written event. Removed 'cached_event_len' and 'get_event_len()' Added usage of auto_increment_increment and auto_increment_offset Added 'artifical_event' to Start_log_event_v3, to hide logic that we in the binary log use log_pos=0 as a flag for an artifical event. sql/mysqld.cc: Added options --auto-increment-increment and --auto-increment-offset sql/set_var.cc: Added variables auto_increment_increment and auto_increment_offset sql/slave.cc: Changed errors -> warnings & information (in error log) sql/sql_class.cc: Added THD::cleanup_after_query(). This makes some code simpler and allows us to clean up 'next_insert_id' after query sql/sql_class.h: Added new auto_increment_xxx variables Moved some functions/variables in THD class sql/sql_help.cc: Removed compiler warning sql/sql_insert.cc: Call 'restore_auto_increment()' if row was not inserted. This makes it easier for handler to reuse the last generated auto-incrment value that was not used (for example in case of duplicate key) sql/sql_parse.cc: Use cleanup_after_query() sql/sql_prepare.cc: Use cleanup_after_query() sql/sql_table.cc: R
This commit is contained in:
parent
b15004a800
commit
ffc0d185da
@ -8,10 +8,10 @@ insert into t2 select * from t1;
|
||||
commit;
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 176 use `test`; insert into t1 values(1)
|
||||
master-bin.000001 238 Query 1 183 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 326 Query 1 389 use `test`; COMMIT
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(1)
|
||||
master-bin.000001 238 Query 1 # use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 326 Query 1 # use `test`; COMMIT
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -23,10 +23,10 @@ Warnings:
|
||||
Warning 1196 Some non-transactional changed tables couldn't be rolled back
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 176 use `test`; insert into t1 values(2)
|
||||
master-bin.000001 238 Query 1 183 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 326 Query 1 391 use `test`; ROLLBACK
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(2)
|
||||
master-bin.000001 238 Query 1 # use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 326 Query 1 # use `test`; ROLLBACK
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -41,13 +41,13 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
|
||||
commit;
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 176 use `test`; insert into t1 values(3)
|
||||
master-bin.000001 238 Query 1 174 use `test`; savepoint my_savepoint
|
||||
master-bin.000001 317 Query 1 176 use `test`; insert into t1 values(4)
|
||||
master-bin.000001 398 Query 1 183 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 486 Query 1 186 use `test`; rollback to savepoint my_savepoint
|
||||
master-bin.000001 577 Query 1 640 use `test`; COMMIT
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(3)
|
||||
master-bin.000001 238 Query 1 # use `test`; savepoint my_savepoint
|
||||
master-bin.000001 317 Query 1 # use `test`; insert into t1 values(4)
|
||||
master-bin.000001 398 Query 1 # use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 486 Query 1 # use `test`; rollback to savepoint my_savepoint
|
||||
master-bin.000001 577 Query 1 # use `test`; COMMIT
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -67,14 +67,14 @@ a
|
||||
7
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 176 use `test`; insert into t1 values(5)
|
||||
master-bin.000001 238 Query 1 174 use `test`; savepoint my_savepoint
|
||||
master-bin.000001 317 Query 1 176 use `test`; insert into t1 values(6)
|
||||
master-bin.000001 398 Query 1 183 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 486 Query 1 186 use `test`; rollback to savepoint my_savepoint
|
||||
master-bin.000001 577 Query 1 176 use `test`; insert into t1 values(7)
|
||||
master-bin.000001 658 Query 1 721 use `test`; COMMIT
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(5)
|
||||
master-bin.000001 238 Query 1 # use `test`; savepoint my_savepoint
|
||||
master-bin.000001 317 Query 1 # use `test`; insert into t1 values(6)
|
||||
master-bin.000001 398 Query 1 # use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 486 Query 1 # use `test`; rollback to savepoint my_savepoint
|
||||
master-bin.000001 577 Query 1 # use `test`; insert into t1 values(7)
|
||||
master-bin.000001 658 Query 1 # use `test`; COMMIT
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -89,10 +89,10 @@ get_lock("a",10)
|
||||
1
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 176 use `test`; insert into t1 values(8)
|
||||
master-bin.000001 238 Query 1 183 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 326 Query 1 391 use `test`; ROLLBACK
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(8)
|
||||
master-bin.000001 238 Query 1 # use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 326 Query 1 # use `test`; ROLLBACK
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -100,8 +100,8 @@ insert into t1 values(9);
|
||||
insert into t2 select * from t1;
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 176 use `test`; insert into t1 values(9)
|
||||
master-bin.000001 176 Query 1 264 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 95 Query 1 # use `test`; insert into t1 values(9)
|
||||
master-bin.000001 176 Query 1 # use `test`; insert into t2 select * from t1
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -110,17 +110,17 @@ begin;
|
||||
insert into t2 select * from t1;
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 177 use `test`; insert into t1 values(10)
|
||||
master-bin.000001 177 Query 1 265 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 95 Query 1 # use `test`; insert into t1 values(10)
|
||||
master-bin.000001 177 Query 1 # use `test`; insert into t2 select * from t1
|
||||
insert into t1 values(11);
|
||||
commit;
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 177 use `test`; insert into t1 values(10)
|
||||
master-bin.000001 177 Query 1 265 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 265 Query 1 327 use `test`; BEGIN
|
||||
master-bin.000001 327 Query 1 347 use `test`; insert into t1 values(11)
|
||||
master-bin.000001 409 Query 1 472 use `test`; COMMIT
|
||||
master-bin.000001 95 Query 1 # use `test`; insert into t1 values(10)
|
||||
master-bin.000001 177 Query 1 # use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 265 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 327 Query 1 # use `test`; insert into t1 values(11)
|
||||
master-bin.000001 409 Query 1 # use `test`; COMMIT
|
||||
alter table t2 engine=INNODB;
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
@ -131,10 +131,10 @@ insert into t2 select * from t1;
|
||||
commit;
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 177 use `test`; insert into t1 values(12)
|
||||
master-bin.000001 239 Query 1 183 use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 327 Query 1 390 use `test`; COMMIT
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(12)
|
||||
master-bin.000001 239 Query 1 # use `test`; insert into t2 select * from t1
|
||||
master-bin.000001 327 Query 1 # use `test`; COMMIT
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -156,9 +156,9 @@ rollback to savepoint my_savepoint;
|
||||
commit;
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 177 use `test`; insert into t1 values(14)
|
||||
master-bin.000001 239 Query 1 302 use `test`; COMMIT
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(14)
|
||||
master-bin.000001 239 Query 1 # use `test`; COMMIT
|
||||
delete from t1;
|
||||
delete from t2;
|
||||
reset master;
|
||||
@ -176,8 +176,8 @@ a
|
||||
18
|
||||
show binlog events from 95;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 95 Query 1 157 use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 177 use `test`; insert into t1 values(16)
|
||||
master-bin.000001 239 Query 1 177 use `test`; insert into t1 values(18)
|
||||
master-bin.000001 321 Query 1 384 use `test`; COMMIT
|
||||
master-bin.000001 95 Query 1 # use `test`; BEGIN
|
||||
master-bin.000001 157 Query 1 # use `test`; insert into t1 values(16)
|
||||
master-bin.000001 239 Query 1 # use `test`; insert into t1 values(18)
|
||||
master-bin.000001 321 Query 1 # use `test`; COMMIT
|
||||
drop table t1,t2;
|
||||
|
185
mysql-test/r/rpl_auto_increment.result
Normal file
185
mysql-test/r/rpl_auto_increment.result
Normal file
@ -0,0 +1,185 @@
|
||||
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 auto_increment,b int, primary key (a)) engine=myisam auto_increment=3;
|
||||
insert into t1 values (NULL,1),(NULL,2),(NULL,3);
|
||||
select * from t1;
|
||||
a b
|
||||
12 1
|
||||
22 2
|
||||
32 3
|
||||
select * from t1;
|
||||
a b
|
||||
12 1
|
||||
22 2
|
||||
32 3
|
||||
drop table t1;
|
||||
create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam;
|
||||
insert into t1 values (1,1),(NULL,2),(3,3),(NULL,4);
|
||||
delete from t1 where b=4;
|
||||
insert into t1 values (NULL,5),(NULL,6);
|
||||
select * from t1;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
22 5
|
||||
32 6
|
||||
select * from t1;
|
||||
a b
|
||||
1 1
|
||||
2 2
|
||||
3 3
|
||||
22 5
|
||||
32 6
|
||||
drop table t1;
|
||||
set @@session.auto_increment_increment=100, @@session.auto_increment_offset=10;
|
||||
show variables like "%auto%";
|
||||
Variable_name Value
|
||||
auto_incrememt_increment 100
|
||||
auto_increment_offset 10
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
|
||||
insert into t1 values (NULL),(5),(NULL);
|
||||
insert into t1 values (250),(NULL);
|
||||
select * from t1;
|
||||
a
|
||||
5
|
||||
10
|
||||
110
|
||||
250
|
||||
310
|
||||
insert into t1 values (1000);
|
||||
set @@insert_id=400;
|
||||
insert into t1 values(NULL),(NULL);
|
||||
select * from t1;
|
||||
a
|
||||
5
|
||||
10
|
||||
110
|
||||
250
|
||||
310
|
||||
400
|
||||
410
|
||||
1000
|
||||
select * from t1;
|
||||
a
|
||||
5
|
||||
10
|
||||
110
|
||||
250
|
||||
310
|
||||
400
|
||||
410
|
||||
1000
|
||||
drop table t1;
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=innodb;
|
||||
insert into t1 values (NULL),(5),(NULL);
|
||||
insert into t1 values (250),(NULL);
|
||||
select * from t1;
|
||||
a
|
||||
5
|
||||
10
|
||||
110
|
||||
250
|
||||
310
|
||||
insert into t1 values (1000);
|
||||
set @@insert_id=400;
|
||||
insert into t1 values(NULL),(NULL);
|
||||
select * from t1;
|
||||
a
|
||||
5
|
||||
10
|
||||
110
|
||||
250
|
||||
310
|
||||
400
|
||||
410
|
||||
1000
|
||||
select * from t1;
|
||||
a
|
||||
5
|
||||
10
|
||||
110
|
||||
250
|
||||
310
|
||||
400
|
||||
410
|
||||
1000
|
||||
drop table t1;
|
||||
set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
|
||||
insert into t1 values (NULL),(5),(NULL),(NULL);
|
||||
insert into t1 values (500),(NULL),(502),(NULL),(NULL);
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
5
|
||||
6
|
||||
7
|
||||
500
|
||||
501
|
||||
502
|
||||
503
|
||||
504
|
||||
set @@insert_id=600;
|
||||
insert into t1 values(600),(NULL),(NULL);
|
||||
ERROR 23000: Duplicate entry '600' for key 1
|
||||
set @@insert_id=600;
|
||||
insert ignore into t1 values(600),(NULL),(NULL),(610),(NULL);
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
5
|
||||
6
|
||||
7
|
||||
500
|
||||
501
|
||||
502
|
||||
503
|
||||
504
|
||||
600
|
||||
610
|
||||
611
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
5
|
||||
6
|
||||
7
|
||||
500
|
||||
501
|
||||
502
|
||||
503
|
||||
504
|
||||
600
|
||||
610
|
||||
611
|
||||
drop table t1;
|
||||
set @@session.auto_increment_increment=10, @@session.auto_increment_offset=1;
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
|
||||
insert into t1 values(2),(12),(22),(32),(42);
|
||||
insert into t1 values (NULL),(NULL);
|
||||
insert into t1 values (3),(NULL),(NULL);
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
3
|
||||
11
|
||||
21
|
||||
31
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
11
|
||||
12
|
||||
21
|
||||
22
|
||||
31
|
||||
32
|
||||
42
|
||||
drop table t1;
|
@ -25,6 +25,7 @@ insert into t1 values(1);
|
||||
insert into t2 select * from t1;
|
||||
commit;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
delete from t1;
|
||||
@ -37,6 +38,7 @@ insert into t2 select * from t1;
|
||||
# should say some changes to non-transact1onal tables couldn't be rolled back
|
||||
rollback;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
delete from t1;
|
||||
@ -51,6 +53,7 @@ insert into t2 select * from t1;
|
||||
rollback to savepoint my_savepoint;
|
||||
commit;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
delete from t1;
|
||||
@ -67,6 +70,7 @@ insert into t1 values(7);
|
||||
commit;
|
||||
select a from t1 order by a; # check that savepoints work :)
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
# and when ROLLBACK is not explicit?
|
||||
@ -87,6 +91,7 @@ connection con2;
|
||||
# so SHOW BINLOG EVENTS may come before con1 does the loggin. To be sure that
|
||||
# logging has been done, we use a user lock.
|
||||
select get_lock("a",10);
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
# and when not in a transact1on?
|
||||
@ -97,6 +102,7 @@ reset master;
|
||||
insert into t1 values(9);
|
||||
insert into t2 select * from t1;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
# Check that when the query updat1ng the MyISAM table is the first in the
|
||||
@ -108,10 +114,12 @@ reset master;
|
||||
insert into t1 values(10); # first make t1 non-empty
|
||||
begin;
|
||||
insert into t2 select * from t1;
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
insert into t1 values(11);
|
||||
commit;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
|
||||
@ -129,6 +137,7 @@ insert into t1 values(12);
|
||||
insert into t2 select * from t1;
|
||||
commit;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
delete from t1;
|
||||
@ -140,6 +149,7 @@ insert into t1 values(13);
|
||||
insert into t2 select * from t1;
|
||||
rollback;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
delete from t1;
|
||||
@ -154,6 +164,7 @@ insert into t2 select * from t1;
|
||||
rollback to savepoint my_savepoint;
|
||||
commit;
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
delete from t1;
|
||||
@ -170,6 +181,7 @@ insert into t1 values(18);
|
||||
commit;
|
||||
select a from t1 order by a; # check that savepoints work :)
|
||||
|
||||
--replace_column 5 #
|
||||
show binlog events from 95;
|
||||
|
||||
drop table t1,t2;
|
||||
|
1
mysql-test/t/rpl_auto_increment-master.opt
Normal file
1
mysql-test/t/rpl_auto_increment-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--auto-increment-increment=10 --auto-increment-offset=2
|
104
mysql-test/t/rpl_auto_increment.test
Normal file
104
mysql-test/t/rpl_auto_increment.test
Normal file
@ -0,0 +1,104 @@
|
||||
#
|
||||
# Test of auto_increment with offset
|
||||
#
|
||||
source include/have_innodb.inc;
|
||||
source include/master-slave.inc;
|
||||
|
||||
create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam auto_increment=3;
|
||||
insert into t1 values (NULL,1),(NULL,2),(NULL,3);
|
||||
select * from t1;
|
||||
|
||||
sync_slave_with_master;
|
||||
select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
|
||||
create table t1 (a int not null auto_increment,b int, primary key (a)) engine=myisam;
|
||||
insert into t1 values (1,1),(NULL,2),(3,3),(NULL,4);
|
||||
delete from t1 where b=4;
|
||||
insert into t1 values (NULL,5),(NULL,6);
|
||||
select * from t1;
|
||||
|
||||
sync_slave_with_master;
|
||||
select * from t1;
|
||||
connection master;
|
||||
|
||||
drop table t1;
|
||||
|
||||
set @@session.auto_increment_increment=100, @@session.auto_increment_offset=10;
|
||||
show variables like "%auto%";
|
||||
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
|
||||
# Insert with 2 insert statements to get better testing of logging
|
||||
insert into t1 values (NULL),(5),(NULL);
|
||||
insert into t1 values (250),(NULL);
|
||||
select * from t1;
|
||||
insert into t1 values (1000);
|
||||
set @@insert_id=400;
|
||||
insert into t1 values(NULL),(NULL);
|
||||
select * from t1;
|
||||
|
||||
sync_slave_with_master;
|
||||
select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Same test with innodb (as the innodb code is a bit different)
|
||||
#
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=innodb;
|
||||
# Insert with 2 insert statements to get better testing of logging
|
||||
insert into t1 values (NULL),(5),(NULL);
|
||||
insert into t1 values (250),(NULL);
|
||||
select * from t1;
|
||||
insert into t1 values (1000);
|
||||
set @@insert_id=400;
|
||||
insert into t1 values(NULL),(NULL);
|
||||
select * from t1;
|
||||
|
||||
sync_slave_with_master;
|
||||
select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
|
||||
set @@session.auto_increment_increment=1, @@session.auto_increment_offset=1;
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
|
||||
# Insert with 2 insert statements to get better testing of logging
|
||||
insert into t1 values (NULL),(5),(NULL),(NULL);
|
||||
insert into t1 values (500),(NULL),(502),(NULL),(NULL);
|
||||
select * from t1;
|
||||
set @@insert_id=600;
|
||||
--error 1062
|
||||
insert into t1 values(600),(NULL),(NULL);
|
||||
set @@insert_id=600;
|
||||
insert ignore into t1 values(600),(NULL),(NULL),(610),(NULL);
|
||||
select * from t1;
|
||||
|
||||
sync_slave_with_master;
|
||||
select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# Test that auto-increment works when slave has rows in the table
|
||||
#
|
||||
set @@session.auto_increment_increment=10, @@session.auto_increment_offset=1;
|
||||
|
||||
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
|
||||
|
||||
sync_slave_with_master;
|
||||
insert into t1 values(2),(12),(22),(32),(42);
|
||||
connection master;
|
||||
|
||||
insert into t1 values (NULL),(NULL);
|
||||
insert into t1 values (3),(NULL),(NULL);
|
||||
select * from t1;
|
||||
|
||||
sync_slave_with_master;
|
||||
select * from t1;
|
||||
connection master;
|
||||
|
||||
drop table t1;
|
||||
|
||||
# End cleanup
|
||||
sync_slave_with_master;
|
@ -2089,9 +2089,9 @@ ha_rows ha_berkeley::records_in_range(uint keynr, key_range *start_key,
|
||||
}
|
||||
|
||||
|
||||
longlong ha_berkeley::get_auto_increment()
|
||||
ulonglong ha_berkeley::get_auto_increment()
|
||||
{
|
||||
longlong nr=1; // Default if error or new key
|
||||
ulonglong nr=1; // Default if error or new key
|
||||
int error;
|
||||
(void) ha_berkeley::extra(HA_EXTRA_KEYREAD);
|
||||
|
||||
@ -2140,7 +2140,7 @@ longlong ha_berkeley::get_auto_increment()
|
||||
}
|
||||
}
|
||||
if (!error)
|
||||
nr=(longlong)
|
||||
nr=(ulonglong)
|
||||
table->next_number_field->val_int_offset(table->rec_buff_length)+1;
|
||||
ha_berkeley::index_end();
|
||||
(void) ha_berkeley::extra(HA_EXTRA_NO_KEYREAD);
|
||||
|
@ -153,7 +153,7 @@ class ha_berkeley: public handler
|
||||
int5store(to,share->auto_ident);
|
||||
pthread_mutex_unlock(&share->mutex);
|
||||
}
|
||||
longlong get_auto_increment();
|
||||
ulonglong get_auto_increment();
|
||||
void print_error(int error, myf errflag);
|
||||
uint8 table_cache_type() { return HA_CACHE_TBL_TRANSACT; }
|
||||
bool primary_key_is_clustered() { return true; }
|
||||
|
@ -484,7 +484,7 @@ void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
|
||||
create_info->auto_increment_value= auto_increment_value;
|
||||
}
|
||||
|
||||
longlong ha_heap::get_auto_increment()
|
||||
ulonglong ha_heap::get_auto_increment()
|
||||
{
|
||||
ha_heap::info(HA_STATUS_AUTO);
|
||||
return auto_increment_value;
|
||||
|
@ -62,7 +62,7 @@ class ha_heap: public handler
|
||||
int write_row(byte * buf);
|
||||
int update_row(const byte * old_data, byte * new_data);
|
||||
int delete_row(const byte * buf);
|
||||
longlong get_auto_increment();
|
||||
ulonglong get_auto_increment();
|
||||
int index_read(byte * buf, const byte * key,
|
||||
uint key_len, enum ha_rkey_function find_flag);
|
||||
int index_read_idx(byte * buf, uint idx, const byte * key,
|
||||
|
171
sql/ha_innodb.cc
171
sql/ha_innodb.cc
@ -1627,8 +1627,6 @@ ha_innobase::open(
|
||||
}
|
||||
}
|
||||
|
||||
auto_inc_counter_for_this_stat = 0;
|
||||
|
||||
block_size = 16 * 1024; /* Index block size in InnoDB: used by MySQL
|
||||
in query optimization */
|
||||
|
||||
@ -2198,7 +2196,7 @@ ha_innobase::write_row(
|
||||
longlong dummy;
|
||||
ibool incremented_auto_inc_for_stat = FALSE;
|
||||
ibool incremented_auto_inc_counter = FALSE;
|
||||
ibool skip_auto_inc_decr;
|
||||
ibool skip_auto_inc_decr, auto_inc_used= FALSE;
|
||||
|
||||
DBUG_ENTER("ha_innobase::write_row");
|
||||
|
||||
@ -2260,98 +2258,13 @@ ha_innobase::write_row(
|
||||
prebuilt->sql_stat_start = TRUE;
|
||||
}
|
||||
|
||||
/* Fetch the value the user possibly has set in the
|
||||
autoincrement field */
|
||||
|
||||
auto_inc = table->next_number_field->val_int();
|
||||
|
||||
/* In replication and also otherwise the auto-inc column
|
||||
can be set with SET INSERT_ID. Then we must look at
|
||||
user_thd->next_insert_id. If it is nonzero and the user
|
||||
has not supplied a value, we must use it, and use values
|
||||
incremented by 1 in all subsequent inserts within the
|
||||
same SQL statement! */
|
||||
|
||||
if (auto_inc == 0 && user_thd->next_insert_id != 0) {
|
||||
auto_inc = user_thd->next_insert_id;
|
||||
auto_inc_counter_for_this_stat = auto_inc;
|
||||
}
|
||||
|
||||
if (auto_inc == 0 && auto_inc_counter_for_this_stat) {
|
||||
/* The user set the auto-inc counter for
|
||||
this SQL statement with SET INSERT_ID. We must
|
||||
assign sequential values from the counter. */
|
||||
|
||||
auto_inc_counter_for_this_stat++;
|
||||
incremented_auto_inc_for_stat = TRUE;
|
||||
|
||||
auto_inc = auto_inc_counter_for_this_stat;
|
||||
|
||||
/* We give MySQL a new value to place in the
|
||||
auto-inc column */
|
||||
user_thd->next_insert_id = auto_inc;
|
||||
}
|
||||
|
||||
if (auto_inc != 0) {
|
||||
/* This call will calculate the max of the current
|
||||
value and the value supplied by the user and
|
||||
update the counter accordingly */
|
||||
|
||||
/* We have to use the transactional lock mechanism
|
||||
on the auto-inc counter of the table to ensure
|
||||
that replication and roll-forward of the binlog
|
||||
exactly imitates also the given auto-inc values.
|
||||
The lock is released at each SQL statement's
|
||||
end. */
|
||||
|
||||
innodb_srv_conc_enter_innodb(prebuilt->trx);
|
||||
error = row_lock_table_autoinc_for_mysql(prebuilt);
|
||||
innodb_srv_conc_exit_innodb(prebuilt->trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
error = convert_error_code_to_mysql(error,
|
||||
user_thd);
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
dict_table_autoinc_update(prebuilt->table, auto_inc);
|
||||
} else {
|
||||
innodb_srv_conc_enter_innodb(prebuilt->trx);
|
||||
|
||||
if (!prebuilt->trx->auto_inc_lock) {
|
||||
|
||||
error = row_lock_table_autoinc_for_mysql(
|
||||
prebuilt);
|
||||
if (error != DB_SUCCESS) {
|
||||
innodb_srv_conc_exit_innodb(
|
||||
prebuilt->trx);
|
||||
|
||||
error = convert_error_code_to_mysql(
|
||||
error, user_thd);
|
||||
goto func_exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* The following call gets the value of the auto-inc
|
||||
counter of the table and increments it by 1 */
|
||||
|
||||
auto_inc = dict_table_autoinc_get(prebuilt->table);
|
||||
incremented_auto_inc_counter = TRUE;
|
||||
|
||||
innodb_srv_conc_exit_innodb(prebuilt->trx);
|
||||
|
||||
/* We can give the new value for MySQL to place in
|
||||
the field */
|
||||
|
||||
user_thd->next_insert_id = auto_inc;
|
||||
}
|
||||
|
||||
/* This call of a handler.cc function places
|
||||
user_thd->next_insert_id to the column value, if the column
|
||||
value was not set by the user */
|
||||
|
||||
/*
|
||||
We must use the handler code to update the auto-increment
|
||||
value to be sure that increment it correctly.
|
||||
*/
|
||||
update_auto_increment();
|
||||
auto_inc_used= 1;
|
||||
|
||||
}
|
||||
|
||||
if (prebuilt->mysql_template == NULL
|
||||
@ -2366,42 +2279,37 @@ ha_innobase::write_row(
|
||||
|
||||
error = row_insert_for_mysql((byte*) record, prebuilt);
|
||||
|
||||
if (error == DB_SUCCESS && auto_inc_used) {
|
||||
|
||||
/* Fetch the value that was set in the autoincrement field */
|
||||
|
||||
auto_inc = table->next_number_field->val_int();
|
||||
|
||||
if (auto_inc != 0) {
|
||||
/* This call will calculate the max of the current
|
||||
value and the value supplied by the user and
|
||||
update the counter accordingly */
|
||||
|
||||
/* We have to use the transactional lock mechanism
|
||||
on the auto-inc counter of the table to ensure
|
||||
that replication and roll-forward of the binlog
|
||||
exactly imitates also the given auto-inc values.
|
||||
The lock is released at each SQL statement's
|
||||
end. */
|
||||
|
||||
error = row_lock_table_autoinc_for_mysql(prebuilt);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
error = convert_error_code_to_mysql(error, user_thd);
|
||||
goto func_exit;
|
||||
}
|
||||
dict_table_autoinc_update(prebuilt->table, auto_inc);
|
||||
}
|
||||
}
|
||||
|
||||
innodb_srv_conc_exit_innodb(prebuilt->trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
/* If the insert did not succeed we restore the value of
|
||||
the auto-inc counter we used; note that this behavior was
|
||||
introduced only in version 4.0.4.
|
||||
NOTE that a REPLACE command handles a duplicate key error
|
||||
itself, and we must not decrement the autoinc counter
|
||||
if we are performing a REPLACE statement.
|
||||
NOTE 2: if there was an error, for example a deadlock,
|
||||
which caused InnoDB to roll back the whole transaction
|
||||
already in the call of row_insert_for_mysql(), we may no
|
||||
longer have the AUTO-INC lock, and cannot decrement
|
||||
the counter here. */
|
||||
|
||||
skip_auto_inc_decr = FALSE;
|
||||
|
||||
if (error == DB_DUPLICATE_KEY
|
||||
&& (user_thd->lex->sql_command == SQLCOM_REPLACE
|
||||
|| user_thd->lex->sql_command
|
||||
== SQLCOM_REPLACE_SELECT)) {
|
||||
|
||||
skip_auto_inc_decr= TRUE;
|
||||
}
|
||||
|
||||
if (!skip_auto_inc_decr && incremented_auto_inc_counter
|
||||
&& prebuilt->trx->auto_inc_lock) {
|
||||
dict_table_autoinc_decrement(prebuilt->table);
|
||||
}
|
||||
|
||||
if (!skip_auto_inc_decr && incremented_auto_inc_for_stat
|
||||
&& prebuilt->trx->auto_inc_lock) {
|
||||
auto_inc_counter_for_this_stat--;
|
||||
}
|
||||
}
|
||||
|
||||
error = convert_error_code_to_mysql(error, user_thd);
|
||||
|
||||
/* Tell InnoDB server that there might be work for
|
||||
@ -2412,6 +2320,7 @@ func_exit:
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************
|
||||
Converts field data for storage in an InnoDB update vector. */
|
||||
inline
|
||||
@ -5217,7 +5126,7 @@ initialized yet. This function does not change the value of the auto-inc
|
||||
counter if it already has been initialized. Returns the value of the
|
||||
auto-inc counter. */
|
||||
|
||||
longlong
|
||||
ulonglong
|
||||
ha_innobase::get_auto_increment()
|
||||
/*=============================*/
|
||||
/* out: auto-increment column value, -1 if error
|
||||
@ -5230,10 +5139,10 @@ ha_innobase::get_auto_increment()
|
||||
|
||||
if (error) {
|
||||
|
||||
return(-1);
|
||||
return(~(ulonglong) 0);
|
||||
}
|
||||
|
||||
return(nr);
|
||||
return((ulonglong) nr);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -164,7 +164,7 @@ class ha_innobase: public handler
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type);
|
||||
void init_table_handle_for_HANDLER();
|
||||
longlong get_auto_increment();
|
||||
ulonglong get_auto_increment();
|
||||
uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
|
||||
static char *get_mysql_bin_log_name();
|
||||
static ulonglong get_mysql_bin_log_pos();
|
||||
|
@ -1520,8 +1520,12 @@ int ha_myisam::rename_table(const char * from, const char * to)
|
||||
}
|
||||
|
||||
|
||||
longlong ha_myisam::get_auto_increment()
|
||||
ulonglong ha_myisam::get_auto_increment()
|
||||
{
|
||||
ulonglong nr;
|
||||
int error;
|
||||
byte key[MI_MAX_KEY_LENGTH];
|
||||
|
||||
if (!table->next_number_key_offset)
|
||||
{ // Autoincrement at key-start
|
||||
ha_myisam::info(HA_STATUS_AUTO);
|
||||
@ -1531,19 +1535,16 @@ longlong ha_myisam::get_auto_increment()
|
||||
/* it's safe to call the following if bulk_insert isn't on */
|
||||
mi_flush_bulk_insert(file, table->next_number_index);
|
||||
|
||||
longlong nr;
|
||||
int error;
|
||||
byte key[MI_MAX_KEY_LENGTH];
|
||||
(void) extra(HA_EXTRA_KEYREAD);
|
||||
key_copy(key,table,table->next_number_index,
|
||||
table->next_number_key_offset);
|
||||
error=mi_rkey(file,table->record[1],(int) table->next_number_index,
|
||||
key,table->next_number_key_offset,HA_READ_PREFIX_LAST);
|
||||
if (error)
|
||||
nr=1;
|
||||
nr= 1;
|
||||
else
|
||||
nr=(longlong)
|
||||
table->next_number_field->val_int_offset(table->rec_buff_length)+1;
|
||||
nr= ((ulonglong) table->next_number_field->
|
||||
val_int_offset(table->rec_buff_length)+1);
|
||||
extra(HA_EXTRA_NO_KEYREAD);
|
||||
return nr;
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class ha_myisam: public handler
|
||||
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type);
|
||||
longlong get_auto_increment();
|
||||
ulonglong get_auto_increment();
|
||||
int rename_table(const char * from, const char * to);
|
||||
int delete_table(const char *name);
|
||||
int check(THD* thd, HA_CHECK_OPT* check_opt);
|
||||
|
@ -3099,19 +3099,18 @@ int ndbcluster_drop_database(const char *path)
|
||||
}
|
||||
|
||||
|
||||
longlong ha_ndbcluster::get_auto_increment()
|
||||
ulonglong ha_ndbcluster::get_auto_increment()
|
||||
{
|
||||
int cache_size;
|
||||
Uint64 auto_value;
|
||||
DBUG_ENTER("get_auto_increment");
|
||||
DBUG_PRINT("enter", ("m_tabname: %s", m_tabname));
|
||||
int cache_size=
|
||||
(rows_to_insert > autoincrement_prefetch) ?
|
||||
rows_to_insert
|
||||
: autoincrement_prefetch;
|
||||
Uint64 auto_value=
|
||||
(skip_auto_increment) ?
|
||||
m_ndb->readAutoIncrementValue((NDBTAB *) m_table)
|
||||
: m_ndb->getAutoIncrementValue((NDBTAB *) m_table, cache_size);
|
||||
DBUG_RETURN((longlong)auto_value);
|
||||
cache_size= ((rows_to_insert > autoincrement_prefetch) ?
|
||||
rows_to_insert : autoincrement_prefetch);
|
||||
auto_value= ((skip_auto_increment) ?
|
||||
m_ndb->readAutoIncrementValue((NDBTAB *) m_table) :
|
||||
m_ndb->getAutoIncrementValue((NDBTAB *) m_table, cache_size));
|
||||
DBUG_RETURN((ulonglong) auto_value);
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,7 +204,7 @@ class ha_ndbcluster: public handler
|
||||
int key_cmp(uint keynr, const byte * old_row, const byte * new_row);
|
||||
void print_results();
|
||||
|
||||
longlong get_auto_increment();
|
||||
ulonglong get_auto_increment();
|
||||
int ndb_err(NdbConnection*);
|
||||
bool uses_blob_value(bool all_fields);
|
||||
|
||||
|
164
sql/handler.cc
164
sql/handler.cc
@ -111,7 +111,7 @@ TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"",
|
||||
|
||||
enum db_type ha_resolve_by_name(const char *name, uint namelen)
|
||||
{
|
||||
THD *thd=current_thd;
|
||||
THD *thd= current_thd;
|
||||
if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) {
|
||||
return (enum db_type) thd->variables.table_type;
|
||||
}
|
||||
@ -142,6 +142,7 @@ const char *ha_get_storage_engine(enum db_type db_type)
|
||||
enum db_type ha_checktype(enum db_type database_type)
|
||||
{
|
||||
show_table_type_st *types;
|
||||
THD *thd= current_thd;
|
||||
for (types= sys_table_types; types->type; types++)
|
||||
{
|
||||
if ((database_type == types->db_type) &&
|
||||
@ -161,8 +162,8 @@ enum db_type ha_checktype(enum db_type database_type)
|
||||
}
|
||||
|
||||
return
|
||||
DB_TYPE_UNKNOWN != (enum db_type) current_thd->variables.table_type ?
|
||||
(enum db_type) current_thd->variables.table_type :
|
||||
DB_TYPE_UNKNOWN != (enum db_type) thd->variables.table_type ?
|
||||
(enum db_type) thd->variables.table_type :
|
||||
DB_TYPE_UNKNOWN != (enum db_type) global_system_variables.table_type ?
|
||||
(enum db_type) global_system_variables.table_type :
|
||||
DB_TYPE_MYISAM;
|
||||
@ -946,7 +947,7 @@ int handler::read_first_row(byte * buf, uint primary_key)
|
||||
|
||||
void handler::update_timestamp(byte *record)
|
||||
{
|
||||
long skr= (long) current_thd->query_start();
|
||||
long skr= (long) table->in_use->query_start();
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (table->db_low_byte_first)
|
||||
{
|
||||
@ -958,42 +959,165 @@ void handler::update_timestamp(byte *record)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Updates field with field_type NEXT_NUMBER according to following:
|
||||
if field = 0 change field to the next free key in database.
|
||||
Generate the next auto-increment number based on increment and offset
|
||||
|
||||
In most cases increment= offset= 1, in which case we get:
|
||||
1,2,3,4,5,...
|
||||
If increment=10 and offset=5 and previous number is 1, we get:
|
||||
1,5,15,25,35,...
|
||||
*/
|
||||
|
||||
inline ulonglong
|
||||
next_insert_id(ulonglong nr,struct system_variables *variables)
|
||||
{
|
||||
nr= (((nr+ variables->auto_increment_increment -
|
||||
variables->auto_increment_offset)) /
|
||||
(ulonglong) variables->auto_increment_increment);
|
||||
return (nr* (ulonglong) variables->auto_increment_increment +
|
||||
variables->auto_increment_offset);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Updates columns with type NEXT_NUMBER if:
|
||||
|
||||
- If column value is set to NULL (in which case
|
||||
auto_increment_field_not_null is 0)
|
||||
- If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not
|
||||
set. In the future we will only set NEXT_NUMBER fields if one sets them
|
||||
to NULL (or they are not included in the insert list).
|
||||
|
||||
|
||||
There are two different cases when the above is true:
|
||||
|
||||
- thd->next_insert_id == 0 (This is the normal case)
|
||||
In this case we set the set the column for the first row to the value
|
||||
next_insert_id(get_auto_increment(column))) which is normally
|
||||
max-used-column-value +1.
|
||||
|
||||
We call get_auto_increment() only for the first row in a multi-row
|
||||
statement. For the following rows we generate new numbers based on the
|
||||
last used number.
|
||||
|
||||
- thd->next_insert_id != 0. This happens when we have read a statement
|
||||
from the binary log or when one has used SET LAST_INSERT_ID=#.
|
||||
|
||||
In this case we will set the column to the value of next_insert_id.
|
||||
The next row will be given the id
|
||||
next_insert_id(next_insert_id)
|
||||
|
||||
The idea is the generated auto_increment values are predicatable and
|
||||
independent of the column values in the table. This is needed to be
|
||||
able to replicate into a table that alread has rows with a higher
|
||||
auto-increment value than the one that is inserted.
|
||||
|
||||
After we have already generated an auto-increment number and the users
|
||||
inserts a column with a higher value than the last used one, we will
|
||||
start counting from the inserted value.
|
||||
|
||||
thd->next_insert_id is cleared after it's been used for a statement.
|
||||
*/
|
||||
|
||||
void handler::update_auto_increment()
|
||||
{
|
||||
longlong nr;
|
||||
THD *thd;
|
||||
ulonglong nr;
|
||||
THD *thd= table->in_use;
|
||||
struct system_variables *variables= &thd->variables;
|
||||
DBUG_ENTER("handler::update_auto_increment");
|
||||
if (table->next_number_field->val_int() != 0 ||
|
||||
|
||||
/*
|
||||
We must save the previous value to be able to restore it if the
|
||||
row was not inserted
|
||||
*/
|
||||
thd->prev_insert_id= thd->next_insert_id;
|
||||
|
||||
if ((nr= table->next_number_field->val_int()) != 0 ||
|
||||
table->auto_increment_field_not_null &&
|
||||
current_thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
|
||||
thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
|
||||
{
|
||||
/* Clear flag for next row */
|
||||
table->auto_increment_field_not_null= FALSE;
|
||||
/* Mark that we didn't generated a new value **/
|
||||
auto_increment_column_changed=0;
|
||||
|
||||
/* Update next_insert_id if we have already generated a value */
|
||||
if (thd->clear_next_insert_id && nr >= thd->next_insert_id)
|
||||
{
|
||||
if (variables->auto_increment_increment != 1)
|
||||
nr= next_insert_id(nr, variables);
|
||||
else
|
||||
nr++;
|
||||
thd->next_insert_id= nr;
|
||||
DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr));
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
table->auto_increment_field_not_null= FALSE;
|
||||
thd=current_thd;
|
||||
if ((nr=thd->next_insert_id))
|
||||
thd->next_insert_id=0; // Clear after use
|
||||
else
|
||||
nr=get_auto_increment();
|
||||
if (!table->next_number_field->store(nr))
|
||||
if (!(nr= thd->next_insert_id))
|
||||
{
|
||||
nr= get_auto_increment();
|
||||
if (variables->auto_increment_increment != 1)
|
||||
nr= next_insert_id(nr-1, variables);
|
||||
/*
|
||||
Update next row based on the found value. This way we don't have to
|
||||
call the handler for every generated auto-increment value on a
|
||||
multi-row statement
|
||||
*/
|
||||
thd->next_insert_id= nr;
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr));
|
||||
|
||||
/* Mark that we should clear next_insert_id before next stmt */
|
||||
thd->clear_next_insert_id= 1;
|
||||
|
||||
if (!table->next_number_field->store((longlong) nr))
|
||||
thd->insert_id((ulonglong) nr);
|
||||
else
|
||||
thd->insert_id(table->next_number_field->val_int());
|
||||
|
||||
/*
|
||||
We can't set next_insert_id if the auto-increment key is not the
|
||||
first key part, as there is no gurantee that the first parts will be in
|
||||
sequence
|
||||
*/
|
||||
if (!table->next_number_key_offset)
|
||||
{
|
||||
/*
|
||||
Set next insert id to point to next auto-increment value to be able to
|
||||
handle multi-row statements
|
||||
This works even if auto_increment_increment > 1
|
||||
*/
|
||||
thd->next_insert_id= next_insert_id(nr, variables);
|
||||
}
|
||||
else
|
||||
thd->next_insert_id= 0;
|
||||
|
||||
/* Mark that we generated a new value */
|
||||
auto_increment_column_changed=1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
restore_auto_increment
|
||||
|
||||
longlong handler::get_auto_increment()
|
||||
In case of error on write, we restore the last used next_insert_id value
|
||||
because the previous value was not used.
|
||||
*/
|
||||
|
||||
void handler::restore_auto_increment()
|
||||
{
|
||||
longlong nr;
|
||||
THD *thd= table->in_use;
|
||||
if (thd->next_insert_id)
|
||||
thd->next_insert_id= thd->prev_insert_id;
|
||||
}
|
||||
|
||||
|
||||
ulonglong handler::get_auto_increment()
|
||||
{
|
||||
ulonglong nr;
|
||||
int error;
|
||||
|
||||
(void) extra(HA_EXTRA_KEYREAD);
|
||||
@ -1014,8 +1138,8 @@ longlong handler::get_auto_increment()
|
||||
if (error)
|
||||
nr=1;
|
||||
else
|
||||
nr=(longlong) table->next_number_field->
|
||||
val_int_offset(table->rec_buff_length)+1;
|
||||
nr=((ulonglong) table->next_number_field->
|
||||
val_int_offset(table->rec_buff_length)+1);
|
||||
index_end();
|
||||
(void) extra(HA_EXTRA_NO_KEYREAD);
|
||||
return nr;
|
||||
|
@ -404,7 +404,8 @@ public:
|
||||
*/
|
||||
virtual int delete_all_rows()
|
||||
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
|
||||
virtual longlong get_auto_increment();
|
||||
virtual ulonglong get_auto_increment();
|
||||
virtual void restore_auto_increment();
|
||||
virtual void update_create_info(HA_CREATE_INFO *create_info) {}
|
||||
|
||||
/* admin commands - called from mysql_admin_table */
|
||||
|
59
sql/log.cc
59
sql/log.cc
@ -366,12 +366,11 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
|
||||
Format_description_log_event s(BINLOG_VERSION);
|
||||
if (!s.is_valid())
|
||||
goto err;
|
||||
s.set_log_pos(this);
|
||||
if (null_created_arg)
|
||||
s.created= 0;
|
||||
if (s.write(&log_file))
|
||||
goto err;
|
||||
bytes_written+= s.get_event_len();
|
||||
bytes_written+= s.data_written;
|
||||
}
|
||||
if (description_event_for_queue &&
|
||||
description_event_for_queue->binlog_version>=4)
|
||||
@ -386,24 +385,24 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
|
||||
has been produced by
|
||||
Format_description_log_event::Format_description_log_event(char*
|
||||
buf,).
|
||||
Why don't we want to write the description_event_for_queue if this event
|
||||
is for format<4 (3.23 or 4.x): this is because in that case, the
|
||||
description_event_for_queue describes the data received from the master,
|
||||
but not the data written to the relay log (*conversion*), which is in
|
||||
format 4 (slave's).
|
||||
Why don't we want to write the description_event_for_queue if this
|
||||
event is for format<4 (3.23 or 4.x): this is because in that case, the
|
||||
description_event_for_queue describes the data received from the
|
||||
master, but not the data written to the relay log (*conversion*),
|
||||
which is in format 4 (slave's).
|
||||
*/
|
||||
/*
|
||||
Set 'created' to 0, so that in next relay logs this event does not trigger
|
||||
cleaning actions on the slave in
|
||||
Set 'created' to 0, so that in next relay logs this event does not
|
||||
trigger cleaning actions on the slave in
|
||||
Format_description_log_event::exec_event().
|
||||
Set 'log_pos' to 0 to show that it's an artificial event.
|
||||
*/
|
||||
description_event_for_queue->created= 0;
|
||||
description_event_for_queue->log_pos= 0;
|
||||
/* Don't set log_pos in event header */
|
||||
description_event_for_queue->artificial_event=1;
|
||||
|
||||
if (description_event_for_queue->write(&log_file))
|
||||
goto err;
|
||||
bytes_written+= description_event_for_queue->get_event_len();
|
||||
bytes_written+= description_event_for_queue->data_written;
|
||||
}
|
||||
if (flush_io_cache(&log_file) ||
|
||||
my_sync(log_file.file, MYF(MY_WME)))
|
||||
@ -881,22 +880,18 @@ int MYSQL_LOG::purge_logs(const char *to_log,
|
||||
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
|
||||
!log_in_use(log_info.log_file_name))
|
||||
{
|
||||
ulong file_size;
|
||||
LINT_INIT(file_size);
|
||||
ulong file_size= 0;
|
||||
if (decrease_log_space) //stat the file we want to delete
|
||||
{
|
||||
MY_STAT s;
|
||||
|
||||
/*
|
||||
If we could not stat, we can't know the amount
|
||||
of space that deletion will free. In most cases,
|
||||
deletion won't work either, so it's not a problem.
|
||||
*/
|
||||
if (my_stat(log_info.log_file_name,&s,MYF(0)))
|
||||
file_size= s.st_size;
|
||||
else
|
||||
{
|
||||
/*
|
||||
If we could not stat, we can't know the amount
|
||||
of space that deletion will free. In most cases,
|
||||
deletion won't work either, so it's not a problem.
|
||||
*/
|
||||
file_size= 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
It's not fatal if we can't delete a log file ;
|
||||
@ -1069,9 +1064,8 @@ void MYSQL_LOG::new_file(bool need_lock)
|
||||
*/
|
||||
THD *thd = current_thd; /* may be 0 if we are reacting to SIGHUP */
|
||||
Rotate_log_event r(thd,new_name+dirname_length(new_name));
|
||||
r.set_log_pos(this);
|
||||
r.write(&log_file);
|
||||
bytes_written += r.get_event_len();
|
||||
bytes_written += r.data_written;
|
||||
}
|
||||
/*
|
||||
Update needs to be signalled even if there is no rotate event
|
||||
@ -1130,7 +1124,7 @@ bool MYSQL_LOG::append(Log_event* ev)
|
||||
error=1;
|
||||
goto err;
|
||||
}
|
||||
bytes_written += ev->get_event_len();
|
||||
bytes_written+= ev->data_written;
|
||||
DBUG_PRINT("info",("max_size: %lu",max_size));
|
||||
if ((uint) my_b_append_tell(&log_file) > max_size)
|
||||
{
|
||||
@ -1376,7 +1370,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
(uint) thd->variables.collation_database->number,
|
||||
(uint) thd->variables.collation_server->number);
|
||||
Query_log_event e(thd, buf, written, 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1392,7 +1385,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
thd->variables.time_zone->get_name()->ptr(),
|
||||
"'", NullS);
|
||||
Query_log_event e(thd, buf, buf_end - buf, 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1401,21 +1393,18 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
{
|
||||
Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
|
||||
thd->current_insert_id);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
if (thd->insert_id_used)
|
||||
{
|
||||
Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
if (thd->rand_used)
|
||||
{
|
||||
Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1431,7 +1420,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
user_var_event->length,
|
||||
user_var_event->type,
|
||||
user_var_event->charset_number);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1443,7 +1431,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
p= strmov(strmov(buf, "SET CHARACTER SET "),
|
||||
thd->variables.convert_set->name);
|
||||
Query_log_event e(thd, buf, (ulong) (p - buf), 0);
|
||||
e.set_log_pos(this);
|
||||
if (e.write(file))
|
||||
goto err;
|
||||
}
|
||||
@ -1452,7 +1439,6 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
|
||||
|
||||
/* Write the SQL command */
|
||||
|
||||
event_info->set_log_pos(this);
|
||||
if (event_info->write(file))
|
||||
goto err;
|
||||
|
||||
@ -1632,7 +1618,6 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
|
||||
master's binlog, which would result in wrong positions being shown to
|
||||
the user, MASTER_POS_WAIT undue waiting etc.
|
||||
*/
|
||||
qinfo.set_log_pos(this);
|
||||
if (qinfo.write(&log_file))
|
||||
goto err;
|
||||
}
|
||||
@ -1658,7 +1643,6 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
|
||||
commit_or_rollback ? "COMMIT" : "ROLLBACK",
|
||||
commit_or_rollback ? 6 : 8,
|
||||
TRUE);
|
||||
qinfo.set_log_pos(this);
|
||||
if (qinfo.write(&log_file) || flush_io_cache(&log_file) ||
|
||||
sync_binlog(&log_file))
|
||||
goto err;
|
||||
@ -1894,9 +1878,8 @@ void MYSQL_LOG::close(uint exiting)
|
||||
(exiting & LOG_CLOSE_STOP_EVENT))
|
||||
{
|
||||
Stop_log_event s;
|
||||
s.set_log_pos(this);
|
||||
s.write(&log_file);
|
||||
bytes_written+= s.get_event_len();
|
||||
bytes_written+= s.data_written;
|
||||
signal_update();
|
||||
}
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
655
sql/log_event.cc
655
sql/log_event.cc
File diff suppressed because it is too large
Load Diff
256
sql/log_event.h
256
sql/log_event.h
@ -139,7 +139,7 @@ struct sql_ex_info
|
||||
field_term_len + enclosed_len + line_term_len +
|
||||
line_start_len + escaped_len + 6 : 7);
|
||||
}
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write_data(IO_CACHE* file);
|
||||
char* init(char* buf,char* buf_end,bool use_new_format);
|
||||
bool new_format()
|
||||
{
|
||||
@ -231,7 +231,7 @@ struct sql_ex_info
|
||||
#define Q_FLAGS2_CODE 0
|
||||
#define Q_SQL_MODE_CODE 1
|
||||
#define Q_CATALOG_CODE 2
|
||||
|
||||
#define Q_AUTO_INCREMENT 3
|
||||
|
||||
/* Intvar event post-header */
|
||||
|
||||
@ -387,8 +387,10 @@ typedef struct st_last_event_info
|
||||
uint32 flags2;
|
||||
bool sql_mode_inited;
|
||||
ulong sql_mode; /* must be same as THD.variables.sql_mode */
|
||||
ulong auto_increment_increment, auto_increment_offset;
|
||||
st_last_event_info()
|
||||
: flags2_inited(0), flags2(0), sql_mode_inited(0), sql_mode(0)
|
||||
:flags2_inited(0), flags2(0), sql_mode_inited(0), sql_mode(0),
|
||||
auto_increment_increment(1),auto_increment_offset(1)
|
||||
{
|
||||
db[0]= 0; /* initially, the db is unknown */
|
||||
}
|
||||
@ -407,13 +409,14 @@ class Log_event
|
||||
{
|
||||
public:
|
||||
/*
|
||||
The offset in the log where this event originally appeared (it is preserved
|
||||
in relay logs, making SHOW SLAVE STATUS able to print coordinates of the
|
||||
event in the master's binlog). Note: when a transaction is written by the
|
||||
master to its binlog (wrapped in BEGIN/COMMIT) the log_pos of all the
|
||||
queries it contains is the one of the BEGIN (this way, when one does SHOW
|
||||
SLAVE STATUS it sees the offset of the BEGIN, which is logical as rollback
|
||||
may occur), except the COMMIT query which has its real offset.
|
||||
The offset in the log where this event originally appeared (it is
|
||||
preserved in relay logs, making SHOW SLAVE STATUS able to print
|
||||
coordinates of the event in the master's binlog). Note: when a
|
||||
transaction is written by the master to its binlog (wrapped in
|
||||
BEGIN/COMMIT) the log_pos of all the queries it contains is the
|
||||
one of the BEGIN (this way, when one does SHOW SLAVE STATUS it
|
||||
sees the offset of the BEGIN, which is logical as rollback may
|
||||
occur), except the COMMIT query which has its real offset.
|
||||
*/
|
||||
my_off_t log_pos;
|
||||
/*
|
||||
@ -422,21 +425,24 @@ public:
|
||||
*/
|
||||
char *temp_buf;
|
||||
/*
|
||||
Timestamp on the master(for debugging and replication of NOW()/TIMESTAMP).
|
||||
It is important for queries and LOAD DATA INFILE. This is set at the event's
|
||||
creation time, except for Query and Load (et al.) events where this is set
|
||||
at the query's execution time, which guarantees good replication (otherwise,
|
||||
we could have a query and its event with different timestamps).
|
||||
Timestamp on the master(for debugging and replication of
|
||||
NOW()/TIMESTAMP). It is important for queries and LOAD DATA
|
||||
INFILE. This is set at the event's creation time, except for Query
|
||||
and Load (et al.) events where this is set at the query's
|
||||
execution time, which guarantees good replication (otherwise, we
|
||||
could have a query and its event with different timestamps).
|
||||
*/
|
||||
time_t when;
|
||||
/* The number of seconds the query took to run on the master. */
|
||||
ulong exec_time;
|
||||
/* Number of bytes written by write() function */
|
||||
ulong data_written;
|
||||
|
||||
/*
|
||||
The master's server id (is preserved in the relay log; used to prevent from
|
||||
infinite loops in circular replication).
|
||||
The master's server id (is preserved in the relay log; used to prevent from
|
||||
infinite loops in circular replication).
|
||||
*/
|
||||
uint32 server_id;
|
||||
uint cached_event_len;
|
||||
|
||||
/*
|
||||
Some 16 flags. Only one is really used now; look above for
|
||||
@ -453,26 +459,25 @@ public:
|
||||
Log_event();
|
||||
Log_event(THD* thd_arg, uint16 flags_arg, bool cache_stmt);
|
||||
/*
|
||||
read_log_event() functions read an event from a binlog or relay log; used by
|
||||
SHOW BINLOG EVENTS, the binlog_dump thread on the master (reads master's
|
||||
binlog), the slave IO thread (reads the event sent by binlog_dump), the
|
||||
slave SQL thread (reads the event from the relay log).
|
||||
If mutex is 0, the read will proceed without mutex.
|
||||
We need the description_event to be able to parse the event (to know the
|
||||
post-header's size); in fact in read_log_event we detect the event's type,
|
||||
then call the specific event's constructor and pass description_event as an
|
||||
argument.
|
||||
read_log_event() functions read an event from a binlog or relay
|
||||
log; used by SHOW BINLOG EVENTS, the binlog_dump thread on the
|
||||
master (reads master's binlog), the slave IO thread (reads the
|
||||
event sent by binlog_dump), the slave SQL thread (reads the event
|
||||
from the relay log). If mutex is 0, the read will proceed without
|
||||
mutex. We need the description_event to be able to parse the
|
||||
event (to know the post-header's size); in fact in read_log_event
|
||||
we detect the event's type, then call the specific event's
|
||||
constructor and pass description_event as an argument.
|
||||
*/
|
||||
static Log_event* read_log_event(IO_CACHE* file,
|
||||
pthread_mutex_t* log_lock,
|
||||
const Format_description_log_event *description_event);
|
||||
static int read_log_event(IO_CACHE* file, String* packet,
|
||||
pthread_mutex_t* log_lock);
|
||||
/* set_log_pos() is used to fill log_pos with tell(log). */
|
||||
void set_log_pos(MYSQL_LOG* log);
|
||||
/*
|
||||
init_show_field_list() prepares the column names and types for the output of
|
||||
SHOW BINLOG EVENTS; it is used only by SHOW BINLOG EVENTS.
|
||||
init_show_field_list() prepares the column names and types for the
|
||||
output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
|
||||
EVENTS.
|
||||
*/
|
||||
static void init_show_field_list(List<Item>* field_list);
|
||||
#ifdef HAVE_REPLICATION
|
||||
@ -494,7 +499,7 @@ public:
|
||||
}
|
||||
#else
|
||||
Log_event() : temp_buf(0) {}
|
||||
// avoid having to link mysqlbinlog against libpthread
|
||||
/* avoid having to link mysqlbinlog against libpthread */
|
||||
static Log_event* read_log_event(IO_CACHE* file,
|
||||
const Format_description_log_event *description_event);
|
||||
/* print*() functions are used by mysqlbinlog */
|
||||
@ -512,13 +517,17 @@ public:
|
||||
my_free((gptr) ptr, MYF(MY_WME|MY_ALLOW_ZERO_PTR));
|
||||
}
|
||||
|
||||
int write(IO_CACHE* file);
|
||||
int write_header(IO_CACHE* file);
|
||||
virtual int write_data(IO_CACHE* file)
|
||||
{ return write_data_header(file) || write_data_body(file); }
|
||||
virtual int write_data_header(IO_CACHE* file __attribute__((unused)))
|
||||
bool write_header(IO_CACHE* file, ulong data_length);
|
||||
virtual bool write(IO_CACHE* file)
|
||||
{
|
||||
return (write_header(file, get_data_size()) ||
|
||||
write_data_header(file) ||
|
||||
write_data_body(file));
|
||||
}
|
||||
virtual bool is_artificial_event() { return 0; }
|
||||
virtual bool write_data_header(IO_CACHE* file)
|
||||
{ return 0; }
|
||||
virtual int write_data_body(IO_CACHE* file __attribute__((unused)))
|
||||
virtual bool write_data_body(IO_CACHE* file __attribute__((unused)))
|
||||
{ return 0; }
|
||||
virtual Log_event_type get_type_code() = 0;
|
||||
virtual bool is_valid() const = 0;
|
||||
@ -535,17 +544,10 @@ public:
|
||||
}
|
||||
}
|
||||
virtual int get_data_size() { return 0;}
|
||||
int get_event_len()
|
||||
{
|
||||
/*
|
||||
We don't re-use the cached event's length anymore (we did in 4.x) because
|
||||
this leads to nasty problems: when the 5.0 slave reads an event from a 4.0
|
||||
master, it caches the event's length, then this event is converted before
|
||||
it goes into the relay log, so it would be written to the relay log with
|
||||
its old length, which is garbage.
|
||||
*/
|
||||
return (cached_event_len=(LOG_EVENT_HEADER_LEN + get_data_size()));
|
||||
}
|
||||
/*
|
||||
Get event length for simple events. For complicated events the length
|
||||
is calculated during write()
|
||||
*/
|
||||
static Log_event* read_log_event(const char* buf, uint event_len,
|
||||
const char **error,
|
||||
const Format_description_log_event
|
||||
@ -592,32 +594,32 @@ public:
|
||||
uint16 error_code;
|
||||
ulong thread_id;
|
||||
/*
|
||||
For events created by Query_log_event::exec_event (and
|
||||
Load_log_event::exec_event()) we need the *original* thread id, to be able
|
||||
to log the event with the original (=master's) thread id (fix for
|
||||
BUG#1686).
|
||||
For events created by Query_log_event::exec_event (and
|
||||
Load_log_event::exec_event()) we need the *original* thread id, to be able
|
||||
to log the event with the original (=master's) thread id (fix for
|
||||
BUG#1686).
|
||||
*/
|
||||
ulong slave_proxy_id;
|
||||
|
||||
/*
|
||||
Binlog format 3 and 4 start to differ (as far as class members are
|
||||
concerned) from here.
|
||||
Binlog format 3 and 4 start to differ (as far as class members are
|
||||
concerned) from here.
|
||||
*/
|
||||
|
||||
int catalog_len; // <= 255 char; -1 means uninited
|
||||
int catalog_len; // <= 255 char; -1 means uninited
|
||||
|
||||
/*
|
||||
We want to be able to store a variable number of N-bit status vars:
|
||||
(generally N=32; but N=64 for SQL_MODE) a user may want to log the number of
|
||||
affected rows (for debugging) while another does not want to lose 4 bytes in
|
||||
this.
|
||||
(generally N=32; but N=64 for SQL_MODE) a user may want to log the number
|
||||
of affected rows (for debugging) while another does not want to lose 4
|
||||
bytes in this.
|
||||
The storage on disk is the following:
|
||||
status_vars_len is part of the post-header,
|
||||
status_vars are in the variable-length part, after the post-header, before
|
||||
the db & query.
|
||||
status_vars on disk is a sequence of pairs (code, value) where 'code' means
|
||||
'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so its
|
||||
first byte is its length. For now the order of status vars is:
|
||||
'sql_mode', 'affected' etc. Sometimes 'value' must be a short string, so
|
||||
its first byte is its length. For now the order of status vars is:
|
||||
flags2 - sql_mode - catalog.
|
||||
We should add the same thing to Load_log_event, but in fact
|
||||
LOAD DATA INFILE is going to be logged with a new type of event (logging of
|
||||
@ -643,6 +645,7 @@ public:
|
||||
uint32 flags2;
|
||||
/* In connections sql_mode is 32 bits now but will be 64 bits soon */
|
||||
ulong sql_mode;
|
||||
ulong auto_increment_increment, auto_increment_offset;
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
|
||||
@ -667,14 +670,8 @@ public:
|
||||
}
|
||||
}
|
||||
Log_event_type get_type_code() { return QUERY_EVENT; }
|
||||
int write(IO_CACHE* file);
|
||||
int write_data(IO_CACHE* file); // returns 0 on success, -1 on error
|
||||
bool write(IO_CACHE* file);
|
||||
bool is_valid() const { return query != 0; }
|
||||
int get_data_size()
|
||||
{
|
||||
/* Note that the "1" below is the db's length. */
|
||||
return (q_len + db_len + 1 + status_vars_len + QUERY_HEADER_LEN);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
@ -713,7 +710,7 @@ public:
|
||||
int get_data_size();
|
||||
bool is_valid() const { return master_host != 0; }
|
||||
Log_event_type get_type_code() { return SLAVE_EVENT; }
|
||||
int write_data(IO_CACHE* file );
|
||||
bool write(IO_CACHE* file);
|
||||
};
|
||||
|
||||
#endif /* HAVE_REPLICATION */
|
||||
@ -804,8 +801,8 @@ public:
|
||||
{
|
||||
return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
|
||||
}
|
||||
int write_data_header(IO_CACHE* file);
|
||||
int write_data_body(IO_CACHE* file);
|
||||
bool write_data_header(IO_CACHE* file);
|
||||
bool write_data_body(IO_CACHE* file);
|
||||
bool is_valid() const { return table_name != 0; }
|
||||
int get_data_size()
|
||||
{
|
||||
@ -830,23 +827,26 @@ extern char server_version[SERVER_VERSION_LENGTH];
|
||||
is >4 (otherwise if ==4 the event will be sent naturally).
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Start_log_event_v3: public Log_event
|
||||
{
|
||||
public:
|
||||
/*
|
||||
If this event is at the start of the first binary log since server startup
|
||||
'created' should be the timestamp when the event (and the binary log) was
|
||||
created.
|
||||
In the other case (i.e. this event is at the start of a binary log created
|
||||
by FLUSH LOGS or automatic rotation), 'created' should be 0.
|
||||
This "trick" is used by MySQL >=4.0.14 slaves to know if they must drop the
|
||||
stale temporary tables or not.
|
||||
Note that when 'created'!=0, it is always equal to the event's timestamp;
|
||||
indeed Start_log_event is written only in log.cc where the first
|
||||
constructor below is called, in which 'created' is set to 'when'.
|
||||
So in fact 'created' is a useless variable. When it is 0
|
||||
we can read the actual value from timestamp ('when') and when it is
|
||||
non-zero we can read the same value from timestamp ('when'). Conclusion:
|
||||
If this event is at the start of the first binary log since server
|
||||
startup 'created' should be the timestamp when the event (and the
|
||||
binary log) was created. In the other case (i.e. this event is at
|
||||
the start of a binary log created by FLUSH LOGS or automatic
|
||||
rotation), 'created' should be 0. This "trick" is used by MySQL
|
||||
>=4.0.14 slaves to know if they must drop the stale temporary
|
||||
tables or not.
|
||||
|
||||
Note that when 'created'!=0, it is always equal to the event's
|
||||
timestamp; indeed Start_log_event is written only in log.cc where
|
||||
the first constructor below is called, in which 'created' is set
|
||||
to 'when'. So in fact 'created' is a useless variable. When it is
|
||||
0 we can read the actual value from timestamp ('when') and when it
|
||||
is non-zero we can read the same value from timestamp
|
||||
('when'). Conclusion:
|
||||
- we use timestamp to print when the binlog was created.
|
||||
- we use 'created' only to know if this is a first binlog or not.
|
||||
In 3.23.57 we did not pay attention to this identity, so mysqlbinlog in
|
||||
@ -856,6 +856,12 @@ public:
|
||||
time_t created;
|
||||
uint16 binlog_version;
|
||||
char server_version[ST_SERVER_VER_LEN];
|
||||
/*
|
||||
artifical_event is 1 in the case where this is a generated event that
|
||||
should not case any cleanup actions. We handle this in the log by
|
||||
setting log_event == 0 (for now).
|
||||
*/
|
||||
bool artificial_event;
|
||||
|
||||
#ifndef MYSQL_CLIENT
|
||||
Start_log_event_v3();
|
||||
@ -872,14 +878,16 @@ public:
|
||||
const Format_description_log_event* description_event);
|
||||
~Start_log_event_v3() {}
|
||||
Log_event_type get_type_code() { return START_EVENT_V3;}
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
bool is_valid() const { return 1; }
|
||||
int get_data_size()
|
||||
{
|
||||
return START_V3_HEADER_LEN; //no variable-sized part
|
||||
}
|
||||
virtual bool is_artificial_event() { return artificial_event; }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
For binlog version 4.
|
||||
This event is saved by threads which read it, as they need it for future
|
||||
@ -912,18 +920,12 @@ public:
|
||||
const Format_description_log_event* description_event);
|
||||
~Format_description_log_event() { my_free((gptr)post_header_len, MYF(0)); }
|
||||
Log_event_type get_type_code() { return FORMAT_DESCRIPTION_EVENT;}
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
bool is_valid() const
|
||||
{
|
||||
return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
|
||||
LOG_EVENT_MINIMAL_HEADER_LEN)) &&
|
||||
(post_header_len != NULL));
|
||||
}
|
||||
int get_event_len()
|
||||
{
|
||||
int i= LOG_EVENT_MINIMAL_HEADER_LEN + get_data_size();
|
||||
DBUG_PRINT("info",("event_len=%d",i));
|
||||
return i;
|
||||
return ((common_header_len >= ((binlog_version==1) ? OLD_HEADER_LEN :
|
||||
LOG_EVENT_MINIMAL_HEADER_LEN)) &&
|
||||
(post_header_len != NULL));
|
||||
}
|
||||
int get_data_size()
|
||||
{
|
||||
@ -944,6 +946,7 @@ public:
|
||||
Logs special variables such as auto_increment values
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Intvar_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
@ -967,10 +970,11 @@ public:
|
||||
Log_event_type get_type_code() { return INTVAR_EVENT;}
|
||||
const char* get_var_type_name();
|
||||
int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;}
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
bool is_valid() const { return 1; }
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Rand Log Event class
|
||||
@ -981,6 +985,7 @@ public:
|
||||
waste, it does not cause bugs).
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Rand_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
@ -1003,10 +1008,11 @@ class Rand_log_event: public Log_event
|
||||
~Rand_log_event() {}
|
||||
Log_event_type get_type_code() { return RAND_EVENT;}
|
||||
int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
bool is_valid() const { return 1; }
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
User var Log Event class
|
||||
@ -1018,6 +1024,7 @@ class Rand_log_event: public Log_event
|
||||
written before the Query_log_event, to set the user variable.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class User_var_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
@ -1044,16 +1051,11 @@ public:
|
||||
User_var_log_event(const char* buf, const Format_description_log_event* description_event);
|
||||
~User_var_log_event() {}
|
||||
Log_event_type get_type_code() { return USER_VAR_EVENT;}
|
||||
int get_data_size()
|
||||
{
|
||||
return (is_null ? UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL :
|
||||
UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
|
||||
UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE + val_len);
|
||||
}
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
bool is_valid() const { return 1; }
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Stop Log Event class
|
||||
@ -1090,6 +1092,7 @@ public:
|
||||
This will be depricated when we move to using sequence ids.
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Rotate_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
@ -1121,22 +1124,18 @@ public:
|
||||
my_free((gptr) new_log_ident, MYF(0));
|
||||
}
|
||||
Log_event_type get_type_code() { return ROTATE_EVENT;}
|
||||
int get_event_len()
|
||||
{
|
||||
return (LOG_EVENT_MINIMAL_HEADER_LEN + get_data_size());
|
||||
}
|
||||
int get_data_size() { return ident_len + ROTATE_HEADER_LEN;}
|
||||
bool is_valid() const { return new_log_ident != 0; }
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
};
|
||||
|
||||
|
||||
/* the classes below are for the new LOAD DATA INFILE logging */
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Create File Log Event class
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Create_file_log_event: public Load_log_event
|
||||
{
|
||||
protected:
|
||||
@ -1187,13 +1186,13 @@ public:
|
||||
4 + 1 + block_len);
|
||||
}
|
||||
bool is_valid() const { return inited_from_old || block != 0; }
|
||||
int write_data_header(IO_CACHE* file);
|
||||
int write_data_body(IO_CACHE* file);
|
||||
bool write_data_header(IO_CACHE* file);
|
||||
bool write_data_body(IO_CACHE* file);
|
||||
/*
|
||||
Cut out Create_file extentions and
|
||||
write it as Load event - used on the slave
|
||||
*/
|
||||
int write_base(IO_CACHE* file);
|
||||
bool write_base(IO_CACHE* file);
|
||||
};
|
||||
|
||||
|
||||
@ -1202,6 +1201,7 @@ public:
|
||||
Append Block Log Event class
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Append_block_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
@ -1209,14 +1209,15 @@ public:
|
||||
uint block_len;
|
||||
uint file_id;
|
||||
/*
|
||||
'db' is filled when the event is created in mysql_load() (the event needs to
|
||||
have a 'db' member to be well filtered by binlog-*-db rules). 'db' is not
|
||||
written to the binlog (it's not used by Append_block_log_event::write()), so
|
||||
it can't be read in the Append_block_log_event(const char* buf, int
|
||||
event_len) constructor.
|
||||
In other words, 'db' is used only for filtering by binlog-*-db rules.
|
||||
Create_file_log_event is different: its 'db' (which is inherited from
|
||||
Load_log_event) is written to the binlog and can be re-read.
|
||||
'db' is filled when the event is created in mysql_load() (the
|
||||
event needs to have a 'db' member to be well filtered by
|
||||
binlog-*-db rules). 'db' is not written to the binlog (it's not
|
||||
used by Append_block_log_event::write()), so it can't be read in
|
||||
the Append_block_log_event(const char* buf, int event_len)
|
||||
constructor. In other words, 'db' is used only for filtering by
|
||||
binlog-*-db rules. Create_file_log_event is different: it's 'db'
|
||||
(which is inherited from Load_log_event) is written to the binlog
|
||||
and can be re-read.
|
||||
*/
|
||||
const char* db;
|
||||
|
||||
@ -1237,15 +1238,17 @@ public:
|
||||
Log_event_type get_type_code() { return APPEND_BLOCK_EVENT;}
|
||||
int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;}
|
||||
bool is_valid() const { return block != 0; }
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
const char* get_db() { return db; }
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Delete File Log Event class
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Delete_file_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
@ -1269,15 +1272,17 @@ public:
|
||||
Log_event_type get_type_code() { return DELETE_FILE_EVENT;}
|
||||
int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
|
||||
bool is_valid() const { return file_id != 0; }
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
const char* get_db() { return db; }
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
Execute Load Log Event class
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
class Execute_load_log_event: public Log_event
|
||||
{
|
||||
public:
|
||||
@ -1300,10 +1305,11 @@ public:
|
||||
Log_event_type get_type_code() { return EXEC_LOAD_EVENT;}
|
||||
int get_data_size() { return EXEC_LOAD_HEADER_LEN ;}
|
||||
bool is_valid() const { return file_id != 0; }
|
||||
int write_data(IO_CACHE* file);
|
||||
bool write(IO_CACHE* file);
|
||||
const char* get_db() { return db; }
|
||||
};
|
||||
|
||||
|
||||
#ifdef MYSQL_CLIENT
|
||||
class Unknown_log_event: public Log_event
|
||||
{
|
||||
|
@ -4068,7 +4068,8 @@ enum options_mysqld
|
||||
OPT_DEFAULT_TIME_ZONE,
|
||||
OPT_OPTIMIZER_SEARCH_DEPTH,
|
||||
OPT_OPTIMIZER_PRUNE_LEVEL,
|
||||
OPT_SQL_UPDATABLE_VIEW_KEY
|
||||
OPT_SQL_UPDATABLE_VIEW_KEY,
|
||||
OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET
|
||||
};
|
||||
|
||||
|
||||
@ -4087,6 +4088,16 @@ struct my_option my_long_options[] =
|
||||
#endif /* HAVE_REPLICATION */
|
||||
{"ansi", 'a', "Use ANSI SQL syntax instead of MySQL syntax.", 0, 0, 0,
|
||||
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"auto-increment-increment", OPT_AUTO_INCREMENT,
|
||||
"Auto-increment columns are incremented by this",
|
||||
(gptr*) &global_system_variables.auto_increment_increment,
|
||||
(gptr*) &max_system_variables.auto_increment_increment, 0, GET_ULONG,
|
||||
OPT_ARG, 1, 1, 65535, 0, 1, 0 },
|
||||
{"auto-increment-offset", OPT_AUTO_INCREMENT_OFFSET,
|
||||
"Offset added to Auto-increment columns. Used when auto-increment-increment != 1",
|
||||
(gptr*) &global_system_variables.auto_increment_offset,
|
||||
(gptr*) &max_system_variables.auto_increment_offset, 0, GET_ULONG, OPT_ARG,
|
||||
1, 1, 65535, 0, 1, 0 },
|
||||
{"basedir", 'b',
|
||||
"Path to installation directory. All paths are usually resolved relative to this.",
|
||||
(gptr*) &mysql_home_ptr, (gptr*) &mysql_home_ptr, 0, GET_STR, REQUIRED_ARG,
|
||||
|
@ -127,6 +127,11 @@ static byte *get_warning_count(THD *thd);
|
||||
alphabetic order
|
||||
*/
|
||||
|
||||
sys_var_thd_ulong sys_auto_increment_increment("auto_increment_increment",
|
||||
&SV::auto_increment_increment);
|
||||
sys_var_thd_ulong sys_auto_increment_offset("auto_increment_offset",
|
||||
&SV::auto_increment_offset);
|
||||
|
||||
sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size",
|
||||
&binlog_cache_size);
|
||||
sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size",
|
||||
@ -476,6 +481,8 @@ sys_var_const_str sys_license("license", STRINGIFY_ARG(LICENSE));
|
||||
sys_var *sys_variables[]=
|
||||
{
|
||||
&sys_auto_is_null,
|
||||
&sys_auto_increment_increment,
|
||||
&sys_auto_increment_offset,
|
||||
&sys_autocommit,
|
||||
&sys_big_tables,
|
||||
&sys_big_selects,
|
||||
@ -624,6 +631,8 @@ sys_var *sys_variables[]=
|
||||
*/
|
||||
|
||||
struct show_var_st init_vars[]= {
|
||||
{"auto_incrememt_increment", (char*) &sys_auto_increment_increment, SHOW_SYS},
|
||||
{"auto_increment_offset", (char*) &sys_auto_increment_offset, SHOW_SYS},
|
||||
{"back_log", (char*) &back_log, SHOW_LONG},
|
||||
{"basedir", mysql_home, SHOW_CHAR},
|
||||
#ifdef HAVE_BERKELEY_DB
|
||||
|
122
sql/slave.cc
122
sql/slave.cc
@ -220,9 +220,10 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
|
||||
look_for_description_event
|
||||
1 if we should look for such an event. We only need
|
||||
this when the SQL thread starts and opens an existing
|
||||
relay log and has to execute it (possibly from an offset
|
||||
>4); then we need to read the first event of the relay
|
||||
log to be able to parse the events we have to execute.
|
||||
relay log and has to execute it (possibly from an
|
||||
offset >4); then we need to read the first event of
|
||||
the relay log to be able to parse the events we have
|
||||
to execute.
|
||||
|
||||
DESCRIPTION
|
||||
- Close old open relay log files.
|
||||
@ -333,8 +334,8 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
|
||||
while (look_for_description_event)
|
||||
{
|
||||
/*
|
||||
Read the possible Format_description_log_event; if position was 4, no need, it will
|
||||
be read naturally.
|
||||
Read the possible Format_description_log_event; if position
|
||||
was 4, no need, it will be read naturally.
|
||||
*/
|
||||
DBUG_PRINT("info",("looking for a Format_description_log_event"));
|
||||
|
||||
@ -373,9 +374,9 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
|
||||
Format_desc (of slave)
|
||||
Rotate (of master)
|
||||
Format_desc (of master)
|
||||
So the Format_desc which really describes the rest of the relay log is
|
||||
the 3rd event (it can't be further than that, because we rotate the
|
||||
relay log when we queue a Rotate event from the master).
|
||||
So the Format_desc which really describes the rest of the relay log
|
||||
is the 3rd event (it can't be further than that, because we rotate
|
||||
the relay log when we queue a Rotate event from the master).
|
||||
But what describes the Rotate is the first Format_desc.
|
||||
So what we do is:
|
||||
go on searching for Format_description events, until you exceed the
|
||||
@ -424,7 +425,7 @@ err:
|
||||
|
||||
|
||||
/*
|
||||
Init functio to set up array for errors that should be skipped for slave
|
||||
Init function to set up array for errors that should be skipped for slave
|
||||
|
||||
SYNOPSIS
|
||||
init_slave_skip_errors()
|
||||
@ -505,26 +506,11 @@ void st_relay_log_info::inc_group_relay_log_pos(ulonglong log_pos,
|
||||
the relay log is not "val".
|
||||
With the end_log_pos solution, we avoid computations involving lengthes.
|
||||
*/
|
||||
DBUG_PRINT("info", ("log_pos=%lld group_master_log_pos=%lld",
|
||||
log_pos,group_master_log_pos));
|
||||
DBUG_PRINT("info", ("log_pos: %lu group_master_log_pos: %lu",
|
||||
(long) log_pos, (long) group_master_log_pos));
|
||||
if (log_pos) // 3.23 binlogs don't have log_posx
|
||||
{
|
||||
#if MYSQL_VERSION_ID < 50000
|
||||
/*
|
||||
If the event was converted from a 3.23 format, get_event_len() has
|
||||
grown by 6 bytes (at least for most events, except LOAD DATA INFILE
|
||||
which is already a big problem for 3.23->4.0 replication); 6 bytes is
|
||||
the difference between the header's size in 4.0 (LOG_EVENT_HEADER_LEN)
|
||||
and the header's size in 3.23 (OLD_HEADER_LEN). Note that using
|
||||
mi->old_format will not help if the I/O thread has not started yet.
|
||||
Yes this is a hack but it's just to make 3.23->4.x replication work;
|
||||
3.23->5.0 replication is working much better.
|
||||
*/
|
||||
group_master_log_pos= log_pos -
|
||||
(mi->old_format ? (LOG_EVENT_HEADER_LEN - OLD_HEADER_LEN) : 0);
|
||||
#else
|
||||
group_master_log_pos= log_pos;
|
||||
#endif /* MYSQL_VERSION_ID < 5000 */
|
||||
}
|
||||
pthread_cond_broadcast(&data_cond);
|
||||
if (!skip_lock)
|
||||
@ -612,7 +598,8 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
|
||||
goto err;
|
||||
}
|
||||
if (!just_reset)
|
||||
error= init_relay_log_pos(rli, rli->group_relay_log_name, rli->group_relay_log_pos,
|
||||
error= init_relay_log_pos(rli, rli->group_relay_log_name,
|
||||
rli->group_relay_log_pos,
|
||||
0 /* do not need data lock */, errmsg, 0);
|
||||
|
||||
err:
|
||||
@ -880,8 +867,8 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
|
||||
second call will make the decision (because
|
||||
all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)).
|
||||
|
||||
Thought which arose from a question of a big customer "I want to include all
|
||||
tables like "abc.%" except the "%.EFG"". This can't be done now. If we
|
||||
Thought which arose from a question of a big customer "I want to include
|
||||
all tables like "abc.%" except the "%.EFG"". This can't be done now. If we
|
||||
supported Perl regexps we could do it with this pattern: /^abc\.(?!EFG)/
|
||||
(I could not find an equivalent in the regex library MySQL uses).
|
||||
|
||||
@ -1390,7 +1377,7 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi)
|
||||
else
|
||||
{
|
||||
mi->clock_diff_with_master= 0; /* The "most sensible" value */
|
||||
sql_print_error("Warning: \"SELECT UNIX_TIMESTAMP()\" failed on master, \
|
||||
sql_print_warning("\"SELECT UNIX_TIMESTAMP()\" failed on master, \
|
||||
do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS");
|
||||
}
|
||||
if (master_res)
|
||||
@ -2151,7 +2138,7 @@ file '%s')", fname);
|
||||
goto errwithmsg;
|
||||
#ifndef HAVE_OPENSSL
|
||||
if (ssl)
|
||||
sql_print_error("SSL information in the master info file "
|
||||
sql_print_warning("SSL information in the master info file "
|
||||
"('%s') are ignored because this MySQL slave was compiled "
|
||||
"without SSL support.", fname);
|
||||
#endif /* HAVE_OPENSSL */
|
||||
@ -2569,17 +2556,16 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
|
||||
ulong init_abort_pos_wait;
|
||||
int error=0;
|
||||
struct timespec abstime; // for timeout checking
|
||||
set_timespec(abstime,timeout);
|
||||
|
||||
const char *msg;
|
||||
DBUG_ENTER("wait_for_pos");
|
||||
DBUG_PRINT("enter",("group_master_log_name: '%s' pos: %lu timeout: %ld",
|
||||
group_master_log_name, (ulong) group_master_log_pos,
|
||||
(long) timeout));
|
||||
DBUG_PRINT("enter",("log_name: '%s' log_pos: %lu timeout: %lu",
|
||||
log_name->c_ptr(), (ulong) log_pos, (ulong) timeout));
|
||||
|
||||
set_timespec(abstime,timeout);
|
||||
pthread_mutex_lock(&data_lock);
|
||||
const char *msg= thd->enter_cond(&data_cond, &data_lock,
|
||||
"Waiting for the slave SQL thread to "
|
||||
"advance position");
|
||||
msg= thd->enter_cond(&data_cond, &data_lock,
|
||||
"Waiting for the slave SQL thread to "
|
||||
"advance position");
|
||||
/*
|
||||
This function will abort when it notices that some CHANGE MASTER or
|
||||
RESET MASTER has changed the master info.
|
||||
@ -2635,6 +2621,12 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
|
||||
bool pos_reached;
|
||||
int cmp_result= 0;
|
||||
|
||||
DBUG_PRINT("info",
|
||||
("init_abort_pos_wait: %ld abort_pos_wait: %ld",
|
||||
init_abort_pos_wait, abort_pos_wait));
|
||||
DBUG_PRINT("info",("group_master_log_name: '%s' pos: %lu",
|
||||
group_master_log_name, (ulong) group_master_log_pos));
|
||||
|
||||
/*
|
||||
group_master_log_name can be "", if we are just after a fresh
|
||||
replication start or after a CHANGE MASTER TO MASTER_HOST/PORT
|
||||
@ -2941,8 +2933,8 @@ server_errno=%d)",
|
||||
/* Check if eof packet */
|
||||
if (len < 8 && mysql->net.read_pos[0] == 254)
|
||||
{
|
||||
sql_print_error("Slave: received end packet from server, apparent\
|
||||
master shutdown: %s",
|
||||
sql_print_information("Slave: received end packet from server, apparent "
|
||||
"master shutdown: %s",
|
||||
mysql_error(mysql));
|
||||
return packet_error;
|
||||
}
|
||||
@ -3261,14 +3253,14 @@ slave_begin:
|
||||
thd->proc_info = "Connecting to master";
|
||||
// we can get killed during safe_connect
|
||||
if (!safe_connect(thd, mysql, mi))
|
||||
sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\
|
||||
sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\
|
||||
replication started in log '%s' at position %s", mi->user,
|
||||
mi->host, mi->port,
|
||||
IO_RPL_LOG_NAME,
|
||||
llstr(mi->master_log_pos,llbuff));
|
||||
else
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while connecting to master");
|
||||
sql_print_information("Slave I/O thread killed while connecting to master");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -3301,7 +3293,7 @@ connected:
|
||||
sql_print_error("Failed on request_dump()");
|
||||
if (io_slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while requesting master \
|
||||
sql_print_information("Slave I/O thread killed while requesting master \
|
||||
dump");
|
||||
goto err;
|
||||
}
|
||||
@ -3325,7 +3317,7 @@ dump");
|
||||
}
|
||||
if (io_slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed while retrying master \
|
||||
sql_print_information("Slave I/O thread killed while retrying master \
|
||||
dump");
|
||||
goto err;
|
||||
}
|
||||
@ -3338,7 +3330,7 @@ reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
|
||||
if (safe_reconnect(thd, mysql, mi, suppress_warnings) ||
|
||||
io_slave_killed(thd,mi))
|
||||
{
|
||||
sql_print_error("Slave I/O thread killed during or \
|
||||
sql_print_information("Slave I/O thread killed during or \
|
||||
after reconnect");
|
||||
goto err;
|
||||
}
|
||||
@ -3360,7 +3352,7 @@ after reconnect");
|
||||
if (io_slave_killed(thd,mi))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("Slave I/O thread killed while reading event");
|
||||
sql_print_information("Slave I/O thread killed while reading event");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -3397,20 +3389,20 @@ max_allowed_packet",
|
||||
if (io_slave_killed(thd,mi))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("Slave I/O thread killed while waiting to \
|
||||
sql_print_information("Slave I/O thread killed while waiting to \
|
||||
reconnect after a failed read");
|
||||
goto err;
|
||||
}
|
||||
thd->proc_info = "Reconnecting after a failed master event read";
|
||||
if (!suppress_warnings)
|
||||
sql_print_error("Slave I/O thread: Failed reading log event, \
|
||||
sql_print_information("Slave I/O thread: Failed reading log event, \
|
||||
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
|
||||
llstr(mi->master_log_pos, llbuff));
|
||||
if (safe_reconnect(thd, mysql, mi, suppress_warnings) ||
|
||||
io_slave_killed(thd,mi))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("Slave I/O thread killed during or after a \
|
||||
sql_print_information("Slave I/O thread killed during or after a \
|
||||
reconnect done to recover from failed read");
|
||||
goto err;
|
||||
}
|
||||
@ -3472,7 +3464,7 @@ log space");
|
||||
// error = 0;
|
||||
err:
|
||||
// print the current replication position
|
||||
sql_print_error("Slave I/O thread exiting, read up to log '%s', position %s",
|
||||
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
|
||||
@ -3623,7 +3615,7 @@ slave_begin:
|
||||
rli->group_master_log_name,
|
||||
llstr(rli->group_master_log_pos,llbuff)));
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("Slave SQL thread initialized, starting replication in \
|
||||
sql_print_information("Slave SQL thread initialized, starting replication in \
|
||||
log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
|
||||
llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
|
||||
llstr(rli->group_relay_log_pos,llbuff1));
|
||||
@ -3661,7 +3653,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
|
||||
}
|
||||
|
||||
/* Thread stopped. Print the current replication position to the log */
|
||||
sql_print_error("Slave SQL thread exiting, replication stopped in log \
|
||||
sql_print_information("Slave SQL thread exiting, replication stopped in log \
|
||||
'%s' at position %s",
|
||||
RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff));
|
||||
|
||||
@ -4373,7 +4365,7 @@ Error: '%s' errno: %d retry-time: %d retries: %d",
|
||||
if (reconnect)
|
||||
{
|
||||
if (!suppress_warnings && global_system_variables.log_warnings)
|
||||
sql_print_error("Slave: connected to master '%s@%s:%d',\
|
||||
sql_print_information("Slave: connected to master '%s@%s:%d',\
|
||||
replication resumed in log '%s' at position %s", mi->user,
|
||||
mi->host, mi->port,
|
||||
IO_RPL_LOG_NAME,
|
||||
@ -4556,12 +4548,12 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
||||
/*
|
||||
Relay log is always in new format - if the master is 3.23, the
|
||||
I/O thread will convert the format for us.
|
||||
A problem: the description event may be in a previous relay log. So if the
|
||||
slave has been shutdown meanwhile, we would have to look in old relay
|
||||
A problem: the description event may be in a previous relay log. So if
|
||||
the slave has been shutdown meanwhile, we would have to look in old relay
|
||||
logs, which may even have been deleted. So we need to write this
|
||||
description event at the beginning of the relay log.
|
||||
When the relay log is created when the I/O thread starts, easy: the master
|
||||
will send the description event and we will queue it.
|
||||
When the relay log is created when the I/O thread starts, easy: the
|
||||
master will send the description event and we will queue it.
|
||||
But if the relay log is created by new_file(): then the solution is:
|
||||
MYSQL_LOG::open() will write the buffered description event.
|
||||
*/
|
||||
@ -4715,8 +4707,8 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
||||
{
|
||||
#ifdef EXTRA_DEBUG
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("next log '%s' is currently active",
|
||||
rli->linfo.log_file_name);
|
||||
sql_print_information("next log '%s' is currently active",
|
||||
rli->linfo.log_file_name);
|
||||
#endif
|
||||
rli->cur_log= cur_log= rli->relay_log.get_log_file();
|
||||
rli->cur_log_old_open_count= rli->relay_log.get_open_count();
|
||||
@ -4745,8 +4737,8 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
|
||||
*/
|
||||
#ifdef EXTRA_DEBUG
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("next log '%s' is not active",
|
||||
rli->linfo.log_file_name);
|
||||
sql_print_information("next log '%s' is not active",
|
||||
rli->linfo.log_file_name);
|
||||
#endif
|
||||
// open_binlog() will check the magic header
|
||||
if ((rli->cur_log_fd=open_binlog(cur_log,rli->linfo.log_file_name,
|
||||
@ -4772,7 +4764,11 @@ event(errno: %d cur_log->error: %d)",
|
||||
}
|
||||
}
|
||||
if (!errmsg && global_system_variables.log_warnings)
|
||||
errmsg = "slave SQL thread was killed";
|
||||
{
|
||||
sql_print_information("Error reading relay log event: %s",
|
||||
"slave SQL thread was killed");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
err:
|
||||
if (errmsg)
|
||||
|
@ -160,8 +160,8 @@ bool foreign_key_prefix(Key *a, Key *b)
|
||||
|
||||
THD::THD()
|
||||
:user_time(0), global_read_lock(0), is_fatal_error(0),
|
||||
last_insert_id_used(0),
|
||||
insert_id_used(0), rand_used(0), time_zone_used(0),
|
||||
rand_used(0), time_zone_used(0),
|
||||
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
|
||||
in_lock_tables(0), bootstrap(0), spcont(NULL)
|
||||
{
|
||||
current_arena= this;
|
||||
@ -496,6 +496,24 @@ bool THD::store_globals()
|
||||
}
|
||||
|
||||
|
||||
/* Cleanup after a query */
|
||||
|
||||
void THD::cleanup_after_query()
|
||||
{
|
||||
if (clear_next_insert_id)
|
||||
{
|
||||
clear_next_insert_id= 0;
|
||||
next_insert_id= 0;
|
||||
}
|
||||
/* Free Items that were created during this execution */
|
||||
free_items(free_list);
|
||||
/*
|
||||
In the rest of code we assume that free_list never points to garbage:
|
||||
Keep this predicate true.
|
||||
*/
|
||||
free_list= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert a string to another character set
|
||||
|
||||
@ -1461,8 +1479,8 @@ void Statement::end_statement()
|
||||
lex_end(lex);
|
||||
delete lex->result;
|
||||
lex->result= 0;
|
||||
free_items(free_list);
|
||||
free_list= 0;
|
||||
/* Note that free_list is freed in cleanup_after_query() */
|
||||
|
||||
/*
|
||||
Don't free mem_root, as mem_root is freed in the end of dispatch_command
|
||||
(once for any command).
|
||||
|
@ -373,6 +373,7 @@ struct system_variables
|
||||
ulonglong myisam_max_sort_file_size;
|
||||
ha_rows select_limit;
|
||||
ha_rows max_join_size;
|
||||
ulong auto_increment_increment, auto_increment_offset;
|
||||
ulong bulk_insert_buff_size;
|
||||
ulong join_buff_size;
|
||||
ulong long_query_time;
|
||||
@ -835,6 +836,8 @@ public:
|
||||
generated auto_increment value in handler.cc
|
||||
*/
|
||||
ulonglong next_insert_id;
|
||||
/* Remember last next_insert_id to reset it if something went wrong */
|
||||
ulonglong prev_insert_id;
|
||||
/*
|
||||
The insert_id used for the last statement or set by SET LAST_INSERT_ID=#
|
||||
or SELECT LAST_INSERT_ID(#). Used for binary log and returned by
|
||||
@ -889,6 +892,9 @@ public:
|
||||
/* for user variables replication*/
|
||||
DYNAMIC_ARRAY user_var_events;
|
||||
|
||||
enum killed_state { NOT_KILLED=0, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
|
||||
killed_state volatile killed;
|
||||
|
||||
/* scramble - random string sent to client on handshake */
|
||||
char scramble[SCRAMBLE_LENGTH+1];
|
||||
|
||||
@ -896,22 +902,10 @@ public:
|
||||
bool locked, some_tables_deleted;
|
||||
bool last_cuted_field;
|
||||
bool no_errors, password, is_fatal_error;
|
||||
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
|
||||
bool time_zone_used;
|
||||
bool query_start_used, rand_used, time_zone_used;
|
||||
bool last_insert_id_used,insert_id_used, clear_next_insert_id;
|
||||
bool in_lock_tables;
|
||||
bool query_error, bootstrap, cleanup_done;
|
||||
|
||||
enum killed_state { NOT_KILLED=0, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
|
||||
killed_state volatile killed;
|
||||
inline int killed_errno() const
|
||||
{
|
||||
return killed;
|
||||
}
|
||||
inline void send_kill_message() const
|
||||
{
|
||||
my_error(killed_errno(), MYF(0));
|
||||
}
|
||||
|
||||
bool tmp_table_used;
|
||||
bool charset_is_system_charset, charset_is_collation_connection;
|
||||
bool slow_command;
|
||||
@ -951,6 +945,7 @@ public:
|
||||
void init_for_queries();
|
||||
void change_user(void);
|
||||
void cleanup(void);
|
||||
void cleanup_after_query();
|
||||
bool store_globals();
|
||||
#ifdef SIGNAL_WITH_VIO_CLOSE
|
||||
inline void set_active_vio(Vio* vio)
|
||||
@ -1070,6 +1065,14 @@ public:
|
||||
}
|
||||
inline CHARSET_INFO *charset() { return variables.character_set_client; }
|
||||
void update_charset();
|
||||
inline int killed_errno() const
|
||||
{
|
||||
return killed;
|
||||
}
|
||||
inline void send_kill_message() const
|
||||
{
|
||||
my_error(killed_errno(), MYF(0));
|
||||
}
|
||||
};
|
||||
|
||||
/* Flags for the THD::system_thread (bitmap) variable */
|
||||
|
@ -640,7 +640,7 @@ int mysqld_help(THD *thd, const char *mask)
|
||||
uint mlen= strlen(mask);
|
||||
MEM_ROOT *mem_root= &thd->mem_root;
|
||||
|
||||
if (res= open_and_lock_tables(thd, tables))
|
||||
if ((res= open_and_lock_tables(thd, tables)))
|
||||
goto end;
|
||||
/*
|
||||
Init tables and fields to be usable from items
|
||||
|
@ -311,8 +311,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
else
|
||||
#endif
|
||||
error=write_record(table,&info);
|
||||
if (error)
|
||||
break;
|
||||
/*
|
||||
If auto_increment values are used, save the first one
|
||||
for LAST_INSERT_ID() and for the update log.
|
||||
@ -323,6 +321,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
{ // Get auto increment value
|
||||
id= thd->last_insert_id;
|
||||
}
|
||||
if (error)
|
||||
break;
|
||||
thd->row_count++;
|
||||
}
|
||||
|
||||
@ -638,9 +638,10 @@ int write_record(TABLE *table,COPY_INFO *info)
|
||||
{
|
||||
while ((error=table->file->write_row(table->record[0])))
|
||||
{
|
||||
uint key_nr;
|
||||
if (error != HA_WRITE_SKIP)
|
||||
goto err;
|
||||
uint key_nr;
|
||||
table->file->restore_auto_increment();
|
||||
if ((int) (key_nr = table->file->get_dup_key(error)) < 0)
|
||||
{
|
||||
error=HA_WRITE_SKIP; /* Database can't find key */
|
||||
@ -733,6 +734,7 @@ int write_record(TABLE *table,COPY_INFO *info)
|
||||
if (info->handle_duplicates != DUP_IGNORE ||
|
||||
(error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE))
|
||||
goto err;
|
||||
table->file->restore_auto_increment();
|
||||
}
|
||||
else
|
||||
info->copied++;
|
||||
|
@ -1571,8 +1571,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
|
||||
break;
|
||||
mysqld_list_fields(thd,&table_list,fields);
|
||||
free_items(thd->free_list);
|
||||
thd->free_list= 0; /* free_list should never point to garbage */
|
||||
thd->cleanup_after_query();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -4520,6 +4519,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
|
||||
}
|
||||
thd->proc_info="freeing items";
|
||||
thd->end_statement();
|
||||
thd->cleanup_after_query();
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -4546,10 +4546,12 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
|
||||
all_tables_not_ok(thd,(TABLE_LIST*) lex->select_lex.table_list.first))
|
||||
error= 1; /* Ignore question */
|
||||
thd->end_statement();
|
||||
thd->cleanup_after_query();
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
** Store field definition for create
|
||||
** Return 0 if ok
|
||||
|
@ -1628,8 +1628,7 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
|
||||
thd->restore_backup_statement(stmt, &thd->stmt_backup);
|
||||
cleanup_items(stmt->free_list);
|
||||
close_thread_tables(thd);
|
||||
free_items(thd->free_list);
|
||||
thd->free_list= 0;
|
||||
thd->cleanup_after_query();
|
||||
thd->current_arena= thd;
|
||||
|
||||
if (error)
|
||||
@ -1856,12 +1855,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
||||
cleanup_items(stmt->free_list);
|
||||
reset_stmt_params(stmt);
|
||||
close_thread_tables(thd); /* to close derived tables */
|
||||
/*
|
||||
Free items that were created during this execution of the PS by
|
||||
query optimizer.
|
||||
*/
|
||||
free_items(thd->free_list);
|
||||
thd->free_list= 0;
|
||||
thd->cleanup_after_query();
|
||||
}
|
||||
|
||||
thd->set_statement(&thd->stmt_backup);
|
||||
@ -1969,13 +1963,8 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
|
||||
reset_stmt_params(stmt);
|
||||
close_thread_tables(thd); // to close derived tables
|
||||
thd->set_statement(&thd->stmt_backup);
|
||||
/* Free Items that were created during this execution of the PS. */
|
||||
free_items(thd->free_list);
|
||||
/*
|
||||
In the rest of prepared statements code we assume that free_list
|
||||
never points to garbage: keep this predicate true.
|
||||
*/
|
||||
thd->free_list= 0;
|
||||
thd->cleanup_after_query();
|
||||
|
||||
if (stmt->state == Item_arena::PREPARED)
|
||||
{
|
||||
thd->current_arena= thd;
|
||||
|
@ -3389,6 +3389,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
|
||||
to->file->print_error(error,MYF(0));
|
||||
break;
|
||||
}
|
||||
to->file->restore_auto_increment();
|
||||
delete_count++;
|
||||
}
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user