summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--client/Makefile.am3
-rw-r--r--client/mysql.cc6
-rw-r--r--client/mysqladmin.cc12
-rw-r--r--client/mysqlbinlog.cc17
-rw-r--r--include/my_time.h5
-rw-r--r--include/mysql_time.h12
-rw-r--r--innobase/lock/lock0lock.c3
-rw-r--r--innobase/trx/trx0purge.c23
-rw-r--r--innobase/trx/trx0undo.c2
-rw-r--r--libmysql/libmysql.c13
-rw-r--r--mysql-test/r/func_group.result16
-rw-r--r--mysql-test/r/func_time.result6
-rw-r--r--mysql-test/r/ps.result21
-rw-r--r--mysql-test/r/type_datetime.result11
-rw-r--r--mysql-test/t/func_group.test11
-rw-r--r--mysql-test/t/func_time.test7
-rw-r--r--mysql-test/t/ps.test14
-rw-r--r--mysql-test/t/type_datetime.test7
-rw-r--r--ndb/src/kernel/blocks/ERROR_codes.txt3
-rw-r--r--ndb/src/kernel/blocks/dbacc/DbaccMain.cpp14
-rw-r--r--ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp11
-rw-r--r--ndb/src/kernel/vm/Configuration.cpp4
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.cpp46
-rw-r--r--ndb/test/ndbapi/testDict.cpp19
-rw-r--r--sql-common/my_time.c7
-rw-r--r--sql/field.cc4
-rw-r--r--sql/item.cc26
-rw-r--r--sql/item.h10
-rw-r--r--sql/item_func.cc1
-rw-r--r--sql/item_sum.cc9
-rw-r--r--sql/item_sum.h9
-rw-r--r--sql/item_timefunc.cc44
-rw-r--r--sql/sql_prepare.cc23
-rw-r--r--tests/client_test.c135
35 files changed, 444 insertions, 111 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 1c1a3efc542..8fcec769a0c 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -163,6 +163,7 @@ pem@mysql.com
peter@linux.local
peter@mysql.com
peterg@mysql.com
+petr@mysql.com
pgulutzan@linux.local
ram@deer.(none)
ram@gw.mysql.r18.ru
diff --git a/client/Makefile.am b/client/Makefile.am
index f59395ae026..0b261b1b105 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -20,8 +20,7 @@
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/regex \
$(openssl_includes)
LIBS = @CLIENT_LIBS@
-DEPLIB= @ndb_mgmclient_libs@ \
- ../libmysql/libmysqlclient.la
+DEPLIB= ../libmysql/libmysqlclient.la
LDADD = @CLIENT_EXTRA_LDFLAGS@ $(DEPLIB)
bin_PROGRAMS = mysql mysqladmin mysqlcheck mysqlshow \
mysqldump mysqlimport mysqltest mysqlbinlog mysqlmanagerc mysqlmanager-pwgen
diff --git a/client/mysql.cc b/client/mysql.cc
index 358b13e652b..8e9dd84c8f0 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -1609,7 +1609,7 @@ static void print_help_item(MYSQL_ROW *cur, int num_name, int num_cat, char *las
char ccat= (*cur)[num_cat][0];
if (*last_char != ccat)
{
- put_info(ccat == 'Y' ? "categories :" : "topics :", INFO_INFO);
+ put_info(ccat == 'Y' ? "categories:" : "topics:", INFO_INFO);
*last_char= ccat;
}
tee_fprintf(PAGER, " %s\n", (*cur)[num_name]);
@@ -1676,8 +1676,8 @@ static int com_server_help(String *buffer __attribute__((unused)),
if (num_fields == 2)
{
- put_info("Many help items for your request exist", INFO_INFO);
- put_info("To make a more specific request, please type 'help <item>',\nwhere item is one of next", INFO_INFO);
+ put_info("Many help items for your request exist.", INFO_INFO);
+ put_info("To make a more specific request, please type 'help <item>',\nwhere item is one of the following", INFO_INFO);
num_name= 0;
num_cat= 1;
last_char= '_';
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index a9fc3f31d03..eec0dcb90fe 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -24,7 +24,7 @@
#include <sys/stat.h>
#include <mysql.h>
-#ifdef HAVE_NDBCLUSTER_DB
+#ifdef LATER_HAVE_NDBCLUSTER_DB
#include "../ndb/src/mgmclient/ndb_mgmclient.h"
#endif
@@ -45,7 +45,7 @@ static uint tcp_port = 0, option_wait = 0, option_silent=0, nr_iterations,
opt_count_iterations= 0;
static ulong opt_connect_timeout, opt_shutdown_timeout;
static my_string unix_port=0;
-#ifdef HAVE_NDBCLUSTER_DB
+#ifdef LATER_HAVE_NDBCLUSTER_DB
static my_bool opt_ndbcluster=0;
static char *opt_ndb_connectstring=0;
#endif
@@ -101,7 +101,7 @@ enum commands {
ADMIN_PING, ADMIN_EXTENDED_STATUS, ADMIN_FLUSH_STATUS,
ADMIN_FLUSH_PRIVILEGES, ADMIN_START_SLAVE, ADMIN_STOP_SLAVE,
ADMIN_FLUSH_THREADS, ADMIN_OLD_PASSWORD
-#ifdef HAVE_NDBCLUSTER_DB
+#ifdef LATER_HAVE_NDBCLUSTER_DB
,ADMIN_NDB_MGM
#endif
};
@@ -114,7 +114,7 @@ static const char *command_names[]= {
"ping", "extended-status", "flush-status",
"flush-privileges", "start-slave", "stop-slave",
"flush-threads","old-password",
-#ifdef HAVE_NDBCLUSTER_DB
+#ifdef LATER_HAVE_NDBCLUSTER_DB
"ndb-mgm",
#endif
NullS
@@ -197,7 +197,7 @@ static struct my_option my_long_options[] =
{"shutdown_timeout", OPT_SHUTDOWN_TIMEOUT, "", (gptr*) &opt_shutdown_timeout,
(gptr*) &opt_shutdown_timeout, 0, GET_ULONG, REQUIRED_ARG,
SHUTDOWN_DEF_TIMEOUT, 0, 3600*12, 0, 1, 0},
-#ifdef HAVE_NDBCLUSTER_DB
+#ifdef LATER_HAVE_NDBCLUSTER_DB
{"ndbcluster", OPT_NDBCLUSTER, ""
"", (gptr*) &opt_ndbcluster,
(gptr*) &opt_ndbcluster, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -903,7 +903,7 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
}
mysql->reconnect=1; /* Automatic reconnect is default */
break;
-#ifdef HAVE_NDBCLUSTER_DB
+#ifdef LATER_HAVE_NDBCLUSTER_DB
case ADMIN_NDB_MGM:
{
if (argc < 2)
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 8015871428e..de53831c43d 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -44,7 +44,7 @@ static const char *load_default_groups[]= { "mysqlbinlog","client",0 };
void sql_print_error(const char *format, ...);
-static bool one_database=0, to_last_remote_log= 0;
+static bool one_database=0, to_last_remote_log= 0, disable_log_bin= 0;
static const char* database= 0;
static my_bool force_opt= 0, short_form= 0, remote_opt= 0;
static ulonglong offset = 0;
@@ -438,6 +438,13 @@ static struct my_option my_long_options[] =
{"database", 'd', "List entries for just this database (local log only).",
(gptr*) &database, (gptr*) &database, 0, GET_STR_ALLOC, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
+ {"disable-log-bin", 'D', "Disable binary log. This is useful, if you "
+ "enabled --to-last-log and are sending the output to the same MySQL server. "
+ "This way you could avoid an endless loop. You would also like to use it "
+ "when restoring after a crash to avoid duplication of the statements you "
+ "already have. NOTE: you will need a SUPER privilege to use this option.",
+ (gptr*) &disable_log_bin, (gptr*) &disable_log_bin, 0, GET_BOOL,
+ NO_ARG, 0, 0, 0, 0, 0, 0},
{"force-read", 'f', "Force reading unknown binlog events.",
(gptr*) &force_opt, (gptr*) &force_opt, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
@@ -1068,6 +1075,11 @@ int main(int argc, char** argv)
fprintf(result_file,
"/*!40019 SET @@session.max_insert_delayed_threads=0*/;\n");
+
+ if (disable_log_bin)
+ fprintf(result_file,
+ "/*!32316 SET @OLD_SQL_LOG_BIN=@@SQL_LOG_BIN, SQL_LOG_BIN=0*/;\n");
+
for (save_stop_position= stop_position, stop_position= ~(my_off_t)0 ;
(--argc >= 0) && !stop_passed ; )
{
@@ -1082,6 +1094,9 @@ int main(int argc, char** argv)
start_position= BIN_LOG_HEADER_SIZE;
}
+ if (disable_log_bin)
+ fprintf(result_file, "/*!32316 SET SQL_LOG_BIN=@OLD_SQL_LOG_BIN*/;\n");
+
if (tmpdir.list)
free_tmpdir(&tmpdir);
if (result_file != stdout)
diff --git a/include/my_time.h b/include/my_time.h
index dab17904b2d..94701e159c4 100644
--- a/include/my_time.h
+++ b/include/my_time.h
@@ -58,14 +58,15 @@ void init_time(void);
my_time_t
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap);
-void set_zero_time(MYSQL_TIME *tm);
+void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type);
/*
Required buffer length for my_time_to_str, my_date_to_str,
my_datetime_to_str and TIME_to_string functions. Note, that the
caller is still responsible to check that given TIME structure
has values in valid ranges, otherwise size of the buffer could
- be not enough.
+ be not enough. We also rely on the fact that even wrong values
+ sent using binary protocol fit in this buffer.
*/
#define MAX_DATE_STRING_REP_LENGTH 30
diff --git a/include/mysql_time.h b/include/mysql_time.h
index ec67d60dea5..5f4fc12c005 100644
--- a/include/mysql_time.h
+++ b/include/mysql_time.h
@@ -33,6 +33,18 @@ enum enum_mysql_timestamp_type
};
+/*
+ Structure which is used to represent datetime values inside MySQL.
+
+ We assume that values in this structure are normalized, i.e. year <= 9999,
+ month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions
+ in server such as my_system_gmt_sec() or make_time() family of functions
+ rely on this (actually now usage of make_*() family relies on a bit weaker
+ restriction). Also functions that produce MYSQL_TIME as result ensure this.
+ There is one exception to this rule though if this structure holds time
+ value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold
+ bigger values.
+*/
typedef struct st_mysql_time
{
unsigned int year, month, day, hour, minute, second;
diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c
index 6f2d58b72c3..78a78c9dd95 100644
--- a/innobase/lock/lock0lock.c
+++ b/innobase/lock/lock0lock.c
@@ -4064,6 +4064,9 @@ lock_print_info(
(ulong) ut_dulint_get_low(purge_sys->purge_undo_no));
fprintf(file,
+ "History list length %lu\n", (ulong) trx_sys->rseg_history_len);
+
+ fprintf(file,
"Total number of lock structs in row lock hash table %lu\n",
(ulong) lock_get_n_rec_locks());
diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c
index 5c62640e011..3df34111281 100644
--- a/innobase/trx/trx0purge.c
+++ b/innobase/trx/trx0purge.c
@@ -289,7 +289,7 @@ trx_purge_add_update_undo_to_history(
flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr));
mlog_write_ulint(rseg_header + TRX_RSEG_HISTORY_SIZE,
- hist_size + undo->size, MLOG_4BYTES, mtr);
+ hist_size + undo->size, MLOG_4BYTES, mtr);
}
/* Add the log as the first in the history list */
@@ -646,6 +646,27 @@ trx_purge_rseg_get_next_history_log(
mutex_exit(&(rseg->mutex));
mtr_commit(&mtr);
+ mutex_enter(&kernel_mutex);
+
+ /* Add debug code to track history list corruption reported
+ on the MySQL mailing list on Nov 9, 2004. The fut0lst.c
+ file-based list was corrupt. The prev node pointer was
+ FIL_NULL, even though the list length was over 8 million nodes!
+ We assume that purge truncates the history list in moderate
+ size pieces, and if we here reach the head of the list, the
+ list cannot be longer than 20 000 undo logs now. */
+
+ if (trx_sys->rseg_history_len > 20000) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Warning: purge reached the head of the history list,\n"
+"InnoDB: but its length is still reported as %lu! Make a detailed bug\n"
+"InnoDB: report, and post it to bugs.mysql.com\n",
+ (ulong)trx_sys->rseg_history_len);
+ }
+
+ mutex_exit(&kernel_mutex);
+
return;
}
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index c1edc223cbc..8d1518753dd 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -1241,7 +1241,7 @@ trx_undo_lists_init(
if (page_no != FIL_NULL
&& srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
-
+
undo = trx_undo_mem_create_at_db_start(rseg, i,
page_no, &mtr);
size += undo->size;
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index a57c82e6424..cb20c5181a8 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -3257,11 +3257,12 @@ static void read_binary_time(MYSQL_TIME *tm, uchar **pos)
tm->hour+= tm->day*24;
tm->day= 0;
}
+ tm->time_type= MYSQL_TIMESTAMP_TIME;
+
*pos+= length;
}
else
- set_zero_time(tm);
- tm->time_type= MYSQL_TIMESTAMP_TIME;
+ set_zero_time(tm, MYSQL_TIMESTAMP_TIME);
}
static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
@@ -3286,12 +3287,12 @@ static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
else
tm->hour= tm->minute= tm->second= 0;
tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
+ tm->time_type= MYSQL_TIMESTAMP_DATETIME;
*pos+= length;
}
else
- set_zero_time(tm);
- tm->time_type= MYSQL_TIMESTAMP_DATETIME;
+ set_zero_time(tm, MYSQL_TIMESTAMP_DATETIME);
}
static void read_binary_date(MYSQL_TIME *tm, uchar **pos)
@@ -3308,12 +3309,12 @@ static void read_binary_date(MYSQL_TIME *tm, uchar **pos)
tm->hour= tm->minute= tm->second= 0;
tm->second_part= 0;
tm->neg= 0;
+ tm->time_type= MYSQL_TIMESTAMP_DATE;
*pos+= length;
}
else
- set_zero_time(tm);
- tm->time_type= MYSQL_TIMESTAMP_DATE;
+ set_zero_time(tm, MYSQL_TIMESTAMP_DATE);
}
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index c25f89d4df3..4bb79a1cb41 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -637,8 +637,22 @@ create table t1 (a char(10));
insert into t1 values ('a'),('b'),('c');
select coercibility(max(a)) from t1;
coercibility(max(a))
-3
+2
drop table t1;
+create table t1 (a char character set latin2);
+insert into t1 values ('a'),('b');
+select charset(max(a)), coercibility(max(a)),
+charset(min(a)), coercibility(min(a)) from t1;
+charset(max(a)) coercibility(max(a)) charset(min(a)) coercibility(min(a))
+latin2 2 latin2 2
+create table t2 select max(a),min(a) from t1;
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `max(a)` char(1) character set latin2 default NULL,
+ `min(a)` char(1) character set latin2 default NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+drop table t2,t1;
create table t1 (a int);
insert into t1 values (1);
select max(a) as b from t1 having b=1;
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 2dc6bffd071..c78b16aed8a 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -474,6 +474,12 @@ unix_timestamp(@a)
select unix_timestamp('1969-12-01 19:00:01');
unix_timestamp('1969-12-01 19:00:01')
0
+select from_unixtime(0);
+from_unixtime(0)
+NULL
+select from_unixtime(2145916800);
+from_unixtime(2145916800)
+NULL
CREATE TABLE t1 (datetime datetime, timestamp timestamp, date date, time time);
INSERT INTO t1 values ("2001-01-02 03:04:05", "2002-01-02 03:04:05", "2003-01-02", "06:07:08");
SELECT * from t1;
diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result
index 6d9cfabb5a7..4a4c8fe22e4 100644
--- a/mysql-test/r/ps.result
+++ b/mysql-test/r/ps.result
@@ -450,3 +450,24 @@ PREPARE stmt FROM 'UPDATE t1 AS P1 INNER JOIN (SELECT N FROM t1 GROUP BY N HAVIN
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
+prepare stmt from "select ? is null, ? is not null, ?";
+select @no_such_var is null, @no_such_var is not null, @no_such_var;
+@no_such_var is null @no_such_var is not null @no_such_var
+1 0 NULL
+execute stmt using @no_such_var, @no_such_var, @no_such_var;
+? is null ? is not null ?
+1 0 NULL
+set @var='abc';
+select @var is null, @var is not null, @var;
+@var is null @var is not null @var
+0 1 abc
+execute stmt using @var, @var, @var;
+? is null ? is not null ?
+0 1 abc
+set @var=null;
+select @var is null, @var is not null, @var;
+@var is null @var is not null @var
+1 0 NULL
+execute stmt using @var, @var, @var;
+? is null ? is not null ?
+1 0 NULL
diff --git a/mysql-test/r/type_datetime.result b/mysql-test/r/type_datetime.result
index 524bc9c50d4..127a54e087b 100644
--- a/mysql-test/r/type_datetime.result
+++ b/mysql-test/r/type_datetime.result
@@ -97,13 +97,15 @@ select * from t1 where a is null or b is null;
a b
drop table t1;
create table t1 (t datetime);
-insert into t1 values (20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460);
+insert into t1 values (20030102030460),(20030102036301),(20030102240401),
+(20030132030401),(20031302030401),(100001202030401);
Warnings:
Warning 1265 Data truncated for column 't' at row 1
Warning 1265 Data truncated for column 't' at row 2
Warning 1265 Data truncated for column 't' at row 3
Warning 1265 Data truncated for column 't' at row 4
Warning 1265 Data truncated for column 't' at row 5
+Warning 1265 Data truncated for column 't' at row 6
select * from t1;
t
0000-00-00 00:00:00
@@ -111,14 +113,18 @@ t
0000-00-00 00:00:00
0000-00-00 00:00:00
0000-00-00 00:00:00
+0000-00-00 00:00:00
delete from t1;
-insert into t1 values ("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460");
+insert into t1 values
+("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"),
+("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00");
Warnings:
Warning 1264 Data truncated; out of range for column 't' at row 1
Warning 1264 Data truncated; out of range for column 't' at row 2
Warning 1264 Data truncated; out of range for column 't' at row 3
Warning 1264 Data truncated; out of range for column 't' at row 4
Warning 1264 Data truncated; out of range for column 't' at row 5
+Warning 1264 Data truncated; out of range for column 't' at row 6
select * from t1;
t
0000-00-00 00:00:00
@@ -126,6 +132,7 @@ t
0000-00-00 00:00:00
0000-00-00 00:00:00
0000-00-00 00:00:00
+0000-00-00 00:00:00
delete from t1;
insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer");
Warnings:
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 8d8779e9d1b..79d6112e6de 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -384,6 +384,17 @@ select coercibility(max(a)) from t1;
drop table t1;
#
+# Bug #6658 MAX(column) returns incorrect coercibility
+#
+create table t1 (a char character set latin2);
+insert into t1 values ('a'),('b');
+select charset(max(a)), coercibility(max(a)),
+ charset(min(a)), coercibility(min(a)) from t1;
+create table t2 select max(a),min(a) from t1;
+show create table t2;
+drop table t2,t1;
+
+#
# aggregate functions on static tables
#
create table t1 (a int);
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 67192c55ef9..b9e592fc5d9 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -230,6 +230,13 @@ select unix_timestamp(@a);
select unix_timestamp('1969-12-01 19:00:01');
#
+# Test for bug #6439 "unix_timestamp() function returns wrong datetime
+# values for too big argument". It should return error instead.
+#
+select from_unixtime(0);
+select from_unixtime(2145916800);
+
+#
# Test types from + INTERVAL
#
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 2b3e961fc28..7fe88ad0ddc 100644
--- a/mysql-test/t/ps.test
+++ b/mysql-test/t/ps.test
@@ -458,3 +458,17 @@ EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
+#
+# Bug#6297 "prepared statement, wrong handling of <parameter> IS NULL"
+# Test that placeholders work with IS NULL/IS NOT NULL clauses.
+#
+prepare stmt from "select ? is null, ? is not null, ?";
+select @no_such_var is null, @no_such_var is not null, @no_such_var;
+execute stmt using @no_such_var, @no_such_var, @no_such_var;
+set @var='abc';
+select @var is null, @var is not null, @var;
+execute stmt using @var, @var, @var;
+set @var=null;
+select @var is null, @var is not null, @var;
+execute stmt using @var, @var, @var;
+
diff --git a/mysql-test/t/type_datetime.test b/mysql-test/t/type_datetime.test
index 47866058524..04e4a73554a 100644
--- a/mysql-test/t/type_datetime.test
+++ b/mysql-test/t/type_datetime.test
@@ -77,10 +77,13 @@ drop table t1;
# warnings (for both strings and numbers)
#
create table t1 (t datetime);
-insert into t1 values (20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460);
+insert into t1 values (20030102030460),(20030102036301),(20030102240401),
+ (20030132030401),(20031302030401),(100001202030401);
select * from t1;
delete from t1;
-insert into t1 values ("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460");
+insert into t1 values
+ ("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"),
+ ("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00");
select * from t1;
delete from t1;
insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer");
diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt
index 7ff03684cff..5193d3eae9d 100644
--- a/ndb/src/kernel/blocks/ERROR_codes.txt
+++ b/ndb/src/kernel/blocks/ERROR_codes.txt
@@ -1,7 +1,7 @@
Next QMGR 1
Next NDBCNTR 1000
Next NDBFS 2000
-Next DBACC 3001
+Next DBACC 3002
Next DBTUP 4013
Next DBLQH 5042
Next DBDICT 6006
@@ -393,6 +393,7 @@ Failed Create Table:
--------------------
7173: Create table failed due to not sufficient number of fragment or
replica records.
+3001: Fail create 1st fragment
4007 12001: Fail create 1st fragment
4008 12002: Fail create 2nd fragment
4009 12003: Fail create 1st attribute in 1st fragment
diff --git a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
index c275e5382f7..5c7cc597672 100644
--- a/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
+++ b/ndb/src/kernel/blocks/dbacc/DbaccMain.cpp
@@ -1062,7 +1062,21 @@ void Dbacc::execACCFRAGREQ(Signal* signal)
{
const AccFragReq * const req = (AccFragReq*)&signal->theData[0];
jamEntry();
+ if (ERROR_INSERTED(3001)) {
+ jam();
+ addFragRefuse(signal, 1);
+ CLEAR_ERROR_INSERT_VALUE;
+ return;
+ }
tabptr.i = req->tableId;
+#ifndef VM_TRACE
+ // config mismatch - do not crash if release compiled
+ if (tabptr.i >= ctablesize) {
+ jam();
+ addFragRefuse(signal, 800);
+ return;
+ }
+#endif
ptrCheckGuard(tabptr, ctablesize, tabrec);
ndbrequire((req->reqInfo & 0xF) == ZADDFRAG);
ndbrequire(!getrootfragmentrec(signal, rootfragrecptr, req->fragId));
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
index 914dba00674..405f790954e 100644
--- a/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
+++ b/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp
@@ -69,6 +69,17 @@ void Dbtup::execTUPFRAGREQ(Signal* signal)
Uint32 noOfAttributeGroups = signal->theData[12];
Uint32 globalCheckpointIdIndicator = signal->theData[13];
+#ifndef VM_TRACE
+ // config mismatch - do not crash if release compiled
+ if (regTabPtr.i >= cnoOfTablerec) {
+ ljam();
+ signal->theData[0] = userptr;
+ signal->theData[1] = 800;
+ sendSignal(userblockref, GSN_TUPFRAGREF, signal, 2, JBB);
+ return;
+ }
+#endif
+
ptrCheckGuard(regTabPtr, cnoOfTablerec, tablerec);
if (cfirstfreeFragopr == RNIL) {
ljam();
diff --git a/ndb/src/kernel/vm/Configuration.cpp b/ndb/src/kernel/vm/Configuration.cpp
index 8288afb1629..3b7d6179dce 100644
--- a/ndb/src/kernel/vm/Configuration.cpp
+++ b/ndb/src/kernel/vm/Configuration.cpp
@@ -752,8 +752,8 @@ Configuration::calcSizeAlt(ConfigValues * ownConfig){
noOfMetaTables);
cfg.put(CFG_TUP_TABLE_DESC,
- 4 * NO_OF_FRAG_PER_NODE * noOfAttributes* noOfReplicas +
- 12 * NO_OF_FRAG_PER_NODE * noOfMetaTables* noOfReplicas );
+ 2 * 6 * NO_OF_FRAG_PER_NODE * noOfAttributes * noOfReplicas +
+ 2 * 10 * NO_OF_FRAG_PER_NODE * noOfMetaTables * noOfReplicas );
cfg.put(CFG_TUP_STORED_PROC,
noOfLocalScanRecords);
diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index 304d1b904d4..345f2caac89 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -1571,7 +1571,13 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
NdbApiSignal tSignal(m_reference);
tSignal.theReceiversBlockNumber = DBDICT;
- if (alter) {
+
+ LinearSectionPtr ptr[3];
+ ptr[0].p = (Uint32*)m_buffer.get_data();
+ ptr[0].sz = m_buffer.length() / 4;
+ int ret;
+ if (alter)
+ {
AlterTableReq * const req =
CAST_PTR(AlterTableReq, tSignal.getDataPtrSend());
@@ -1582,8 +1588,10 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
req->tableVersion = impl.m_version;;
tSignal.theVerId_signalNumber = GSN_ALTER_TABLE_REQ;
tSignal.theLength = AlterTableReq::SignalLength;
+ ret= alterTable(&tSignal, ptr);
}
- else {
+ else
+ {
CreateTableReq * const req =
CAST_PTR(CreateTableReq, tSignal.getDataPtrSend());
@@ -1591,25 +1599,21 @@ NdbDictInterface::createOrAlterTable(Ndb & ndb,
req->senderData = 0;
tSignal.theVerId_signalNumber = GSN_CREATE_TABLE_REQ;
tSignal.theLength = CreateTableReq::SignalLength;
- }
-
- LinearSectionPtr ptr[3];
- ptr[0].p = (Uint32*)m_buffer.get_data();
- ptr[0].sz = m_buffer.length() / 4;
-
- int ret = (alter) ?
- alterTable(&tSignal, ptr)
- : createTable(&tSignal, ptr);
-
- if (!alter && haveAutoIncrement) {
- if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(),
- autoIncrementValue)) {
- if (ndb.theError.code == 0) {
- m_error.code = 4336;
- ndb.theError = m_error;
- } else
- m_error= ndb.theError;
- ret = -1; // errorcode set in initialize_autoincrement
+ ret= createTable(&tSignal, ptr);
+
+ if (ret)
+ return ret;
+
+ if (haveAutoIncrement) {
+ if (!ndb.setAutoIncrementValue(impl.m_externalName.c_str(),
+ autoIncrementValue)) {
+ if (ndb.theError.code == 0) {
+ m_error.code = 4336;
+ ndb.theError = m_error;
+ } else
+ m_error= ndb.theError;
+ ret = -1; // errorcode set in initialize_autoincrement
+ }
}
}
return ret;
diff --git a/ndb/test/ndbapi/testDict.cpp b/ndb/test/ndbapi/testDict.cpp
index 712ab2e4d25..0a43bb02fff 100644
--- a/ndb/test/ndbapi/testDict.cpp
+++ b/ndb/test/ndbapi/testDict.cpp
@@ -1480,8 +1480,10 @@ runTestDictionaryPerf(NDBT_Context* ctx, NDBT_Step* step){
}
int runFailAddFragment(NDBT_Context* ctx, NDBT_Step* step){
+ static int acclst[] = { 3001 };
static int tuplst[] = { 4007, 4008, 4009, 4010, 4011, 4012 };
static int tuxlst[] = { 12001, 12002, 12003, 12004, 12005, 12006 };
+ static unsigned acccnt = sizeof(acclst)/sizeof(acclst[0]);
static unsigned tupcnt = sizeof(tuplst)/sizeof(tuplst[0]);
static unsigned tuxcnt = sizeof(tuxlst)/sizeof(tuxlst[0]);
@@ -1509,6 +1511,19 @@ int runFailAddFragment(NDBT_Context* ctx, NDBT_Step* step){
(void)pDic->dropTable(tab.getName());
for (int l = 0; l < loops; l++) {
+ for (unsigned i0 = 0; i0 < acccnt; i0++) {
+ unsigned j = (l == 0 ? i0 : myRandom48(acccnt));
+ int errval = acclst[j];
+ g_info << "insert error node=" << nodeId << " value=" << errval << endl;
+ CHECK2(restarter.insertErrorInNode(nodeId, errval) == 0,
+ "failed to set error insert");
+ CHECK2(pDic->createTable(tab) != 0,
+ "failed to fail after error insert " << errval);
+ CHECK2(pDic->createTable(tab) == 0,
+ pDic->getNdbError());
+ CHECK2(pDic->dropTable(tab.getName()) == 0,
+ pDic->getNdbError());
+ }
for (unsigned i1 = 0; i1 < tupcnt; i1++) {
unsigned j = (l == 0 ? i1 : myRandom48(tupcnt));
int errval = tuplst[j];
@@ -1638,7 +1653,7 @@ TESTCASE("DictionaryPerf",
INITIALIZER(runTestDictionaryPerf);
}
TESTCASE("FailAddFragment",
- "Fail add fragment or attribute in TUP or TUX\n"){
+ "Fail add fragment or attribute in ACC or TUP or TUX\n"){
INITIALIZER(runFailAddFragment);
}
NDBT_TESTSUITE_END(testDict);
@@ -1650,5 +1665,3 @@ int main(int argc, const char** argv){
myRandom48Init(NdbTick_CurrentMillisecond());
return testDict.execute(argc, argv);
}
-
-
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index d1a36a75a5a..29935696b7d 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -343,7 +343,8 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
(l_time->month || l_time->day))
l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
- if (number_of_fields < 3 || l_time->month > 12 ||
+ if (number_of_fields < 3 ||
+ l_time->year > 9999 || l_time->month > 12 ||
l_time->day > 31 || l_time->hour > 23 ||
l_time->minute > 59 || l_time->second > 59 ||
(!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0)))
@@ -733,10 +734,10 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
/* Set MYSQL_TIME structure to 0000-00-00 00:00:00.000000 */
-void set_zero_time(MYSQL_TIME *tm)
+void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type)
{
bzero((void*) tm, sizeof(*tm));
- tm->time_type= MYSQL_TIMESTAMP_NONE;
+ tm->time_type= time_type;
}
diff --git a/sql/field.cc b/sql/field.cc
index bbd21247b8e..72c27b6adf9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -4086,6 +4086,10 @@ int Field_datetime::store(longlong nr)
void Field_datetime::store_time(TIME *ltime,timestamp_type type)
{
longlong tmp;
+ /*
+ We don't perform range checking here since values stored in TIME
+ structure always fit into DATETIME range.
+ */
if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
(ltime->hour*10000L+ltime->minute*100+ltime->second));
diff --git a/sql/item.cc b/sql/item.cc
index 0e7a2b50b51..31c35e87cd4 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -837,6 +837,21 @@ void Item_param::set_double(double d)
}
+/*
+ Set parameter value from TIME value.
+
+ SYNOPSIS
+ set_time()
+ tm - datetime value to set (time_type is ignored)
+ type - type of datetime value
+ max_length_arg - max length of datetime value as string
+
+ NOTE
+ If we value to be stored is not normalized, zero value will be stored
+ instead and proper warning will be produced. This function relies on
+ the fact that even wrong value sent over binary protocol fits into
+ MAX_DATE_STRING_REP_LENGTH buffer.
+*/
void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
{
DBUG_ENTER("Item_param::set_time");
@@ -844,6 +859,17 @@ void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
value.time= *tm;
value.time.time_type= type;
+ if (value.time.year > 9999 || value.time.month > 12 ||
+ value.time.day > 31 ||
+ type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 ||
+ value.time.minute > 59 || value.time.second > 59)
+ {
+ char buff[MAX_DATE_STRING_REP_LENGTH];
+ uint length= my_TIME_to_str(&value.time, buff);
+ make_truncated_value_warning(current_thd, buff, length, type);
+ set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
+ }
+
state= TIME_VALUE;
maybe_null= 0;
max_length= max_length_arg;
diff --git a/sql/item.h b/sql/item.h
index 547577a7ee0..ccb0fda1c49 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -266,6 +266,14 @@ public:
virtual bool get_time(TIME *ltime);
virtual bool get_date_result(TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
+ /*
+ This function is used only in Item_func_isnull/Item_func_isnotnull
+ (implementations of IS NULL/IS NOT NULL clauses). Item_func_is{not}null
+ calls this method instead of one of val/result*() methods, which
+ normally will set null_value. This allows to determine nullness of
+ a complex expression without fully evaluating it.
+ Any new item which can be NULL must implement this call.
+ */
virtual bool is_null() { return 0; }
/*
it is "top level" item of WHERE clause and we do not need correct NULL
@@ -573,6 +581,8 @@ public:
void print(String *str) { str->append('?'); }
/* parameter never equal to other parameter of other item */
bool eq(const Item *item, bool binary_cmp) const { return 0; }
+ bool is_null()
+ { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
};
class Item_int :public Item_num
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c07e9f23ea2..3fb5bcd01c6 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -350,6 +350,7 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
{
uint el= fields.elements;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
+ new_item->collation.set(item->collation);
fields.push_front(item);
ref_pointer_array[el]= item;
thd->change_item_tree(arg, new_item);
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 3b3a6083725..c43a7d87f8f 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -218,16 +218,13 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
hybrid_type= item->result_type();
if (hybrid_type == INT_RESULT)
{
- cmp_charset= &my_charset_bin;
max_length=20;
}
else if (hybrid_type == REAL_RESULT)
{
- cmp_charset= &my_charset_bin;
max_length=float_length(decimals);
}else
{
- cmp_charset= item->collation.collation;
max_length=item->max_length;
}
decimals=item->decimals;
@@ -557,7 +554,7 @@ bool Item_sum_min::add()
{
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
- (null_value || sortcmp(&value,result,cmp_charset) > 0))
+ (null_value || sortcmp(&value,result,collation.collation) > 0))
{
value.copy(*result);
null_value=0;
@@ -610,7 +607,7 @@ bool Item_sum_max::add()
{
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
- (null_value || sortcmp(&value,result,cmp_charset) < 0))
+ (null_value || sortcmp(&value,result,collation.collation) < 0))
{
value.copy(*result);
null_value=0;
@@ -921,7 +918,7 @@ Item_sum_hybrid::min_max_update_str_field()
result_field->val_str(&tmp_value);
if (result_field->is_null() ||
- (cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0)
+ (cmp_sign * sortcmp(res_str,&tmp_value,collation.collation)) < 0)
result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
result_field->set_notnull();
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 5aa0d37190b..f9c48304795 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -402,20 +402,19 @@ class Item_sum_hybrid :public Item_sum
enum_field_types hybrid_field_type;
int cmp_sign;
table_map used_table_cache;
- CHARSET_INFO *cmp_charset;
public:
Item_sum_hybrid(Item *item_par,int sign)
:Item_sum(item_par), sum(0.0), sum_int(0),
hybrid_type(INT_RESULT), hybrid_field_type(FIELD_TYPE_LONGLONG),
- cmp_sign(sign), used_table_cache(~(table_map) 0),
- cmp_charset(&my_charset_bin)
- {}
+ cmp_sign(sign), used_table_cache(~(table_map) 0)
+ { collation.set(&my_charset_bin); }
Item_sum_hybrid(THD *thd, Item_sum_hybrid *item):
Item_sum(thd, item), value(item->value),
sum(item->sum), sum_int(item->sum_int), hybrid_type(item->hybrid_type),
hybrid_field_type(item->hybrid_field_type),cmp_sign(item->cmp_sign),
- used_table_cache(item->used_table_cache), cmp_charset(item->cmp_charset) {}
+ used_table_cache(item->used_table_cache)
+ { collation.set(item->collation); }
bool fix_fields(THD *, TABLE_LIST *, Item **);
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index d8142352e70..354c8b5c50c 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1601,50 +1601,46 @@ void Item_func_from_unixtime::fix_length_and_dec()
String *Item_func_from_unixtime::val_str(String *str)
{
TIME time_tmp;
- my_time_t tmp;
-
+
DBUG_ASSERT(fixed == 1);
- tmp= (time_t) args[0]->val_int();
- if ((null_value=args[0]->null_value))
- goto null_date;
-
- thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, tmp);
-
+
+ if (get_date(&time_tmp, 0))
+ return 0;
+
if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN))
- goto null_date;
+ {
+ null_value= 1;
+ return 0;
+ }
+
make_datetime((DATE_TIME_FORMAT *) 0, &time_tmp, str);
return str;
-
-null_date:
- null_value=1;
- return 0;
}
longlong Item_func_from_unixtime::val_int()
{
TIME time_tmp;
- my_time_t tmp;
-
+
DBUG_ASSERT(fixed == 1);
- tmp= (time_t) (ulong) args[0]->val_int();
- if ((null_value=args[0]->null_value))
+ if (get_date(&time_tmp, 0))
return 0;
-
- current_thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, tmp);
-
+
return (longlong) TIME_to_ulonglong_datetime(&time_tmp);
}
bool Item_func_from_unixtime::get_date(TIME *ltime,
uint fuzzy_date __attribute__((unused)))
{
- my_time_t tmp=(my_time_t) args[0]->val_int();
- if ((null_value=args[0]->null_value))
+ longlong tmp= args[0]->val_int();
+
+ if ((null_value= (args[0]->null_value ||
+ tmp < TIMESTAMP_MIN_VALUE ||
+ tmp > TIMESTAMP_MAX_VALUE)))
return 1;
-
- current_thd->variables.time_zone->gmt_sec_to_TIME(ltime, tmp);
+
+ thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)tmp);
return 0;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index d81ed2cd014..a790e6fe9d8 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -349,12 +349,6 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
tm.neg= (bool) to[0];
day= (uint) sint4korr(to+1);
- /*
- Note, that though ranges of hour, minute and second are not checked
- here we rely on them being < 256: otherwise
- we'll get buffer overflow in make_{date,time} functions,
- which are called when time value is converted to string.
- */
tm.hour= (uint) to[5] + day * 24;
tm.minute= (uint) to[6];
tm.second= (uint) to[7];
@@ -369,7 +363,7 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
tm.day= tm.year= tm.month= 0;
}
else
- set_zero_time(&tm);
+ set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length;
@@ -388,11 +382,6 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.year= (uint) sint2korr(to);
tm.month= (uint) to[2];
tm.day= (uint) to[3];
- /*
- Note, that though ranges of hour, minute and second are not checked
- here we rely on them being < 256: otherwise
- we'll get buffer overflow in make_{date,time} functions.
- */
if (length > 4)
{
tm.hour= (uint) to[4];
@@ -405,7 +394,7 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
}
else
- set_zero_time(&tm);
+ set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length;
@@ -419,11 +408,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
if (length >= 4)
{
uchar *to= *pos;
- /*
- Note, that though ranges of hour, minute and second are not checked
- here we rely on them being < 256: otherwise
- we'll get buffer overflow in make_{date,time} functions.
- */
+
tm.year= (uint) sint2korr(to);
tm.month= (uint) to[2];
tm.day= (uint) to[3];
@@ -433,7 +418,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
tm.neg= 0;
}
else
- set_zero_time(&tm);
+ set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
*pos+= length;
diff --git a/tests/client_test.c b/tests/client_test.c
index 0ada98d44b0..35990a521a4 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -11121,6 +11121,140 @@ static void test_bug6096()
}
+/*
+ Test of basic checks that are performed in server for components
+ of MYSQL_TIME parameters.
+*/
+
+static void test_datetime_ranges()
+{
+ const char *stmt_text;
+ int rc, i;
+ MYSQL_STMT *stmt;
+ MYSQL_BIND bind[6];
+ MYSQL_TIME tm[6];
+
+ myheader("test_datetime_ranges");
+
+ stmt_text= "drop table if exists t1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "create table t1 (year datetime, month datetime, day datetime, "
+ "hour datetime, min datetime, sec datetime)";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt= mysql_simple_prepare(mysql,
+ "INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?)");
+ check_stmt(stmt);
+ verify_param_count(stmt, 6);
+
+ bzero(bind, sizeof(bind));
+ for (i= 0; i < 6; i++)
+ {
+ bind[i].buffer_type= MYSQL_TYPE_DATETIME;
+ bind[i].buffer= &tm[i];
+ }
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+
+ tm[0].year= 2004; tm[0].month= 11; tm[0].day= 10;
+ tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
+ tm[0].second_part= 0; tm[0].neg= 0;
+
+ tm[5]= tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
+ tm[0].year= 10000; tm[1].month= 13; tm[2].day= 32;
+ tm[3].hour= 24; tm[4].minute= 60; tm[5].second= 60;
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ DIE_UNLESS(mysql_warning_count(mysql) != 6);
+
+ verify_col_data("t1", "year", "0000-00-00 00:00:00");
+ verify_col_data("t1", "month", "0000-00-00 00:00:00");
+ verify_col_data("t1", "day", "0000-00-00 00:00:00");
+ verify_col_data("t1", "hour", "0000-00-00 00:00:00");
+ verify_col_data("t1", "min", "0000-00-00 00:00:00");
+ verify_col_data("t1", "sec", "0000-00-00 00:00:00");
+
+ mysql_stmt_close(stmt);
+
+ stmt_text= "delete from t1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 (year, month, day) "
+ "VALUES (?, ?, ?)");
+ check_stmt(stmt);
+ verify_param_count(stmt, 3);
+
+ /*
+ We reuse contents of bind and tm arrays left from previous part of test.
+ */
+ for (i= 0; i < 3; i++)
+ bind[i].buffer_type= MYSQL_TYPE_DATE;
+
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ DIE_UNLESS(mysql_warning_count(mysql) != 3);
+
+ verify_col_data("t1", "year", "0000-00-00 00:00:00");
+ verify_col_data("t1", "month", "0000-00-00 00:00:00");
+ verify_col_data("t1", "day", "0000-00-00 00:00:00");
+
+ mysql_stmt_close(stmt);
+
+ stmt_text= "drop table t1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt_text= "create table t1 (day_ovfl time, day time, hour time, min time, sec time)";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+
+ stmt= mysql_simple_prepare(mysql,
+ "INSERT INTO t1 VALUES (?, ?, ?, ?, ?)");
+ check_stmt(stmt);
+ verify_param_count(stmt, 5);
+
+ /*
+ Again we reuse what we can from previous part of test.
+ */
+ for (i= 0; i < 5; i++)
+ bind[i].buffer_type= MYSQL_TYPE_TIME;
+
+ rc= mysql_stmt_bind_param(stmt, bind);
+ check_execute(stmt, rc);
+
+ tm[0].year= 0; tm[0].month= 0; tm[0].day= 10;
+ tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
+ tm[0].second_part= 0; tm[0].neg= 0;
+
+ tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
+ tm[0].day= 35; tm[1].day= 34; tm[2].hour= 30; tm[3].minute= 60; tm[4].second= 60;
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ DIE_UNLESS(mysql_warning_count(mysql) != 2);
+
+ verify_col_data("t1", "day_ovfl", "838:59:59");
+ verify_col_data("t1", "day", "828:30:30");
+ verify_col_data("t1", "hour", "270:30:30");
+ verify_col_data("t1", "min", "00:00:00");
+ verify_col_data("t1", "sec", "00:00:00");
+
+ mysql_stmt_close(stmt);
+
+ stmt_text= "drop table t1";
+ rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
+ myquery(rc);
+}
+
+
static void test_bug4172()
{
MYSQL_STMT *stmt;
@@ -11455,6 +11589,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug6046", test_bug6046 },
{ "test_bug6081", test_bug6081 },
{ "test_bug6096", test_bug6096 },
+ { "test_datetime_ranges", test_datetime_ranges },
{ "test_bug4172", test_bug4172 },
{ "test_conversion", test_conversion },
{ 0, 0 }