Skip to content

Commit 6668da2

Browse files
author
Alexander Barkov
committed
MDEV-15289 Binding an out-of-range DATETIME value in binary protocol breaks replication
1 parent 5ab4602 commit 6668da2

File tree

4 files changed

+141
-1
lines changed

4 files changed

+141
-1
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
include/show_binlog_events.inc
2+
Log_name Pos Event_type Server_id End_log_pos Info
3+
master-bin.000001 # Gtid # # GTID #-#-#
4+
master-bin.000001 # Query # # CREATE DATABASE IF NOT EXISTS client_test_db
5+
master-bin.000001 # Gtid # # GTID #-#-#
6+
master-bin.000001 # Query # # use `client_test_db`; create or replace table t1 (t time, d date, dt datetime,ts timestamp)
7+
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
8+
master-bin.000001 # Query # # use `client_test_db`; INSERT INTO t1 VALUES (TIMESTAMP'0000-00-00 00:00:00', TIMESTAMP'0000-00-00 00:00:00', TIMESTAMP'0000-00-00 00:00:00', TIMESTAMP'0000-00-00 00:00:00')
9+
master-bin.000001 # Query # # COMMIT
10+
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
11+
master-bin.000001 # Query # # use `client_test_db`; INSERT INTO t1 VALUES (DATE'0000-00-00', DATE'0000-00-00', DATE'0000-00-00', DATE'0000-00-00')
12+
master-bin.000001 # Query # # COMMIT
13+
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
14+
master-bin.000001 # Query # # use `client_test_db`; INSERT INTO t1 VALUES (TIME'00:00:00', TIME'00:00:00', TIME'00:00:00', TIME'00:00:00')
15+
master-bin.000001 # Query # # COMMIT
16+
master-bin.000001 # Gtid # # GTID #-#-#
17+
master-bin.000001 # Query # # use `client_test_db`; DROP TABLE `t1` /* generated by server */
18+
master-bin.000001 # Gtid # # GTID #-#-#
19+
master-bin.000001 # Query # # DROP DATABASE IF EXISTS client_test_db
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
--source include/not_embedded.inc
2+
--source include/have_binlog_format_statement.inc
3+
4+
--exec $MYSQL_CLIENT_TEST test_datetime_ranges_mdev15289 > $MYSQLTEST_VARDIR/log/binlog_stm_datetime_ranges_mysql_client_test.out.log 2>&1
5+
6+
--let $binlog_file = LAST
7+
source include/show_binlog_events.inc;

sql/item.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3562,7 +3562,7 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
35623562
ErrConvTime str(&value.time);
35633563
make_truncated_value_warning(current_thd, Sql_condition::WARN_LEVEL_WARN,
35643564
&str, time_type, 0);
3565-
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
3565+
set_zero_time(&value.time, time_type);
35663566
}
35673567
maybe_null= 0;
35683568
null_value= 0;

tests/mysql_client_test.c

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12333,6 +12333,119 @@ static void test_datetime_ranges()
1233312333
}
1233412334

1233512335

12336+
/*
12337+
This test is used in:
12338+
mysql-test/suite/binlog/binlog_stm_datetime_ranges_mdev15289.test
12339+
*/
12340+
static void test_datetime_ranges_mdev15289()
12341+
{
12342+
const char *stmt_text;
12343+
int rc, i;
12344+
MYSQL_STMT *stmt;
12345+
MYSQL_BIND my_bind[4];
12346+
MYSQL_TIME tm[4];
12347+
12348+
myheader("test_datetime_ranges_mdev15289");
12349+
12350+
stmt_text= "SET sql_mode=''";
12351+
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
12352+
myquery(rc);
12353+
12354+
stmt_text= "create or replace table t1 "
12355+
"(t time, d date, dt datetime,ts timestamp)";
12356+
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
12357+
myquery(rc);
12358+
12359+
stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 VALUES (?, ?, ?, ?)");
12360+
check_stmt(stmt);
12361+
verify_param_count(stmt, 4);
12362+
12363+
/*** Testing DATETIME ***/
12364+
bzero((char*) my_bind, sizeof(my_bind));
12365+
for (i= 0; i < 4; i++)
12366+
{
12367+
my_bind[i].buffer_type= MYSQL_TYPE_DATETIME;
12368+
my_bind[i].buffer= &tm[i];
12369+
}
12370+
rc= mysql_stmt_bind_param(stmt, my_bind);
12371+
check_execute(stmt, rc);
12372+
12373+
/* Notice bad year */
12374+
tm[0].year= 20010; tm[0].month= 1; tm[0].day= 2;
12375+
tm[0].hour= 03; tm[0].minute= 04; tm[0].second= 05;
12376+
tm[0].second_part= 0; tm[0].neg= 0;
12377+
tm[0].time_type= MYSQL_TIMESTAMP_DATETIME;
12378+
tm[3]= tm[2]= tm[1]= tm[0];
12379+
12380+
rc= mysql_stmt_execute(stmt);
12381+
check_execute(stmt, rc);
12382+
my_process_warnings(mysql, 4);
12383+
12384+
verify_col_data("t1", "t", "00:00:00");
12385+
verify_col_data("t1", "d", "0000-00-00");
12386+
verify_col_data("t1", "dt", "0000-00-00 00:00:00");
12387+
verify_col_data("t1", "ts", "0000-00-00 00:00:00");
12388+
12389+
/*** Testing DATE ***/
12390+
bzero((char*) my_bind, sizeof(my_bind));
12391+
for (i= 0; i < 4; i++)
12392+
{
12393+
my_bind[i].buffer_type= MYSQL_TYPE_DATE;
12394+
my_bind[i].buffer= &tm[i];
12395+
}
12396+
rc= mysql_stmt_bind_param(stmt, my_bind);
12397+
check_execute(stmt, rc);
12398+
12399+
/* Notice bad year */
12400+
tm[0].year= 20010; tm[0].month= 1; tm[0].day= 2;
12401+
tm[0].hour= 00; tm[0].minute= 00; tm[0].second= 00;
12402+
tm[0].second_part= 0; tm[0].neg= 0;
12403+
tm[0].time_type= MYSQL_TIMESTAMP_DATE;
12404+
tm[3]= tm[2]= tm[1]= tm[0];
12405+
12406+
rc= mysql_stmt_execute(stmt);
12407+
check_execute(stmt, rc);
12408+
my_process_warnings(mysql, 4);
12409+
12410+
verify_col_data("t1", "t", "00:00:00");
12411+
verify_col_data("t1", "d", "0000-00-00");
12412+
verify_col_data("t1", "dt", "0000-00-00 00:00:00");
12413+
verify_col_data("t1", "ts", "0000-00-00 00:00:00");
12414+
12415+
/*** Testing TIME ***/
12416+
bzero((char*) my_bind, sizeof(my_bind));
12417+
for (i= 0; i < 4; i++)
12418+
{
12419+
my_bind[i].buffer_type= MYSQL_TYPE_TIME;
12420+
my_bind[i].buffer= &tm[i];
12421+
}
12422+
rc= mysql_stmt_bind_param(stmt, my_bind);
12423+
check_execute(stmt, rc);
12424+
12425+
/* Notice bad hour */
12426+
tm[0].year= 0; tm[0].month= 0; tm[0].day= 0;
12427+
tm[0].hour= 100; tm[0].minute= 64; tm[0].second= 05;
12428+
tm[0].second_part= 0; tm[0].neg= 0;
12429+
tm[0].time_type= MYSQL_TIMESTAMP_TIME;
12430+
tm[3]= tm[2]= tm[1]= tm[0];
12431+
12432+
rc= mysql_stmt_execute(stmt);
12433+
check_execute(stmt, rc);
12434+
my_process_warnings(mysql, 4);
12435+
12436+
verify_col_data("t1", "t", "00:00:00");
12437+
verify_col_data("t1", "d", "0000-00-00");
12438+
verify_col_data("t1", "dt", "0000-00-00 00:00:00");
12439+
verify_col_data("t1", "ts", "0000-00-00 00:00:00");
12440+
12441+
mysql_stmt_close(stmt);
12442+
12443+
stmt_text= "drop table t1";
12444+
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
12445+
myquery(rc);
12446+
}
12447+
12448+
1233612449
static void test_bug4172()
1233712450
{
1233812451
MYSQL_STMT *stmt;
@@ -19714,6 +19827,7 @@ static struct my_tests_st my_tests[]= {
1971419827
{ "test_bug6081", test_bug6081 },
1971519828
{ "test_bug6096", test_bug6096 },
1971619829
{ "test_datetime_ranges", test_datetime_ranges },
19830+
{ "test_datetime_ranges_mdev15289", test_datetime_ranges_mdev15289 },
1971719831
{ "test_bug4172", test_bug4172 },
1971819832
{ "test_conversion", test_conversion },
1971919833
{ "test_rewind", test_rewind },

0 commit comments

Comments
 (0)