Commit b1bc23d6 authored by unknown's avatar unknown

Merge neptunus.(none):/home/msvensson/mysql/mysql-4.1

into  neptunus.(none):/home/msvensson/mysql/mysql-4.1-maint


mysql-test/Makefile.am:
  Auto merged
mysql-test/r/func_time.result:
  Auto merged
mysql-test/t/func_time.test:
  Auto merged
sql-common/my_time.c:
  Auto merged
sql/item_timefunc.cc:
  Auto merged
mysql-test/mysql-test-run-shell.sh:
  Auto merged
mysql-test/mysql-test-run.pl:
  Manual merge of changes for RPM
parents 04e5eefd bf7ff05f
......@@ -28,9 +28,17 @@ fi
CHANGESET=`bk -R prs -r+ -h -d':P:::I:' ChangeSet`
CSETKEY=`bk -R prs -r+ -h -d':KEY:' ChangeSet`
BUG=`bk -R prs -r+ -h -d':C:' ChangeSet | sed -ne 's/^.*[Bb][Uu][Gg] *# *\([0-9][0-9]*\).*$/\1/p'`
WL=`bk -R prs -r+ -h -d':C:' ChangeSet | sed -ne 's/^.*[Ww][Ll] *# *\([0-9][0-9]*\).*$/ WL#\1/p'`
#
# composing subject lines of commit mails.
# if a fix targets to a WL and there is a bug referred
# then X-Bug mail header will contain the first found bug's number
#
BUG=`bk -R prs -r+ -h -d':C:' ChangeSet | \
sed -ne 's/[Bb][Uu][Gg] *# *\([0-9][0-9]*\).*$/BUG#\1/
s/.*BUG#\([0-9][0-9]*\)/\1/p'`
WL=`bk -R prs -r+ -h -d':C:' ChangeSet | \
sed -ne 's/[Ww][Ll] *# *\([0-9][0-9]*\).*$/WL#\1/
s/.*\(WL#[0-9][0-9]*\)/ \1/p'`
if [ "$BUG" = "" ]
then
TO=dev-public@mysql.com
......
......@@ -1835,6 +1835,30 @@ dnl END OF MYSQL_CHECK_NDBCLUSTER SECTION
dnl ---------------------------------------------------------------------------
dnl
dnl Macro to check time_t range: according to C standard
dnl array index myst be greater then 0 => if time_t is signed
dnl the code in the macros below won't compile.
dnl
AC_DEFUN([MYSQL_CHECK_TIME_T],[
AC_MSG_CHECKING(if time_t is unsigned)
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
[[
#include <time.h>
]],
[[
int array[(((time_t)-1) > 0) ? 1 : -1];
]] )
], [
AC_DEFINE([TIME_T_UNSIGNED], 1, [Define to 1 if time_t is unsigned])
AC_MSG_RESULT(yes)
],
[AC_MSG_RESULT(no)]
)
])
dnl By default, many hosts won't let programs access large files;
dnl one must use special compiler options to get large-file access to work.
dnl For more details about this brain damage please see:
......
......@@ -1824,6 +1824,13 @@ then
AC_MSG_ERROR("MySQL needs a off_t type.")
fi
dnl
dnl check if time_t is unsigned
dnl
MYSQL_CHECK_TIME_T
# do we need #pragma interface/#pragma implementation ?
# yes if it's gcc 2.x, and not icc pretending to be gcc, and not cygwin
AC_MSG_CHECKING(the need for @%:@pragma interface/implementation)
......
......@@ -38,6 +38,14 @@ typedef long my_time_t;
#define MY_TIME_T_MAX LONG_MAX
#define MY_TIME_T_MIN LONG_MIN
/* Time handling defaults */
#define TIMESTAMP_MAX_YEAR 2038
#define YY_PART_YEAR 70
#define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1)
#define TIMESTAMP_MAX_VALUE INT_MAX32
#define TIMESTAMP_MIN_VALUE 1
#define YY_PART_YEAR 70
/* Flags to str_to_datetime */
......@@ -67,6 +75,30 @@ long calc_daynr(uint year,uint month,uint day);
void init_time(void);
/*
Function to check sanity of a TIMESTAMP value
DESCRIPTION
Check if a given MYSQL_TIME value fits in TIMESTAMP range.
This function doesn't make precise check, but rather a rough
estimate.
RETURN VALUES
FALSE The value seems sane
TRUE The MYSQL_TIME value is definitely out of range
*/
static inline bool validate_timestamp_range(const MYSQL_TIME *t)
{
if ((t->year > TIMESTAMP_MAX_YEAR || t->year < TIMESTAMP_MIN_YEAR) ||
(t->year == TIMESTAMP_MAX_YEAR && (t->month > 1 || t->day > 19)) ||
(t->year == TIMESTAMP_MIN_YEAR && (t->month < 12 || t->day < 31)))
return FALSE;
return TRUE;
}
my_time_t
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap);
......
......@@ -42,7 +42,7 @@ static int _mi_put_key_in_record(MI_INFO *info,uint keynr,byte *record);
uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
const byte *record, my_off_t filepos)
{
byte *pos,*end;
byte *pos;
uchar *start;
reg1 HA_KEYSEG *keyseg;
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
......@@ -84,18 +84,17 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
pos= (byte*) record+keyseg->start;
if (keyseg->flag & HA_SPACE_PACK)
{
end= pos + length;
if (type != HA_KEYTYPE_NUM)
{
while (end > pos && end[-1] == ' ')
end--;
length= cs->cset->lengthsp(cs, pos, length);
}
else
{
byte *end= pos + length;
while (pos < end && pos[0] == ' ')
pos++;
length=(uint) (end-pos);
}
length=(uint) (end-pos);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((byte*) key,(byte*) pos,(size_t) char_length);
......@@ -358,8 +357,10 @@ static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
pos= record+keyseg->start;
if (keyseg->type != (int) HA_KEYTYPE_NUM)
{
memcpy(pos,key,(size_t) length);
bfill(pos+length,keyseg->length-length,' ');
memcpy(pos,key,(size_t) length);
keyseg->charset->cset->fill(keyseg->charset,
pos + length, keyseg->length - length,
' ');
}
else
{
......
......@@ -326,6 +326,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
goto err;
}
}
else if (pos->type == HA_KEYTYPE_BINARY)
pos->charset= &my_charset_bin;
}
if (share->keyinfo[i].flag & HA_SPATIAL)
{
......
......@@ -315,6 +315,7 @@ pthread_handler_decl(thr_find_all_keys,arg)
uint memavl,old_memavl,keys,sort_length;
uint idx, maxbuffer;
uchar **sort_keys=0;
DBUG_ENTER("thr_find_all_keys"); /* FIXME why no matching DBUG_RETURN ? */
LINT_INIT(keys);
......@@ -322,8 +323,9 @@ pthread_handler_decl(thr_find_all_keys,arg)
if (my_thread_init())
goto err;
DBUG_ENTER("thr_find_all_keys");
DBUG_PRINT("enter", ("master: %d", sort_param->master));
if (sort_param->sort_info->got_error)
goto err;
......
......@@ -57,6 +57,7 @@ dist-hook:
-$(INSTALL_DATA) $(srcdir)/t/*.disabled $(distdir)/t
$(INSTALL_DATA) $(srcdir)/t/*.opt $(srcdir)/t/*.sh $(srcdir)/t/*.slave-mi $(distdir)/t
$(INSTALL_DATA) $(srcdir)/include/*.inc $(distdir)/include
$(INSTALL_DATA) $(srcdir)/include/*.test $(distdir)/include
$(INSTALL_DATA) $(srcdir)/r/*.result $(srcdir)/r/*.require $(distdir)/r
$(INSTALL_DATA) $(srcdir)/std_data/Moscow_leap $(distdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.dat $(srcdir)/std_data/*.000001 $(distdir)/std_data
......@@ -84,6 +85,7 @@ install-data-local:
$(INSTALL_DATA) $(srcdir)/r/*.result $(DESTDIR)$(testdir)/r
$(INSTALL_DATA) $(srcdir)/r/*.require $(DESTDIR)$(testdir)/r
$(INSTALL_DATA) $(srcdir)/include/*.inc $(DESTDIR)$(testdir)/include
$(INSTALL_DATA) $(srcdir)/include/*.test $(DESTDIR)$(testdir)/include
$(INSTALL_DATA) $(srcdir)/std_data/*.dat $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.*001 $(DESTDIR)$(testdir)/std_data
$(INSTALL_DATA) $(srcdir)/std_data/*.cnf $(DESTDIR)$(testdir)/std_data
......
#
# show server variables
#
--disable_query_log
--echo ===== ENGINES =====
show engines;
--echo ===== VARIABLES =====
show variables;
--echo ===== STOP =====
--enable_query_log
#!/bin/sh
# Copyright (C) 1997-2002 MySQL AB
# Copyright (C) 1997-2006 MySQL AB
# For a more info consult the file COPYRIGHT distributed with this file
# This scripts creates the privilege tables db, host, user, tables_priv,
......@@ -7,19 +7,26 @@
if [ x$1 = x"--bin" ]; then
shift 1
BINARY_DIST=1
bindir=../bin
scriptdir=../bin
libexecdir=../libexec
# Check if it's a binary distribution or a 'make install'
if test -x ../libexec/mysqld
then
execdir=../libexec
elif test -x ../../sbin/mysqld # RPM installation
then
execdir=../../sbin
bindir=../../bin
scriptdir=../../bin
libexecdir=../../libexec
else
execdir=../bin
fi
bindir=../bin
BINARY_DIST=1
fix_bin=mysql-test
scriptdir=../bin
libexecdir=../libexec
else
execdir=../sql
bindir=../client
......
......@@ -158,18 +158,29 @@ fi
# Misc. Definitions
#--
if [ -d ../sql ] ; then
# BASEDIR is always above mysql-test directory ...
MYSQL_TEST_DIR=`pwd`
cd ..
if [ -d ./sql ] ; then
SOURCE_DIST=1
else
BINARY_DIST=1
fi
#BASEDIR is always one above mysql-test directory
CWD=`pwd`
cd ..
BASEDIR=`pwd`
cd $CWD
MYSQL_TEST_DIR=$BASEDIR/mysql-test
# ... one level for tar.gz, two levels for a RPM installation
if [ -d ./bin ] ; then
# this is not perfect: we have
# /usr/share/mysql/ # mysql-test-run is here, so this is "$MYSQL_TEST_DIR"
# /usr/bin/ # with MySQL client programs
# so the existence of "/usr/share/bin/" would make this test fail.
BASEDIR=`pwd`
else
cd ..
BASEDIR=`pwd`
fi
cd $MYSQL_TEST_DIR
MYSQL_TEST_WINDIR=$MYSQL_TEST_DIR
MYSQLTEST_VARDIR=$MYSQL_TEST_DIR/var
export MYSQL_TEST_DIR MYSQL_TEST_WINDIR MYSQLTEST_VARDIR
......@@ -648,8 +659,15 @@ else
if test -x "$BASEDIR/libexec/mysqld"
then
MYSQLD="$VALGRIND $BASEDIR/libexec/mysqld"
else
elif test -x "$BASEDIR/bin/mysqld"
then
MYSQLD="$VALGRIND $BASEDIR/bin/mysqld"
elif test -x "$BASEDIR/sbin/mysqld"
then
MYSQLD="$VALGRIND $BASEDIR/sbin/mysqld"
else
$ECHO "Fatal error: Cannot find program mysqld in $BASEDIR/{libexec,bin,sbin}" 1>&2
exit 1
fi
CLIENT_BINDIR="$BASEDIR/bin"
if test -d "$BASEDIR/tests"
......@@ -1261,7 +1279,7 @@ start_master()
then
$ECHO "set args $master_args" > $GDB_MASTER_INIT$1
$ECHO "To start gdb for the master , type in another window:"
$ECHO "cd $CWD ; gdb -x $GDB_MASTER_INIT$1 $MASTER_MYSQLD"
$ECHO "cd $MYSQL_TEST_DIR ; gdb -x $GDB_MASTER_INIT$1 $MASTER_MYSQLD"
wait_for_master=1500
else
( $ECHO set args $master_args;
......@@ -1377,7 +1395,7 @@ start_slave()
then
$ECHO "set args $slave_args" > $GDB_SLAVE_INIT
echo "To start gdb for the slave, type in another window:"
echo "cd $CWD ; gdb -x $GDB_SLAVE_INIT $SLAVE_MYSQLD"
echo "cd $MYSQL_TEST_DIR ; gdb -x $GDB_SLAVE_INIT $SLAVE_MYSQLD"
wait_for_slave=1500
else
( $ECHO set args $slave_args;
......@@ -1606,10 +1624,13 @@ run_testcase ()
--result-file=*)
result_file=`$ECHO "$EXTRA_MASTER_OPT" | $SED -e "s;--result-file=;;"`
result_file="r/$result_file.result"
# Note that this must be set to space, not "" for test-reset to
# work
# Note that this must be set to space, not "" for test-reset to work
EXTRA_MASTER_OPT=" "
;;
--force-restart)
# Note that this must be set to space, not "" for test-reset to work
EXTRA_MASTER_OPT=" "
;;
esac
stop_master
stop_master 1
......
......@@ -187,6 +187,7 @@ our $opt_fast;
our $opt_force;
our $opt_reorder= 0;
our $opt_enable_disabled;
our $opt_report_features;
our $opt_mem= $ENV{'MTR_MEM'};
our $opt_gcov;
......@@ -423,17 +424,20 @@ sub main () {
if ( ! $need_im )
{
$opt_skip_im= 1;
}
}
initialize_servers();
if ( $opt_report_features ) {
run_report_features();
}
run_suite($opt_suite, $tests);
}
mtr_exit(0);
}
##############################################################################
#
# Default settings
......@@ -591,6 +595,7 @@ sub command_line_setup () {
'mem' => \$opt_mem,
# Misc
'report-features' => \$opt_report_features,
'comment=s' => \$opt_comment,
'debug' => \$opt_debug,
'fast' => \$opt_fast,
......@@ -632,7 +637,7 @@ sub command_line_setup () {
$glob_hostname= mtr_short_hostname();
# 'basedir' is always parent of "mysql-test" directory
# Find the absolute path to the test directory
$glob_mysql_test_dir= cwd();
if ( $glob_cygwin_perl )
{
......@@ -640,11 +645,27 @@ sub command_line_setup () {
$glob_mysql_test_dir= `cygpath -m "$glob_mysql_test_dir"`;
chomp($glob_mysql_test_dir);
}
$glob_basedir= dirname($glob_mysql_test_dir);
# In most cases, the base directory we find everything relative to,
# is the parent directory of the "mysql-test" directory. For source
# distributions, TAR binary distributions and some other packages.
$glob_basedir= dirname($glob_mysql_test_dir);
# In the RPM case, binaries and libraries are installed in the
# default system locations, instead of having our own private base
# directory. And we install "/usr/share/mysql-test". Moving up one
# more directory relative to "mysql-test" gives us a usable base
# directory for RPM installs.
if ( ! $opt_source_dist and ! -d "$glob_basedir/bin" )
{
$glob_basedir= dirname($glob_basedir);
}
# Expect mysql-bench to be located adjacent to the source tree, by default
$glob_mysql_bench_dir= "$glob_basedir/../mysql-bench"
unless defined $glob_mysql_bench_dir;
$glob_mysql_bench_dir= undef
unless -d $glob_mysql_bench_dir;
$path_my_basedir=
$source_dist ? $glob_mysql_test_dir : $glob_basedir;
......@@ -788,6 +809,13 @@ sub command_line_setup () {
$opt_vardir= "$glob_mysql_test_dir/$opt_vardir";
}
# Ensure a proper error message
mkpath("$opt_vardir");
unless ( -d $opt_vardir and -w $opt_vardir )
{
mtr_error("Writable 'var' directory is needed, use the '--vardir' option");
}
# --------------------------------------------------------------------------
# Set tmpdir
# --------------------------------------------------------------------------
......@@ -1300,7 +1328,8 @@ sub executable_setup_im () {
mtr_exe_maybe_exists(
"$glob_basedir/server-tools/instance-manager/mysqlmanager",
"$glob_basedir/libexec/mysqlmanager",
"$glob_basedir/bin/mysqlmanager");
"$glob_basedir/bin/mysqlmanager",
"$glob_basedir/sbin/mysqlmanager");
return ($exe_im eq "");
}
......@@ -4196,6 +4225,43 @@ sub run_check_testcase ($$) {
return $res;
}
##############################################################################
#
# Report the features that were compiled in
#
##############################################################################
sub run_report_features () {
my $args;
if ( ! $glob_use_embedded_server )
{
mysqld_start($master->[0],[],[]);
if ( ! $master->[0]->{'pid'} )
{
mtr_error("Can't start the mysqld server");
}
mysqld_wait_started($master->[0]);
}
my $tinfo = {};
$tinfo->{'name'} = 'report features';
$tinfo->{'result_file'} = undef;
$tinfo->{'component_id'} = 'mysqld';
$tinfo->{'path'} = 'include/report-features.test';
$tinfo->{'timezone'}= "GMT-3";
$tinfo->{'slave_num'} = 0;
$tinfo->{'master_opt'} = [];
$tinfo->{'slave_opt'} = [];
$tinfo->{'slave_mi'} = [];
$tinfo->{'comment'} = 'report server features';
run_mysqltest($tinfo);
if ( ! $glob_use_embedded_server )
{
stop_all_servers();
}
}
sub run_mysqltest ($) {
......@@ -4328,8 +4394,10 @@ sub run_mysqltest ($) {
mtr_add_arg($args, "--test-file");
mtr_add_arg($args, $tinfo->{'path'});
mtr_add_arg($args, "--result-file");
mtr_add_arg($args, $tinfo->{'result_file'});
if ( defined $tinfo->{'result_file'} ) {
mtr_add_arg($args, "--result-file");
mtr_add_arg($args, $tinfo->{'result_file'});
}
if ( $opt_record )
{
......@@ -4735,3 +4803,4 @@ HERE
mtr_exit(1);
}
......@@ -715,6 +715,28 @@ lily
river
drop table t1;
deallocate prepare stmt;
create table t1 (
a char(10) unicode not null,
index a (a)
) engine=myisam;
insert into t1 values (repeat(0x201f, 10));
insert into t1 values (repeat(0x2020, 10));
insert into t1 values (repeat(0x2021, 10));
explain select hex(a) from t1 order by a;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index NULL a 20 NULL 3 Using index
select hex(a) from t1 order by a;
hex(a)
201F201F201F201F201F201F201F201F201F201F
2020202020202020202020202020202020202020
2021202120212021202120212021202120212021
alter table t1 drop index a;
select hex(a) from t1 order by a;
hex(a)
201F201F201F201F201F201F201F201F201F201F
2020202020202020202020202020202020202020
2021202120212021202120212021202120212021
drop table t1;
CREATE TABLE t1 (id int, s char(5) CHARACTER SET ucs2 COLLATE ucs2_unicode_ci);
INSERT INTO t1 VALUES (1, 'ZZZZZ'), (1, 'ZZZ'), (2, 'ZZZ'), (2, 'ZZZZZ');
SELECT id, MIN(s) FROM t1 GROUP BY id;
......
......@@ -599,12 +599,72 @@ count(distinct (f1+1))
1
3
drop table t1;
set names utf8;
create table t1
(
x text character set utf8 not null,
y integer not null
);
insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0);
set group_concat_max_len= 1022 + 10;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1032 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7
set group_concat_max_len= 1022 + 9;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1031 1031 1027 aaaaaaa,÷÷÷÷ C3B7C3B7C3B7
set group_concat_max_len= 1022 + 8;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1030 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7
set group_concat_max_len= 1022 + 7;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1029 1029 1026 aaaaaaaa,÷÷÷ C3B7C3B7C3B7
set group_concat_max_len= 1022 + 6;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1028 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7
set group_concat_max_len= 1022 + 5;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1027 1027 1025 aaaaaaaaa,÷÷ 612CC3B7C3B7
set group_concat_max_len= 1022 + 4;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1026 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7
set group_concat_max_len= 1022 + 3;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1025 1025 1024 aaaaaaaaaa,÷ 6161612CC3B7
set group_concat_max_len= 1022 + 2;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1024 1023 1023 aaaaaaaaaaa, 61616161612C
set group_concat_max_len= 1022 + 1;
select @x:=group_concat(x) from t1 group by y;
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
@@group_concat_max_len length(@x) char_length(@x) right(@x,12) right(HEX(@x),12)
1023 1023 1023 aaaaaaaaaaa, 61616161612C
drop table t1;
set group_concat_max_len=1024;
set names latin1;
create table t1 (f1 int unsigned, f2 varchar(255));
insert into t1 values (1,repeat('a',255)),(2,repeat('b',255));
select f2,group_concat(f1) from t1 group by f2;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t1 t1 f2 f2 253 255 255 Y 0 0 8
def group_concat(f1) 252 400 1 Y 128 0 63
def group_concat(f1) 252 1024 1 Y 128 0 63
f2 group_concat(f1)
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 2
......
......@@ -485,12 +485,48 @@ unix_timestamp('1969-12-01 19:00:01')
select from_unixtime(-1);
from_unixtime(-1)
NULL
select from_unixtime(2145916800);
from_unixtime(2145916800)
select from_unixtime(2147483647);
from_unixtime(2147483647)
2038-01-19 06:14:07
select from_unixtime(2147483648);
from_unixtime(2147483648)
NULL
select from_unixtime(0);
from_unixtime(0)
1970-01-01 03:00:00
select unix_timestamp(from_unixtime(2147483647));
unix_timestamp(from_unixtime(2147483647))
2147483647
select unix_timestamp(from_unixtime(2147483648));
unix_timestamp(from_unixtime(2147483648))
NULL
select unix_timestamp('2039-01-20 01:00:00');
unix_timestamp('2039-01-20 01:00:00')
0
select unix_timestamp('1968-01-20 01:00:00');
unix_timestamp('1968-01-20 01:00:00')
0
select unix_timestamp('2038-02-10 01:00:00');
unix_timestamp('2038-02-10 01:00:00')
0
select unix_timestamp('1969-11-20 01:00:00');
unix_timestamp('1969-11-20 01:00:00')
0
select unix_timestamp('2038-01-20 01:00:00');
unix_timestamp('2038-01-20 01:00:00')
0
select unix_timestamp('1969-12-30 01:00:00');
unix_timestamp('1969-12-30 01:00:00')
0
select unix_timestamp('2038-01-17 12:00:00');
unix_timestamp('2038-01-17 12:00:00')
2147331600
select unix_timestamp('1970-01-01 03:00:01');
unix_timestamp('1970-01-01 03:00:01')
1
select unix_timestamp('2038-01-19 07:14:07');
unix_timestamp('2038-01-19 07:14:07')
0
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;
......
......@@ -54,3 +54,4 @@ Tables_in_test
t2
t4
drop table t2, t4;
End of 4.1 tests
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
drop database if exists DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
create database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
select @@net_buffer_length, @@max_allowed_packet;
@@net_buffer_length @@max_allowed_packet
1024 1024
create table `t1` (`f1` LONGTEXT) ENGINE=MyISAM;
INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1023');
select count(*) from `DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________`.`t1` /* must be 1 */;
count(*)
1
drop database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
......@@ -41,7 +41,7 @@ Warning 1299 Invalid TIMESTAMP value in column 'ts' at row 2
DROP TABLE t1;
select unix_timestamp('1970-01-01 01:00:00'),
unix_timestamp('1970-01-01 01:00:01'),
unix_timestamp('2038-01-01 00:59:59'),
unix_timestamp('2038-01-01 01:00:00');
unix_timestamp('1970-01-01 01:00:00') unix_timestamp('1970-01-01 01:00:01') unix_timestamp('2038-01-01 00:59:59') unix_timestamp('2038-01-01 01:00:00')
0 1 2145916799 0
unix_timestamp('2038-01-19 04:14:07'),
unix_timestamp('2038-01-19 04:14:08');
unix_timestamp('1970-01-01 01:00:00') unix_timestamp('1970-01-01 01:00:01') unix_timestamp('2038-01-19 04:14:07') unix_timestamp('2038-01-19 04:14:08')
0 1 2147483647 0
......@@ -106,7 +106,7 @@ create table t1 (ts timestamp);
set time_zone='UTC';
insert into t1 values ('0000-00-00 00:00:00'),('1969-12-31 23:59:59'),
('1970-01-01 00:00:00'),('1970-01-01 00:00:01'),
('2037-12-31 23:59:59'),('2038-01-01 00:00:00');
('2038-01-19 03:14:07'),('2038-01-19 03:14:08');
Warnings:
Warning 1264 Data truncated; out of range for column 'ts' at row 2
Warning 1264 Data truncated; out of range for column 'ts' at row 3
......@@ -117,13 +117,13 @@ ts
0000-00-00 00:00:00
0000-00-00 00:00:00
1970-01-01 00:00:01
2037-12-31 23:59:59
2038-01-19 03:14:07
0000-00-00 00:00:00
delete from t1;
set time_zone='MET';
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 00:30:00'),
('1970-01-01 01:00:00'),('1970-01-01 01:00:01'),
('2038-01-01 00:59:59'),('2038-01-01 01:00:00');
('2038-01-19 04:14:07'),('2038-01-19 04:14:08');
Warnings:
Warning 1264 Data truncated; out of range for column 'ts' at row 2
Warning 1264 Data truncated; out of range for column 'ts' at row 3
......@@ -134,13 +134,13 @@ ts
0000-00-00 00:00:00
0000-00-00 00:00:00
1970-01-01 01:00:01
2038-01-01 00:59:59
2038-01-19 04:14:07
0000-00-00 00:00:00
delete from t1;
set time_zone='+01:30';
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 01:00:00'),
('1970-01-01 01:30:00'),('1970-01-01 01:30:01'),
('2038-01-01 01:29:59'),('2038-01-01 01:30:00');
('2038-01-19 04:44:07'),('2038-01-19 04:44:08');
Warnings:
Warning 1264 Data truncated; out of range for column 'ts' at row 2
Warning 1264 Data truncated; out of range for column 'ts' at row 3
......@@ -151,7 +151,7 @@ ts
0000-00-00 00:00:00
0000-00-00 00:00:00
1970-01-01 01:30:01
2038-01-01 01:29:59
2038-01-19 04:44:07
0000-00-00 00:00:00
drop table t1;
show variables like 'time_zone';
......@@ -213,12 +213,12 @@ convert_tz('2003-10-26 02:59:59', 'MET', 'UTC')
select convert_tz('2003-10-26 04:00:00', 'MET', 'UTC');
convert_tz('2003-10-26 04:00:00', 'MET', 'UTC')
2003-10-26 03:00:00
select convert_tz('2038-01-01 00:59:59', 'MET', 'UTC');
convert_tz('2038-01-01 00:59:59', 'MET', 'UTC')
2037-12-31 23:59:59
select convert_tz('2038-01-01 01:00:00', 'MET', 'UTC');
convert_tz('2038-01-01 01:00:00', 'MET', 'UTC')
2038-01-01 01:00:00
select convert_tz('2038-01-19 04:14:07', 'MET', 'UTC');
convert_tz('2038-01-19 04:14:07', 'MET', 'UTC')
2038-01-19 03:14:07
select convert_tz('2038-01-19 04:14:08', 'MET', 'UTC');
convert_tz('2038-01-19 04:14:08', 'MET', 'UTC')
2038-01-19 04:14:08
select convert_tz('2103-01-01 04:00:00', 'MET', 'UTC');
convert_tz('2103-01-01 04:00:00', 'MET', 'UTC')
2103-01-01 04:00:00
......
select from_unixtime(0);
from_unixtime(0)
1969-12-31 14:00:00
select unix_timestamp('1969-12-31 14:00:01');
unix_timestamp('1969-12-31 14:00:01')
1
......@@ -452,6 +452,24 @@ select utext from t1 where utext like '%%';
drop table t1;
deallocate prepare stmt;
#
# Bug#22052 Trailing spaces are not removed from UNICODE fields in an index
#
create table t1 (
a char(10) unicode not null,
index a (a)
) engine=myisam;
insert into t1 values (repeat(0x201f, 10));
insert into t1 values (repeat(0x2020, 10));
insert into t1 values (repeat(0x2021, 10));
# make sure "index read" is used
explain select hex(a) from t1 order by a;
select hex(a) from t1 order by a;
alter table t1 drop index a;
select hex(a) from t1 order by a;
drop table t1;
#
# Bug #20076: server crashes for a query with GROUP BY if MIN/MAX aggregation
# over a 'ucs2' field uses a temporary table
......
......@@ -390,6 +390,30 @@ select f1, group_concat(f1+1) from t1 group by f1 with rollup;
select count(distinct (f1+1)) from t1 group by f1 with rollup;
drop table t1;
#
# Bug#23451 GROUP_CONCAT truncates a multibyte utf8 character
#
set names utf8;
create table t1
(
x text character set utf8 not null,
y integer not null
);
insert into t1 values (repeat('a', 1022), 0), (repeat(_utf8 0xc3b7, 4), 0);
let $1= 10;
while ($1)
{
eval set group_concat_max_len= 1022 + $1;
--disable_result_log
select @x:=group_concat(x) from t1 group by y;
--enable_result_log
select @@group_concat_max_len, length(@x), char_length(@x), right(@x,12), right(HEX(@x),12);
dec $1;
}
drop table t1;
set group_concat_max_len=1024;
set names latin1;
#
# Bug#14169 type of group_concat() result changed to blob if tmp_table was used
#
......
......@@ -236,16 +236,56 @@ 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" and bug #7515 "from_unixtime(0) now
# returns NULL instead of the epoch". unix_timestamp() should return error
# for too big or negative argument. It should return Epoch value for zero
# argument since it seems that many user's rely on this fact.
# Tests for bug #6439 "unix_timestamp() function returns wrong datetime
# values for too big argument", bug #7515 "from_unixtime(0) now
# returns NULL instead of the epoch" and bug #9191
# "TIMESTAMP/from_unixtime() no longer accepts 2^31-1."
# unix_timestamp() should return error for too big or negative argument.
# It should return Epoch value for zero argument since it seems that many
# users rely on this fact, from_unixtime() should work with values
# up to INT_MAX32 because of the same reason.
#
select from_unixtime(-1);
select from_unixtime(2145916800);
# check for from_unixtime(2^31-1) and from_unixtime(2^31)
select from_unixtime(2147483647);
select from_unixtime(2147483648);
select from_unixtime(0);
#
# Some more tests for bug #9191 "TIMESTAMP/from_unixtime() no
# longer accepts 2^31-1". Here we test that from_unixtime and
# unix_timestamp are consistent, when working with boundary dates.
#
select unix_timestamp(from_unixtime(2147483647));
select unix_timestamp(from_unixtime(2147483648));
# check for invalid dates
# bad year
select unix_timestamp('2039-01-20 01:00:00');
select unix_timestamp('1968-01-20 01:00:00');
# bad month
select unix_timestamp('2038-02-10 01:00:00');
select unix_timestamp('1969-11-20 01:00:00');
# bad day
select unix_timestamp('2038-01-20 01:00:00');
select unix_timestamp('1969-12-30 01:00:00');
#
# Check negative shift (we subtract several days for boundary dates during
# conversion).
select unix_timestamp('2038-01-17 12:00:00');
#
# Check positive shift. (it happens only on
# platfroms with unsigned time_t, such as QNX)
#
select unix_timestamp('1970-01-01 03:00:01');
# check bad date, close to the boundary (we cut them off in the very end)
select unix_timestamp('2038-01-19 07:14:07');
#
# Test types from + INTERVAL
#
......
......@@ -70,4 +70,8 @@ show tables;
drop table t2, t4;
# End of 4.1 tests
disconnect con2;
disconnect con1;
connection default;
--echo End of 4.1 tests
-O max_allowed_packet=1024 -O net_buffer_length=1024
-O max_allowed_packet=1024 -O net_buffer_length=1024
#
# Check replication protocol packet size handling
# Bug#19402 SQL close to the size of the max_allowed_packet fails on slave
#
# max-out size db name
source include/master-slave.inc;
let $db= DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
disable_warnings;
eval drop database if exists $db;
enable_warnings;
eval create database $db;
connection master;
select @@net_buffer_length, @@max_allowed_packet;
disconnect master;
# alas, can't use eval here; if db name changed apply the change here
connect (master,localhost,root,,DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________);
connection master;
create table `t1` (`f1` LONGTEXT) ENGINE=MyISAM;
INSERT INTO `t1`(`f1`) VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1023');
save_master_pos;
connection slave;
sync_with_master;
eval select count(*) from `$db`.`t1` /* must be 1 */;
connection master;
eval drop database $db;
save_master_pos;
connection slave;
sync_with_master;
# End of tests
......@@ -52,11 +52,12 @@ INSERT INTO t1 (ts) VALUES ('2003-03-30 01:59:59'),
DROP TABLE t1;
#
# Test for fix for Bug#2523
# Test for fix for Bug#2523 Check that boundary dates are processed
# correctly.
#
select unix_timestamp('1970-01-01 01:00:00'),
unix_timestamp('1970-01-01 01:00:01'),
unix_timestamp('2038-01-01 00:59:59'),
unix_timestamp('2038-01-01 01:00:00');
unix_timestamp('2038-01-19 04:14:07'),
unix_timestamp('2038-01-19 04:14:08');
# End of 4.1 tests
......@@ -107,21 +107,21 @@ create table t1 (ts timestamp);
set time_zone='UTC';
insert into t1 values ('0000-00-00 00:00:00'),('1969-12-31 23:59:59'),
('1970-01-01 00:00:00'),('1970-01-01 00:00:01'),
('2037-12-31 23:59:59'),('2038-01-01 00:00:00');
('2038-01-19 03:14:07'),('2038-01-19 03:14:08');
select * from t1;
delete from t1;
# MET time zone has range shifted by one hour
set time_zone='MET';
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 00:30:00'),
('1970-01-01 01:00:00'),('1970-01-01 01:00:01'),
('2038-01-01 00:59:59'),('2038-01-01 01:00:00');
('2038-01-19 04:14:07'),('2038-01-19 04:14:08');
select * from t1;
delete from t1;
# same for +01:30 time zone
set time_zone='+01:30';
insert into t1 values ('0000-00-00 00:00:00'),('1970-01-01 01:00:00'),
('1970-01-01 01:30:00'),('1970-01-01 01:30:01'),
('2038-01-01 01:29:59'),('2038-01-01 01:30:00');
('2038-01-19 04:44:07'),('2038-01-19 04:44:08');
select * from t1;
drop table t1;
......@@ -171,8 +171,8 @@ select convert_tz('2003-10-26 01:00:00', 'MET', 'UTC');
select convert_tz('2003-10-26 02:00:00', 'MET', 'UTC');
select convert_tz('2003-10-26 02:59:59', 'MET', 'UTC');
select convert_tz('2003-10-26 04:00:00', 'MET', 'UTC');
select convert_tz('2038-01-01 00:59:59', 'MET', 'UTC');
select convert_tz('2038-01-01 01:00:00', 'MET', 'UTC');
select convert_tz('2038-01-19 04:14:07', 'MET', 'UTC');
select convert_tz('2038-01-19 04:14:08', 'MET', 'UTC');
select convert_tz('2103-01-01 04:00:00', 'MET', 'UTC');
# Let us test variable time zone argument
......
#
# Tests for time functions. The difference from func_time test is the
# timezone. In func_time it's GMT-3. In our case it's GMT+10
#
#
# Test for bug bug #9191 "TIMESTAMP/from_unixtime() no longer accepts 2^31-1"
#
select from_unixtime(0);
# check 0 boundary
select unix_timestamp('1969-12-31 14:00:01');
......@@ -4,4 +4,7 @@
*/
#ifdef DEFINE_CXA_PURE_VIRTUAL
extern "C" { int __cxa_pure_virtual() { return 0;} }
#else
/* Some compiler/linker combinations fail on files without exported symbols. */
extern "C" { int dummy_export_symbol() { return 0;} }
#endif
......@@ -224,6 +224,7 @@ $CP mysql-test/lib/*.pl $BASE/mysql-test/lib
$CP mysql-test/lib/*.sql $BASE/mysql-test/lib
$CP mysql-test/t/*.def $BASE/mysql-test/t
$CP mysql-test/include/*.inc $BASE/mysql-test/include
$CP mysql-test/include/*.test $BASE/mysql-test/include
$CP mysql-test/std_data/*.dat mysql-test/std_data/*.*001 \
mysql-test/std_data/*.cnf \
$BASE/mysql-test/std_data
......
......@@ -717,14 +717,27 @@ long calc_daynr(uint year,uint month,uint day)
RETURN VALUE
Time in UTC seconds since Unix Epoch representation.
*/
my_time_t
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
my_time_t
my_system_gmt_sec(const MYSQL_TIME *t_src, long *my_timezone,
bool *in_dst_time_gap)
{
uint loop;
time_t tmp;
time_t tmp= 0;
int shift= 0;
MYSQL_TIME tmp_time;
MYSQL_TIME *t= &tmp_time;
struct tm *l_time,tm_tmp;
long diff, current_timezone;
/*
Use temp variable to avoid trashing input data, which could happen in
case of shift required for boundary dates processing.
*/
memcpy(&tmp_time, t_src, sizeof(MYSQL_TIME));
if (!validate_timestamp_range(t))
return 0;
/*
Calculate the gmt time based on current time and timezone
The -1 on the end is to ensure that if have a date that exists twice
......@@ -738,13 +751,89 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
Note: this code assumes that our time_t estimation is not too far away
from real value (we assume that localtime_r(tmp) will return something
within 24 hrs from t) which is probably true for all current time zones.
Note2: For the dates, which have time_t representation close to
MAX_INT32 (efficient time_t limit for supported platforms), we should
do a small trick to avoid overflow. That is, convert the date, which is
two days earlier, and then add these days to the final value.
The same trick is done for the values close to 0 in time_t
representation for platfroms with unsigned time_t (QNX).
To be more verbose, here is a sample (extracted from the code below):
(calc_daynr(2038, 1, 19) - (long) days_at_timestart)*86400L + 4*3600L
would return -2147480896 because of the long type overflow. In result
we would get 1901 year in localtime_r(), which is an obvious error.
Alike problem raises with the dates close to Epoch. E.g.
(calc_daynr(1969, 12, 31) - (long) days_at_timestart)*86400L + 23*3600L
will give -3600.
On some platforms, (E.g. on QNX) time_t is unsigned and localtime(-3600)
wil give us a date around 2106 year. Which is no good.
Theoreticaly, there could be problems with the latter conversion:
there are at least two timezones, which had time switches near 1 Jan
of 1970 (because of political reasons). These are America/Hermosillo and
America/Mazatlan time zones. They changed their offset on
1970-01-01 08:00:00 UTC from UTC-8 to UTC-7. For these zones
the code below will give incorrect results for dates close to
1970-01-01, in the case OS takes into account these historical switches.
Luckily, it seems that we support only one platform with unsigned
time_t. It's QNX. And QNX does not support historical timezone data at all.
E.g. there are no /usr/share/zoneinfo/ files or any other mean to supply
historical information for localtime_r() etc. That is, the problem is not
relevant to QNX.
We are safe with shifts close to MAX_INT32, as there are no known
time switches on Jan 2038 yet :)
*/
tmp=(time_t) (((calc_daynr((uint) t->year,(uint) t->month,(uint) t->day) -
(long) days_at_timestart)*86400L + (long) t->hour*3600L +
(long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
3600);
current_timezone= my_time_zone;
if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && (t->day > 4))
{
/*
Below we will pass (uint) (t->day - shift) to calc_daynr.
As we don't want to get an overflow here, we will shift
only safe dates. That's why we have (t->day > 4) above.
*/
t->day-= 2;
shift= 2;
}
#ifdef TIME_T_UNSIGNED
else
{
/*
We can get 0 in time_t representaion only on 1969, 31 of Dec or on
1970, 1 of Jan. For both dates we use shift, which is added
to t->day in order to step out a bit from the border.
This is required for platforms, where time_t is unsigned.
As far as I know, among the platforms we support it's only QNX.
Note: the order of below if-statements is significant.
*/
if ((t->year == TIMESTAMP_MIN_YEAR + 1) && (t->month == 1)
&& (t->day <= 10))
{
t->day+= 2;
shift= -2;
}
if ((t->year == TIMESTAMP_MIN_YEAR) && (t->month == 12)
&& (t->day == 31))
{
t->year++;
t->month= 1;
t->day= 2;
shift= -2;
}
}
#endif
tmp= (time_t) (((calc_daynr((uint) t->year, (uint) t->month, (uint) t->day) -
(long) days_at_timestart)*86400L + (long) t->hour*3600L +
(long) (t->minute*60 + t->second)) + (time_t) my_time_zone -
3600);
current_timezone= my_time_zone;
localtime_r(&tmp,&tm_tmp);
l_time=&tm_tmp;
for (loop=0;
......@@ -796,7 +885,24 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
*in_dst_time_gap= 1;
}
*my_timezone= current_timezone;
/* shift back, if we were dealing with boundary dates */
tmp+= shift*86400L;
/*
This is possible for dates, which slightly exceed boundaries.
Conversion will pass ok for them, but we don't allow them.
First check will pass for platforms with signed time_t.
instruction above (tmp+= shift*86400L) could exceed
MAX_INT32 (== TIMESTAMP_MAX_VALUE) and overflow will happen.
So, tmp < TIMESTAMP_MIN_VALUE will be triggered. On platfroms
with unsigned time_t tmp+= shift*86400L might result in a number,
larger then TIMESTAMP_MAX_VALUE, so another check will work.
*/
if ((tmp < TIMESTAMP_MIN_VALUE) || (tmp > TIMESTAMP_MAX_VALUE))
tmp= 0;
end:
return (my_time_t) tmp;
} /* my_system_gmt_sec */
......
......@@ -1673,6 +1673,7 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
{
char buff[MAX_FIELD_WIDTH];
String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2;
uint old_length= item->result.length();
if (item->no_appended)
item->no_appended= FALSE;
......@@ -1711,8 +1712,22 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
/* stop if length of result more than group_concat_max_len */
if (item->result.length() > item->group_concat_max_len)
{
int well_formed_error;
CHARSET_INFO *cs= item->collation.collation;
const char *ptr= item->result.ptr();
uint add_length;
/*
It's ok to use item->result.length() as the fourth argument
as this is never used to limit the length of the data.
Cut is done with the third argument.
*/
add_length= cs->cset->well_formed_len(cs,
ptr + old_length,
ptr + item->group_concat_max_len,
item->result.length(),
&well_formed_error);
item->result.length(old_length + add_length);
item->count_cut_values++;
item->result.length(item->group_concat_max_len);
item->warning_for_row= TRUE;
return 1;
}
......@@ -1902,8 +1917,7 @@ bool Item_func_group_concat::add()
we can dump the row here in case of GROUP_CONCAT(DISTINCT...)
instead of doing tree traverse later.
*/
if (result.length() <= group_concat_max_len &&
!warning_for_row &&
if (!warning_for_row &&
(!tree_mode || (el->count == 1 && distinct && !arg_count_order)))
dump_leaf_key(table->record[0], 1, this);
......
......@@ -1931,15 +1931,10 @@ bool Item_func_convert_tz::get_date(TIME *ltime,
return 1;
}
/* Check if we in range where we treat datetime values as non-UTC */
if (ltime->year < TIMESTAMP_MAX_YEAR && ltime->year > TIMESTAMP_MIN_YEAR ||
ltime->year==TIMESTAMP_MAX_YEAR && ltime->month==1 && ltime->day==1 ||
ltime->year==TIMESTAMP_MIN_YEAR && ltime->month==12 && ltime->day==31)
{
my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, &not_used);
if (my_time_tmp >= TIMESTAMP_MIN_VALUE && my_time_tmp <= TIMESTAMP_MAX_VALUE)
to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
}
my_time_tmp= from_tz->TIME_to_gmt_sec(ltime, &not_used);
/* my_time_tmp is guranteed to be in the allowed range */
if (my_time_tmp)
to_tz->gmt_sec_to_TIME(ltime, my_time_tmp);
null_value= 0;
return 0;
......
......@@ -147,6 +147,14 @@ struct sql_ex_info
#define EXEC_LOAD_HEADER_LEN 4
#define DELETE_FILE_HEADER_LEN 4
/*
Max number of possible extra bytes in a replication event compared to a
packet (i.e. a query) sent from client to master.
*/
#define MAX_LOG_EVENT_HEADER (LOG_EVENT_HEADER_LEN + /* write_header */ \
QUERY_HEADER_LEN + /* write_data */ \
NAME_LEN + 1)
/*
Event header offsets;
these point to places inside the fixed header.
......
......@@ -144,12 +144,6 @@ MY_LOCALE *my_locale_by_name(const char *name);
/* Characters shown for the command in 'show processlist' */
#define PROCESS_LIST_WIDTH 100
/* Time handling defaults */
#define TIMESTAMP_MAX_YEAR 2038
#define YY_PART_YEAR 70
#define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1)
#define TIMESTAMP_MAX_VALUE 2145916799
#define TIMESTAMP_MIN_VALUE 1
#define PRECISION_FOR_DOUBLE 53
#define PRECISION_FOR_FLOAT 24
......
......@@ -2618,6 +2618,13 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO;
thd->host_or_ip= "";
my_net_init(&thd->net, 0);
/*
Adding MAX_LOG_EVENT_HEADER_LEN to the max_allowed_packet on all
slave threads, since a replication event can become this much larger
than the corresponding packet (query) sent from client to master.
*/
thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
+ MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */
thd->net.read_timeout = slave_net_timeout;
thd->master_access= ~(ulong)0;
thd->priv_user = 0;
......@@ -3143,16 +3150,24 @@ extern "C" pthread_handler_decl(handle_slave_io,arg)
sql_print_error("Slave I/O thread: error in mysql_init()");
goto err;
}
thd->proc_info = "Connecting to master";
// we can get killed during safe_connect
if (!safe_connect(thd, mysql, mi))
{
sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\
replication started in log '%s' at position %s", mi->user,
mi->host, mi->port,
IO_RPL_LOG_NAME,
llstr(mi->master_log_pos,llbuff));
mi->host, mi->port,
IO_RPL_LOG_NAME,
llstr(mi->master_log_pos,llbuff));
/*
Adding MAX_LOG_EVENT_HEADER_LEN to the max_packet_size on the I/O
thread, since a replication event can become this much larger than
the corresponding packet (query) sent from client to master.
*/
mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER;
}
else
{
sql_print_error("Slave I/O thread killed while connecting to master");
......
......@@ -420,6 +420,12 @@ impossible position";
goto err;
}
packet->set("\0", 1, &my_charset_bin);
/*
Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become
this larger than the corresponding packet (query) sent
from client to master.
*/
thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER;
while (!net->error && net->vio != 0 && !thd->killed)
{
......
......@@ -230,14 +230,11 @@ my_time_t TIME_to_timestamp(THD *thd, const TIME *t, bool *in_dst_time_gap)
*in_dst_time_gap= 0;
if (t->year < TIMESTAMP_MAX_YEAR && t->year > TIMESTAMP_MIN_YEAR ||
t->year == TIMESTAMP_MAX_YEAR && t->month == 1 && t->day == 1 ||
t->year == TIMESTAMP_MIN_YEAR && t->month == 12 && t->day == 31)
timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
if (timestamp)
{
thd->time_zone_used= 1;
timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap);
if (timestamp >= TIMESTAMP_MIN_VALUE && timestamp <= TIMESTAMP_MAX_VALUE)
return timestamp;
return timestamp;
}
/* If we are here we have range error. */
......
......@@ -885,9 +885,14 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp, bool *in_dst_time_gap)
my_time_t local_t;
uint saved_seconds;
uint i;
int shift= 0;
DBUG_ENTER("TIME_to_gmt_sec");
if (!validate_timestamp_range(t))
DBUG_RETURN(0);
/* We need this for correct leap seconds handling */
if (t->second < SECS_PER_MIN)
saved_seconds= 0;
......@@ -895,11 +900,29 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp, bool *in_dst_time_gap)
saved_seconds= t->second;
/*
NOTE If we want to convert full my_time_t range without MySQL
restrictions we should catch overflow here somehow.
NOTE: to convert full my_time_t range we do a shift of the
boundary dates here to avoid overflow of my_time_t.
We use alike approach in my_system_gmt_sec().
However in that function we also have to take into account
overflow near 0 on some platforms. That's because my_system_gmt_sec
uses localtime_r(), which doesn't work with negative values correctly
on platforms with unsigned time_t (QNX). Here we don't use localtime()
=> we negative values of local_t are ok.
*/
local_t= sec_since_epoch(t->year, t->month, t->day,
if ((t->year == TIMESTAMP_MAX_YEAR) && (t->month == 1) && t->day > 4)
{
/*
We will pass (t->day - shift) to sec_since_epoch(), and
want this value to be a positive number, so we shift
only dates > 4.01.2038 (to avoid owerflow).
*/
shift= 2;
}
local_t= sec_since_epoch(t->year, t->month, (t->day - shift),
t->hour, t->minute,
saved_seconds ? 0 : t->second);
......@@ -918,6 +941,22 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp, bool *in_dst_time_gap)
/* binary search for our range */
i= find_time_range(local_t, sp->revts, sp->revcnt);
/*
As there are no offset switches at the end of TIMESTAMP range,
we could simply check for overflow here (and don't need to bother
about DST gaps etc)
*/
if (shift)
{
if (local_t > (TIMESTAMP_MAX_VALUE - shift*86400L +
sp->revtis[i].rt_offset - saved_seconds))
{
DBUG_RETURN(0); /* my_time_t overflow */
}
else
local_t+= shift*86400L;
}
if (sp->revtis[i].rt_type)
{
/*
......@@ -927,10 +966,16 @@ TIME_to_gmt_sec(const TIME *t, const TIME_ZONE_INFO *sp, bool *in_dst_time_gap)
beginning of the gap.
*/
*in_dst_time_gap= 1;
DBUG_RETURN(sp->revts[i] - sp->revtis[i].rt_offset + saved_seconds);
local_t= sp->revts[i] - sp->revtis[i].rt_offset + saved_seconds;
}
else
DBUG_RETURN(local_t - sp->revtis[i].rt_offset + saved_seconds);
local_t= local_t - sp->revtis[i].rt_offset + saved_seconds;
/* check for TIMESTAMP_MAX_VALUE was already done above */
if (local_t < TIMESTAMP_MIN_VALUE)
local_t= 0;
DBUG_RETURN(local_t);
}
......@@ -1294,9 +1339,24 @@ Time_zone_offset::Time_zone_offset(long tz_offset_arg):
my_time_t
Time_zone_offset::TIME_to_gmt_sec(const TIME *t, bool *in_dst_time_gap) const
{
return sec_since_epoch(t->year, t->month, t->day,
t->hour, t->minute, t->second) -
offset;
my_time_t local_t;
/*
Check timestamp range.we have to do this as calling function relies on
us to make all validation checks here.
*/
if (!validate_timestamp_range(t))
return 0;
local_t= sec_since_epoch(t->year, t->month, t->day,
t->hour, t->minute, t->second) -
offset;
if (local_t >= TIMESTAMP_MIN_VALUE && local_t <= TIMESTAMP_MAX_VALUE)
return local_t;
/* range error*/
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment