Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
a820c732
Commit
a820c732
authored
Oct 14, 2009
by
Georgi Kodinov
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
88aa7af8
adab17b9
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
393 additions
and
164 deletions
+393
-164
mysql-test/extra/binlog_tests/binlog.test
mysql-test/extra/binlog_tests/binlog.test
+39
-0
mysql-test/r/func_group.result
mysql-test/r/func_group.result
+44
-0
mysql-test/suite/binlog/r/binlog_row_binlog.result
mysql-test/suite/binlog/r/binlog_row_binlog.result
+24
-0
mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result
...test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result
+8
-8
mysql-test/suite/binlog/r/binlog_stm_binlog.result
mysql-test/suite/binlog/r/binlog_stm_binlog.result
+21
-0
mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test
...l-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test
+8
-4
mysql-test/t/func_group.test
mysql-test/t/func_group.test
+48
-0
sql/log_event.cc
sql/log_event.cc
+33
-33
sql/log_event_old.cc
sql/log_event_old.cc
+50
-54
sql/opt_sum.cc
sql/opt_sum.cc
+2
-1
sql/slave.cc
sql/slave.cc
+26
-31
sql/slave.h
sql/slave.h
+1
-2
sql/sql_binlog.cc
sql/sql_binlog.cc
+27
-24
sql/sql_class.h
sql/sql_class.h
+26
-1
sql/sql_select.cc
sql/sql_select.cc
+22
-5
sql/sql_select.h
sql/sql_select.h
+14
-1
No files found.
mysql-test/extra/binlog_tests/binlog.test
View file @
a820c732
...
@@ -270,3 +270,42 @@ INSERT INTO test.t1 VALUES (1), (2);
...
@@ -270,3 +270,42 @@ INSERT INTO test.t1 VALUES (1), (2);
CREATE
TABLE
test
.
t2
SELECT
*
FROM
test
.
t1
;
CREATE
TABLE
test
.
t2
SELECT
*
FROM
test
.
t1
;
USE
test
;
USE
test
;
DROP
TABLES
t1
,
t2
;
DROP
TABLES
t1
,
t2
;
#
# Bug#46640
# This test verifies if the server_id stored in the "format
# description BINLOG statement" will override the server_id
# of the server executing the statements.
#
connect
(
fresh
,
localhost
,
root
,,
test
);
connection
fresh
;
RESET
MASTER
;
CREATE
TABLE
t1
(
a
INT
PRIMARY
KEY
);
# Format description event, with server_id = 10;
BINLOG
'
3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA
AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
'
;
# What server_id is logged for a statement? Should be our own, not the
# one from the format description event.
INSERT
INTO
t1
VALUES
(
1
);
# INSERT INTO t1 VALUES (2), with server_id=20. Check that this is logged
# with our own server id, not the 20 from the BINLOG statement.
BINLOG
'
3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA=
3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA==
'
;
# Show binlog events to check that server ids are correct.
--
replace_column
1
# 2 # 5 #
--
replace_regex
/
Server
ver
:
.*
,
Binlog
ver
:
.*/
Server
ver
:
#, Binlog ver: #/ /table_id: [0-9]+/table_id: #/
SHOW
BINLOG
EVENTS
;
DROP
TABLE
t1
;
disconnect
fresh
;
mysql-test/r/func_group.result
View file @
a820c732
...
@@ -1477,3 +1477,47 @@ COUNT(*)
...
@@ -1477,3 +1477,47 @@ COUNT(*)
SET SQL_MODE=default;
SET SQL_MODE=default;
DROP TABLE t1;
DROP TABLE t1;
End of 5.0 tests
End of 5.0 tests
#
# BUG#47280 - strange results from count(*) with order by multiple
# columns without where/group
#
#
# Initialize test
#
CREATE TABLE t1 (
pk INT NOT NULL,
i INT,
PRIMARY KEY (pk)
);
INSERT INTO t1 VALUES (1,11),(2,12),(3,13);
#
# Start test
# All the following queries shall return 1 record
#
# Masking all correct values {11...13} for column i in this result.
SELECT MAX(pk) as max, i
FROM t1
ORDER BY max;
max i
3 #
EXPLAIN
SELECT MAX(pk) as max, i
FROM t1
ORDER BY max;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using temporary
# Only 11 is correct for collumn i in this result
SELECT MAX(pk) as max, i
FROM t1
WHERE pk<2
ORDER BY max;
max i
1 11
#
# Cleanup
#
DROP TABLE t1;
End of 5.1 tests
mysql-test/suite/binlog/r/binlog_row_binlog.result
View file @
a820c732
...
@@ -1309,3 +1309,27 @@ INSERT INTO test.t1 VALUES (1), (2);
...
@@ -1309,3 +1309,27 @@ INSERT INTO test.t1 VALUES (1), (2);
CREATE TABLE test.t2 SELECT * FROM test.t1;
CREATE TABLE test.t2 SELECT * FROM test.t1;
USE test;
USE test;
DROP TABLES t1, t2;
DROP TABLES t1, t2;
RESET MASTER;
CREATE TABLE t1 (a INT PRIMARY KEY);
BINLOG '
3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA
AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
';
INSERT INTO t1 VALUES (1);
BINLOG '
3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA=
3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA==
';
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
# # Format_desc 1 # Server ver: #, Binlog ver: #
# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY)
# # Query 1 # BEGIN
# # Table_map 1 # table_id: # (test.t1)
# # Write_rows 1 # table_id: # flags: STMT_END_F
# # Query 1 # COMMIT
# # Query 1 # BEGIN
# # Table_map 1 # table_id: # (test.t1)
# # Write_rows 1 # table_id: # flags: STMT_END_F
# # Query 1 # COMMIT
DROP TABLE t1;
mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_verbose.result
View file @
a820c732
Verbose statements from : write-partial-row.binlog
Verbose statements from : write-partial-row.binlog
select
tx
t from raw_binlog_rows where txt like '###%';
select
replace(txt,'\r', '') as stm
t from raw_binlog_rows where txt like '###%';
tx
t
stm
t
### INSERT INTO mysql.ndb_apply_status
### INSERT INTO mysql.ndb_apply_status
### SET
### SET
### @1=1
### @1=1
...
@@ -37,8 +37,8 @@ txt
...
@@ -37,8 +37,8 @@ txt
### @1=2
### @1=2
drop table raw_binlog_rows;
drop table raw_binlog_rows;
Verbose statements from : write-full-row.binlog
Verbose statements from : write-full-row.binlog
select
tx
t from raw_binlog_rows where txt like '###%';
select
replace(txt,'\r', '') as stm
t from raw_binlog_rows where txt like '###%';
tx
t
stm
t
### INSERT INTO mysql.ndb_apply_status
### INSERT INTO mysql.ndb_apply_status
### SET
### SET
### @1=2
### @1=2
...
@@ -76,8 +76,8 @@ txt
...
@@ -76,8 +76,8 @@ txt
### @1=2
### @1=2
drop table raw_binlog_rows;
drop table raw_binlog_rows;
Verbose statements from : update-partial-row.binlog
Verbose statements from : update-partial-row.binlog
select
tx
t from raw_binlog_rows where txt like '###%';
select
replace(txt,'\r', '') as stm
t from raw_binlog_rows where txt like '###%';
tx
t
stm
t
### INSERT INTO mysql.ndb_apply_status
### INSERT INTO mysql.ndb_apply_status
### SET
### SET
### @1=3
### @1=3
...
@@ -117,8 +117,8 @@ txt
...
@@ -117,8 +117,8 @@ txt
### @1=2
### @1=2
drop table raw_binlog_rows;
drop table raw_binlog_rows;
Verbose statements from : update-full-row.binlog
Verbose statements from : update-full-row.binlog
select
tx
t from raw_binlog_rows where txt like '###%';
select
replace(txt,'\r', '') as stm
t from raw_binlog_rows where txt like '###%';
tx
t
stm
t
### INSERT INTO mysql.ndb_apply_status
### INSERT INTO mysql.ndb_apply_status
### SET
### SET
### @1=4
### @1=4
...
...
mysql-test/suite/binlog/r/binlog_stm_binlog.result
View file @
a820c732
...
@@ -784,3 +784,24 @@ INSERT INTO test.t1 VALUES (1), (2);
...
@@ -784,3 +784,24 @@ INSERT INTO test.t1 VALUES (1), (2);
CREATE TABLE test.t2 SELECT * FROM test.t1;
CREATE TABLE test.t2 SELECT * FROM test.t1;
USE test;
USE test;
DROP TABLES t1, t2;
DROP TABLES t1, t2;
RESET MASTER;
CREATE TABLE t1 (a INT PRIMARY KEY);
BINLOG '
3u9kSA8KAAAAZgAAAGoAAAABAAQANS4xLjM1LW1hcmlhLWJldGExLWRlYnVnLWxvZwAAAAAAAAAA
AAAAAAAAAAAAAAAAAADe72RIEzgNAAgAEgAEBAQEEgAAUwAEGggAAAAICAgC
';
INSERT INTO t1 VALUES (1);
BINLOG '
3u9kSBMUAAAAKQAAAJEBAAAAABoAAAAAAAAABHRlc3QAAnQxAAEDAAA=
3u9kSBcUAAAAIgAAALMBAAAQABoAAAAAAAEAAf/+AgAAAA==
';
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
# # Format_desc 1 # Server ver: #, Binlog ver: #
# # Query 1 # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY)
# # Query 1 # use `test`; INSERT INTO t1 VALUES (1)
# # Query 1 # BEGIN
# # Table_map 1 # table_id: # (test.t1)
# # Write_rows 1 # table_id: # flags: STMT_END_F
# # Query 1 # COMMIT
DROP TABLE t1;
mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_verbose.test
View file @
a820c732
...
@@ -45,7 +45,8 @@ create table raw_binlog_rows (txt varchar(1000));
...
@@ -45,7 +45,8 @@ create table raw_binlog_rows (txt varchar(1000));
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
enable_query_log
--
enable_query_log
--
echo
Verbose
statements
from
:
$binlog_file
--
echo
Verbose
statements
from
:
$binlog_file
select
txt
from
raw_binlog_rows
where
txt
like
'###%'
;
# Output --verbose lines, with extra Windows CR's trimmed
select
replace
(
txt
,
'\r'
,
''
)
as
stmt
from
raw_binlog_rows
where
txt
like
'###%'
;
drop
table
raw_binlog_rows
;
drop
table
raw_binlog_rows
;
--
disable_query_log
--
disable_query_log
...
@@ -56,7 +57,8 @@ create table raw_binlog_rows (txt varchar(1000));
...
@@ -56,7 +57,8 @@ create table raw_binlog_rows (txt varchar(1000));
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
enable_query_log
--
enable_query_log
--
echo
Verbose
statements
from
:
$binlog_file
--
echo
Verbose
statements
from
:
$binlog_file
select
txt
from
raw_binlog_rows
where
txt
like
'###%'
;
# Output --verbose lines, with extra Windows CR's trimmed
select
replace
(
txt
,
'\r'
,
''
)
as
stmt
from
raw_binlog_rows
where
txt
like
'###%'
;
drop
table
raw_binlog_rows
;
drop
table
raw_binlog_rows
;
--
disable_query_log
--
disable_query_log
...
@@ -67,7 +69,8 @@ create table raw_binlog_rows (txt varchar(1000));
...
@@ -67,7 +69,8 @@ create table raw_binlog_rows (txt varchar(1000));
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
enable_query_log
--
enable_query_log
--
echo
Verbose
statements
from
:
$binlog_file
--
echo
Verbose
statements
from
:
$binlog_file
select
txt
from
raw_binlog_rows
where
txt
like
'###%'
;
# Output --verbose lines, with extra Windows CR's trimmed
select
replace
(
txt
,
'\r'
,
''
)
as
stmt
from
raw_binlog_rows
where
txt
like
'###%'
;
drop
table
raw_binlog_rows
;
drop
table
raw_binlog_rows
;
--
disable_query_log
--
disable_query_log
...
@@ -78,5 +81,6 @@ create table raw_binlog_rows (txt varchar(1000));
...
@@ -78,5 +81,6 @@ create table raw_binlog_rows (txt varchar(1000));
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
remove_file
$MYSQLTEST_VARDIR
/
tmp
/
mysqlbinlog_verbose
.
sql
--
enable_query_log
--
enable_query_log
--
echo
Verbose
statements
from
:
$binlog_file
--
echo
Verbose
statements
from
:
$binlog_file
select
txt
from
raw_binlog_rows
where
txt
like
'###%'
;
# Output --verbose lines, with extra Windows CR's trimmed
select
replace
(
txt
,
'\r'
,
''
)
as
stmt
from
raw_binlog_rows
where
txt
like
'###%'
;
drop
table
raw_binlog_rows
;
drop
table
raw_binlog_rows
;
mysql-test/t/func_group.test
View file @
a820c732
...
@@ -1006,3 +1006,51 @@ DROP TABLE t1;
...
@@ -1006,3 +1006,51 @@ DROP TABLE t1;
###
###
--
echo
End
of
5.0
tests
--
echo
End
of
5.0
tests
--
echo
#
--
echo
# BUG#47280 - strange results from count(*) with order by multiple
--
echo
# columns without where/group
--
echo
#
--
echo
#
--
echo
# Initialize test
--
echo
#
CREATE
TABLE
t1
(
pk
INT
NOT
NULL
,
i
INT
,
PRIMARY
KEY
(
pk
)
);
INSERT
INTO
t1
VALUES
(
1
,
11
),(
2
,
12
),(
3
,
13
);
--
echo
#
--
echo
# Start test
--
echo
# All the following queries shall return 1 record
--
echo
#
--
echo
--
echo
# Masking all correct values {11...13} for column i in this result.
--
replace_column
2
#
SELECT
MAX
(
pk
)
as
max
,
i
FROM
t1
ORDER
BY
max
;
--
echo
EXPLAIN
SELECT
MAX
(
pk
)
as
max
,
i
FROM
t1
ORDER
BY
max
;
--
echo
--
echo
# Only 11 is correct for collumn i in this result
SELECT
MAX
(
pk
)
as
max
,
i
FROM
t1
WHERE
pk
<
2
ORDER
BY
max
;
--
echo
#
--
echo
# Cleanup
--
echo
#
DROP
TABLE
t1
;
--
echo
End
of
5.1
tests
sql/log_event.cc
View file @
a820c732
...
@@ -3859,6 +3859,7 @@ bool Format_description_log_event::write(IO_CACHE* file)
...
@@ -3859,6 +3859,7 @@ bool Format_description_log_event::write(IO_CACHE* file)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int
Format_description_log_event
::
do_apply_event
(
Relay_log_info
const
*
rli
)
int
Format_description_log_event
::
do_apply_event
(
Relay_log_info
const
*
rli
)
{
{
int
ret
=
0
;
DBUG_ENTER
(
"Format_description_log_event::do_apply_event"
);
DBUG_ENTER
(
"Format_description_log_event::do_apply_event"
);
#ifdef USING_TRANSACTIONS
#ifdef USING_TRANSACTIONS
...
@@ -3900,17 +3901,21 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli)
...
@@ -3900,17 +3901,21 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli)
0, then 96, then jump to first really asked event (which is
0, then 96, then jump to first really asked event (which is
>96). So this is ok.
>96). So this is ok.
*/
*/
DBUG_RETURN
(
Start_log_event_v3
::
do_apply_event
(
rli
)
);
ret
=
Start_log_event_v3
::
do_apply_event
(
rli
);
}
}
DBUG_RETURN
(
0
);
if
(
!
ret
)
{
/* Save the information describing this binlog */
delete
rli
->
relay_log
.
description_event_for_exec
;
const_cast
<
Relay_log_info
*>
(
rli
)
->
relay_log
.
description_event_for_exec
=
this
;
}
DBUG_RETURN
(
ret
);
}
}
int
Format_description_log_event
::
do_update_pos
(
Relay_log_info
*
rli
)
int
Format_description_log_event
::
do_update_pos
(
Relay_log_info
*
rli
)
{
{
/* save the information describing this binlog */
delete
rli
->
relay_log
.
description_event_for_exec
;
rli
->
relay_log
.
description_event_for_exec
=
this
;
if
(
server_id
==
(
uint32
)
::
server_id
)
if
(
server_id
==
(
uint32
)
::
server_id
)
{
{
/*
/*
...
@@ -7506,6 +7511,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
...
@@ -7506,6 +7511,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
thd
->
reset_current_stmt_binlog_row_based
();
thd
->
reset_current_stmt_binlog_row_based
();
const_cast
<
Relay_log_info
*>
(
rli
)
->
cleanup_context
(
thd
,
error
);
const_cast
<
Relay_log_info
*>
(
rli
)
->
cleanup_context
(
thd
,
error
);
thd
->
is_slave_error
=
1
;
thd
->
is_slave_error
=
1
;
DBUG_RETURN
(
error
);
}
}
/*
/*
This code would ideally be placed in do_update_pos() instead, but
This code would ideally be placed in do_update_pos() instead, but
...
@@ -7534,6 +7540,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
...
@@ -7534,6 +7540,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
const_cast
<
Relay_log_info
*>
(
rli
)
->
last_event_start_time
=
my_time
(
0
);
const_cast
<
Relay_log_info
*>
(
rli
)
->
last_event_start_time
=
my_time
(
0
);
}
}
if
(
get_flags
(
STMT_END_F
))
if
(
error
=
rows_event_stmt_cleanup
(
rli
,
thd
))
rli
->
report
(
ERROR_LEVEL
,
error
,
"Error in %s event: commit of row events failed, "
"table `%s`.`%s`"
,
get_type_str
(),
m_table
->
s
->
db
.
str
,
m_table
->
s
->
table_name
.
str
);
DBUG_RETURN
(
error
);
DBUG_RETURN
(
error
);
}
}
...
@@ -7632,33 +7646,19 @@ Rows_log_event::do_update_pos(Relay_log_info *rli)
...
@@ -7632,33 +7646,19 @@ Rows_log_event::do_update_pos(Relay_log_info *rli)
if
(
get_flags
(
STMT_END_F
))
if
(
get_flags
(
STMT_END_F
))
{
{
if
((
error
=
rows_event_stmt_cleanup
(
rli
,
thd
))
==
0
)
/*
{
Indicate that a statement is finished.
/*
Step the group log position if we are not in a transaction,
Indicate that a statement is finished.
otherwise increase the event log position.
Step the group log position if we are not in a transaction,
*/
otherwise increase the event log position.
rli
->
stmt_done
(
log_pos
,
when
);
*/
/*
rli
->
stmt_done
(
log_pos
,
when
);
Clear any errors in thd->net.last_err*. It is not known if this is
needed or not. It is believed that any errors that may exist in
/*
thd->net.last_err* are allowed. Examples of errors are "key not
Clear any errors pushed in thd->net.last_err* if for example "no key
found", which is produced in the test case rpl_row_conflicts.test
found" (as this is allowed). This is a safety measure; apparently
*/
those errors (e.g. when executing a Delete_rows_log_event of a
thd
->
clear_error
();
non-existing row, like in rpl_row_mystery22.test,
thd->net.last_error = "Can't find record in 't1'" and last_errno=1032)
do not become visible. We still prefer to wipe them out.
*/
thd
->
clear_error
();
}
else
{
rli
->
report
(
ERROR_LEVEL
,
error
,
"Error in %s event: commit of row events failed, "
"table `%s`.`%s`"
,
get_type_str
(),
m_table
->
s
->
db
.
str
,
m_table
->
s
->
table_name
.
str
);
}
}
}
else
else
{
{
...
...
sql/log_event_old.cc
View file @
a820c732
...
@@ -1814,33 +1814,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
...
@@ -1814,33 +1814,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
const_cast
<
Relay_log_info
*>
(
rli
)
->
last_event_start_time
=
my_time
(
0
);
const_cast
<
Relay_log_info
*>
(
rli
)
->
last_event_start_time
=
my_time
(
0
);
}
}
DBUG_RETURN
(
0
);
}
Log_event
::
enum_skip_reason
Old_rows_log_event
::
do_shall_skip
(
Relay_log_info
*
rli
)
{
/*
If the slave skip counter is 1 and this event does not end a
statement, then we should not start executing on the next event.
Otherwise, we defer the decision to the normal skipping logic.
*/
if
(
rli
->
slave_skip_counter
==
1
&&
!
get_flags
(
STMT_END_F
))
return
Log_event
::
EVENT_SKIP_IGNORE
;
else
return
Log_event
::
do_shall_skip
(
rli
);
}
int
Old_rows_log_event
::
do_update_pos
(
Relay_log_info
*
rli
)
{
DBUG_ENTER
(
"Old_rows_log_event::do_update_pos"
);
int
error
=
0
;
DBUG_PRINT
(
"info"
,
(
"flags: %s"
,
get_flags
(
STMT_END_F
)
?
"STMT_END_F "
:
""
));
if
(
get_flags
(
STMT_END_F
))
if
(
get_flags
(
STMT_END_F
))
{
{
/*
/*
...
@@ -1869,7 +1842,12 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli)
...
@@ -1869,7 +1842,12 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli)
are involved, commit the transaction and flush the pending event to the
are involved, commit the transaction and flush the pending event to the
binlog.
binlog.
*/
*/
error
=
ha_autocommit_or_rollback
(
thd
,
0
);
if
(
error
=
ha_autocommit_or_rollback
(
thd
,
0
))
rli
->
report
(
ERROR_LEVEL
,
error
,
"Error in %s event: commit of row events failed, "
"table `%s`.`%s`"
,
get_type_str
(),
m_table
->
s
->
db
.
str
,
m_table
->
s
->
table_name
.
str
);
/*
/*
Now what if this is not a transactional engine? we still need to
Now what if this is not a transactional engine? we still need to
...
@@ -1882,33 +1860,51 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli)
...
@@ -1882,33 +1860,51 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli)
*/
*/
thd
->
reset_current_stmt_binlog_row_based
();
thd
->
reset_current_stmt_binlog_row_based
();
rli
->
cleanup_context
(
thd
,
0
);
const_cast
<
Relay_log_info
*>
(
rli
)
->
cleanup_context
(
thd
,
0
);
if
(
error
==
0
)
}
{
/*
Indicate that a statement is finished.
Step the group log position if we are not in a transaction,
otherwise increase the event log position.
*/
rli
->
stmt_done
(
log_pos
,
when
);
/*
DBUG_RETURN
(
error
);
Clear any errors pushed in thd->net.client_last_err* if for
}
example "no key found" (as this is allowed). This is a safety
measure; apparently those errors (e.g. when executing a
Delete_rows_log_event_old of a non-existing row, like in
Log_event
::
enum_skip_reason
rpl_row_mystery22.test, thd->net.last_error = "Can't
Old_rows_log_event
::
do_shall_skip
(
Relay_log_info
*
rli
)
find record in 't1'" and last_errno=1032) do not become
{
visible. We still prefer to wipe them out.
/*
*/
If the slave skip counter is 1 and this event does not end a
thd
->
clear_error
();
statement, then we should not start executing on the next event.
}
Otherwise, we defer the decision to the normal skipping logic.
else
*/
rli
->
report
(
ERROR_LEVEL
,
error
,
if
(
rli
->
slave_skip_counter
==
1
&&
!
get_flags
(
STMT_END_F
))
"Error in %s event: commit of row events failed, "
return
Log_event
::
EVENT_SKIP_IGNORE
;
"table `%s`.`%s`"
,
else
get_type_str
(),
m_table
->
s
->
db
.
str
,
return
Log_event
::
do_shall_skip
(
rli
);
m_table
->
s
->
table_name
.
str
);
}
int
Old_rows_log_event
::
do_update_pos
(
Relay_log_info
*
rli
)
{
DBUG_ENTER
(
"Old_rows_log_event::do_update_pos"
);
int
error
=
0
;
DBUG_PRINT
(
"info"
,
(
"flags: %s"
,
get_flags
(
STMT_END_F
)
?
"STMT_END_F "
:
""
));
if
(
get_flags
(
STMT_END_F
))
{
/*
Indicate that a statement is finished.
Step the group log position if we are not in a transaction,
otherwise increase the event log position.
*/
rli
->
stmt_done
(
log_pos
,
when
);
/*
Clear any errors in thd->net.last_err*. It is not known if this is
needed or not. It is believed that any errors that may exist in
thd->net.last_err* are allowed. Examples of errors are "key not
found", which is produced in the test case rpl_row_conflicts.test
*/
thd
->
clear_error
();
}
}
else
else
{
{
...
...
sql/opt_sum.cc
View file @
a820c732
...
@@ -97,7 +97,8 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables)
...
@@ -97,7 +97,8 @@ static ulonglong get_exact_record_count(TABLE_LIST *tables)
@note
@note
This function is only called for queries with sum functions and no
This function is only called for queries with sum functions and no
GROUP BY part.
GROUP BY part. This means that the result set shall contain a single
row only
@retval
@retval
0 no errors
0 no errors
...
...
sql/slave.cc
View file @
a820c732
...
@@ -2082,8 +2082,7 @@ static int has_temporary_error(THD *thd)
...
@@ -2082,8 +2082,7 @@ static int has_temporary_error(THD *thd)
@retval 2 No error calling ev->apply_event(), but error calling
@retval 2 No error calling ev->apply_event(), but error calling
ev->update_pos().
ev->update_pos().
*/
*/
int
apply_event_and_update_pos
(
Log_event
*
ev
,
THD
*
thd
,
Relay_log_info
*
rli
,
int
apply_event_and_update_pos
(
Log_event
*
ev
,
THD
*
thd
,
Relay_log_info
*
rli
)
bool
skip
)
{
{
int
exec_res
=
0
;
int
exec_res
=
0
;
...
@@ -2128,37 +2127,33 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
...
@@ -2128,37 +2127,33 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli,
ev
->
when
=
my_time
(
0
);
ev
->
when
=
my_time
(
0
);
ev
->
thd
=
thd
;
// because up to this point, ev->thd == 0
ev
->
thd
=
thd
;
// because up to this point, ev->thd == 0
if
(
skip
)
int
reason
=
ev
->
shall_skip
(
rli
);
{
if
(
reason
==
Log_event
::
EVENT_SKIP_COUNT
)
int
reason
=
ev
->
shall_skip
(
rli
);
--
rli
->
slave_skip_counter
;
if
(
reason
==
Log_event
::
EVENT_SKIP_COUNT
)
pthread_mutex_unlock
(
&
rli
->
data_lock
);
--
rli
->
slave_skip_counter
;
if
(
reason
==
Log_event
::
EVENT_SKIP_NOT
)
pthread_mutex_unlock
(
&
rli
->
data_lock
);
exec_res
=
ev
->
apply_event
(
rli
);
if
(
reason
==
Log_event
::
EVENT_SKIP_NOT
)
exec_res
=
ev
->
apply_event
(
rli
);
#ifndef DBUG_OFF
#ifndef DBUG_OFF
/*
/*
This only prints information to the debug trace.
This only prints information to the debug trace.
TODO: Print an informational message to the error log?
TODO: Print an informational message to the error log?
*/
*/
static
const
char
*
const
explain
[]
=
{
static
const
char
*
const
explain
[]
=
{
// EVENT_SKIP_NOT,
// EVENT_SKIP_NOT,
"not skipped"
,
"not skipped"
,
// EVENT_SKIP_IGNORE,
// EVENT_SKIP_IGNORE,
"skipped because event should be ignored"
,
"skipped because event should be ignored"
,
// EVENT_SKIP_COUNT
// EVENT_SKIP_COUNT
"skipped because event skip counter was non-zero"
"skipped because event skip counter was non-zero"
};
};
DBUG_PRINT
(
"info"
,
(
"OPTION_BEGIN: %d; IN_STMT: %d"
,
DBUG_PRINT
(
"info"
,
(
"OPTION_BEGIN: %d; IN_STMT: %d"
,
thd
->
options
&
OPTION_BEGIN
?
1
:
0
,
thd
->
options
&
OPTION_BEGIN
?
1
:
0
,
rli
->
get_flag
(
Relay_log_info
::
IN_STMT
)));
rli
->
get_flag
(
Relay_log_info
::
IN_STMT
)));
DBUG_PRINT
(
"skip_event"
,
(
"%s event was %s"
,
DBUG_PRINT
(
"skip_event"
,
(
"%s event was %s"
,
ev
->
get_type_str
(),
explain
[
reason
]));
ev
->
get_type_str
(),
explain
[
reason
]));
#endif
#endif
}
else
exec_res
=
ev
->
apply_event
(
rli
);
DBUG_PRINT
(
"info"
,
(
"apply_event error = %d"
,
exec_res
));
DBUG_PRINT
(
"info"
,
(
"apply_event error = %d"
,
exec_res
));
if
(
exec_res
==
0
)
if
(
exec_res
==
0
)
...
@@ -2278,7 +2273,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
...
@@ -2278,7 +2273,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
delete
ev
;
delete
ev
;
DBUG_RETURN
(
1
);
DBUG_RETURN
(
1
);
}
}
exec_res
=
apply_event_and_update_pos
(
ev
,
thd
,
rli
,
TRUE
);
exec_res
=
apply_event_and_update_pos
(
ev
,
thd
,
rli
);
/*
/*
Format_description_log_event should not be deleted because it will be
Format_description_log_event should not be deleted because it will be
...
...
sql/slave.h
View file @
a820c732
...
@@ -190,8 +190,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
...
@@ -190,8 +190,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
void
set_slave_thread_options
(
THD
*
thd
);
void
set_slave_thread_options
(
THD
*
thd
);
void
set_slave_thread_default_charset
(
THD
*
thd
,
Relay_log_info
const
*
rli
);
void
set_slave_thread_default_charset
(
THD
*
thd
,
Relay_log_info
const
*
rli
);
void
rotate_relay_log
(
Master_info
*
mi
);
void
rotate_relay_log
(
Master_info
*
mi
);
int
apply_event_and_update_pos
(
Log_event
*
ev
,
THD
*
thd
,
Relay_log_info
*
rli
,
int
apply_event_and_update_pos
(
Log_event
*
ev
,
THD
*
thd
,
Relay_log_info
*
rli
);
bool
skip
);
pthread_handler_t
handle_slave_io
(
void
*
arg
);
pthread_handler_t
handle_slave_io
(
void
*
arg
);
pthread_handler_t
handle_slave_sql
(
void
*
arg
);
pthread_handler_t
handle_slave_sql
(
void
*
arg
);
...
...
sql/sql_binlog.cc
View file @
a820c732
...
@@ -56,17 +56,20 @@ void mysql_client_binlog_statement(THD* thd)
...
@@ -56,17 +56,20 @@ void mysql_client_binlog_statement(THD* thd)
Format_description_event.
Format_description_event.
*/
*/
my_bool
have_fd_event
=
TRUE
;
my_bool
have_fd_event
=
TRUE
;
if
(
!
thd
->
rli_fake
)
int
err
;
Relay_log_info
*
rli
;
rli
=
thd
->
rli_fake
;
if
(
!
rli
)
{
{
thd
->
rli_fake
=
new
Relay_log_info
;
rli
=
thd
->
rli_fake
=
new
Relay_log_info
;
#ifdef HAVE_purify
#ifdef HAVE_purify
thd
->
rli_fake
->
is_fake
=
TRUE
;
rli
->
is_fake
=
TRUE
;
#endif
#endif
have_fd_event
=
FALSE
;
have_fd_event
=
FALSE
;
}
}
if
(
thd
->
rli_fake
&&
!
thd
->
rli_fake
->
relay_log
.
description_event_for_exec
)
if
(
rli
&&
!
rli
->
relay_log
.
description_event_for_exec
)
{
{
thd
->
rli_fake
->
relay_log
.
description_event_for_exec
=
rli
->
relay_log
.
description_event_for_exec
=
new
Format_description_log_event
(
4
);
new
Format_description_log_event
(
4
);
have_fd_event
=
FALSE
;
have_fd_event
=
FALSE
;
}
}
...
@@ -78,16 +81,16 @@ void mysql_client_binlog_statement(THD* thd)
...
@@ -78,16 +81,16 @@ void mysql_client_binlog_statement(THD* thd)
/*
/*
Out of memory check
Out of memory check
*/
*/
if
(
!
(
thd
->
rli_fake
&&
if
(
!
(
rli
&&
thd
->
rli_fake
->
relay_log
.
description_event_for_exec
&&
rli
->
relay_log
.
description_event_for_exec
&&
buf
))
buf
))
{
{
my_error
(
ER_OUTOFMEMORY
,
MYF
(
0
),
1
);
/* needed 1 bytes */
my_error
(
ER_OUTOFMEMORY
,
MYF
(
0
),
1
);
/* needed 1 bytes */
goto
end
;
goto
end
;
}
}
thd
->
rli_fake
->
sql_thd
=
thd
;
rli
->
sql_thd
=
thd
;
thd
->
rli_fake
->
no_storage
=
TRUE
;
rli
->
no_storage
=
TRUE
;
for
(
char
const
*
strptr
=
thd
->
lex
->
comment
.
str
;
for
(
char
const
*
strptr
=
thd
->
lex
->
comment
.
str
;
strptr
<
thd
->
lex
->
comment
.
str
+
thd
->
lex
->
comment
.
length
;
)
strptr
<
thd
->
lex
->
comment
.
str
+
thd
->
lex
->
comment
.
length
;
)
...
@@ -170,8 +173,7 @@ void mysql_client_binlog_statement(THD* thd)
...
@@ -170,8 +173,7 @@ void mysql_client_binlog_statement(THD* thd)
}
}
ev
=
Log_event
::
read_log_event
(
bufptr
,
event_len
,
&
error
,
ev
=
Log_event
::
read_log_event
(
bufptr
,
event_len
,
&
error
,
thd
->
rli_fake
->
relay_log
.
rli
->
relay_log
.
description_event_for_exec
);
description_event_for_exec
);
DBUG_PRINT
(
"info"
,(
"binlog base64 err=%s"
,
error
));
DBUG_PRINT
(
"info"
,(
"binlog base64 err=%s"
,
error
));
if
(
!
ev
)
if
(
!
ev
)
...
@@ -209,18 +211,10 @@ void mysql_client_binlog_statement(THD* thd)
...
@@ -209,18 +211,10 @@ void mysql_client_binlog_statement(THD* thd)
reporting.
reporting.
*/
*/
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
if
(
apply_event_and_update_pos
(
ev
,
thd
,
thd
->
rli_fake
,
FALSE
))
err
=
ev
->
apply_event
(
rli
);
{
#else
delete
ev
;
err
=
0
;
/*
TODO: Maybe a better error message since the BINLOG statement
now contains several events.
*/
my_error
(
ER_UNKNOWN_ERROR
,
MYF
(
0
),
"Error executing BINLOG statement"
);
goto
end
;
}
#endif
#endif
/*
/*
Format_description_log_event should not be deleted because it
Format_description_log_event should not be deleted because it
will be used to read info about the relay log's format; it
will be used to read info about the relay log's format; it
...
@@ -228,8 +222,17 @@ void mysql_client_binlog_statement(THD* thd)
...
@@ -228,8 +222,17 @@ void mysql_client_binlog_statement(THD* thd)
i.e. when this thread terminates.
i.e. when this thread terminates.
*/
*/
if
(
ev
->
get_type_code
()
!=
FORMAT_DESCRIPTION_EVENT
)
if
(
ev
->
get_type_code
()
!=
FORMAT_DESCRIPTION_EVENT
)
delete
ev
;
delete
ev
;
ev
=
0
;
ev
=
0
;
if
(
err
)
{
/*
TODO: Maybe a better error message since the BINLOG statement
now contains several events.
*/
my_error
(
ER_UNKNOWN_ERROR
,
MYF
(
0
),
"Error executing BINLOG statement"
);
goto
end
;
}
}
}
}
}
...
@@ -238,7 +241,7 @@ void mysql_client_binlog_statement(THD* thd)
...
@@ -238,7 +241,7 @@ void mysql_client_binlog_statement(THD* thd)
my_ok
(
thd
);
my_ok
(
thd
);
end:
end:
thd
->
rli_fake
->
clear_tables_to_lock
();
rli
->
clear_tables_to_lock
();
my_free
(
buf
,
MYF
(
MY_ALLOW_ZERO_PTR
));
my_free
(
buf
,
MYF
(
MY_ALLOW_ZERO_PTR
));
DBUG_VOID_RETURN
;
DBUG_VOID_RETURN
;
}
}
sql/sql_class.h
View file @
a820c732
...
@@ -2647,7 +2647,32 @@ class TMP_TABLE_PARAM :public Sql_alloc
...
@@ -2647,7 +2647,32 @@ class TMP_TABLE_PARAM :public Sql_alloc
MI_COLUMNDEF
*
recinfo
,
*
start_recinfo
;
MI_COLUMNDEF
*
recinfo
,
*
start_recinfo
;
KEY
*
keyinfo
;
KEY
*
keyinfo
;
ha_rows
end_write_records
;
ha_rows
end_write_records
;
uint
field_count
,
sum_func_count
,
func_count
;
/**
Number of normal fields in the query, including those referred to
from aggregate functions. Hence, "SELECT `field1`,
SUM(`field2`) from t1" sets this counter to 2.
@see count_field_types
*/
uint
field_count
;
/**
Number of fields in the query that have functions. Includes both
aggregate functions (e.g., SUM) and non-aggregates (e.g., RAND).
Also counts functions referred to from aggregate functions, i.e.,
"SELECT SUM(RAND())" sets this counter to 2.
@see count_field_types
*/
uint
func_count
;
/**
Number of fields in the query that have aggregate functions. Note
that the optimizer may choose to optimize away these fields by
replacing them with constants, in which case sum_func_count will
need to be updated.
@see opt_sum_query, count_field_types
*/
uint
sum_func_count
;
uint
hidden_field_count
;
uint
hidden_field_count
;
uint
group_parts
,
group_length
,
group_null_parts
;
uint
group_parts
,
group_length
,
group_null_parts
;
uint
quick_group
;
uint
quick_group
;
...
...
sql/sql_select.cc
View file @
a820c732
...
@@ -644,8 +644,11 @@ JOIN::prepare(Item ***rref_pointer_array,
...
@@ -644,8 +644,11 @@ JOIN::prepare(Item ***rref_pointer_array,
this
->
group
=
group_list
!=
0
;
this
->
group
=
group_list
!=
0
;
unit
=
unit_arg
;
unit
=
unit_arg
;
if
(
tmp_table_param
.
sum_func_count
&&
!
group_list
)
implicit_grouping
=
TRUE
;
#ifdef RESTRICTED_GROUP
#ifdef RESTRICTED_GROUP
if
(
sum_func_count
&&
!
group_list
&&
(
func_count
||
field_count
)
)
if
(
implicit_grouping
)
{
{
my_message
(
ER_WRONG_SUM_SELECT
,
ER
(
ER_WRONG_SUM_SELECT
),
MYF
(
0
));
my_message
(
ER_WRONG_SUM_SELECT
,
ER
(
ER_WRONG_SUM_SELECT
),
MYF
(
0
));
goto
err
;
goto
err
;
...
@@ -881,15 +884,23 @@ JOIN::optimize()
...
@@ -881,15 +884,23 @@ JOIN::optimize()
}
}
#endif
#endif
/* Optimize count(*), min() and max() */
/*
if
(
tables_list
&&
tmp_table_param
.
sum_func_count
&&
!
group_list
)
Try to optimize count(*), min() and max() to const fields if
there is implicit grouping (aggregate functions but no
group_list). In this case, the result set shall only contain one
row.
*/
if
(
tables_list
&&
implicit_grouping
)
{
{
int
res
;
int
res
;
/*
/*
opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match
opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match
to the WHERE conditions,
to the WHERE conditions,
or 1 if all items were resolved,
or 1 if all items were resolved
(optimized away)
,
or 0, or an error number HA_ERR_...
or 0, or an error number HA_ERR_...
If all items were resolved by opt_sum_query, there is no need to
open any tables.
*/
*/
if
((
res
=
opt_sum_query
(
select_lex
->
leaf_tables
,
all_fields
,
conds
)))
if
((
res
=
opt_sum_query
(
select_lex
->
leaf_tables
,
all_fields
,
conds
)))
{
{
...
@@ -2024,7 +2035,7 @@ JOIN::exec()
...
@@ -2024,7 +2035,7 @@ JOIN::exec()
count_field_types
(
select_lex
,
&
curr_join
->
tmp_table_param
,
count_field_types
(
select_lex
,
&
curr_join
->
tmp_table_param
,
*
curr_all_fields
,
0
);
*
curr_all_fields
,
0
);
if
(
curr_join
->
group
||
curr_join
->
tmp_table_param
.
sum_func_count
||
if
(
curr_join
->
group
||
curr_join
->
implicit_grouping
||
(
procedure
&&
(
procedure
->
flags
&
PROC_GROUP
)))
(
procedure
&&
(
procedure
->
flags
&
PROC_GROUP
)))
{
{
if
(
make_group_fields
(
this
,
curr_join
))
if
(
make_group_fields
(
this
,
curr_join
))
...
@@ -10811,6 +10822,12 @@ Next_select_func setup_end_select_func(JOIN *join)
...
@@ -10811,6 +10822,12 @@ Next_select_func setup_end_select_func(JOIN *join)
}
}
else
else
{
{
/*
Choose method for presenting result to user. Use end_send_group
if the query requires grouping (has a GROUP BY clause and/or one or
more aggregate functions). Use end_send if the query should not
be grouped.
*/
if
((
join
->
sort_and_group
||
if
((
join
->
sort_and_group
||
(
join
->
procedure
&&
join
->
procedure
->
flags
&
PROC_GROUP
))
&&
(
join
->
procedure
&&
join
->
procedure
->
flags
&
PROC_GROUP
))
&&
!
tmp_tbl
->
precomputed_group_by
)
!
tmp_tbl
->
precomputed_group_by
)
...
...
sql/sql_select.h
View file @
a820c732
...
@@ -278,7 +278,14 @@ class JOIN :public Sql_alloc
...
@@ -278,7 +278,14 @@ class JOIN :public Sql_alloc
TABLE
**
table
,
**
all_tables
,
*
sort_by_table
;
TABLE
**
table
,
**
all_tables
,
*
sort_by_table
;
uint
tables
,
const_tables
;
uint
tables
,
const_tables
;
uint
send_group_parts
;
uint
send_group_parts
;
bool
sort_and_group
,
first_record
,
full_join
,
group
,
no_field_update
;
/**
Indicates that grouping will be performed on the result set during
query execution. This field belongs to query execution.
@see make_group_fields, alloc_group_fields, JOIN::exec
*/
bool
sort_and_group
;
bool
first_record
,
full_join
,
group
,
no_field_update
;
bool
do_send_rows
;
bool
do_send_rows
;
/**
/**
TRUE when we want to resume nested loop iterations when
TRUE when we want to resume nested loop iterations when
...
@@ -428,6 +435,7 @@ class JOIN :public Sql_alloc
...
@@ -428,6 +435,7 @@ class JOIN :public Sql_alloc
tables
=
0
;
tables
=
0
;
const_tables
=
0
;
const_tables
=
0
;
join_list
=
0
;
join_list
=
0
;
implicit_grouping
=
FALSE
;
sort_and_group
=
0
;
sort_and_group
=
0
;
first_record
=
0
;
first_record
=
0
;
do_send_rows
=
1
;
do_send_rows
=
1
;
...
@@ -533,6 +541,11 @@ class JOIN :public Sql_alloc
...
@@ -533,6 +541,11 @@ class JOIN :public Sql_alloc
select_lex
==
unit
->
fake_select_lex
));
select_lex
==
unit
->
fake_select_lex
));
}
}
private:
private:
/**
TRUE if the query contains an aggregate function but has no GROUP
BY clause.
*/
bool
implicit_grouping
;
bool
make_simple_join
(
JOIN
*
join
,
TABLE
*
tmp_table
);
bool
make_simple_join
(
JOIN
*
join
,
TABLE
*
tmp_table
);
};
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment