This commit is contained in:
Georgi Kodinov 2009-10-14 18:46:45 +03:00
commit a820c73229
16 changed files with 405 additions and 176 deletions

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -1,6 +1,6 @@
Verbose statements from : write-partial-row.binlog Verbose statements from : write-partial-row.binlog
select txt from raw_binlog_rows where txt like '###%'; select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%';
txt stmt
### INSERT INTO mysql.ndb_apply_status ### INSERT INTO mysql.ndb_apply_status
### SET ### SET
### @1=1 ### @1=1
@ -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 txt from raw_binlog_rows where txt like '###%'; select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%';
txt stmt
### INSERT INTO mysql.ndb_apply_status ### INSERT INTO mysql.ndb_apply_status
### SET ### SET
### @1=2 ### @1=2
@ -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 txt from raw_binlog_rows where txt like '###%'; select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%';
txt stmt
### INSERT INTO mysql.ndb_apply_status ### INSERT INTO mysql.ndb_apply_status
### SET ### SET
### @1=3 ### @1=3
@ -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 txt from raw_binlog_rows where txt like '###%'; select replace(txt,'\r', '') as stmt from raw_binlog_rows where txt like '###%';
txt stmt
### INSERT INTO mysql.ndb_apply_status ### INSERT INTO mysql.ndb_apply_status
### SET ### SET
### @1=4 ### @1=4

View file

@ -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;

View file

@ -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));
--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));
--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));
--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;

View file

@ -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

View 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)
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)
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)
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)
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
{ {

View file

@ -1814,7 +1814,56 @@ 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); if (get_flags(STMT_END_F))
{
/*
This is the end of a statement or transaction, so close (and
unlock) the tables we opened when processing the
Table_map_log_event starting the statement.
OBSERVER. This will clear *all* mappings, not only those that
are open for the table. There is not good handle for on-close
actions for tables.
NOTE. Even if we have no table ('table' == 0) we still need to be
here, so that we increase the group relay log position. If we didn't, we
could have a group relay log position which lags behind "forever"
(assume the last master's transaction is ignored by the slave because of
replicate-ignore rules).
*/
thd->binlog_flush_pending_rows_event(true);
/*
If this event is not in a transaction, the call below will, if some
transactional storage engines are involved, commit the statement into
them and flush the pending event to binlog.
If this event is in a transaction, the call will do nothing, but a
Xid_log_event will come next which will, if some transactional engines
are involved, commit the transaction and flush the pending event to the
binlog.
*/
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
flush the pending event to the binlog; we did it with
thd->binlog_flush_pending_rows_event(). Note that we imitate
what is done for real queries: a call to
ha_autocommit_or_rollback() (sometimes only if involves a
transactional engine), and a call to be sure to have the pending
event flushed.
*/
thd->reset_current_stmt_binlog_row_based();
const_cast<Relay_log_info*>(rli)->cleanup_context(thd, 0);
}
DBUG_RETURN(error);
} }
@ -1844,71 +1893,18 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli)
if (get_flags(STMT_END_F)) if (get_flags(STMT_END_F))
{ {
/* /*
This is the end of a statement or transaction, so close (and Indicate that a statement is finished.
unlock) the tables we opened when processing the Step the group log position if we are not in a transaction,
Table_map_log_event starting the statement. otherwise increase the event log position.
*/
OBSERVER. This will clear *all* mappings, not only those that rli->stmt_done(log_pos, when);
are open for the table. There is not good handle for on-close
actions for tables.
NOTE. Even if we have no table ('table' == 0) we still need to be
here, so that we increase the group relay log position. If we didn't, we
could have a group relay log position which lags behind "forever"
(assume the last master's transaction is ignored by the slave because of
replicate-ignore rules).
*/
thd->binlog_flush_pending_rows_event(true);
/* /*
If this event is not in a transaction, the call below will, if some Clear any errors in thd->net.last_err*. It is not known if this is
transactional storage engines are involved, commit the statement into needed or not. It is believed that any errors that may exist in
them and flush the pending event to binlog. thd->net.last_err* are allowed. Examples of errors are "key not
If this event is in a transaction, the call will do nothing, but a found", which is produced in the test case rpl_row_conflicts.test
Xid_log_event will come next which will, if some transactional engines
are involved, commit the transaction and flush the pending event to the
binlog.
*/ */
error= ha_autocommit_or_rollback(thd, 0); thd->clear_error();
/*
Now what if this is not a transactional engine? we still need to
flush the pending event to the binlog; we did it with
thd->binlog_flush_pending_rows_event(). Note that we imitate
what is done for real queries: a call to
ha_autocommit_or_rollback() (sometimes only if involves a
transactional engine), and a call to be sure to have the pending
event flushed.
*/
thd->reset_current_stmt_binlog_row_based();
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);
/*
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
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
{ {

View file

@ -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

View file

@ -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,38 +2127,34 @@ 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);
if (reason == Log_event::EVENT_SKIP_NOT)
exec_res= ev->apply_event(rli);
#ifndef DBUG_OFF
/*
This only prints information to the debug trace.
TODO: Print an informational message to the error log?
*/
static const char *const explain[] = {
// EVENT_SKIP_NOT,
"not skipped",
// EVENT_SKIP_IGNORE,
"skipped because event should be ignored",
// EVENT_SKIP_COUNT
"skipped because event skip counter was non-zero"
};
DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d",
thd->options & OPTION_BEGIN ? 1 : 0,
rli->get_flag(Relay_log_info::IN_STMT)));
DBUG_PRINT("skip_event", ("%s event was %s",
ev->get_type_str(), explain[reason]));
#endif
}
else
exec_res= ev->apply_event(rli); exec_res= ev->apply_event(rli);
#ifndef DBUG_OFF
/*
This only prints information to the debug trace.
TODO: Print an informational message to the error log?
*/
static const char *const explain[] = {
// EVENT_SKIP_NOT,
"not skipped",
// EVENT_SKIP_IGNORE,
"skipped because event should be ignored",
// EVENT_SKIP_COUNT
"skipped because event skip counter was non-zero"
};
DBUG_PRINT("info", ("OPTION_BEGIN: %d; IN_STMT: %d",
thd->options & OPTION_BEGIN ? 1 : 0,
rli->get_flag(Relay_log_info::IN_STMT)));
DBUG_PRINT("skip_event", ("%s event was %s",
ev->get_type_str(), explain[reason]));
#endif
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)
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

View file

@ -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);

View file

@ -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)
/* /*
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)
} }
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)
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)
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)
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;
} }

View file

@ -2647,7 +2647,32 @@ public:
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;

View file

@ -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()
} }
#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()
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)
} }
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)

View file

@ -278,7 +278,14 @@ public:
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 @@ public:
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 @@ public:
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);
}; };