summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBUILD/compile-pentium-valgrind-max1
-rw-r--r--VC++Files/libmysqld/libmysqld.dsp4
-rw-r--r--VC++Files/sql/mysqld.dsp20
-rw-r--r--VC++Files/sql/mysqldmax.dsp16
-rw-r--r--VC++Files/strings/strings.dsp4
-rw-r--r--include/m_ctype.h2
-rw-r--r--include/m_string.h1
-rw-r--r--include/mysqld_error.h9
-rw-r--r--include/sql_state.h2
-rw-r--r--libmysqld/Makefile.am2
-rw-r--r--mysql-test/mysql-test-run.sh6
-rw-r--r--mysql-test/r/ctype_latin1_de.result12
-rw-r--r--mysql-test/r/ctype_recoding.result4
-rw-r--r--mysql-test/r/date_formats.result436
-rw-r--r--mysql-test/r/func_compress.result2
-rw-r--r--mysql-test/r/rpl_temporary.result1
-rw-r--r--mysql-test/t/create.test22
-rw-r--r--mysql-test/t/ctype_latin1_de.test2
-rw-r--r--mysql-test/t/ctype_recoding.test4
-rw-r--r--mysql-test/t/date_formats-master.opt2
-rw-r--r--mysql-test/t/date_formats.test253
-rw-r--r--mysql-test/t/rpl_temporary-master.opt0
-rw-r--r--mysql-test/t/rpl_temporary.test8
-rw-r--r--mysql-test/t/symlink.test4
-rw-r--r--mysys/default.c3
-rw-r--r--sql/Makefile.am2
-rw-r--r--sql/derror.cc1
-rw-r--r--sql/field.cc159
-rw-r--r--sql/field.h11
-rw-r--r--sql/init.cc2
-rw-r--r--sql/item.cc63
-rw-r--r--sql/item.h29
-rw-r--r--sql/item_create.cc3
-rw-r--r--sql/item_func.cc15
-rw-r--r--sql/item_func.h4
-rw-r--r--sql/item_strfunc.h4
-rw-r--r--sql/item_timefunc.cc1046
-rw-r--r--sql/item_timefunc.h127
-rw-r--r--sql/mysql_priv.h45
-rw-r--r--sql/mysqld.cc127
-rw-r--r--sql/protocol.cc38
-rw-r--r--sql/set_var.cc238
-rw-r--r--sql/set_var.h46
-rw-r--r--sql/share/czech/errmsg.txt7
-rw-r--r--sql/share/danish/errmsg.txt7
-rw-r--r--sql/share/dutch/errmsg.txt7
-rw-r--r--sql/share/english/errmsg.txt19
-rw-r--r--sql/share/estonian/errmsg.txt7
-rw-r--r--sql/share/french/errmsg.txt7
-rw-r--r--sql/share/german/errmsg.txt7
-rw-r--r--sql/share/greek/errmsg.txt7
-rw-r--r--sql/share/hungarian/errmsg.txt7
-rw-r--r--sql/share/italian/errmsg.txt7
-rw-r--r--sql/share/japanese/errmsg.txt7
-rw-r--r--sql/share/korean/errmsg.txt7
-rw-r--r--sql/share/norwegian-ny/errmsg.txt7
-rw-r--r--sql/share/norwegian/errmsg.txt7
-rw-r--r--sql/share/polish/errmsg.txt7
-rw-r--r--sql/share/portuguese/errmsg.txt7
-rw-r--r--sql/share/romanian/errmsg.txt7
-rw-r--r--sql/share/russian/errmsg.txt7
-rw-r--r--sql/share/serbian/errmsg.txt7
-rw-r--r--sql/share/slovak/errmsg.txt7
-rw-r--r--sql/share/spanish/errmsg.txt7
-rw-r--r--sql/share/swedish/errmsg.txt7
-rw-r--r--sql/share/ukrainian/errmsg.txt7
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_class.cc12
-rw-r--r--sql/sql_class.h6
-rw-r--r--sql/sql_db.cc4
-rw-r--r--sql/sql_lex.cc78
-rw-r--r--sql/sql_parse.cc31
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_table.cc6
-rw-r--r--sql/sql_yacc.yy38
-rw-r--r--sql/strfunc.cc147
-rw-r--r--sql/structs.h47
-rw-r--r--sql/time.cc885
-rw-r--r--strings/Makefile.am7
-rw-r--r--strings/ctype-bin.c12
-rw-r--r--strings/my_vsnprintf.c24
81 files changed, 2628 insertions, 1627 deletions
diff --git a/BUILD/compile-pentium-valgrind-max b/BUILD/compile-pentium-valgrind-max
index f47061b95dd..d0e25fa2f40 100755
--- a/BUILD/compile-pentium-valgrind-max
+++ b/BUILD/compile-pentium-valgrind-max
@@ -14,6 +14,7 @@ extra_configs="$extra_configs --with-berkeley-db --with-innodb --without-isam --
if test -z "$just_print"
then
+ set +v
echo "\
******************************************************************************
Note that by default BUILD/compile-pentium-valgrind-max calls 'configure' with
diff --git a/VC++Files/libmysqld/libmysqld.dsp b/VC++Files/libmysqld/libmysqld.dsp
index 593c53a57ba..953761be297 100644
--- a/VC++Files/libmysqld/libmysqld.dsp
+++ b/VC++Files/libmysqld/libmysqld.dsp
@@ -446,6 +446,10 @@ SOURCE=..\strings\strcont.c
# End Source File
# Begin Source File
+SOURCE=..\sql\strfunc.cpp
+# End Source File
+# Begin Source File
+
SOURCE=..\strings\strinstr.c
# End Source File
# Begin Source File
diff --git a/VC++Files/sql/mysqld.dsp b/VC++Files/sql/mysqld.dsp
index f8724fb0b06..b8413a9a7ae 100644
--- a/VC++Files/sql/mysqld.dsp
+++ b/VC++Files/sql/mysqld.dsp
@@ -1253,6 +1253,26 @@ SOURCE=.\sql_yacc.cpp
# End Source File
# Begin Source File
+SOURCE=.\strfunc.cpp
+
+!IF "$(CFG)" == "mysqld - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max nt"
+
+!ELSEIF "$(CFG)" == "mysqld - Win32 Max"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
SOURCE=.\table.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/sql/mysqldmax.dsp b/VC++Files/sql/mysqldmax.dsp
index 24ea83159d9..a7ed1b918c7 100644
--- a/VC++Files/sql/mysqldmax.dsp
+++ b/VC++Files/sql/mysqldmax.dsp
@@ -945,6 +945,22 @@ SOURCE=.\sql_yacc.cpp
# End Source File
# Begin Source File
+SOURCE=.\strfunc.cpp
+
+!IF "$(CFG)" == "mysqldmax - Win32 Release"
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 Debug"
+
+# ADD CPP /G5
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "mysqldmax - Win32 nt"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
SOURCE=.\table.cpp
# End Source File
# Begin Source File
diff --git a/VC++Files/strings/strings.dsp b/VC++Files/strings/strings.dsp
index 038f460771d..4e43cc875c8 100644
--- a/VC++Files/strings/strings.dsp
+++ b/VC++Files/strings/strings.dsp
@@ -188,6 +188,10 @@ SOURCE=.\longlong2str.c
# End Source File
# Begin Source File
+SOURCE=.\my_strtoll10.c
+# End Source File
+# Begin Source File
+
SOURCE=.\my_vsnprintf.c
# End Source File
# Begin Source File
diff --git a/include/m_ctype.h b/include/m_ctype.h
index e344c434f81..d5e386bb8f3 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -86,7 +86,7 @@ enum my_lex_states
{
MY_LEX_START, MY_LEX_CHAR, MY_LEX_IDENT,
MY_LEX_IDENT_SEP, MY_LEX_IDENT_START,
- MY_LEX_FOUND_IDENT, MY_LEX_REAL, MY_LEX_HEX_NUMBER,
+ MY_LEX_REAL, MY_LEX_HEX_NUMBER,
MY_LEX_CMP_OP, MY_LEX_LONG_CMP_OP, MY_LEX_STRING, MY_LEX_COMMENT, MY_LEX_END,
MY_LEX_OPERATOR_OR_IDENT, MY_LEX_NUMBER_IDENT, MY_LEX_INT_OR_REAL,
MY_LEX_REAL_OR_POINT, MY_LEX_BOOL, MY_LEX_EOL, MY_LEX_ESCAPE,
diff --git a/include/m_string.h b/include/m_string.h
index 062d0b4cf65..d72342fb3c1 100644
--- a/include/m_string.h
+++ b/include/m_string.h
@@ -232,6 +232,7 @@ extern char *int2str(long val,char *dst,int radix);
extern char *int10_to_str(long val,char *dst,int radix);
extern char *str2int(const char *src,int radix,long lower,long upper,
long *val);
+longlong my_strtoll10(const char *nptr, char **endptr, int *error);
#if SIZEOF_LONG == SIZEOF_LONG_LONG
#define longlong2str(A,B,C) int2str((A),(B),(C))
#define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C))
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index 53714505fc2..59eeef86998 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -295,5 +295,10 @@
#define ER_BAD_SLAVE_UNTIL_COND 1276
#define ER_MISSING_SKIP_SLAVE 1277
#define ER_UNTIL_COND_IGNORED 1278
-#define ER_WRONG_INDEX_NAME 1279
-#define ER_ERROR_MESSAGES 280
+#define ER_WRONG_NAME 1279
+#define ER_TABLE 1280
+#define ER_DATABASE 1281
+#define ER_COLUMN 1282
+#define ER_INDEX 1283
+#define ER_CATALOG 1284
+#define ER_ERROR_MESSAGES 285
diff --git a/include/sql_state.h b/include/sql_state.h
index 222636d3bec..d55fb137e27 100644
--- a/include/sql_state.h
+++ b/include/sql_state.h
@@ -159,4 +159,4 @@ ER_WARN_TOO_MANY_RECORDS, "01000", "",
ER_WARN_NULL_TO_NOTNULL, "01000", "",
ER_WARN_DATA_OUT_OF_RANGE, "01000", "",
ER_WARN_DATA_TRUNCATED, "01000", "",
-ER_WRONG_INDEX_NAME, "42000", "",
+ER_WRONG_NAME, "42000", "",
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index 09b03bce79a..7e04f53e9ff 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -38,7 +38,7 @@ libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c
noinst_HEADERS = embedded_priv.h
-sqlsources = derror.cc field.cc field_conv.cc filesort.cc \
+sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
ha_innodb.cc ha_berkeley.cc ha_heap.cc ha_isam.cc ha_isammrg.cc \
ha_myisam.cc ha_myisammrg.cc handler.cc sql_handler.cc \
hostname.cc init.cc password.c \
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index b7e39549411..90e15417c1c 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -392,7 +392,7 @@ SLAVE_MYLOG="$MYSQL_TEST_DIR/var/log/slave.log"
SLAVE_MYERR="$MYSQL_TEST_DIR/var/log/slave.err"
CURRENT_TEST="$MYSQL_TEST_DIR/var/log/current_test"
-SMALL_SERVER="-O key_buffer_size=1M -O sort_buffer=256K -O max_heap_table_size=1M"
+SMALL_SERVER="--key_buffer_size=1M --sort_buffer=256K --max_heap_table_size=1M"
export MASTER_MYPORT
export SLAVE_MYPORT
@@ -793,13 +793,13 @@ manager_launch()
ident=$1
shift
if [ $USE_MANAGER = 0 ] ; then
- $@ >> $CUR_MYERR 2>&1 &
+ $@ >> $CUR_MYERR 2>&1 &
sleep 2 #hack
return
fi
$MYSQL_MANAGER_CLIENT $MANAGER_QUIET_OPT --user=$MYSQL_MANAGER_USER \
--password=$MYSQL_MANAGER_PW --port=$MYSQL_MANAGER_PORT <<EOF
-def_exec $ident $@
+def_exec $ident "$@"
set_exec_stdout $ident $CUR_MYERR
set_exec_stderr $ident $CUR_MYERR
set_exec_con $ident root localhost $CUR_MYSOCK
diff --git a/mysql-test/r/ctype_latin1_de.result b/mysql-test/r/ctype_latin1_de.result
index 3db2f3d5519..07ea97258d9 100644
--- a/mysql-test/r/ctype_latin1_de.result
+++ b/mysql-test/r/ctype_latin1_de.result
@@ -219,6 +219,13 @@ a
test
drop table t1;
create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `word` varchar(255) collate latin1_german2_ci NOT NULL default '',
+ `word2` varchar(255) collate latin1_german2_ci NOT NULL default '',
+ KEY `word` (`word`)
+) TYPE=MyISAM CHARSET=latin1 COLLATE=latin1_german2_ci
insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae');
update t1 set word2=word;
select word, word=binary 0xdf as t from t1 having t > 0;
@@ -273,6 +280,11 @@ drop table t1;
CREATE TABLE t1 (
s1 CHAR(5) CHARACTER SET latin1 COLLATE latin1_german2_ci
);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `s1` char(5) collate latin1_german2_ci default NULL
+) TYPE=MyISAM CHARSET=latin1 COLLATE=latin1_german2_ci
INSERT INTO t1 VALUES ('Ü');
INSERT INTO t1 VALUES ('ue');
SELECT DISTINCT s1 FROM t1;
diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result
index 5a53c1db2e1..1fe07692290 100644
--- a/mysql-test/r/ctype_recoding.result
+++ b/mysql-test/r/ctype_recoding.result
@@ -1,5 +1,5 @@
SET CHARACTER SET koi8r;
-DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ;
+DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ, t1;
SET CHARACTER SET koi8r;
CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp1251) SELECT _koi8r'ÐÒÏÂÁ' AS a;
SHOW CREATE TABLE t1;
@@ -14,7 +14,7 @@ SELECT HEX(a) FROM t1;
HEX(a)
EFF0EEE1E0
DROP TABLE t1;
-CREATE TABLE ÔÁÂÌÉÃÁ
+CREATE TABLE `ÔÁÂÌÉÃÁ`
(
ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÐÏÌÑ"
) COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÔÁÂÌÉÃÙ";
diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result
index 590a1d6904b..c2fbbca190f 100644
--- a/mysql-test/r/date_formats.result
+++ b/mysql-test/r/date_formats.result
@@ -1,151 +1,315 @@
+drop table if exists t1;
+Warnings:
+Note 1051 Unknown table 't1'
SHOW GLOBAL VARIABLES LIKE "%_format%";
Variable_name Value
date_format %d.%m.%Y
-datetime_format %Y/%d/%m-%H:%i:%s
+datetime_format %Y-%m-%d %H:%i:%s
default_week_format 0
time_format %H.%i.%s
SHOW SESSION VARIABLES LIKE "%_format%";
Variable_name Value
date_format %d.%m.%Y
-datetime_format %Y/%d/%m-%H:%i:%s
+datetime_format %Y-%m-%d %H:%i:%s
default_week_format 0
time_format %H.%i.%s
-SET date_format="%d.%m.%Y";
-select CAST("01.01.2001" as DATE) as a;
-a
-01.01.2001
-SET datetime_format="%d.%m.%Y %H.%i.%s";
-select CAST("01.01.2001 05.12.06" as DATETIME) as a;
-a
-01.01.2001 05.12.06
-SET time_format="%H.%i.%s";
-select CAST("05.12.06" as TIME) as a;
-a
-05.12.06
-SET datetime_format="%d.%m.%Y %h:%i:%s %p";
-select CAST("01.01.2001 05:12:06AM" as DATETIME) as a;
-a
-01.01.2001 05:12:06 AM
-select CAST("01.01.2001 05:12:06 PM" as DATETIME) as a;
-a
-01.01.2001 05:12:06 PM
-SET time_format="%h:%i:%s %p";
-select CAST("05:12:06 AM" as TIME) as a;
-a
-05:12:06 AM
-select CAST("05:12:06.1234PM" as TIME) as a;
-a
-05:12:06.001234 PM
-SET time_format="%h.%i.%s %p";
-SET date_format='%d.%m.%y';
-SET datetime_format="%d.%m.%y %h.%i.%s %p";
-select CAST("12-12-06" as DATE) as a;
-a
-12.12.06
-select adddate("01.01.97 11.59.59.000001 PM", 10);
-adddate("01.01.97 11.59.59.000001 PM", 10)
-11.01.97 11.59.59.000001 PM
-select datediff("31.12.97 11.59:59.000001 PM","01.01.98");
-datediff("31.12.97 11.59:59.000001 PM","01.01.98")
--1
-select weekofyear("31.11.97 11:59:59.000001 PM");
-weekofyear("31.11.97 11:59:59.000001 PM")
-49
-select makedate(1997,1);
-makedate(1997,1)
-01.01.97
-select addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002");
-addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002")
-02.01.98 01.01.01.000001 AM
-select maketime(23,11,12);
-maketime(23,11,12)
-11.11.12 PM
-select timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM");
-timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM")
-8795.59.59.999999 PM
-SET time_format="%H%i%s";
-SET time_format="%h%i%s";
-ERROR HY000: Unknown error
+SET time_format='%H%i%s';
+SET time_format='%H:%i:%s.%f';
+SET time_format='%h-%i-%s.%f%p';
+SET time_format='%h:%i:%s.%f %p';
+SET time_format='%h:%i:%s%p';
+SET date_format='%Y%m%d';
+SET date_format='%Y.%m.%d';
+SET date_format='%d.%m.%Y';
+SET date_format='%m-%d-%Y';
+set datetime_format= '%Y%m%d%H%i%s';
+set datetime_format= '%Y-%m-%d %H:%i:%s';
+set datetime_format= '%m-%d-%y %H:%i:%s.%f';
+set datetime_format= '%d-%m-%Y %h:%i:%s%p';
+set datetime_format= '%H:%i:%s %Y-%m-%d';
+set datetime_format= '%H:%i:%s.%f %m-%d-%Y';
+set datetime_format= '%h:%i:%s %p %Y-%m-%d';
+set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d';
+SHOW SESSION VARIABLES LIKE "%format";
+Variable_name Value
+date_format %m-%d-%Y
+datetime_format %h:%i:%s.%f %p %Y-%m-%d
+default_week_format 0
+time_format %h:%i:%s%p
+SET time_format='%h:%i:%s';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s'
+SET time_format='%H %i:%s';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%H %i:%s'
+SET time_format='%H::%i:%s';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%H::%i:%s'
+SET time_format='%H:%i:%s%f';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i:%s%f'
+SET time_format='%H:%i.%f:%s';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i.%f:%s'
+SET time_format='%H:%i:%s%p';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i:%s%p'
+SET time_format='%h:%i:%s.%f %p %Y-%m-%d';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%h:%i:%s.%f %p %Y-%m-%d'
+SET time_format='%H%i%s.%f';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%H%i%s.%f'
+SET time_format='%H:%i-%s.%f';
+ERROR 42000: Variable 'time_format' can't be set to the value of '%H:%i-%s.%f'
SET date_format='%d.%m.%d';
-ERROR HY000: Unknown error
-SET datetime_format="%d.%m.%y %h.%i.%s";
-ERROR HY000: Unknown error
+ERROR 42000: Variable 'date_format' can't be set to the value of '%d.%m.%d'
+SET datetime_format='%h.%m.%y %d.%i.%s';
+ERROR 42000: Variable 'datetime_format' can't be set to the value of '%h.%m.%y %d.%i.%s'
+set datetime_format= '%H:%i:%s.%f %p %Y-%m-%d';
+ERROR 42000: Variable 'datetime_format' can't be set to the value of '%H:%i:%s.%f %p %Y-%m-%d'
+set GLOBAL datetime_format= '%H:%i:%s %Y-%m-%d';
+SET SESSION datetime_format=default;
+select @@global.datetime_format, @@session.datetime_format;
+@@global.datetime_format @@session.datetime_format
+%H:%i:%s %Y-%m-%d %H:%i:%s %Y-%m-%d
+SET GLOBAL datetime_format=default;
+SET SESSION datetime_format=default;
+select @@global.datetime_format, @@session.datetime_format;
+@@global.datetime_format @@session.datetime_format
+%Y-%m-%d %H:%i:%s %Y-%m-%d %H:%i:%s
SET GLOBAL date_format=default;
-SHOW GLOBAL VARIABLES LIKE "date_format%";
-Variable_name Value
-date_format %d.%m.%Y
SET GLOBAL time_format=default;
-SHOW GLOBAL VARIABLES LIKE "time_format%";
-Variable_name Value
-time_format %H.%i.%s
SET GLOBAL datetime_format=default;
-SHOW GLOBAL VARIABLES LIKE "datetime_format%";
-Variable_name Value
-datetime_format %Y/%d/%m-%H:%i:%s
-SET date_format=default;
-SHOW SESSION VARIABLES LIKE "date_format%";
-Variable_name Value
-date_format %d.%m.%Y
SET time_format=default;
-SHOW SESSION VARIABLES LIKE "time_format%";
-Variable_name Value
-time_format %H.%i.%s
+SET date_format=default;
SET datetime_format=default;
-SHOW SESSION VARIABLES LIKE "datetime_format%";
-Variable_name Value
-datetime_format %Y/%d/%m-%H:%i:%s
-SET time_format='%i:%s:%H';
-select cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME);
-cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME)
-59:59:12
-SET GLOBAL date_format='%Y-%m-%d';
-SET GLOBAL time_format='%H:%i:%s';
-SET GLOBAL datetime_format='%Y-%m-%d %H:%i:%s';
-SET date_format='%Y-%m-%d';
-SET time_format='%H:%i:%s';
-SET datetime_format='%Y-%m-%d %H:%i:%s';
-select str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S");
-str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S")
-2001-01-15 12:59:59
-select str_to_date("15 September 2001", "%d %M %Y");
-str_to_date("15 September 2001", "%d %M %Y")
-2001-09-15 00:00:00
-select str_to_date("15 Septembeb 2001", "%d %M %Y");
-str_to_date("15 Septembeb 2001", "%d %M %Y")
-NULL
-select str_to_date("15 MAY 2001", "%d %b %Y");
-str_to_date("15 MAY 2001", "%d %b %Y")
-2001-05-15 00:00:00
-select str_to_date("Sunday 15 MAY 2001", "%W %d %b %Y");
-str_to_date("Sunday 15 MAY 2001", "%W %d %b %Y")
-2001-05-15 00:00:00
-select str_to_date("Sundai 15 MAY 2001", "%W %d %b %Y");
-str_to_date("Sundai 15 MAY 2001", "%W %d %b %Y")
-NULL
-select str_to_date("Sundai 15 MA", "%W %d %b %Y");
-str_to_date("Sundai 15 MA", "%W %d %b %Y")
-NULL
-select str_to_date("Tuesday 52 2001", "%W %V %X");
-str_to_date("Tuesday 52 2001", "%W %V %X")
-NULL
-select str_to_date("Sunday 01 2001", "%W %V %X");
-str_to_date("Sunday 01 2001", "%W %V %X")
-NULL
-select str_to_date("Tuesday 00 2002", "%W %U %Y");
-str_to_date("Tuesday 00 2002", "%W %U %Y")
-2002-01-01 00:00:00
-select str_to_date("Thursday 53 1998", "%W %u %Y");
-str_to_date("Thursday 53 1998", "%W %u %Y")
-1998-12-31 00:00:00
-select str_to_date("15-01-2001", "%d-%m-%Y %H:%i:%S");
-str_to_date("15-01-2001", "%d-%m-%Y %H:%i:%S")
-2001-01-15 00:00:00
-select str_to_date("15-01-20", "%d-%m-%Y");
-str_to_date("15-01-20", "%d-%m-%Y")
-NULL
-select str_to_date("15-2001-1", "%d-%Y-%c");
-str_to_date("15-2001-1", "%d-%Y-%c")
-2001-01-15 00:00:00
+select str_to_date(concat('15-01-2001',' 2:59:58.999'),
+concat('%d-%m-%Y',' ','%H:%i:%s.%f'));
+str_to_date(concat('15-01-2001',' 2:59:58.999'),
+concat('%d-%m-%Y',' ','%H:%i:%s.%f'))
+2001-01-15 02:59:58.000999
+create table t1 (date char(30), format char(30) not null);
+insert into t1 values
+('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'),
+('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S'),
+('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'),
+('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'),
+('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'),
+('2003-01-02 12:11:12.12345 am', '%Y-%m-%d %h:%i:%S.%f%p'),
+('2003-01-02 11:11:12Pm', '%Y-%m-%d %h:%i:%S%p'),
+('10:20:10', '%H:%i:%s'),
+('10:20:10', '%h:%i:%s.%f'),
+('10:20:10AM', '%h:%i:%s%p'),
+('10:20:10.44AM', '%h:%i:%s.%f%p'),
+('15-01-2001 12:59:58', '%d-%m-%Y %H:%i:%S'),
+('15 September 2001', '%d %M %Y'),
+('15 SEPTEMB 2001', '%d %M %Y'),
+('15 MAY 2001', '%d %b %Y'),
+('Sunday 15 MAY 2001', '%W %d %b %Y'),
+('Sund 15 MAY 2001', '%W %d %b %Y'),
+('Tuesday 00 2002', '%W %U %Y'),
+('Thursday 53 1998', '%W %u %Y'),
+('15-01-2001', '%d-%m-%Y %H:%i:%S'),
+('15-01-20', '%d-%m-%y'),
+('15-2001-1', '%d-%Y-%c');
+select date,format,str_to_date(date, format) as str_to_date from t1;
+date format str_to_date
+2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02
+2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345
+2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12
+10:20:10 %H:%i:%s 0000-00-00 10:20:10
+10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10
+10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10
+10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044
+15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58
+15 September 2001 %d %M %Y 2001-09-15 00:00:00
+15 SEPTEMB 2001 %d %M %Y 2001-01-15 00:00:00
+15 MAY 2001 %d %b %Y 2001-05-15 00:00:00
+Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00
+Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00
+Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00
+Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00
+15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00
+15-01-20 %d-%m-%y 2020-01-15 00:00:00
+15-2001-1 %d-%Y-%c 2001-01-15 00:00:00
+select date,format,concat('',str_to_date(date, format)) as con from t1;
+date format con
+2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02
+2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345
+2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12
+10:20:10 %H:%i:%s 0000-00-00 10:20:10
+10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10
+10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10
+10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044
+15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58
+15 September 2001 %d %M %Y 2001-09-15 00:00:00
+15 SEPTEMB 2001 %d %M %Y 2001-01-15 00:00:00
+15 MAY 2001 %d %b %Y 2001-05-15 00:00:00
+Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00
+Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00
+Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00
+Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00
+15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00
+15-01-20 %d-%m-%y 2020-01-15 00:00:00
+15-2001-1 %d-%Y-%c 2001-01-15 00:00:00
+select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1;
+date format datetime
+2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02 10:11:12
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02 08:11:02
+2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02 22:11:12
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 01:11:12.012345
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02 02:11:12.012345
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02 00:11:12.012345
+2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02 23:11:12
+10:20:10 %H:%i:%s 0000-00-00 10:20:10
+10:20:10 %h:%i:%s.%f 0000-00-00 10:20:10
+10:20:10AM %h:%i:%s%p 0000-00-00 10:20:10
+10:20:10.44AM %h:%i:%s.%f%p 0000-00-00 10:20:10.000044
+15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15 12:59:58
+15 September 2001 %d %M %Y 2001-09-15 00:00:00
+15 SEPTEMB 2001 %d %M %Y 2001-01-15 00:00:00
+15 MAY 2001 %d %b %Y 2001-05-15 00:00:00
+Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00
+Sund 15 MAY 2001 %W %d %b %Y 2001-05-15 00:00:00
+Tuesday 00 2002 %W %U %Y 2002-01-01 00:00:00
+Thursday 53 1998 %W %u %Y 1998-12-31 00:00:00
+15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15 00:00:00
+15-01-20 %d-%m-%y 2020-01-15 00:00:00
+15-2001-1 %d-%Y-%c 2001-01-15 00:00:00
+select date,format,DATE(str_to_date(date, format)) as date2 from t1;
+date format date2
+2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 2003-01-02
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 2003-01-02
+2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 2003-01-02
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 2003-01-02
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 2003-01-02
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 2003-01-02
+2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 2003-01-02
+10:20:10 %H:%i:%s 0000-00-00
+10:20:10 %h:%i:%s.%f 0000-00-00
+10:20:10AM %h:%i:%s%p 0000-00-00
+10:20:10.44AM %h:%i:%s.%f%p 0000-00-00
+15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 2001-01-15
+15 September 2001 %d %M %Y 2001-09-15
+15 SEPTEMB 2001 %d %M %Y 2001-01-15
+15 MAY 2001 %d %b %Y 2001-05-15
+Sunday 15 MAY 2001 %W %d %b %Y 2001-05-15
+Sund 15 MAY 2001 %W %d %b %Y 2001-05-15
+Tuesday 00 2002 %W %U %Y 2002-01-01
+Thursday 53 1998 %W %u %Y 1998-12-31
+15-01-2001 %d-%m-%Y %H:%i:%S 2001-01-15
+15-01-20 %d-%m-%y 2020-01-15
+15-2001-1 %d-%Y-%c 2001-01-15
+select date,format,TIME(str_to_date(date, format)) as time from t1;
+date format time
+2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 08:11:02
+2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.012345
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.012345
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.012345
+2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12
+10:20:10 %H:%i:%s 10:20:10
+10:20:10 %h:%i:%s.%f 10:20:10
+10:20:10AM %h:%i:%s%p 10:20:10
+10:20:10.44AM %h:%i:%s.%f%p 10:20:10.000044
+15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58
+15 September 2001 %d %M %Y 00:00:00
+15 SEPTEMB 2001 %d %M %Y 00:00:00
+15 MAY 2001 %d %b %Y 00:00:00
+Sunday 15 MAY 2001 %W %d %b %Y 00:00:00
+Sund 15 MAY 2001 %W %d %b %Y 00:00:00
+Tuesday 00 2002 %W %U %Y 00:00:00
+Thursday 53 1998 %W %u %Y 00:00:00
+15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00
+15-01-20 %d-%m-%y 00:00:00
+15-2001-1 %d-%Y-%c 00:00:00
+select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1;
+date format time2
+2003-01-02 10:11:12 %Y-%m-%d %H:%i:%S 10:11:12
+03-01-02 8:11:2.123456 %y-%m-%d %H:%i:%S 08:11:02
+2003-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 22:11:12
+2003-01-02 01:11:12.12345AM %Y-%m-%d %h:%i:%S.%f%p 01:11:12.012345
+2003-01-02 02:11:12.12345AM %Y-%m-%d %h:%i:%S.%f %p 02:11:12.012345
+2003-01-02 12:11:12.12345 am %Y-%m-%d %h:%i:%S.%f%p 00:11:12.012345
+2003-01-02 11:11:12Pm %Y-%m-%d %h:%i:%S%p 23:11:12
+10:20:10 %H:%i:%s 10:20:10
+10:20:10 %h:%i:%s.%f 10:20:10
+10:20:10AM %h:%i:%s%p 10:20:10
+10:20:10.44AM %h:%i:%s.%f%p 10:20:10.000044
+15-01-2001 12:59:58 %d-%m-%Y %H:%i:%S 12:59:58
+15 September 2001 %d %M %Y 00:00:00
+15 SEPTEMB 2001 %d %M %Y 00:00:00
+15 MAY 2001 %d %b %Y 00:00:00
+Sunday 15 MAY 2001 %W %d %b %Y 00:00:00
+Sund 15 MAY 2001 %W %d %b %Y 00:00:00
+Tuesday 00 2002 %W %U %Y 00:00:00
+Thursday 53 1998 %W %u %Y 00:00:00
+15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00
+15-01-20 %d-%m-%y 00:00:00
+15-2001-1 %d-%Y-%c 00:00:00
+truncate table t1;
+insert into t1 values
+('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'),
+('2003-01-02 10:11:12.123456', '%Y-%m-%d %h:%i:%S %p'),
+('2003-01-02 10:11:12AM', '%Y-%m-%d %h:%i:%S.%f %p'),
+('2003-01-02 10:11:12AN', '%Y-%m-%d %h:%i:%S%p'),
+('2003-01-02 10:11:12 PM', '%y-%m-%d %H:%i:%S %p'),
+('10:20:10AM', '%H:%i:%s%p'),
+('15 Septembei 2001', '%d %M %Y'),
+('15 Ju 2001', '%d %M %Y'),
+('Sund 15 MA', '%W %d %b %Y'),
+('Sunday 01 2001', '%W %V %X'),
+('Thursdai 12 1998', '%W %u %Y'),
+(NULL, get_format(DATE,'USA')),
+('Tuesday 52 2001', '%W %V %X');
+select date,format,str_to_date(date, format) as str_to_date from t1;
+date format str_to_date
+2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL
+2003-01-02 10:11:12.123456 %Y-%m-%d %h:%i:%S %p NULL
+2003-01-02 10:11:12AM %Y-%m-%d %h:%i:%S.%f %p NULL
+2003-01-02 10:11:12AN %Y-%m-%d %h:%i:%S%p NULL
+2003-01-02 10:11:12 PM %y-%m-%d %H:%i:%S %p NULL
+10:20:10AM %H:%i:%s%p NULL
+15 Septembei 2001 %d %M %Y NULL
+15 Ju 2001 %d %M %Y NULL
+Sund 15 MA %W %d %b %Y NULL
+Sunday 01 2001 %W %V %X NULL
+Thursdai 12 1998 %W %u %Y NULL
+NULL %m.%d.%Y NULL
+Tuesday 52 2001 %W %V %X NULL
+select date,format,concat(str_to_date(date, format),'') as con from t1;
+date format con
+2003-01-02 10:11:12 PM %Y-%m-%d %H:%i:%S %p NULL
+2003-01-02 10:11:12.123456 %Y-%m-%d %h:%i:%S %p NULL
+2003-01-02 10:11:12AM %Y-%m-%d %h:%i:%S.%f %p NULL
+2003-01-02 10:11:12AN %Y-%m-%d %h:%i:%S%p NULL
+2003-01-02 10:11:12 PM %y-%m-%d %H:%i:%S %p NULL
+10:20:10AM %H:%i:%s%p NULL
+15 Septembei 2001 %d %M %Y NULL
+15 Ju 2001 %d %M %Y NULL
+Sund 15 MA %W %d %b %Y NULL
+Sunday 01 2001 %W %V %X NULL
+Thursdai 12 1998 %W %u %Y NULL
+NULL %m.%d.%Y NULL
+Tuesday 52 2001 %W %V %X NULL
+truncate table t1;
+insert into t1 values
+('10:20:10AM', '%h:%i:%s'),
+('2003-01-02 10:11:12', '%Y-%m-%d %h:%i:%S'),
+('03-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p');
+select date,format,str_to_date(date, format) as str_to_date from t1;
+date format str_to_date
+10:20:10AM %h:%i:%s 0000-00-00 10:20:10
+2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12
+03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 0003-01-02 22:11:12
+select date,format,concat(str_to_date(date, format),'') as con from t1;
+date format con
+10:20:10AM %h:%i:%s 0000-00-00 10:20:10
+2003-01-02 10:11:12 %Y-%m-%d %h:%i:%S 2003-01-02 10:11:12
+03-01-02 10:11:12 PM %Y-%m-%d %h:%i:%S %p 0003-01-02 22:11:12
+drop table t1;
select get_format(DATE, 'USA') as a;
a
%m.%d.%Y
@@ -154,4 +318,10 @@ a
%H%i%s
select get_format(DATETIME, 'eur') as a;
a
-%Y-%m-%d-%H.%i.%s
+%Y-%m-%d %H.%i.%s
+select get_format(DATE, 'TEST') as a;
+a
+NULL
+select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA'));
+str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA'))
+NULL
diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result
index 85842f28e64..08906a54c04 100644
--- a/mysql-test/r/func_compress.result
+++ b/mysql-test/r/func_compress.result
@@ -55,6 +55,6 @@ NULL
50000
NULL
Warnings:
-Error 1258 Z_DATA_ERROR: Input data was corrupted for zlib
+Error 1258 ZLIB: Input data was corrupted for zlib
Error 1255 Too big size of uncompressed data. The maximum size is 1048576. (probably, length of uncompressed data was corrupted)
drop table t1;
diff --git a/mysql-test/r/rpl_temporary.result b/mysql-test/r/rpl_temporary.result
index cf2b8814047..e7b64066c37 100644
--- a/mysql-test/r/rpl_temporary.result
+++ b/mysql-test/r/rpl_temporary.result
@@ -74,3 +74,4 @@ f
5
7
drop table t1,t2;
+create temporary table t3 (f int);
diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test
index 059808161a3..cec7dd17e6d 100644
--- a/mysql-test/t/create.test
+++ b/mysql-test/t/create.test
@@ -40,9 +40,9 @@ create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null
-- error 1044,1
create table not_existing_database.test (a int);
---error 1103
+--error 1279
create table `a/a` (a int);
---error 1103
+--error 1279
create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int);
--error 1059
create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int);
@@ -66,11 +66,11 @@ create table test_$1.test2$ (a int);
drop table test_$1.test2$;
drop database test_$1;
---error 1103
+--error 1279
create table `` (a int);
---error 1103
+--error 1279
drop table if exists ``;
---error 1166
+--error 1279
create table t1 (`` int);
--error 1279
create table t1 (i int, index `` (i));
@@ -254,12 +254,16 @@ create table t2 like t3;
show create table t2;
select * from t2;
create table t3 like t1;
-!$1050 create table t3 like test_$1.t3;
+--error 1050
+create table t3 like test_$1.t3;
--error 1044,1
create table non_existing_database.t1 like t1;
-!$1051 create table t3 like non_existing_table;
-!$1050 create temporary table t3 like t1;
-!$1103 create table t3 like `a/a`;
+--error 1051
+create table t3 like non_existing_table;
+--error 1050
+create temporary table t3 like t1;
+--error 1279
+create table t3 like `a/a`;
drop table t1, t2, t3;
drop table t3;
drop database test_$1;
diff --git a/mysql-test/t/ctype_latin1_de.test b/mysql-test/t/ctype_latin1_de.test
index 52ee227b011..a5d0c29baf6 100644
--- a/mysql-test/t/ctype_latin1_de.test
+++ b/mysql-test/t/ctype_latin1_de.test
@@ -64,6 +64,7 @@ drop table t1;
# The below checks both binary and character comparisons.
#
create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word));
+show create table t1;
insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae');
update t1 set word2=word;
select word, word=binary 0xdf as t from t1 having t > 0;
@@ -85,6 +86,7 @@ drop table t1;
CREATE TABLE t1 (
s1 CHAR(5) CHARACTER SET latin1 COLLATE latin1_german2_ci
);
+show create table t1;
INSERT INTO t1 VALUES ('Ü');
INSERT INTO t1 VALUES ('ue');
SELECT DISTINCT s1 FROM t1;
diff --git a/mysql-test/t/ctype_recoding.test b/mysql-test/t/ctype_recoding.test
index 325a8f075ed..2f08e021df2 100644
--- a/mysql-test/t/ctype_recoding.test
+++ b/mysql-test/t/ctype_recoding.test
@@ -1,7 +1,7 @@
SET CHARACTER SET koi8r;
--disable_warnings
-DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ;
+DROP TABLE IF EXISTS ÔÁÂÌÉÃÁ, t1;
--enable_warnings
SET CHARACTER SET koi8r;
@@ -11,7 +11,7 @@ SELECT a FROM t1;
SELECT HEX(a) FROM t1;
DROP TABLE t1;
-CREATE TABLE ÔÁÂÌÉÃÁ
+CREATE TABLE `ÔÁÂÌÉÃÁ`
(
ÐÏÌÅ CHAR(32) CHARACTER SET koi8r NOT NULL COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÐÏÌÑ"
) COMMENT "ËÏÍÍÅÎÔÁÒÉÊ ÔÁÂÌÉÃÙ";
diff --git a/mysql-test/t/date_formats-master.opt b/mysql-test/t/date_formats-master.opt
index 7977a601dd7..ab243fe729c 100644
--- a/mysql-test/t/date_formats-master.opt
+++ b/mysql-test/t/date_formats-master.opt
@@ -1 +1 @@
---date_format=%d.%m.%Y --time_format=%H.%i.%s --datetime_format=%Y/%d/%m-%H:%i:%s
+--date-format=%d.%m.%Y --time-format=%H.%i.%s
diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test
index 9551efaa648..f174e61d164 100644
--- a/mysql-test/t/date_formats.test
+++ b/mysql-test/t/date_formats.test
@@ -1,82 +1,201 @@
+#
+# Test of date format functions
+#
+
+--disable-warnings
+drop table if exists t1;
+--enable-warnings
+
SHOW GLOBAL VARIABLES LIKE "%_format%";
SHOW SESSION VARIABLES LIKE "%_format%";
-SET date_format="%d.%m.%Y";
-select CAST("01.01.2001" as DATE) as a;
-SET datetime_format="%d.%m.%Y %H.%i.%s";
-select CAST("01.01.2001 05.12.06" as DATETIME) as a;
-SET time_format="%H.%i.%s";
-select CAST("05.12.06" as TIME) as a;
-
-SET datetime_format="%d.%m.%Y %h:%i:%s %p";
-select CAST("01.01.2001 05:12:06AM" as DATETIME) as a;
-select CAST("01.01.2001 05:12:06 PM" as DATETIME) as a;
-
-SET time_format="%h:%i:%s %p";
-select CAST("05:12:06 AM" as TIME) as a;
-select CAST("05:12:06.1234PM" as TIME) as a;
-
-SET time_format="%h.%i.%s %p";
-SET date_format='%d.%m.%y';
-SET datetime_format="%d.%m.%y %h.%i.%s %p";
-select CAST("12-12-06" as DATE) as a;
-
-select adddate("01.01.97 11.59.59.000001 PM", 10);
-select datediff("31.12.97 11.59:59.000001 PM","01.01.98");
-select weekofyear("31.11.97 11:59:59.000001 PM");
-select makedate(1997,1);
-select addtime("31.12.97 11.59.59.999999 PM", "1 1.1.1.000002");
-select maketime(23,11,12);
-select timediff("01.01.97 11:59:59.000001 PM","31.12.95 11:59:59.000002 PM");
-
-SET time_format="%H%i%s";
---error 1105
-SET time_format="%h%i%s";
---error 1105
+#
+# Test setting a lot of different formats to see which formats are accepted and
+# which aren't
+#
+
+SET time_format='%H%i%s';
+SET time_format='%H:%i:%s.%f';
+SET time_format='%h-%i-%s.%f%p';
+SET time_format='%h:%i:%s.%f %p';
+SET time_format='%h:%i:%s%p';
+
+SET date_format='%Y%m%d';
+SET date_format='%Y.%m.%d';
+SET date_format='%d.%m.%Y';
+SET date_format='%m-%d-%Y';
+
+set datetime_format= '%Y%m%d%H%i%s';
+set datetime_format= '%Y-%m-%d %H:%i:%s';
+set datetime_format= '%m-%d-%y %H:%i:%s.%f';
+set datetime_format= '%d-%m-%Y %h:%i:%s%p';
+set datetime_format= '%H:%i:%s %Y-%m-%d';
+set datetime_format= '%H:%i:%s.%f %m-%d-%Y';
+set datetime_format= '%h:%i:%s %p %Y-%m-%d';
+set datetime_format= '%h:%i:%s.%f %p %Y-%m-%d';
+
+SHOW SESSION VARIABLES LIKE "%format";
+
+--error 1231
+SET time_format='%h:%i:%s';
+--error 1231
+SET time_format='%H %i:%s';
+--error 1231
+SET time_format='%H::%i:%s';
+--error 1231
+SET time_format='%H:%i:%s%f';
+--error 1231
+SET time_format='%H:%i.%f:%s';
+--error 1231
+SET time_format='%H:%i:%s%p';
+--error 1231
+SET time_format='%h:%i:%s.%f %p %Y-%m-%d';
+--error 1231
+SET time_format='%H%i%s.%f';
+--error 1231
+SET time_format='%H:%i-%s.%f';
+--error 1231
SET date_format='%d.%m.%d';
---error 1105
-SET datetime_format="%d.%m.%y %h.%i.%s";
+--error 1231
+SET datetime_format='%h.%m.%y %d.%i.%s';
+--error 1231
+set datetime_format= '%H:%i:%s.%f %p %Y-%m-%d';
+
+#
+# Test GLOBAL values
+
+set GLOBAL datetime_format= '%H:%i:%s %Y-%m-%d';
+SET SESSION datetime_format=default;
+select @@global.datetime_format, @@session.datetime_format;
+SET GLOBAL datetime_format=default;
+SET SESSION datetime_format=default;
+select @@global.datetime_format, @@session.datetime_format;
SET GLOBAL date_format=default;
-SHOW GLOBAL VARIABLES LIKE "date_format%";
SET GLOBAL time_format=default;
-SHOW GLOBAL VARIABLES LIKE "time_format%";
SET GLOBAL datetime_format=default;
-SHOW GLOBAL VARIABLES LIKE "datetime_format%";
-
-SET date_format=default;
-SHOW SESSION VARIABLES LIKE "date_format%";
SET time_format=default;
-SHOW SESSION VARIABLES LIKE "time_format%";
+SET date_format=default;
SET datetime_format=default;
-SHOW SESSION VARIABLES LIKE "datetime_format%";
-
-SET time_format='%i:%s:%H';
-select cast(str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S") as TIME);
-
-SET GLOBAL date_format='%Y-%m-%d';
-SET GLOBAL time_format='%H:%i:%s';
-SET GLOBAL datetime_format='%Y-%m-%d %H:%i:%s';
-SET date_format='%Y-%m-%d';
-SET time_format='%H:%i:%s';
-SET datetime_format='%Y-%m-%d %H:%i:%s';
-
-select str_to_date("15-01-2001 12:59:59", "%d-%m-%Y %H:%i:%S");
-select str_to_date("15 September 2001", "%d %M %Y");
-select str_to_date("15 Septembeb 2001", "%d %M %Y");
-select str_to_date("15 MAY 2001", "%d %b %Y");
-select str_to_date("Sunday 15 MAY 2001", "%W %d %b %Y");
-select str_to_date("Sundai 15 MAY 2001", "%W %d %b %Y");
-select str_to_date("Sundai 15 MA", "%W %d %b %Y");
-select str_to_date("Tuesday 52 2001", "%W %V %X");
-select str_to_date("Sunday 01 2001", "%W %V %X");
-select str_to_date("Tuesday 00 2002", "%W %U %Y");
-select str_to_date("Thursday 53 1998", "%W %u %Y");
-select str_to_date("15-01-2001", "%d-%m-%Y %H:%i:%S");
-select str_to_date("15-01-20", "%d-%m-%Y");
-select str_to_date("15-2001-1", "%d-%Y-%c");
+
+#
+# The following tests will work only when we at some point will enable
+# dynamic changing of formats
+#
+
+# SET date_format='%d.%m.%Y';
+# select CAST('01.01.2001' as DATE) as a;
+# SET datetime_format='%d.%m.%Y %H.%i.%s';
+# select CAST('01.01.2001 05.12.06' as DATETIME) as a;
+# SET time_format='%H.%i.%s';
+# select CAST('05.12.06' as TIME) as a;
+#
+# SET datetime_format='%d.%m.%Y %h:%i:%s %p';
+# select CAST('01.01.2001 05:12:06AM' as DATETIME) as a;
+# select CAST('01.01.2001 05:12:06 PM' as DATETIME) as a;
+#
+# SET time_format='%h:%i:%s %p';
+# select CAST('05:12:06 AM' as TIME) as a;
+# select CAST('05:12:06.1234PM' as TIME) as a;
+#
+# SET time_format='%h.%i.%s %p';
+# SET date_format='%d.%m.%y';
+# SET datetime_format='%d.%m.%y %h.%i.%s %p';
+# select CAST('12-12-06' as DATE) as a;
+#
+# select adddate('01.01.97 11.59.59.000001 PM', 10);
+# select datediff('31.12.97 11.59:59.000001 PM','01.01.98');
+# select weekofyear('31.11.97 11:59:59.000001 PM');
+# select makedate(1997,1);
+# select addtime('31.12.97 11.59.59.999999 PM', '1 1.1.1.000002');
+# select maketime(23,11,12);
+# select timediff('01.01.97 11:59:59.000001 PM','31.12.95 11:59:59.000002 PM');
+#
+# SET time_format='%i:%s:%H';
+# select cast(str_to_date('15-01-2001 12:59:59', '%d-%m-%Y %H:%i:%S') as TIME);
+
+#
+# Test of str_to_date
+#
+
+select str_to_date(concat('15-01-2001',' 2:59:58.999'),
+ concat('%d-%m-%Y',' ','%H:%i:%s.%f'));
+
+create table t1 (date char(30), format char(30) not null);
+insert into t1 values
+('2003-01-02 10:11:12', '%Y-%m-%d %H:%i:%S'),
+('03-01-02 8:11:2.123456', '%y-%m-%d %H:%i:%S'),
+('2003-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p'),
+('2003-01-02 01:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f%p'),
+('2003-01-02 02:11:12.12345AM', '%Y-%m-%d %h:%i:%S.%f %p'),
+('2003-01-02 12:11:12.12345 am', '%Y-%m-%d %h:%i:%S.%f%p'),
+('2003-01-02 11:11:12Pm', '%Y-%m-%d %h:%i:%S%p'),
+('10:20:10', '%H:%i:%s'),
+('10:20:10', '%h:%i:%s.%f'),
+('10:20:10AM', '%h:%i:%s%p'),
+('10:20:10.44AM', '%h:%i:%s.%f%p'),
+('15-01-2001 12:59:58', '%d-%m-%Y %H:%i:%S'),
+('15 September 2001', '%d %M %Y'),
+('15 SEPTEMB 2001', '%d %M %Y'),
+('15 MAY 2001', '%d %b %Y'),
+('Sunday 15 MAY 2001', '%W %d %b %Y'),
+('Sund 15 MAY 2001', '%W %d %b %Y'),
+('Tuesday 00 2002', '%W %U %Y'),
+('Thursday 53 1998', '%W %u %Y'),
+('15-01-2001', '%d-%m-%Y %H:%i:%S'),
+('15-01-20', '%d-%m-%y'),
+('15-2001-1', '%d-%Y-%c');
+
+# Use through protocol functions
+select date,format,str_to_date(date, format) as str_to_date from t1;
+# Use as a string
+select date,format,concat('',str_to_date(date, format)) as con from t1;
+# Use as datetime
+select date,format,cast(str_to_date(date, format) as datetime) as datetime from t1;
+select date,format,DATE(str_to_date(date, format)) as date2 from t1;
+select date,format,TIME(str_to_date(date, format)) as time from t1;
+select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1;
+
+# Test wrong dates
+
+truncate table t1;
+insert into t1 values
+('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'),
+('2003-01-02 10:11:12.123456', '%Y-%m-%d %h:%i:%S %p'),
+('2003-01-02 10:11:12AM', '%Y-%m-%d %h:%i:%S.%f %p'),
+('2003-01-02 10:11:12AN', '%Y-%m-%d %h:%i:%S%p'),
+('2003-01-02 10:11:12 PM', '%y-%m-%d %H:%i:%S %p'),
+('10:20:10AM', '%H:%i:%s%p'),
+('15 Septembei 2001', '%d %M %Y'),
+('15 Ju 2001', '%d %M %Y'),
+('Sund 15 MA', '%W %d %b %Y'),
+('Sunday 01 2001', '%W %V %X'),
+('Thursdai 12 1998', '%W %u %Y'),
+(NULL, get_format(DATE,'USA')),
+('Tuesday 52 2001', '%W %V %X');
+select date,format,str_to_date(date, format) as str_to_date from t1;
+select date,format,concat(str_to_date(date, format),'') as con from t1;
+
+# Test 'maybe' date formats and 'strange but correct' results
+
+truncate table t1;
+insert into t1 values
+('10:20:10AM', '%h:%i:%s'),
+('2003-01-02 10:11:12', '%Y-%m-%d %h:%i:%S'),
+('03-01-02 10:11:12 PM', '%Y-%m-%d %h:%i:%S %p');
+
+select date,format,str_to_date(date, format) as str_to_date from t1;
+select date,format,concat(str_to_date(date, format),'') as con from t1;
+
+drop table t1;
+
+#
+# Test of get_format
+#
select get_format(DATE, 'USA') as a;
select get_format(TIME, 'internal') as a;
select get_format(DATETIME, 'eur') as a;
+select get_format(DATE, 'TEST') as a;
+select str_to_date('15-01-2001 12:59:59', GET_FORMAT(DATE,'USA'));
diff --git a/mysql-test/t/rpl_temporary-master.opt b/mysql-test/t/rpl_temporary-master.opt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/mysql-test/t/rpl_temporary-master.opt
diff --git a/mysql-test/t/rpl_temporary.test b/mysql-test/t/rpl_temporary.test
index f1373d7ef23..0df8ceb6377 100644
--- a/mysql-test/t/rpl_temporary.test
+++ b/mysql-test/t/rpl_temporary.test
@@ -108,3 +108,11 @@ drop temporary table t3;
select * from t2;
drop table t1,t2;
+
+# Create last a temporary table that is not dropped at end to ensure that we
+# don't get any memory leaks for this
+
+create temporary table t3 (f int);
+sync_with_master;
+
+# The server will now close done
diff --git a/mysql-test/t/symlink.test b/mysql-test/t/symlink.test
index f618c342936..4be0cd0c6a2 100644
--- a/mysql-test/t/symlink.test
+++ b/mysql-test/t/symlink.test
@@ -65,7 +65,7 @@ drop table t1;
#
disable_query_log;
---error 1103,1103
+--error 1279,1279
create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="tmp";
# Check that we cannot link over a table from another database.
@@ -75,7 +75,7 @@ create database mysqltest;
--error 1,1
create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist";
---error 1103,1103
+--error 1279,1279
create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path";
--error 1,1
diff --git a/mysys/default.c b/mysys/default.c
index 15eb358df22..b1d9e40a1c2 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -214,6 +214,7 @@ int load_defaults(const char *conf_file, const char **groups,
res= (char**) (ptr+sizeof(alloc));
/* copy name + found arguments + command line arguments to new array */
+ res[0]= argv[0][0]; /* Name MUST be set, even by embedded library */
memcpy((gptr) (res+1), args.buffer, args.elements*sizeof(char*));
/* Skipp --defaults-file and --defaults-extra-file */
(*argc)-= args_used;
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 69b9c58dd6d..0167124a892 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -63,7 +63,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
thr_malloc.cc item_create.cc item_subselect.cc \
item_row.cc item_geofunc.cc \
- field.cc key.cc sql_class.cc sql_list.cc \
+ field.cc strfunc.cc key.cc sql_class.cc sql_list.cc \
net_serv.cc protocol.cc sql_state.c \
lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
diff --git a/sql/derror.cc b/sql/derror.cc
index 7f4068c487e..654fa2d1e1a 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -136,6 +136,7 @@ err1:
if (file != FERR)
VOID(my_close(file,MYF(MY_WME)));
unireg_abort(1);
+ return 0; // Impossible
} /* read_texts */
diff --git a/sql/field.cc b/sql/field.cc
index b025f65a798..1a5206ff07b 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -274,13 +274,14 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
return copy->length+(int) copy->strip;
}
-bool Field::get_date(TIME *ltime,bool fuzzydate)
+
+bool Field::get_date(TIME *ltime,uint fuzzydate)
{
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
- str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate,current_thd)<=
- WRONG_TIMESTAMP_FULL)
+ str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <=
+ TIMESTAMP_DATETIME_ERROR)
return 1;
return 0;
}
@@ -290,39 +291,44 @@ bool Field::get_time(TIME *ltime)
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
- str_to_time(res->ptr(),res->length(),ltime,current_thd))
+ str_to_time(res->ptr(),res->length(),ltime))
return 1;
return 0;
}
+/*
+ This is called when storing a date in a string
+
+ NOTES
+ Needs to be changed if/when we want to support different time formats
+*/
-/* This is called when storing a date in a string */
void Field::store_time(TIME *ltime,timestamp_type type)
{
char buff[25];
- String tmp((char*) buff,sizeof(buff),&my_charset_bin);
- DATETIME_FORMAT *tmp_format= 0;
- bool is_time_only= 0;
-
switch (type) {
case TIMESTAMP_NONE:
- case WRONG_TIMESTAMP_FULL:
+ case TIMESTAMP_DATETIME_ERROR:
store("",0,&my_charset_bin); // Probably an error
- return;
+ break;
case TIMESTAMP_DATE:
- tmp_format= &t_datetime_frm(current_thd, DATE_FORMAT_TYPE).datetime_format;
+ sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day);
+ store(buff,10,&my_charset_bin);
break;
- case TIMESTAMP_FULL:
- tmp_format=&t_datetime_frm(current_thd,DATETIME_FORMAT_TYPE).datetime_format;
+ case TIMESTAMP_DATETIME:
+ sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
+ ltime->year,ltime->month,ltime->day,
+ ltime->hour,ltime->minute,ltime->second);
+ store(buff,19,&my_charset_bin);
break;
case TIMESTAMP_TIME:
- tmp_format= &t_datetime_frm(current_thd, TIME_FORMAT_TYPE).datetime_format;
- is_time_only= 1;
+ {
+ ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d",
+ ltime->hour,ltime->minute,ltime->second));
+ store(buff,(uint) length, &my_charset_bin);
break;
}
- make_datetime(&tmp, ltime, is_time_only, 0,
- tmp_format->format, tmp_format->format_length, 1);
- store(tmp.ptr(),tmp.length(),&my_charset_bin);
+ }
}
@@ -2693,7 +2699,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
{
- long tmp=(long) str_to_timestamp(from,len,current_thd);
+ long tmp=(long) str_to_timestamp(from,len);
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -2908,7 +2914,7 @@ String *Field_timestamp::val_str(String *val_buffer,
}
-bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate)
+bool Field_timestamp::get_date(TIME *ltime, uint fuzzydate)
{
long temp;
#ifdef WORDS_BIGENDIAN
@@ -2937,7 +2943,7 @@ bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate)
ltime->second= start->tm_sec;
ltime->second_part= 0;
ltime->neg= 0;
- ltime->time_type=TIMESTAMP_FULL;
+ ltime->time_type=TIMESTAMP_DATETIME;
}
return 0;
}
@@ -2951,7 +2957,7 @@ bool Field_timestamp::get_time(TIME *ltime)
bool Field_timestamp::send_binary(Protocol *protocol)
{
TIME tm;
- Field_timestamp::get_date(&tm, 1);
+ Field_timestamp::get_date(&tm, TIME_FUZZY_DATE);
return protocol->store(&tm);
}
@@ -3027,7 +3033,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
TIME ltime;
long tmp;
int error= 0;
- if (str_to_time(from,len,&ltime,current_thd))
+ if (str_to_time(from,len,&ltime))
{
tmp=0L;
error= 1;
@@ -3137,27 +3143,23 @@ String *Field_time::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
TIME ltime;
- val_buffer->alloc(16);
+ val_buffer->alloc(19);
long tmp=(long) sint3korr(ptr);
- const char *sign="";
ltime.neg= 0;
if (tmp < 0)
{
tmp= -tmp;
ltime.neg= 1;
}
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (current_thd, TIME_FORMAT_TYPE).datetime_format);
ltime.day= (uint) 0;
ltime.hour= (uint) (tmp/10000);
ltime.minute= (uint) (tmp/100 % 100);
ltime.second= (uint) (tmp % 100);
- make_datetime(val_buffer, &ltime, 0, 0,
- tmp_format->format,
- tmp_format->format_length, 1);
+ make_time((DATE_TIME_FORMAT*) 0, &ltime, val_buffer);
return val_buffer;
}
+
bool Field_time::get_time(TIME *ltime)
{
long tmp=(long) sint3korr(ptr);
@@ -3320,7 +3322,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
TIME l_time;
uint32 tmp;
int error= 0;
- if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL)
+ if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR)
{
tmp=0;
error= 1;
@@ -3432,7 +3434,6 @@ String *Field_date::val_str(String *val_buffer,
{
TIME ltime;
val_buffer->alloc(field_length);
- val_buffer->length(field_length);
int32 tmp;
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -3440,18 +3441,15 @@ String *Field_date::val_str(String *val_buffer,
else
#endif
longget(tmp,ptr);
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (current_thd, DATE_FORMAT_TYPE).datetime_format);
ltime.neg= 0;
ltime.year= (int) ((uint32) tmp/10000L % 10000);
ltime.month= (int) ((uint32) tmp/100 % 100);
ltime.day= (int) ((uint32) tmp % 100);
- make_datetime(val_buffer, &ltime, 0, 0,
- tmp_format->format,
- tmp_format->format_length, 1);
+ make_date((DATE_TIME_FORMAT *) 0, &ltime, val_buffer);
return val_buffer;
}
+
int Field_date::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
@@ -3507,7 +3505,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
TIME l_time;
long tmp;
int error= 0;
- if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL)
+ if (str_to_TIME(from,len,&l_time,1) <= TIMESTAMP_DATETIME_ERROR)
{
tmp=0L;
error= 1;
@@ -3572,7 +3570,7 @@ int Field_newdate::store(longlong nr)
void Field_newdate::store_time(TIME *ltime,timestamp_type type)
{
long tmp;
- if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL)
+ if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME)
tmp=ltime->year*16*32+ltime->month*32+ltime->day;
else
{
@@ -3628,7 +3626,7 @@ String *Field_newdate::val_str(String *val_buffer,
return val_buffer;
}
-bool Field_newdate::get_date(TIME *ltime,bool fuzzydate)
+bool Field_newdate::get_date(TIME *ltime,uint fuzzydate)
{
if (is_null())
return 1;
@@ -3676,7 +3674,7 @@ void Field_newdate::sql_type(String &res) const
int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
{
- longlong tmp=str_to_datetime(from,len,1,current_thd);
+ longlong tmp=str_to_datetime(from,len,1);
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -3730,7 +3728,7 @@ int Field_datetime::store(longlong nr)
void Field_datetime::store_time(TIME *ltime,timestamp_type type)
{
longlong tmp;
- if (type == TIMESTAMP_DATE || type == TIMESTAMP_FULL)
+ if (type == TIMESTAMP_DATE || type == TIMESTAMP_DATETIME)
tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
(ltime->hour*10000L+ltime->minute*100+ltime->second));
else
@@ -3751,7 +3749,7 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type)
bool Field_datetime::send_binary(Protocol *protocol)
{
TIME tm;
- Field_datetime::get_date(&tm, 1);
+ Field_datetime::get_date(&tm, TIME_FUZZY_DATE);
return protocol->store(&tm);
}
@@ -3822,14 +3820,14 @@ String *Field_datetime::val_str(String *val_buffer,
return val_buffer;
}
-bool Field_datetime::get_date(TIME *ltime,bool fuzzydate)
+bool Field_datetime::get_date(TIME *ltime, uint fuzzydate)
{
longlong tmp=Field_datetime::val_int();
uint32 part1,part2;
part1=(uint32) (tmp/LL(1000000));
part2=(uint32) (tmp - (ulonglong) part1*LL(1000000));
- ltime->time_type= TIMESTAMP_FULL;
+ ltime->time_type= TIMESTAMP_DATETIME;
ltime->neg= 0;
ltime->second_part= 0;
ltime->second= (int) (part2%100);
@@ -4921,26 +4919,6 @@ void Field_enum::store_type(ulonglong value)
}
-uint find_enum(TYPELIB *lib,const char *x, uint length)
-{
- const char *end=x+length;
- while (end > x && my_isspace(system_charset_info,end[-1]))
- end--;
-
- const char *i;
- const char *j;
- for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++)
- {
- for (i=x ; i != end &&
- my_toupper(system_charset_info,*i) ==
- my_toupper(system_charset_info,*j) ; i++, j++) ;
- if (i == end && ! *j)
- return(pos+1);
- }
- return(0);
-}
-
-
/*
** Note. Storing a empty string in a enum field gives a warning
** (if there isn't a empty value in the enum)
@@ -4958,7 +4936,11 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
from= tmpstr.ptr();
length= tmpstr.length();
}
- uint tmp=find_enum(typelib,from,length);
+
+ /* Remove end space */
+ while (length > 0 && my_isspace(system_charset_info,from[length-1]))
+ length--;
+ uint tmp=find_type(typelib, from, length, 0);
if (!tmp)
{
if (length < 6) // Can't be more than 99999 enums
@@ -5111,49 +5093,8 @@ void Field_enum::sql_type(String &res) const
For example "One,two,five"
If one uses this string in a number context one gets the bits as a longlong
number.
-
- If there was a value in string that wasn't in set, the 'err_pos' points to
- the last invalid value found. 'err_len' will be set to length of the
- error string.
*/
-ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos,
- uint *err_len, bool *set_warning)
-{
- const char *end= x + length;
- *err_pos= 0; // No error yet
- while (end > x && my_isspace(system_charset_info, end[-1]))
- end--;
-
- *err_len= 0;
- ulonglong found= 0;
- if (x != end)
- {
- const char *start= x;
- for (;;)
- {
- const char *pos= start;
- uint var_len;
-
- for (; pos != end && *pos != field_separator; pos++) ;
- var_len= (uint) (pos - start);
- uint find= find_enum(lib, start, var_len);
- if (!find)
- {
- *err_pos= (char*) start;
- *err_len= var_len;
- *set_warning= 1;
- }
- else
- found|= ((longlong) 1 << (find - 1));
- if (pos == end)
- break;
- start= pos + 1;
- }
- }
- return found;
-}
-
int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
{
@@ -5512,7 +5453,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
default: sql_type= FIELD_TYPE_LONG_BLOB; break;
}
- length /= charset->mbmaxlen;
+ length /= charset->mbmaxlen; // QQ: Probably not needed
break;
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
diff --git a/sql/field.h b/sql/field.h
index fe5141e9d80..73deeec9fb9 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -222,7 +222,7 @@ public:
uint offset(); // Should be inline ...
void copy_from_tmp(int offset);
uint fill_cache_field(struct st_cache_field *copy);
- virtual bool get_date(TIME *ltime,bool fuzzydate);
+ virtual bool get_date(TIME *ltime,uint fuzzydate);
virtual bool get_time(TIME *ltime);
virtual CHARSET_INFO *charset(void) const { return &my_charset_bin; }
virtual bool has_charset(void) const { return FALSE; }
@@ -645,7 +645,7 @@ public:
longget(tmp,ptr);
return tmp;
}
- bool get_date(TIME *ltime,bool fuzzydate);
+ bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime);
};
@@ -733,7 +733,7 @@ public:
void sql_type(String &str) const;
bool store_for_compare() { return 1; }
bool zero_pack() const { return 1; }
- bool get_date(TIME *ltime,bool fuzzydate);
+ bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime);
};
@@ -803,7 +803,7 @@ public:
void sql_type(String &str) const;
bool store_for_compare() { return 1; }
bool zero_pack() const { return 1; }
- bool get_date(TIME *ltime,bool fuzzydate);
+ bool get_date(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime);
};
@@ -1158,9 +1158,6 @@ uint pack_length_to_packflag(uint type);
uint32 calc_pack_length(enum_field_types type,uint32 length);
bool set_field_to_null(Field *field);
bool set_field_to_null_with_conversions(Field *field, bool no_conversions);
-uint find_enum(TYPELIB *typelib,const char *x, uint length);
-ulonglong find_set(TYPELIB *typelib,const char *x, uint length,
- char **err_pos, uint *err_len, bool *set_warning);
bool test_if_int(const char *str, int length, const char *int_end,
CHARSET_INFO *cs);
diff --git a/sql/init.cc b/sql/init.cc
index 8b15fef4ee3..033dfd72843 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -42,8 +42,6 @@ void unireg_init(ulong options)
#endif
VOID(strmov(reg_ext,".frm"));
- for (i=0 ; i < 6 ; i++) // YYMMDDHHMMSS
- dayord.pos[i]=i;
specialflag=SPECIAL_SAME_DB_NAME;
/* Make a tab of powers of 10 */
for (i=0,nr=1.0; i < array_elements(log_10) ; i++)
diff --git a/sql/item.cc b/sql/item.cc
index 0462a78376f..8f7edfd01dd 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -46,8 +46,10 @@ Item::Item():
collation.set(default_charset(), DERIVATION_COERCIBLE);
name= 0;
decimals= 0; max_length= 0;
- thd= current_thd;
- next= thd->free_list; // Put in free list
+
+ /* Put item in free list so that we can free all items at end */
+ THD *thd= current_thd;
+ next= thd->free_list;
thd->free_list= this;
/*
Item constructor can be called during execution other then SQL_COM
@@ -69,7 +71,7 @@ Item::Item():
Used for duplicating lists in processing queries with temporary
tables
*/
-Item::Item(THD *c_thd, Item &item):
+Item::Item(THD *thd, Item &item):
str_value(item.str_value),
name(item.name),
max_length(item.max_length),
@@ -82,8 +84,7 @@ Item::Item(THD *c_thd, Item &item):
fixed(item.fixed),
collation(item.collation)
{
- next=c_thd->free_list; // Put in free list
- thd= c_thd;
+ next= thd->free_list; // Put in free list
thd->free_list= this;
}
@@ -170,13 +171,13 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
As a extra convenience the time structure is reset on error!
*/
-bool Item::get_date(TIME *ltime,bool fuzzydate)
+bool Item::get_date(TIME *ltime,uint fuzzydate)
{
char buff[40];
String tmp(buff,sizeof(buff), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate, thd) <=
- WRONG_TIMESTAMP_FULL)
+ str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) <=
+ TIMESTAMP_DATETIME_ERROR)
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
@@ -194,7 +195,7 @@ bool Item::get_time(TIME *ltime)
char buff[40];
String tmp(buff,sizeof(buff),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
- str_to_time(res->ptr(),res->length(),ltime, thd))
+ str_to_time(res->ptr(),res->length(),ltime))
{
bzero((char*) ltime,sizeof(*ltime));
return 1;
@@ -347,7 +348,7 @@ String *Item_field::str_result(String *str)
return result_field->val_str(str,&str_value);
}
-bool Item_field::get_date(TIME *ltime,bool fuzzydate)
+bool Item_field::get_date(TIME *ltime,uint fuzzydate)
{
if ((null_value=field->is_null()) || field->get_date(ltime,fuzzydate))
{
@@ -357,7 +358,7 @@ bool Item_field::get_date(TIME *ltime,bool fuzzydate)
return 0;
}
-bool Item_field::get_date_result(TIME *ltime,bool fuzzydate)
+bool Item_field::get_date_result(TIME *ltime,uint fuzzydate)
{
if ((null_value=result_field->is_null()) ||
result_field->get_date(ltime,fuzzydate))
@@ -677,28 +678,25 @@ String *Item_param::query_val_str(String* str)
}
else
{
- DATETIME_FORMAT *tmp_format= 0;
- bool is_time_only= 0;
+ char buff[40];
+ String tmp(buff,sizeof(buff), &my_charset_bin);
switch (ltime.time_type) {
- case TIMESTAMP_NONE:
- case WRONG_TIMESTAMP_FULL:
- break;
- case TIMESTAMP_DATE:
- tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format;
- break;
- case TIMESTAMP_FULL:
- tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format;
- break;
- case TIMESTAMP_TIME:
- {
- tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format;
- is_time_only= 1;
- break;
- }
+ case TIMESTAMP_NONE:
+ case TIMESTAMP_DATETIME_ERROR:
+ tmp.length(0); // Should never happen
+ break;
+ case TIMESTAMP_DATE:
+ make_date((DATE_TIME_FORMAT*) 0, &ltime, &tmp);
+ break;
+ case TIMESTAMP_DATETIME:
+ make_datetime((DATE_TIME_FORMAT*) 0, &ltime, &tmp);
+ break;
+ case TIMESTAMP_TIME:
+ make_time((DATE_TIME_FORMAT*) 0, &ltime, &tmp);
+ break;
}
- make_datetime(str, &ltime, is_time_only, 0,
- tmp_format->format, tmp_format->format_length, 0);
+ str->append(tmp);
}
str->append("'");
}
@@ -754,7 +752,7 @@ String* Item_ref_null_helper::val_str(String* s)
owner->was_null|= null_value= (*ref)->null_value;
return tmp;
}
-bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate)
+bool Item_ref_null_helper::get_date(TIME *ltime, uint fuzzydate)
{
return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate));
}
@@ -964,6 +962,7 @@ enum_field_types Item::field_type() const
FIELD_TYPE_DOUBLE);
}
+
Field *Item::tmp_table_field_from_field_type(TABLE *table)
{
switch (field_type())
@@ -1340,7 +1339,7 @@ bool Item::send(Protocol *protocol, String *buffer)
case MYSQL_TYPE_TIMESTAMP:
{
TIME tm;
- get_date(&tm, 1);
+ get_date(&tm, TIME_FUZZY_DATE);
if (!null_value)
{
if (type == MYSQL_TYPE_DATE)
diff --git a/sql/item.h b/sql/item.h
index c738f92124f..c514a641d9f 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -114,14 +114,6 @@ public:
my_bool fixed; /* If item fixed with fix_fields */
DTCollation collation;
-
- /*
- thd is current_thd value. Like some other Item's fields it
- will be a problem for using one Item in different threads
- (as stored procedures may want to do in the future)
- */
- THD *thd;
-
// alloc & destruct is done as start of select using sql_alloc
Item();
/*
@@ -132,7 +124,7 @@ public:
top AND/OR ctructure of WHERE clause to protect it of
optimisation changes in prepared statements
*/
- Item(THD *c_thd, Item &item);
+ Item(THD *thd, Item &item);
virtual ~Item() { name=0; } /*lint -e1509 */
void set_name(const char *str,uint length, CHARSET_INFO *cs);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
@@ -184,9 +176,9 @@ public:
virtual void print(String *str_arg) { str_arg->append(full_name()); }
virtual void update_used_tables() {}
virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {}
- virtual bool get_date(TIME *ltime,bool fuzzydate);
+ virtual bool get_date(TIME *ltime,uint fuzzydate);
virtual bool get_time(TIME *ltime);
- virtual bool get_date_result(TIME *ltime,bool fuzzydate)
+ virtual bool get_date_result(TIME *ltime,uint fuzzydate)
{ return get_date(ltime,fuzzydate); }
virtual bool is_null() { return 0; }
virtual void top_level_item() {}
@@ -282,8 +274,8 @@ public:
}
Field *get_tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
- bool get_date(TIME *ltime,bool fuzzydate);
- bool get_date_result(TIME *ltime,bool fuzzydate);
+ bool get_date(TIME *ltime,uint fuzzydate);
+ bool get_date_result(TIME *ltime,uint fuzzydate);
bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); }
Item *get_tmp_table_item(THD *thd);
@@ -463,6 +455,13 @@ public:
{
collation.set(cs, dv);
str_value.set(str,length,cs);
+ /*
+ We have to have a different max_length than 'length' here to
+ ensure that we get the right length if we do use the item
+ to create a new table. In this case max_length must be the maximum
+ number of chars for a string of this type because we in create_field::
+ divide the max_length with mbmaxlen).
+ */
max_length= str_value.numchars()*cs->mbmaxlen;
set_name(str, length, cs);
decimals=NOT_FIXED_DEC;
@@ -617,7 +616,7 @@ public:
(void) (*ref)->val_int_result();
return (*ref)->null_value;
}
- bool get_date(TIME *ltime,bool fuzzydate)
+ bool get_date(TIME *ltime,uint fuzzydate)
{
return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
}
@@ -651,7 +650,7 @@ public:
double val();
longlong val_int();
String* val_str(String* s);
- bool get_date(TIME *ltime, bool fuzzydate);
+ bool get_date(TIME *ltime, uint fuzzydate);
void print(String *str)
{
str->append("ref_null_helper(");
diff --git a/sql/item_create.cc b/sql/item_create.cc
index fce59d68c1f..6bd2d826405 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -450,7 +450,8 @@ Item *create_load_file(Item* a)
}
-Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs)
+Item *create_func_cast(Item *a, Cast_target cast_type, int len,
+ CHARSET_INFO *cs)
{
Item *res;
LINT_INIT(res);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index ce0614f1e7c..c740b514c7c 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1284,8 +1284,8 @@ void Item_func_find_in_set::fix_length_and_dec()
String *find=args[0]->val_str(&value);
if (find)
{
- enum_value=find_enum(((Field_enum*) field)->typelib,find->ptr(),
- find->length());
+ enum_value= find_type(((Field_enum*) field)->typelib,find->ptr(),
+ find->length(), 0);
enum_bit=0;
if (enum_value)
enum_bit=LL(1) << (enum_value-1);
@@ -2094,8 +2094,8 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
}
/*
- When a user variable is updated (in a SET command or a query like SELECT @a:=
- ).
+ When a user variable is updated (in a SET command or a query like
+ SELECT @a:= ).
*/
bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
@@ -2454,14 +2454,15 @@ void Item_func_get_user_var::fix_length_and_dec()
sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION'
in dispatch_command()). Instead of building a one-element list to pass to
sql_set_variables(), we could instead manually call check() and update();
- this would save memory and time; but calling sql_set_variables() makes one
- unique place to maintain (sql_set_variables()).
+ this would save memory and time; but calling sql_set_variables() makes
+ one unique place to maintain (sql_set_variables()).
*/
List<set_var_base> tmp_var_list;
tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name,
new Item_null())));
- if (sql_set_variables(thd, &tmp_var_list)) /* this will create the variable */
+ /* Create the variable */
+ if (sql_set_variables(thd, &tmp_var_list))
goto err;
if (!(var_entry= get_variable(&thd->user_vars, name, 0)))
goto err;
diff --git a/sql/item_func.h b/sql/item_func.h
index fe9c2645216..47ba86d02e3 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -125,9 +125,9 @@ public:
void print(String *str);
void print_op(String *str);
void fix_num_length_and_dec();
- inline bool get_arg0_date(TIME *ltime,bool fuzzy_date)
+ inline bool get_arg0_date(TIME *ltime, uint fuzzy_date)
{
- return (null_value=args[0]->get_date(ltime,fuzzy_date));
+ return (null_value=args[0]->get_date(ltime, fuzzy_date));
}
inline bool get_arg0_time(TIME *ltime)
{
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index b82dacb4fe0..90afd0c72ca 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -354,7 +354,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen;
+ max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen;
}
const char *func_name() const { return "database"; }
};
@@ -366,7 +366,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen;
+ max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen;
}
const char *func_name() const { return "user"; }
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 4009256ee17..5dee11af5be 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -25,310 +25,290 @@
#include <m_ctype.h>
#include <time.h>
-/*
-** Todo: Move month and days to language files
-*/
+/* TODO: Move month and days to language files */
#define MAX_DAY_NUMBER 3652424L
-static String month_names[] =
-{
- String("January", &my_charset_latin1),
- String("February", &my_charset_latin1),
- String("March", &my_charset_latin1),
- String("April", &my_charset_latin1),
- String("May", &my_charset_latin1),
- String("June", &my_charset_latin1),
- String("July", &my_charset_latin1),
- String("August", &my_charset_latin1),
- String("September", &my_charset_latin1),
- String("October", &my_charset_latin1),
- String("November", &my_charset_latin1),
- String("December", &my_charset_latin1)
+static const char *month_names[]=
+{
+ "January", "February", "March", "April", "May", "June", "July", "August",
+ "September", "October", "November", "December", NullS
};
-static String day_names[] =
+
+TYPELIB month_names_typelib=
+{ array_elements(month_names)-1,"", month_names };
+
+static const char *day_names[]=
+{
+ "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday" ,"Sunday", NullS
+};
+
+TYPELIB day_names_typelib=
+{ array_elements(day_names)-1,"", day_names};
+
+
+enum date_time_format_types
{
- String("Monday", &my_charset_latin1),
- String("Tuesday", &my_charset_latin1),
- String("Wednesday", &my_charset_latin1),
- String("Thursday", &my_charset_latin1),
- String("Friday", &my_charset_latin1),
- String("Saturday", &my_charset_latin1),
- String("Sunday", &my_charset_latin1)
+ TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
};
-uint check_names(String *arr,int item_count,const char *val_ptr,
- const char *val_end, uint *val, bool check_part)
+/*
+ OPTIMIZATION TODO:
+ - Replace the switch with a function that should be called for each
+ date type.
+ - Remove sprintf and opencode the conversion, like we do in
+ Field_datetime.
+
+ The reason for this functions existence is that as we don't have a
+ way to know if a datetime/time value has microseconds in them
+ we are now only adding microseconds to the output if the
+ value has microseconds.
+
+ We can't use a standard make_date_time() for this as we don't know
+ if someone will use %f in the format specifier in which case we would get
+ the microseconds twice.
+*/
+
+static bool make_datetime(date_time_format_types format, TIME *ltime,
+ String *str)
{
- for (int i= 0; i < item_count; i++)
- {
- String *tmp=&arr[i];
- if (!my_strnncoll(&my_charset_latin1,
- (const uchar *) val_ptr, 3,
- (const uchar *) tmp->ptr(), 3))
- {
- if (check_part)
- {
- *val= i+1;
- return 3;
- }
+ char *buff;
+ CHARSET_INFO *cs= &my_charset_bin;
+ uint length= 30;
- int part_len= tmp->length() - 3;
- int val_len= val_end - val_ptr - 3;
- if (val_len < part_len)
- return 0;
- val_ptr+=3;
- if (!my_strnncoll(&my_charset_latin1,
- (const uchar *) val_ptr, part_len,
- (const uchar *) tmp->ptr() + 3, part_len))
- {
- *val= i+1;
- return tmp->length();
- }
- return 0;
- }
- }
- return 0;
-}
+ if (str->alloc(length))
+ return 1;
+ buff= (char*) str->ptr();
-uint check_val_is_digit(const char *ptr, uint val_len, uint digit_count)
-{
- uint i;
- uint verify_count= (val_len < digit_count ? val_len : digit_count);
- uint digit_found= 0;
- for (i= 0; i < verify_count; i++)
- {
- if (!my_isdigit(&my_charset_latin1, *(ptr+i)))
- break;
- digit_found++;
+ switch (format) {
+ case TIME_ONLY:
+ length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d",
+ ltime->neg ? "-" : "",
+ ltime->hour, ltime->minute, ltime->second);
+ break;
+ case TIME_MICROSECOND:
+ length= cs->cset->snprintf(cs, buff, length, "%s%02d:%02d:%02d.%06d",
+ ltime->neg ? "-" : "",
+ ltime->hour, ltime->minute, ltime->second,
+ ltime->second_part);
+ break;
+ case DATE_ONLY:
+ length= cs->cset->snprintf(cs, buff, length, "%04d-%02d-%02d",
+ ltime->year, ltime->month, ltime->day);
+ break;
+ case DATE_TIME:
+ length= cs->cset->snprintf(cs, buff, length,
+ "%04d-%02d-%02d %02d:%02d:%02d",
+ ltime->year, ltime->month, ltime->day,
+ ltime->hour, ltime->minute, ltime->second);
+ break;
+ case DATE_TIME_MICROSECOND:
+ length= cs->cset->snprintf(cs, buff, length,
+ "%04d-%02d-%02d %02d:%02d:%02d.%06d",
+ ltime->year, ltime->month, ltime->day,
+ ltime->hour, ltime->minute, ltime->second,
+ ltime->second_part);
+ break;
}
- return digit_found;
+
+ str->length(length);
+ str->set_charset(cs);
+ return 0;
}
/*
Extract datetime value to TIME struct from string value
according to format string.
+
+ SYNOPSIS
+ extract_date_time()
+ format date/time format specification
+ val String to decode
+ length Length of string
+ l_time Store result here
+
+ RETURN
+ 0 ok
+ 1 error
*/
-bool extract_datetime(const char *str_val, uint str_val_len,
- const char *str_format, uint str_format_len,
- TIME *l_time)
+
+static bool extract_date_time(DATE_TIME_FORMAT *format,
+ const char *val, uint length, TIME *l_time)
{
- char intbuff[15];
int weekday= 0, yearday= 0, daypart= 0, len;
- int val_len= 0;
int week_number= -1;
- ulong length;
CHARSET_INFO *cs= &my_charset_bin;
- int err= 0;
+ int error= 0;
bool usa_time= 0;
bool sunday_first= 0;
- const char *rT_format= "%H:%i:%s";
uint part_len= 0;
- const char *val_ptr=str_val;
- const char *val_end= str_val + str_val_len;
- const char *ptr=str_format;
- const char *end=ptr+ str_format_len;
+ const char *val_ptr= val;
+ const char *val_end= val + length;
+ const char *ptr= format->format.str;
+ const char *end= ptr+ format->format.length;
+ DBUG_ENTER("extract_date_time");
- DBUG_ENTER("extract_datetime");
- for (; ptr != end && val_ptr != val_end; ptr++)
+ bzero((char*) l_time, sizeof(*l_time));
+
+ for (; ptr != end && val != val_end; ptr++)
{
+
if (*ptr == '%' && ptr+1 != end)
{
- val_len= val_end - val_ptr;
- char *val_end1= (char *) val_end;
+ int val_len;
+ char *tmp;
+
+ /* Skip pre-space between each argument */
+ while (my_isspace(cs, *val) && val != val_end)
+ val++;
+
+ val_len= (uint) (val_end - val);
switch (*++ptr) {
- case 'h':
- case 'I':
- case 'H':
- l_time->hour= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
- usa_time= (*ptr == 'I' || *ptr == 'h');
- val_ptr+=2;
- break;
- case 'k':
- case 'l':
- l_time->hour= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err)
- return 1;
- usa_time= (*ptr == 'l');
- val_ptr= val_end1;
- break;
- case 'e':
- l_time->day= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err)
- return 1;
- val_ptr= val_end1;
- break;
- case 'c':
- l_time->month= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err)
- return 1;
- val_ptr= val_end1;
- break;
+ /* Year */
case 'Y':
- l_time->year= my_strntoll(cs, val_ptr,
- 4, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 4))
- return 1;
- val_ptr+=4;
+ tmp= (char*) val + min(4, val_len);
+ l_time->year= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
case 'y':
- l_time->year= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
+ tmp= (char*) val + min(2, val_len);
+ l_time->year= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
- val_ptr+=2;
break;
+
+ /* Month */
case 'm':
- l_time->month= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
- val_ptr+=2;
+ case 'c':
+ tmp= (char*) val + min(2, val_len);
+ l_time->month= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
+ break;
+ case 'M':
+ case 'b':
+ if ((l_time->month= check_word(&month_names_typelib,
+ val, val_end, &val)) <= 0)
+ goto err;
break;
+ /* Day */
case 'd':
- l_time->day= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
- val_ptr+=2;
+ case 'e':
+ tmp= (char*) val + min(2, val_len);
+ l_time->day= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
case 'D':
- l_time->day= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err || (val_len < val_end1 - val_ptr + 2))
- return 1;
- val_ptr= val_end1 + 2;
+ tmp= (char*) val + min(2, val_len);
+ l_time->day= (int) my_strtoll10(val, &tmp, &error);
+ /* Skip 'st, 'nd, 'th .. */
+ val= tmp + min((int) (end-tmp), 2);
+ break;
+
+ /* Hour */
+ case 'h':
+ case 'I':
+ case 'l':
+ usa_time= 1;
+ /* fall through */
+ case 'k':
+ case 'H':
+ tmp= (char*) val + min(2, val_len);
+ l_time->hour= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
+
+ /* Minute */
case 'i':
- l_time->minute=my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
- val_ptr+=2;
+ tmp= (char*) val + min(2, val_len);
+ l_time->minute= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
+
+ /* Second */
case 's':
case 'S':
- l_time->second= my_strntoll(cs, val_ptr,
- 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
- val_ptr+=2;
+ tmp= (char*) val + min(2, val_len);
+ l_time->second= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
- case 'M':
- if (val_len < 3 ||
- !(part_len= check_names(month_names, 12 , val_ptr,
- val_end, &l_time->month, 0)))
- return 1;
- val_ptr+= part_len;
+
+ /* Second part */
+ case 'f':
+ tmp= (char*) val_end;
+ l_time->second_part= my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
- case 'b':
- if (val_len < 3 ||
- !(part_len= check_names(month_names, 12 , val_ptr,
- val_end,(uint *) &l_time->month, 1)))
- return 1;
- val_ptr+= part_len;
+
+ /* AM / PM */
+ case 'p':
+ if (val_len < 2 || ! usa_time)
+ goto err;
+ if (!my_strnncoll(&my_charset_latin1,
+ (const uchar *) val, 2,
+ (const uchar *) "PM", 2))
+ daypart= 12;
+ else if (my_strnncoll(&my_charset_latin1,
+ (const uchar *) val, 2,
+ (const uchar *) "AM", 2))
+ goto err;
break;
+
+ /* Exotic things */
case 'W':
- if (val_len < 3 ||
- !(part_len= check_names(day_names, 7 , val_ptr,
- val_end,(uint *) &weekday, 0)))
- return 1;
- val_ptr+= part_len;
- break;
case 'a':
- if (val_len < 3 ||
- !(part_len= check_names(day_names, 7 , val_ptr,
- val_end,(uint *) &weekday, 1)))
- return 1;
- val_ptr+= part_len;
+ if ((weekday= check_word(&day_names_typelib, val, val_end, &val)) <= 0)
+ goto err;
break;
case 'w':
- weekday= my_strntoll(cs, val_ptr, 1, 10, &val_end1, &err);
- if (err)
- return 1;
- val_ptr++;
+ tmp= (char*) val + 1;
+ if ((weekday= (int) my_strtoll10(val, &tmp, &error)) <= 0 ||
+ weekday >= 7)
+ goto err;
+ val= tmp;
break;
case 'j':
- yearday= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 3))
- return 1;
- val_ptr+=3;
- break;
- case 'f':
- l_time->second_part= my_strntoll(cs, val_ptr, 3, 10, &val_end1, &err);
- if (err)
- return 1;
- val_ptr= val_end1;
- break;
- case 'p':
- if (val_len < 2)
- return 1;
- if (!my_strnncoll(&my_charset_latin1,
- (const uchar *) val_ptr, 2,
- (const uchar *) "PM", 2))
- {
- daypart= 12;
- val_ptr+= 2;
- }
+ tmp= (char*) val + min(val_len, 3);
+ yearday= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
+
case 'U':
- week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
sunday_first= 1;
- val_ptr+=2;
- break;
+ /* Fall through */
case 'u':
- week_number= my_strntoll(cs, val_ptr, 2, 10, &val_end1, &err);
- if (err || (val_end1 - val_ptr != 2))
- return 1;
- sunday_first=0;
- val_ptr+=2;
- break;
- case 'r':
- case 'T':
- usa_time= (*ptr == 'r');
- if (extract_datetime(val_ptr, val_end-val_ptr,
- rT_format, strlen(rT_format),
- l_time))
- return 1;
- val_ptr+=8;
+ tmp= (char*) val + min(val_len, 2);
+ week_number= (int) my_strtoll10(val, &tmp, &error);
+ val= tmp;
break;
+
default:
- if (*val_ptr != *ptr)
- return 1;
- val_ptr++;
+ goto err;
}
+ if (error) // Error from my_strtoll10
+ goto err;
}
- else
+ else if (!my_isspace(cs, *ptr))
{
- if (*val_ptr != *ptr)
- return 1;
- val_ptr++;
+ if (*val != *ptr)
+ goto err;
+ val++;
}
}
if (usa_time)
{
if (l_time->hour > 12 || l_time->hour < 1)
- return 1;
+ goto err;
l_time->hour= l_time->hour%12+daypart;
}
if (yearday > 0)
{
uint days= calc_daynr(l_time->year,1,1) + yearday - 1;
- if (days > 0 || days < MAX_DAY_NUMBER)
- {
- get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
- }
+ if (days <= 0 || days >= MAX_DAY_NUMBER)
+ goto err;
+ get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
}
if (week_number >= 0 && weekday)
@@ -337,7 +317,7 @@ bool extract_datetime(const char *str_val, uint str_val_len,
uint weekday_b;
if (weekday > 7 || weekday < 0)
- return 1;
+ goto err;
if (sunday_first)
weekday = weekday%7;
@@ -361,43 +341,43 @@ bool extract_datetime(const char *str_val, uint str_val_len,
weekday =weekday - weekday_b - !sunday_first;
days+= weekday;
}
- if (days > 0 || days < MAX_DAY_NUMBER)
- {
- get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
- }
+ if (days <= 0 || days >= MAX_DAY_NUMBER)
+ goto err;
+ get_date_from_daynr(days,&l_time->year,&l_time->month,&l_time->day);
}
if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 ||
l_time->minute > 59 || l_time->second > 59)
- return 1;
+ goto err;
DBUG_RETURN(0);
-}
+err:
+ DBUG_RETURN(1);
+}
/*
- Print datetime string from TIME struct
- according to format string.
+ Create a formated date/time value in a string
*/
-
-String *make_datetime(String *str, TIME *l_time,
- const bool is_time_only,
- const bool add_second_frac,
- const char *ptr, uint format_length,
- bool set_len_to_zero)
+bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
+ timestamp_type type, String *str)
{
char intbuff[15];
uint days_i;
uint hours_i;
uint weekday;
ulong length;
- if (set_len_to_zero)
- str->length(0);
+ const char *ptr, *end;
+
+ str->length(0);
+ str->set_charset(&my_charset_bin);
+
if (l_time->neg)
str->append("-", 1);
- const char *end=ptr+format_length;
+
+ end= (ptr= format->format.str) + format->format.length;
for (; ptr != end ; ptr++)
{
if (*ptr != '%' || ptr+1 == end)
@@ -407,29 +387,31 @@ String *make_datetime(String *str, TIME *l_time,
switch (*++ptr) {
case 'M':
if (!l_time->month)
- return 0;
+ return 1;
str->append(month_names[l_time->month-1]);
break;
case 'b':
if (!l_time->month)
- return 0;
- str->append(month_names[l_time->month-1].ptr(),3);
+ return 1;
+ str->append(month_names[l_time->month-1],3);
break;
case 'W':
- if (is_time_only)
- return 0;
- weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0);
+ if (type == TIMESTAMP_TIME)
+ return 1;
+ weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
+ l_time->day),0);
str->append(day_names[weekday]);
break;
case 'a':
- if (is_time_only)
- return 0;
- weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),0);
- str->append(day_names[weekday].ptr(),3);
+ if (type == TIMESTAMP_TIME)
+ return 1;
+ weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
+ l_time->day),0);
+ str->append(day_names[weekday],3);
break;
case 'D':
- if (is_time_only)
- return 0;
+ if (type == TIMESTAMP_TIME)
+ return 1;
length= int10_to_str(l_time->day, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 1, '0');
if (l_time->day >= 10 && l_time->day <= 19)
@@ -496,9 +478,10 @@ String *make_datetime(String *str, TIME *l_time,
str->append_with_prefill(intbuff, length, 2, '0');
break;
case 'j':
- if (is_time_only)
- return 0;
- length= int10_to_str(calc_daynr(l_time->year,l_time->month,l_time->day) -
+ if (type == TIMESTAMP_TIME)
+ return 1;
+ length= int10_to_str(calc_daynr(l_time->year,l_time->month,
+ l_time->day) -
calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 3, '0');
break;
@@ -529,12 +512,6 @@ String *make_datetime(String *str, TIME *l_time,
case 's':
length= int10_to_str(l_time->second, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 2, '0');
- if (add_second_frac)
- {
- str->append(".", 1);
- length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff;
- str->append_with_prefill(intbuff, length, 6, '0');
- }
break;
case 'T':
length= my_sprintf(intbuff,
@@ -549,8 +526,8 @@ String *make_datetime(String *str, TIME *l_time,
case 'u':
{
uint year;
- if (is_time_only)
- return 0;
+ if (type == TIMESTAMP_TIME)
+ return 1;
length= int10_to_str(calc_week(l_time, 0, (*ptr) == 'U', &year),
intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 2, '0');
@@ -560,8 +537,8 @@ String *make_datetime(String *str, TIME *l_time,
case 'V':
{
uint year;
- if (is_time_only)
- return 0;
+ if (type == TIMESTAMP_TIME)
+ return 1;
length= int10_to_str(calc_week(l_time, 1, (*ptr) == 'V', &year),
intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 2, '0');
@@ -571,27 +548,29 @@ String *make_datetime(String *str, TIME *l_time,
case 'X':
{
uint year;
- if (is_time_only)
- return 0;
+ if (type == TIMESTAMP_TIME)
+ return 1;
(void) calc_week(l_time, 1, (*ptr) == 'X', &year);
length= int10_to_str(year, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 4, '0');
}
break;
case 'w':
- if (is_time_only)
- return 0;
- weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,l_time->day),1);
+ if (type == TIMESTAMP_TIME)
+ return 1;
+ weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
+ l_time->day),1);
length= int10_to_str(weekday, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 1, '0');
break;
+
default:
str->append(*ptr);
break;
}
}
}
- return str;
+ return 0;
}
@@ -691,21 +670,24 @@ longlong Item_func_month::val_int()
return (longlong) ltime.month;
}
+
String* Item_func_monthname::val_str(String* str)
{
+ const char *name;
uint month=(uint) Item_func_month::val_int();
+
if (!month) // This is also true for NULL
{
null_value=1;
return (String*) 0;
}
null_value=0;
-
- String *m=&month_names[month-1];
- str->copy(m->ptr(), m->length(), m->charset(), default_charset());
+ name= month_names[month-1];
+ str->set(name, strlen(name), system_charset_info);
return str;
}
+
// Returns the quarter of the year
longlong Item_func_quarter::val_int()
@@ -785,14 +767,17 @@ longlong Item_func_weekday::val_int()
return (longlong) calc_weekday(tmp_value,odbc_type)+test(odbc_type);
}
+
String* Item_func_dayname::val_str(String* str)
{
uint weekday=(uint) val_int(); // Always Item_func_daynr()
+ const char *name;
+
if (null_value)
return (String*) 0;
- String *d=&day_names[weekday];
- str->copy(d->ptr(), d->length(), d->charset(), default_charset());
+ name= day_names[weekday];
+ str->set(name, strlen(name), system_charset_info);
return str;
}
@@ -808,7 +793,7 @@ longlong Item_func_year::val_int()
longlong Item_func_unix_timestamp::val_int()
{
if (arg_count == 0)
- return (longlong) thd->query_start();
+ return (longlong) current_thd->query_start();
if (args[0]->type() == FIELD_ITEM)
{ // Optimize timestamp field
Field *field=((Item_field*) args[0])->field;
@@ -820,7 +805,7 @@ longlong Item_func_unix_timestamp::val_int()
{
return 0; /* purecov: inspected */
}
- return (longlong) str_to_timestamp(str->ptr(),str->length(), thd);
+ return (longlong) str_to_timestamp(str->ptr(),str->length());
}
@@ -840,15 +825,18 @@ longlong Item_func_time_to_sec::val_int()
*/
static bool get_interval_value(Item *args,interval_type int_type,
- String *str_value, INTERVAL *t)
+ String *str_value, INTERVAL *interval)
{
long array[5],value;
const char *str;
uint32 length;
- LINT_INIT(value); LINT_INIT(str); LINT_INIT(length);
CHARSET_INFO *cs=str_value->charset();
- bzero((char*) t,sizeof(*t));
+ LINT_INIT(value);
+ LINT_INIT(str);
+ LINT_INIT(length);
+
+ bzero((char*) interval,sizeof(*interval));
if ((int) int_type <= INTERVAL_MICROSECOND)
{
value=(long) args->val_int();
@@ -856,7 +844,7 @@ static bool get_interval_value(Item *args,interval_type int_type,
return 1;
if (value < 0)
{
- t->neg=1;
+ interval->neg=1;
value= -value;
}
}
@@ -866,14 +854,14 @@ static bool get_interval_value(Item *args,interval_type int_type,
if (!(res=args->val_str(str_value)))
return (1);
- /* record negative intervalls in t->neg */
+ /* record negative intervalls in interval->neg */
str=res->ptr();
const char *end=str+res->length();
while (str != end && my_isspace(cs,*str))
str++;
if (str != end && *str == '-')
{
- t->neg=1;
+ interval->neg=1;
str++;
}
length=(uint32) (end-str); // Set up pointers to new str
@@ -881,101 +869,101 @@ static bool get_interval_value(Item *args,interval_type int_type,
switch (int_type) {
case INTERVAL_YEAR:
- t->year=value;
+ interval->year=value;
break;
case INTERVAL_MONTH:
- t->month=value;
+ interval->month=value;
break;
case INTERVAL_DAY:
- t->day=value;
+ interval->day=value;
break;
case INTERVAL_HOUR:
- t->hour=value;
+ interval->hour=value;
break;
case INTERVAL_MICROSECOND:
- t->second_part=value;
+ interval->second_part=value;
break;
case INTERVAL_MINUTE:
- t->minute=value;
+ interval->minute=value;
break;
case INTERVAL_SECOND:
- t->second=value;
+ interval->second=value;
break;
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
if (get_interval_info(str,length,cs,2,array))
return (1);
- t->year=array[0];
- t->month=array[1];
+ interval->year=array[0];
+ interval->month=array[1];
break;
case INTERVAL_DAY_HOUR:
if (get_interval_info(str,length,cs,2,array))
return (1);
- t->day=array[0];
- t->hour=array[1];
+ interval->day=array[0];
+ interval->hour=array[1];
break;
case INTERVAL_DAY_MICROSECOND:
if (get_interval_info(str,length,cs,5,array))
return (1);
- t->day=array[0];
- t->hour=array[1];
- t->minute=array[2];
- t->second=array[3];
- t->second_part=array[4];
+ interval->day=array[0];
+ interval->hour=array[1];
+ interval->minute=array[2];
+ interval->second=array[3];
+ interval->second_part=array[4];
break;
case INTERVAL_DAY_MINUTE:
if (get_interval_info(str,length,cs,3,array))
return (1);
- t->day=array[0];
- t->hour=array[1];
- t->minute=array[2];
+ interval->day=array[0];
+ interval->hour=array[1];
+ interval->minute=array[2];
break;
case INTERVAL_DAY_SECOND:
if (get_interval_info(str,length,cs,4,array))
return (1);
- t->day=array[0];
- t->hour=array[1];
- t->minute=array[2];
- t->second=array[3];
+ interval->day=array[0];
+ interval->hour=array[1];
+ interval->minute=array[2];
+ interval->second=array[3];
break;
case INTERVAL_HOUR_MICROSECOND:
if (get_interval_info(str,length,cs,4,array))
return (1);
- t->hour=array[0];
- t->minute=array[1];
- t->second=array[2];
- t->second_part=array[3];
+ interval->hour=array[0];
+ interval->minute=array[1];
+ interval->second=array[2];
+ interval->second_part=array[3];
break;
case INTERVAL_HOUR_MINUTE:
if (get_interval_info(str,length,cs,2,array))
return (1);
- t->hour=array[0];
- t->minute=array[1];
+ interval->hour=array[0];
+ interval->minute=array[1];
break;
case INTERVAL_HOUR_SECOND:
if (get_interval_info(str,length,cs,3,array))
return (1);
- t->hour=array[0];
- t->minute=array[1];
- t->second=array[2];
+ interval->hour=array[0];
+ interval->minute=array[1];
+ interval->second=array[2];
break;
case INTERVAL_MINUTE_MICROSECOND:
if (get_interval_info(str,length,cs,3,array))
return (1);
- t->minute=array[0];
- t->second=array[1];
- t->second_part=array[2];
+ interval->minute=array[0];
+ interval->second=array[1];
+ interval->second_part=array[2];
break;
case INTERVAL_MINUTE_SECOND:
if (get_interval_info(str,length,cs,2,array))
return (1);
- t->minute=array[0];
- t->second=array[1];
+ interval->minute=array[0];
+ interval->second=array[1];
break;
case INTERVAL_SECOND_MICROSECOND:
if (get_interval_info(str,length,cs,2,array))
return (1);
- t->second=array[0];
- t->second_part=array[1];
+ interval->second=array[0];
+ interval->second_part=array[1];
break;
}
return 0;
@@ -984,34 +972,33 @@ static bool get_interval_value(Item *args,interval_type int_type,
String *Item_date::val_str(String *str)
{
- DATETIME_FORMAT *tmp_format;
TIME ltime;
ulong value=(ulong) val_int();
if (null_value)
- goto null_date;
+ return (String*) 0;
+
+ if (str->alloc(11))
+ {
+ null_value= 1;
+ return (String *) 0;
+ }
ltime.year= (value/10000L) % 10000;
ltime.month= (value/100)%100;
ltime.day= (value%100);
- ltime.neg=0;
+ ltime.neg= 0;
ltime.time_type=TIMESTAMP_DATE;
- tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format;
- if (make_datetime(str, &ltime, 0, 0,
- tmp_format->format, tmp_format->format_length, 1))
- return str;
-
- null_value= 1;
-null_date:
- return 0;
+ make_date((DATE_TIME_FORMAT *) 0, &ltime, str);
+ return str;
}
int Item_date::save_in_field(Field *field, bool no_conversions)
{
TIME ltime;
- timestamp_type t_type=TIMESTAMP_FULL;
- if (get_date(&ltime,1))
+ timestamp_type t_type=TIMESTAMP_DATETIME;
+ if (get_date(&ltime, TIME_FUZZY_DATE))
{
if (null_value)
return set_field_to_null(field);
@@ -1039,11 +1026,11 @@ void Item_func_curdate::fix_length_and_dec()
{
struct tm start;
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
decimals=0;
- max_length=10*default_charset()->mbmaxlen;
+ max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
- store_now_in_tm(thd->query_start(),&start);
+ store_now_in_tm(current_thd->query_start(),&start);
value=(longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+
((uint) start.tm_mon+1)*100+
@@ -1062,7 +1049,7 @@ void Item_func_curdate::fix_length_and_dec()
bool Item_func_curdate::get_date(TIME *res,
- bool fuzzy_date __attribute__((unused)))
+ uint fuzzy_date __attribute__((unused)))
{
*res=ltime;
return 0;
@@ -1091,19 +1078,19 @@ void Item_func_curdate_utc::store_now_in_tm(time_t now, struct tm *now_tm)
String *Item_func_curtime::val_str(String *str)
{
- str_value.set(buff,buff_length,default_charset());
+ str_value.set(buff, buff_length, &my_charset_bin);
return &str_value;
}
+
void Item_func_curtime::fix_length_and_dec()
{
struct tm start;
- DATETIME_FORMAT *tmp_format;
- String tmp((char*) buff,sizeof(buff),default_charset());
+ String tmp((char*) buff,sizeof(buff), &my_charset_bin);
TIME ltime;
decimals=0;
- store_now_in_tm(thd->query_start(),&start);
+ store_now_in_tm(current_thd->query_start(),&start);
value=(longlong) ((ulong) ((uint) start.tm_hour)*10000L+
(ulong) (((uint) start.tm_min)*100L+
(uint) start.tm_sec));
@@ -1113,12 +1100,8 @@ void Item_func_curtime::fix_length_and_dec()
ltime.second= start.tm_sec;
ltime.second_part= 0;
ltime.neg= 0;
- ltime.time_type= TIMESTAMP_TIME;
- tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format;
- make_datetime(&tmp, &ltime, 0, 0,
- tmp_format->format, tmp_format->format_length, 1);
- buff_length= tmp.length();
- max_length= buff_length;
+ make_time((DATE_TIME_FORMAT *) 0, &ltime, &tmp);
+ max_length= buff_length= tmp.length();
}
@@ -1144,7 +1127,7 @@ void Item_func_curtime_utc::store_now_in_tm(time_t now, struct tm *now_tm)
String *Item_func_now::val_str(String *str)
{
- str_value.set(buff,buff_length,default_charset());
+ str_value.set(buff,buff_length, &my_charset_bin);
return &str_value;
}
@@ -1152,11 +1135,12 @@ String *Item_func_now::val_str(String *str)
void Item_func_now::fix_length_and_dec()
{
struct tm start;
- DATETIME_FORMAT *tmp_format;
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
-
+
decimals=0;
- store_now_in_tm(thd->query_start(),&start);
+ collation.set(&my_charset_bin);
+
+ store_now_in_tm(current_thd->query_start(),&start);
value=((longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+
(((uint) start.tm_mon+1)*100+
(uint) start.tm_mday))*(longlong) 1000000L+
@@ -1173,17 +1157,15 @@ void Item_func_now::fix_length_and_dec()
ltime.second= start.tm_sec;
ltime.second_part= 0;
ltime.neg= 0;
- ltime.time_type= TIMESTAMP_FULL;
+ ltime.time_type= TIMESTAMP_DATETIME;
- tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format;
- make_datetime(&tmp, &ltime, 0, 0,
- tmp_format->format, tmp_format->format_length, 1);
- buff_length= tmp.length();
- max_length= buff_length;
+ make_datetime((DATE_TIME_FORMAT *) 0, &ltime, &tmp);
+ max_length= buff_length= tmp.length();
}
+
bool Item_func_now::get_date(TIME *res,
- bool fuzzy_date __attribute__((unused)))
+ uint fuzzy_date __attribute__((unused)))
{
*res=ltime;
return 0;
@@ -1193,7 +1175,7 @@ bool Item_func_now::get_date(TIME *res,
int Item_func_now::save_in_field(Field *to, bool no_conversions)
{
to->set_notnull();
- to->store_time(&ltime,TIMESTAMP_FULL);
+ to->store_time(&ltime,TIMESTAMP_DATETIME);
return 0;
}
@@ -1222,12 +1204,13 @@ String *Item_func_sec_to_time::val_str(String *str)
{
longlong seconds=(longlong) args[0]->val_int();
uint sec;
-
- DATETIME_FORMAT *tmp_format;
TIME ltime;
- if ((null_value=args[0]->null_value))
- goto null_date;
+ if ((null_value=args[0]->null_value) || str->alloc(19))
+ {
+ null_value= 1;
+ return (String*) 0;
+ }
ltime.neg= 0;
if (seconds < 0)
@@ -1242,14 +1225,8 @@ String *Item_func_sec_to_time::val_str(String *str)
ltime.minute= sec/60;
ltime.second= sec % 60;
- tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format;
- if (make_datetime(str, &ltime, 0, 0,
- tmp_format->format, tmp_format->format_length, 1))
- return str;
-
- null_value= 1;
-null_date:
- return (String*) 0;
+ make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
+ return str;
}
@@ -1359,9 +1336,9 @@ String *Item_func_date_format::val_str(String *str)
{
String *format;
TIME l_time;
- uint size,weekday;
+ uint size;
- if (!date_or_time)
+ if (!is_time_format)
{
if (get_arg0_date(&l_time,1))
return 0;
@@ -1369,10 +1346,8 @@ String *Item_func_date_format::val_str(String *str)
else
{
String *res;
- if (!(res=args[0]->val_str(str)))
- goto null_date;
-
- if (str_to_time(res->ptr(),res->length(),&l_time, thd))
+ if (!(res=args[0]->val_str(str)) ||
+ (str_to_time(res->ptr(),res->length(),&l_time)))
goto null_date;
l_time.year=l_time.month=l_time.day=0;
@@ -1391,10 +1366,13 @@ String *Item_func_date_format::val_str(String *str)
if (str->alloc(size))
goto null_date;
+ DATE_TIME_FORMAT date_time_format;
+ date_time_format.format.str= (char*) format->ptr();
+ date_time_format.format.length= format->length();
/* Create the result string */
- if (make_datetime(str, &l_time, 0, 0,
- format->ptr(), format->length(), 1))
+ if (!make_date_time(&date_time_format, &l_time,
+ is_time_format ? TIMESTAMP_TIME : TIMESTAMP_DATE, str))
return str;
null_date:
@@ -1406,10 +1384,8 @@ null_date:
String *Item_func_from_unixtime::val_str(String *str)
{
struct tm tm_tmp,*start;
- DATETIME_FORMAT *tmp_format;
time_t tmp=(time_t) args[0]->val_int();
- uint32 l;
- CHARSET_INFO *cs=default_charset();
+ CHARSET_INFO *cs= &my_charset_bin;
TIME ltime;
if ((null_value=args[0]->null_value))
@@ -1427,14 +1403,13 @@ String *Item_func_from_unixtime::val_str(String *str)
ltime.second_part= 0;
ltime.neg=0;
- l=20*cs->mbmaxlen+32;
- tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format;
- if (str->alloc(l) && make_datetime(str, &ltime, 1, 0,
- tmp_format->format,
- tmp_format->format_length, 1))
- return str;
- null_value= 1;
+ if (str->alloc(20*MY_CHARSET_BIN_MB_MAXLEN))
+ goto null_date;
+ make_datetime((DATE_TIME_FORMAT *) 0, &ltime, str);
+ return str;
+
null_date:
+ null_value=1;
return 0;
}
@@ -1456,7 +1431,7 @@ longlong Item_func_from_unixtime::val_int()
}
bool Item_func_from_unixtime::get_date(TIME *ltime,
- bool fuzzy_date __attribute__((unused)))
+ uint fuzzy_date __attribute__((unused)))
{
time_t tmp=(time_t) (ulong) args[0]->val_int();
if ((null_value=args[0]->null_value))
@@ -1479,10 +1454,11 @@ bool Item_func_from_unixtime::get_date(TIME *ltime,
void Item_date_add_interval::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- collation.set(default_charset());
+
+ collation.set(&my_charset_bin);
maybe_null=1;
- max_length=26*MY_CHARSET_BIN_MB_MAXLEN;
- value.alloc(32);
+ max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
+ value.alloc(max_length);
/*
The field type for the result of an Item_date function is defined as
@@ -1512,10 +1488,11 @@ void Item_date_add_interval::fix_length_and_dec()
/* Here arg[1] is a Item_interval object */
-bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date)
+bool Item_date_add_interval::get_date(TIME *ltime, uint fuzzy_date)
{
long period,sign;
INTERVAL interval;
+
ltime->neg= 0;
if (args[0]->get_date(ltime,0) ||
get_interval_value(args[1],int_type,&value,&interval))
@@ -1541,7 +1518,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date)
case INTERVAL_DAY_MINUTE:
case INTERVAL_DAY_HOUR:
long sec,days,daynr,microseconds,extra_sec;
- ltime->time_type=TIMESTAMP_FULL; // Return full date
+ ltime->time_type=TIMESTAMP_DATETIME; // Return full date
microseconds= ltime->second_part + sign*interval.second_part;
extra_sec= microseconds/1000000L;
microseconds= microseconds%1000000L;
@@ -1616,23 +1593,26 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date)
String *Item_date_add_interval::val_str(String *str)
{
TIME ltime;
- DATETIME_FORMAT *tmp_format;
+ enum date_time_format_types format;
if (Item_date_add_interval::get_date(&ltime,0))
return 0;
if (ltime.time_type == TIMESTAMP_DATE)
- tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format;
- else
- tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format;
- if (make_datetime(str, &ltime, 1, ltime.second_part,
- tmp_format->format, tmp_format->format_length, 1))
+ format= DATE_ONLY;
+ else if (ltime.second_part)
+ format= DATE_TIME_MICROSECOND;
+ else
+ format= DATE_TIME;
+
+ if (!make_datetime(format, &ltime, str))
return str;
null_value=1;
return 0;
}
+
longlong Item_date_add_interval::val_int()
{
TIME ltime;
@@ -1685,7 +1665,7 @@ longlong Item_extract::val_int()
else
{
String *res= args[0]->val_str(&value);
- if (!res || str_to_time(res->ptr(),res->length(),&ltime, thd))
+ if (!res || str_to_time(res->ptr(),res->length(),&ltime))
{
null_value=1;
return 0;
@@ -1811,15 +1791,13 @@ void Item_char_typecast::fix_length_and_dec()
max_length= char_length * cast_cs->mbmaxlen;
}
+
String *Item_datetime_typecast::val_str(String *str)
{
TIME ltime;
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (thd, DATETIME_FORMAT_TYPE).datetime_format);
-
if (!get_arg0_date(&ltime,1) &&
- make_datetime(str, &ltime, 1, ltime.second_part,
- tmp_format->format, tmp_format->format_length, 1))
+ !make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
+ &ltime, str))
return str;
null_date:
@@ -1839,12 +1817,10 @@ bool Item_time_typecast::get_time(TIME *ltime)
String *Item_time_typecast::val_str(String *str)
{
TIME ltime;
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (thd, TIME_FORMAT_TYPE).datetime_format);
if (!get_arg0_time(&ltime) &&
- make_datetime(str, &ltime, 0, ltime.second_part,
- tmp_format->format, tmp_format->format_length, 1))
+ !make_datetime(ltime.second_part ? TIME_MICROSECOND : TIME_ONLY,
+ &ltime, str))
return str;
null_value=1;
@@ -1852,7 +1828,7 @@ String *Item_time_typecast::val_str(String *str)
}
-bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date)
+bool Item_date_typecast::get_date(TIME *ltime, uint fuzzy_date)
{
bool res= get_arg0_date(ltime,1);
ltime->time_type= TIMESTAMP_DATE;
@@ -1863,19 +1839,18 @@ bool Item_date_typecast::get_date(TIME *ltime, bool fuzzy_date)
String *Item_date_typecast::val_str(String *str)
{
TIME ltime;
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (thd, DATE_FORMAT_TYPE).datetime_format);
- if (!get_arg0_date(&ltime,1) &&
- make_datetime(str, &ltime, 1, 0,
- tmp_format->format, tmp_format->format_length, 1))
- return str;
+ if (!get_arg0_date(&ltime,1) && !str->alloc(11))
+ {
+ make_date((DATE_TIME_FORMAT *) 0,&ltime, str);
+ return str;
+ }
-null_date:
null_value=1;
return 0;
}
+
/*
MAKEDATE(a,b) is a date function that creates a date value
from a year and day value.
@@ -1890,22 +1865,21 @@ String *Item_func_makedate::val_str(String *str)
if (args[0]->null_value || args[1]->null_value ||
yearnr < 0 || daynr <= 0)
- goto null_date;
+ goto err;
days= calc_daynr(yearnr,1,1) + daynr - 1;
- if (days > 0 || days < MAX_DAY_NUMBER) // Day number from year 0 to 9999-12-31
+ // Day number from year 0 to 9999-12-31
+ if (days >= 0 && days < MAX_DAY_NUMBER)
{
null_value=0;
get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day);
-
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (thd, DATE_FORMAT_TYPE).datetime_format);
- if (make_datetime(str, &l_time, 1, 0,
- tmp_format->format, tmp_format->format_length, 1))
- return str;
+ if (str->alloc(11))
+ goto err;
+ make_date((DATE_TIME_FORMAT *) 0, &l_time, str);
+ return str;
}
-null_date:
+err:
null_value=1;
return 0;
}
@@ -1915,11 +1889,11 @@ void Item_func_add_time::fix_length_and_dec()
{
enum_field_types arg0_field_type;
decimals=0;
- max_length=26*MY_CHARSET_BIN_MB_MAXLEN;
+ max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
/*
- The field type for the result of an Item_func_add_time function is defined as
- follows:
+ The field type for the result of an Item_func_add_time function is defined
+ as follows:
- If first arg is a MYSQL_TYPE_DATETIME or MYSQL_TYPE_TIMESTAMP
result is MYSQL_TYPE_DATETIME
@@ -1938,7 +1912,8 @@ void Item_func_add_time::fix_length_and_dec()
}
/*
- ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a time/datetime value
+ ADDTIME(t,a) and SUBTIME(t,a) are time functions that calculate a
+ time/datetime value
t: time_or_datetime_expression
a: time_expression
@@ -1952,7 +1927,6 @@ String *Item_func_add_time::val_str(String *str)
bool is_time= 0;
long microseconds, seconds, days= 0;
int l_sign= sign;
- DATETIME_FORMAT *tmp_format;
null_value=0;
l_time3.neg= 0;
@@ -1968,7 +1942,7 @@ String *Item_func_add_time::val_str(String *str)
{
if (args[0]->get_time(&l_time1) ||
args[1]->get_time(&l_time2) ||
- l_time2.time_type == TIMESTAMP_FULL)
+ l_time2.time_type == TIMESTAMP_DATETIME)
goto null_date;
is_time= (l_time1.time_type == TIMESTAMP_TIME);
if (is_time && (l_time2.neg == l_time1.neg && l_time1.neg))
@@ -1984,7 +1958,8 @@ String *Item_func_add_time::val_str(String *str)
if (is_time)
seconds+= l_time1.day*86400L;
else
- days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month, (uint) l_time1.day);
+ days+= calc_daynr((uint) l_time1.year,(uint) l_time1.month,
+ (uint) l_time1.day);
seconds= seconds + microseconds/1000000L;
microseconds= microseconds%1000000L;
days+= seconds/86400L;
@@ -2017,21 +1992,19 @@ String *Item_func_add_time::val_str(String *str)
calc_time_from_sec(&l_time3, seconds, microseconds);
if (!is_time)
{
- tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format;
get_date_from_daynr(days,&l_time3.year,&l_time3.month,&l_time3.day);
if (l_time3.day &&
- make_datetime(str, &l_time3, 1,
- l_time1.second_part || l_time2.second_part,
- tmp_format->format, tmp_format->format_length, 1))
+ !make_datetime(l_time1.second_part || l_time2.second_part ?
+ DATE_TIME_MICROSECOND : DATE_TIME,
+ &l_time3, str))
return str;
goto null_date;
}
- tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format;
l_time3.hour+= days*24;
- if (make_datetime(str, &l_time3, 0,
- l_time1.second_part || l_time2.second_part,
- tmp_format->format, tmp_format->format_length, 1))
+ if (!make_datetime(l_time1.second_part || l_time2.second_part ?
+ TIME_MICROSECOND : TIME_ONLY,
+ &l_time3, str))
return str;
null_date:
@@ -2054,7 +2027,6 @@ String *Item_func_timediff::val_str(String *str)
long days;
int l_sign= 1;
TIME l_time1 ,l_time2, l_time3;
- DATETIME_FORMAT *tmp_format;
null_value= 0;
if (args[0]->get_time(&l_time1) ||
@@ -2101,10 +2073,9 @@ String *Item_func_timediff::val_str(String *str)
calc_time_from_sec(&l_time3, seconds, microseconds);
- tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format;
- if (make_datetime(str, &l_time3, 0,
- l_time1.second_part || l_time2.second_part,
- tmp_format->format, tmp_format->format_length, 1))
+ if (!make_datetime(l_time1.second_part || l_time2.second_part ?
+ TIME_MICROSECOND : TIME_ONLY,
+ &l_time3, str))
return str;
null_date:
@@ -2121,7 +2092,6 @@ null_date:
String *Item_func_maketime::val_str(String *str)
{
TIME ltime;
- DATETIME_FORMAT *tmp_format;
long hour= args[0]->val_int();
long minute= args[1]->val_int();
@@ -2131,8 +2101,9 @@ String *Item_func_maketime::val_str(String *str)
args[1]->null_value ||
args[2]->null_value ||
minute > 59 || minute < 0 ||
- second > 59 || second < 0)))
- goto null_date;
+ second > 59 || second < 0 ||
+ str->alloc(19))))
+ return 0;
ltime.neg= 0;
if (hour < 0)
@@ -2143,21 +2114,19 @@ String *Item_func_maketime::val_str(String *str)
ltime.hour= (ulong)hour;
ltime.minute= (ulong)minute;
ltime.second= (ulong)second;
- tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format;
- if (make_datetime(str, &ltime, 0, 0,
- tmp_format->format, tmp_format->format_length, 1))
- return str;
-
-null_date:
- return 0;
+ make_time((DATE_TIME_FORMAT *) 0, &ltime, str);
+ return str;
}
+
/*
- MICROSECOND(a) is a function ( extraction) that extracts the microseconds from a.
+ MICROSECOND(a) is a function ( extraction) that extracts the microseconds
+ from a.
a: Datetime or time value
Result: int value
*/
+
longlong Item_func_microsecond::val_int()
{
TIME ltime;
@@ -2166,78 +2135,103 @@ longlong Item_func_microsecond::val_int()
return 0;
}
-/*
- Array of MySQL date/time/datetime formats
- Firts element is date format
- Second element is time format
- Third element is datetime format
- Fourth is format name.
-*/
-
-const char *datetime_formats[4][5]=
-{
- {"%m.%d.%Y", "%Y-%m-%d", "%Y-%m-%d", "%d.%m.%Y", "%Y%m%d"},
- {"%h:%i:%s %p", "%H:%i:%s", "%H:%i:%s", "%H.%i.%S", "%H%i%s"},
- {"%Y-%m-%d-%H.%i.%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d %H:%i:%s", "%Y-%m-%d-%H.%i.%s", "%Y%m%d%H%i%s"},
- {"USA", "JIS", "ISO", "EUR", "INTERNAL"}
-};
-
-
-/*
- Return format string according format name.
- If name is unknown, result is ISO format string
-*/
String *Item_func_get_format::val_str(String *str)
{
- String *val=args[0]->val_str(str);
- const char *format_str= datetime_formats[tm_format][ISO_FORMAT];
+ const char *format_name;
+ KNOWN_DATE_TIME_FORMAT *format;
+ String *val= args[0]->val_str(str);
+ ulong val_len;
- if (!args[0]->null_value)
+ if ((null_value= args[0]->null_value))
+ return 0;
+
+ val_len= val->length();
+ for (format= &known_date_time_formats[0];
+ (format_name= format->format_name);
+ format++)
{
- const char *val_ptr= val->ptr();
- uint val_len= val->length();
- for (int i= 0; i < 5; i++)
+ uint format_name_len;
+ format_name_len= strlen(format_name);
+ if (val_len == format_name_len &&
+ !my_strnncoll(&my_charset_latin1,
+ (const uchar *) val->ptr(), val_len,
+ (const uchar *) format_name, val_len))
{
- const char *name_format_str= datetime_formats[3][i];
- uint format_str_len= strlen(name_format_str);
- if ( val_len == format_str_len &&
- !my_strnncoll(&my_charset_latin1,
- (const uchar *) val_ptr, val_len,
- (const uchar *) name_format_str, format_str_len))
- {
- format_str= datetime_formats[tm_format][i];
- break;
- }
+ const char *format_str= get_date_time_format_str(format, type);
+ str->set(format_str, strlen(format_str), &my_charset_bin);
+ return str;
}
}
+ null_value= 1;
+ return 0;
+}
+
+
+void Item_func_get_format::print(String *str)
+{
+ str->append(func_name());
+ str->append('(');
+
+ switch (type) {
+ case TIMESTAMP_DATE:
+ str->append("DATE, ");
+ break;
+ case TIMESTAMP_DATETIME:
+ str->append("DATETIME, ");
+ break;
+ case TIMESTAMP_TIME:
+ str->append("TIME, ");
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+ args[0]->print(str);
+ str->append(')');
+}
+
+
+bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date)
+{
+ DATE_TIME_FORMAT date_time_format;
+ char val_buff[64], format_buff[64];
+ String val_str(val_buff, sizeof(val_buff), &my_charset_bin), *val;
+ String format_str(format_buff, sizeof(format_buff), &my_charset_bin), *format;
+
+ val= args[0]->val_str(&val_str);
+ format= args[1]->val_str(&format_str);
+ if (args[0]->null_value || args[1]->null_value)
+ goto null_date;
+
null_value= 0;
- str->length(0);
- str->append(format_str);
- return str;
+ bzero((char*) ltime, sizeof(ltime));
+ date_time_format.format.str= (char*) format->ptr();
+ date_time_format.format.length= format->length();
+ if (extract_date_time(&date_time_format, val->ptr(), val->length(),
+ ltime))
+ goto null_date;
+ return 0;
+
+null_date:
+ return (null_value=1);
}
String *Item_func_str_to_date::val_str(String *str)
{
TIME ltime;
- bzero((char*) &ltime, sizeof(ltime));
- DATETIME_FORMAT *tmp_format;
- String *val=args[0]->val_str(str);
- String *format=args[1]->val_str(str);
- if (args[0]->null_value || args[1]->null_value ||
- extract_datetime(val->ptr(), val->length(),
- format->ptr(), val->length(),
- &ltime))
- goto null_date;
- tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format;
- if (make_datetime(str, &ltime, 0, 0, tmp_format->format,
- tmp_format->format_length, 1))
- return str;
+ if (Item_func_str_to_date::get_date(&ltime, TIME_FUZZY_DATE))
+ return 0;
-null_date:
- null_value=1;
+ /*
+ The following DATE_TIME should be done dynamicly based on the
+ format string (wen it's a constant). For example, we should only return
+ microseconds if there was an %f in the format
+ */
+ if (!make_datetime(ltime.second_part ? DATE_TIME_MICROSECOND : DATE_TIME,
+ &ltime, str))
+ return str;
return 0;
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index b7bf294b83d..e98b5eb1f1d 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -29,7 +29,7 @@ public:
const char *func_name() const { return "period_add"; }
void fix_length_and_dec()
{
- max_length=6*default_charset()->mbmaxlen;
+ max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
};
@@ -43,7 +43,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=6*default_charset()->mbmaxlen;
+ max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
}
};
@@ -57,7 +57,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=6*default_charset()->mbmaxlen;
+ max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -72,7 +72,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=2*default_charset()->mbmaxlen;
+ max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -86,16 +86,16 @@ public:
double val() { return (double) Item_func_month::val_int(); }
String *val_str(String *str)
{
- str->set(val_int(), default_charset());
+ str->set(val_int(), &my_charset_bin);
return null_value ? 0 : str;
}
const char *func_name() const { return "month"; }
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
decimals=0;
- max_length=2*default_charset()->mbmaxlen;
+ max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -110,9 +110,9 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
decimals=0;
- max_length=10*default_charset()->mbmaxlen;
+ max_length=10*my_charset_bin.mbmaxlen;
maybe_null=1;
}
};
@@ -127,7 +127,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=3*default_charset()->mbmaxlen;
+ max_length=3*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -142,7 +142,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=2*default_charset()->mbmaxlen;
+ max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -157,7 +157,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=2*default_charset()->mbmaxlen;
+ max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -172,7 +172,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=1*default_charset()->mbmaxlen;
+ max_length=1*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -187,7 +187,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=2*default_charset()->mbmaxlen;
+ max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -202,7 +202,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=2*default_charset()->mbmaxlen;
+ max_length=2*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -216,7 +216,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=6*default_charset()->mbmaxlen;
+ max_length=6*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -231,7 +231,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=4*default_charset()->mbmaxlen;
+ max_length=4*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -247,16 +247,16 @@ public:
double val() { return (double) val_int(); }
String *val_str(String *str)
{
- str->set(val_int(), default_charset());
+ str->set(val_int(), &my_charset_bin);
return null_value ? 0 : str;
}
const char *func_name() const { return "weekday"; }
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
decimals=0;
- max_length=1*default_charset()->mbmaxlen;
+ max_length=1*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -270,9 +270,9 @@ class Item_func_dayname :public Item_func_weekday
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
decimals=0;
- max_length=9*default_charset()->mbmaxlen;
+ max_length=9*MY_CHARSET_BIN_MB_MAXLEN;
maybe_null=1;
}
};
@@ -289,7 +289,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=10*default_charset()->mbmaxlen;
+ max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
}
};
@@ -303,7 +303,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=10*default_charset()->mbmaxlen;
+ max_length=10*MY_CHARSET_BIN_MB_MAXLEN;
}
};
@@ -322,14 +322,14 @@ public:
const char *func_name() const { return "date"; }
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
decimals=0;
- max_length=10*default_charset()->mbmaxlen;
+ max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
int save_in_field(Field *to, bool no_conversions);
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_date(maybe_null, name, t_arg, default_charset()));
+ return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
}
};
@@ -343,7 +343,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_datetime(maybe_null, name, t_arg, default_charset()));
+ return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
}
};
@@ -366,7 +366,7 @@ public:
void fix_length_and_dec();
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_time(maybe_null, name, t_arg, default_charset()));
+ return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
/*
Abstract method that defines which time zone is used for conversion.
@@ -408,7 +408,7 @@ public:
void set_result_from_tm(struct tm *now);
longlong val_int() { return (value) ; }
void fix_length_and_dec();
- bool get_date(TIME *res,bool fuzzy_date);
+ bool get_date(TIME *res, uint fuzzy_date);
virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0;
};
@@ -448,7 +448,7 @@ public:
int save_in_field(Field *to, bool no_conversions);
String *val_str(String *str);
void fix_length_and_dec();
- bool get_date(TIME *res,bool fuzzy_date);
+ bool get_date(TIME *res, uint fuzzy_date);
virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0;
};
@@ -485,11 +485,11 @@ public:
class Item_func_date_format :public Item_str_func
{
int fixed_length;
- const bool date_or_time;
+ const bool is_time_format;
String value;
public:
- Item_func_date_format(Item *a,Item *b,bool date_or_time_arg)
- :Item_str_func(a,b),date_or_time(date_or_time_arg) {}
+ Item_func_date_format(Item *a,Item *b,bool is_time_format_arg)
+ :Item_str_func(a,b),is_time_format(is_time_format_arg) {}
String *val_str(String *str);
const char *func_name() const { return "date_format"; }
void fix_length_and_dec();
@@ -507,11 +507,11 @@ class Item_func_from_unixtime :public Item_date_func
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
decimals=0;
- max_length=19*default_charset()->mbmaxlen;
+ max_length=MAX_DATETIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
- bool get_date(TIME *res,bool fuzzy_date);
+ bool get_date(TIME *res, uint fuzzy_date);
};
@@ -524,15 +524,15 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
maybe_null=1;
- max_length=13*default_charset()->mbmaxlen;
+ max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
const char *func_name() const { return "sec_to_time"; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_time(maybe_null, name, t_arg, default_charset()));
+ return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
};
@@ -567,7 +567,7 @@ public:
enum_field_types field_type() const { return cached_field_type; }
double val() { return (double) val_int(); }
longlong val_int();
- bool get_date(TIME *res,bool fuzzy_date);
+ bool get_date(TIME *res, uint fuzzy_date);
};
@@ -601,7 +601,7 @@ public:
}
void fix_length_and_dec()
{
- collation.set(default_charset());
+ collation.set(&my_charset_bin);
max_length=args[0]->max_length;
}
void print(String *str);
@@ -627,12 +627,12 @@ class Item_date_typecast :public Item_typecast
public:
Item_date_typecast(Item *a) :Item_typecast(a) {}
String *val_str(String *str);
- bool get_date(TIME *ltime, bool fuzzy_date);
+ bool get_date(TIME *ltime, uint fuzzy_date);
const char *func_name() const { return "date"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_date(maybe_null, name, t_arg, default_charset()));
+ return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
}
};
@@ -647,7 +647,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_time(maybe_null, name, t_arg, default_charset()));
+ return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
};
@@ -661,7 +661,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_datetime(maybe_null, name, t_arg, default_charset()));
+ return (new Field_datetime(maybe_null, name, t_arg, &my_charset_bin));
}
};
@@ -675,7 +675,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=8*MY_CHARSET_BIN_MB_MAXLEN;
+ max_length=MAX_DATE_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
Field *tmp_table_field(TABLE *t_arg)
{
@@ -724,7 +724,7 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=17*MY_CHARSET_BIN_MB_MAXLEN;
+ max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
Field *tmp_table_field(TABLE *t_arg)
{
@@ -743,11 +743,11 @@ public:
void fix_length_and_dec()
{
decimals=0;
- max_length=8*MY_CHARSET_BIN_MB_MAXLEN;
+ max_length=MAX_TIME_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
Field *tmp_table_field(TABLE *t_arg)
{
- return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
+ return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
}
};
@@ -765,44 +765,43 @@ public:
};
-enum datetime_format
+enum date_time_format
{
USA_FORMAT, JIS_FORMAT, ISO_FORMAT, EUR_FORMAT, INTERNAL_FORMAT
};
-
-enum datetime_format_types
-{
- DATE_FORMAT_TYPE= 0, TIME_FORMAT_TYPE, DATETIME_FORMAT_TYPE
-};
-
-
class Item_func_get_format :public Item_str_func
{
- const datetime_format_types tm_format;
+ const timestamp_type type;
public:
- Item_func_get_format(datetime_format_types type_arg1, Item *a)
- :Item_str_func(a), tm_format(type_arg1) {}
+ Item_func_get_format(timestamp_type type_arg, Item *a)
+ :Item_str_func(a), type(type_arg)
+ {}
String *val_str(String *str);
const char *func_name() const { return "get_format"; }
void fix_length_and_dec()
{
+ maybe_null= 1;
decimals=0;
max_length=17*MY_CHARSET_BIN_MB_MAXLEN;
}
+ void print(String *str);
};
-class Item_func_str_to_date :public Item_str_func
+class Item_func_str_to_date :public Item_date_func
{
public:
Item_func_str_to_date(Item *a, Item *b)
- :Item_str_func(a, b) {}
+ :Item_date_func(a, b)
+ {}
String *val_str(String *str);
+ bool get_date(TIME *ltime, uint fuzzy_date);
const char *func_name() const { return "str_to_date"; }
void fix_length_and_dec()
{
+ maybe_null= 1;
decimals=0;
- max_length=29*MY_CHARSET_BIN_MB_MAXLEN;
+ max_length=MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN;
}
};
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 1926314cef1..92ad413098b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -741,6 +741,13 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
/* mysqld.cc */
extern void yyerror(const char*);
+/* strfunc.cc */
+ulonglong find_set(TYPELIB *typelib,const char *x, uint length,
+ char **err_pos, uint *err_len, bool *set_warning);
+uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match);
+uint check_word(TYPELIB *lib, const char *val, const char *end,
+ const char **end_of_word);
+
/*
External variables
*/
@@ -828,7 +835,6 @@ extern pthread_attr_t connection_attrib;
extern I_List<THD> threads;
extern I_List<NAMED_LIST> key_caches;
extern MY_BITMAP temp_pool;
-extern DATE_FORMAT dayord;
extern String my_empty_string;
extern String my_null_string;
extern SHOW_VAR init_vars[],status_vars[], internal_vars[];
@@ -840,12 +846,8 @@ extern struct system_variables global_system_variables;
extern struct system_variables max_system_variables;
extern struct rand_struct sql_rand;
-#define g_datetime_frm(a) (global_system_variables.datetime_formats[(a)])
-#define t_datetime_frm(a, b) ((a)->variables.datetime_formats[(b)])
-
-extern const char *datetime_formats[4][5];
-extern const char *opt_datetime_format_names[3];
-extern const char *opt_datetime_formats[3];
+extern const char *opt_date_time_formats[];
+extern KNOWN_DATE_TIME_FORMAT known_date_time_formats[];
extern String null_string;
extern HASH open_cache;
@@ -917,23 +919,26 @@ void get_date_from_daynr(long daynr,uint *year, uint *month,
uint *day);
void init_time(void);
long my_gmt_sec(TIME *, long *current_timezone);
-time_t str_to_timestamp(const char *str,uint length, THD *thd);
-bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd);
-longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd);
+time_t str_to_timestamp(const char *str,uint length);
+bool str_to_time(const char *str,uint length,TIME *l_time);
+longlong str_to_datetime(const char *str,uint length, uint fuzzy_date);
timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time,
- bool fuzzy_date, THD *thd);
+ uint flags);
void localtime_to_TIME(TIME *to, struct tm *from);
void calc_time_from_sec(TIME *to, long seconds, long microseconds);
-extern DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format,
- datetime_format_types format_type,
- const char *format_str,
- uint format_length, bool is_alloc);
-extern String *make_datetime(String *str, TIME *l_time,
- const bool is_time_only,
- const bool add_second_frac,
- const char *ptr, uint format_length,
- bool set_len_to_zero);
+extern DATE_TIME_FORMAT *date_time_format_make(timestamp_type format_type,
+ const char *format_str,
+ uint format_length);
+extern DATE_TIME_FORMAT *date_time_format_copy(THD *thd,
+ DATE_TIME_FORMAT *format);
+const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
+ timestamp_type type);
+extern bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
+ timestamp_type type, String *str);
+extern void make_time(DATE_TIME_FORMAT *format, TIME *l_time, String *str);
+void make_date(DATE_TIME_FORMAT *format, TIME *l_time, String *str);
+void make_datetime(DATE_TIME_FORMAT *format, TIME *l_time, String *str);
int test_if_number(char *str,int *res,bool allow_wildcards);
void change_byte(byte *,uint,char,char);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index da7d3df0251..adbfcdfcb1a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -320,10 +320,7 @@ char mysql_real_data_home[FN_REFLEN],
language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN],
max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file;
-const char *opt_datetime_formats[3];
-const char *opt_datetime_format_names[3]= {"date_format",
- "time_format",
- "datetime_format"};
+const char *opt_date_time_formats[3];
char *language_ptr, *default_collation_name, *default_character_set_name;
char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home;
@@ -351,7 +348,6 @@ struct system_variables global_system_variables;
struct system_variables max_system_variables;
MY_TMPDIR mysql_tmpdir_list;
-DATE_FORMAT dayord;
MY_BITMAP temp_pool;
CHARSET_INFO *system_charset_info, *files_charset_info ;
@@ -912,9 +908,12 @@ void clean_up(bool print_message)
#ifdef USE_RAID
end_raid();
#endif
- g_datetime_frm(DATE_FORMAT_TYPE).clean();
- g_datetime_frm(TIME_FORMAT_TYPE).clean();
- g_datetime_frm(DATETIME_FORMAT_TYPE).clean();
+ my_free((char*) global_system_variables.date_format,
+ MYF(MY_ALLOW_ZERO_PTR));
+ my_free((char*) global_system_variables.time_format,
+ MYF(MY_ALLOW_ZERO_PTR));
+ my_free((char*) global_system_variables.datetime_format,
+ MYF(MY_ALLOW_ZERO_PTR));
if (defaults_argv)
free_defaults(defaults_argv);
free_tmpdir(&mysql_tmpdir_list);
@@ -2008,33 +2007,46 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
}
-int init_global_datetime_format(datetime_format_types format_type, bool is_alloc)
+/*
+ Initialize one of the global date/time format variables
+
+ SYNOPSIS
+ init_global_datetime_format()
+ format_type What kind of format should be supported
+ var_ptr Pointer to variable that should be updated
+
+ NOTES
+ The default value is taken from either opt_date_time_formats[] or
+ the ISO format (ANSI SQL)
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool init_global_datetime_format(timestamp_type format_type,
+ DATE_TIME_FORMAT **var_ptr)
{
- const char *format_str= opt_datetime_formats[format_type];
- uint format_length= 0;
- DATETIME_FORMAT *tmp_format= &g_datetime_frm(format_type).datetime_format;
+ /* Get command line option */
+ const char *str= opt_date_time_formats[format_type];
+ DATE_TIME_FORMAT *format;
- if (format_str)
- {
- format_str= opt_datetime_formats[format_type];
- format_length= strlen(format_str);
- }
- else
+ if (!str) // No specified format
{
- format_str= datetime_formats[format_type][ISO_FORMAT];
- format_length= strlen(datetime_formats[format_type][ISO_FORMAT]);
- opt_datetime_formats[format_type]= format_str;
+ str= get_date_time_format_str(&known_date_time_formats[ISO_FORMAT],
+ format_type);
+ /*
+ Set the "command line" option to point to the generated string so
+ that we can set global formats back to default
+ */
+ opt_date_time_formats[format_type]= str;
}
- if (make_format(tmp_format, format_type, format_str,
- format_length, is_alloc))
+ if (!(*var_ptr= date_time_format_make(format_type, str, strlen(str))))
{
- g_datetime_frm(format_type).name= opt_datetime_format_names[format_type];
- g_datetime_frm(format_type).name_length=
- strlen(opt_datetime_format_names[format_type]);
- g_datetime_frm(format_type).format_type= format_type;
- return 0;
+ fprintf(stderr, "Wrong date/time format specifier: %s\n", str);
+ return 1;
}
- return 1;
+ return 0;
}
@@ -2149,17 +2161,12 @@ static int init_common_variables(const char *conf_file_name, int argc,
}
default_charset_info= default_collation;
}
- global_system_variables.collation_server= default_charset_info;
- global_system_variables.collation_database= default_charset_info;
- global_system_variables.collation_connection= default_charset_info;
+ /* Set collactions that depends on the default collation */
+ global_system_variables.collation_server= default_charset_info;
+ global_system_variables.collation_database= default_charset_info;
+ global_system_variables.collation_connection= default_charset_info;
global_system_variables.character_set_results= default_charset_info;
- global_system_variables.character_set_client= default_charset_info;
- global_system_variables.collation_connection= default_charset_info;
-
- if (init_global_datetime_format(DATE_FORMAT_TYPE, 1) ||
- init_global_datetime_format(TIME_FORMAT_TYPE, 1) ||
- init_global_datetime_format(DATETIME_FORMAT_TYPE, 1))
- return 1;
+ global_system_variables.character_set_client= default_charset_info;
if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
return 1;
@@ -4572,7 +4579,7 @@ The minimum value for this variable is 4096.",
(gptr*) &max_system_variables.net_wait_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
{"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
- "Logs will be rotated after expire-log-days days. ",
+ "Logs will be rotated after expire-log-days days ",
(gptr*) &expire_logs_days,
(gptr*) &expire_logs_days, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
@@ -4582,23 +4589,24 @@ The minimum value for this variable is 4096.",
(gptr*) &max_system_variables.default_week_format,
0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0},
{ "date-format", OPT_DATE_FORMAT,
- "The DATE format.",
- (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE],
- (gptr*) &opt_datetime_formats[DATE_FORMAT_TYPE],
+ "The DATE format (For future).",
+ (gptr*) &opt_date_time_formats[TIMESTAMP_DATE],
+ (gptr*) &opt_date_time_formats[TIMESTAMP_DATE],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "datetime-format", OPT_DATETIME_FORMAT,
- "The DATETIME/TIMESTAMP format.",
- (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE],
- (gptr*) &opt_datetime_formats[DATETIME_FORMAT_TYPE],
+ "The DATETIME/TIMESTAMP format (for future).",
+ (gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME],
+ (gptr*) &opt_date_time_formats[TIMESTAMP_DATETIME],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{ "time-format", OPT_TIME_FORMAT,
- "The TIME format.",
- (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE],
- (gptr*) &opt_datetime_formats[TIME_FORMAT_TYPE],
+ "The TIME format (for future).",
+ (gptr*) &opt_date_time_formats[TIMESTAMP_TIME],
+ (gptr*) &opt_date_time_formats[TIMESTAMP_TIME],
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
+
struct show_var_st status_vars[]= {
{"Aborted_clients", (char*) &aborted_threads, SHOW_LONG},
{"Aborted_connects", (char*) &aborted_connects, SHOW_LONG},
@@ -4904,6 +4912,8 @@ static void mysql_init_variables(void)
national_charset_info= &my_charset_utf8_general_ci;
table_alias_charset= &my_charset_bin;
+ opt_date_time_formats[0]= opt_date_time_formats[1]= opt_date_time_formats[2]= 0;
+
/* Things with default values that are not zero */
delay_key_write_options= (uint) DELAY_KEY_WRITE_ON;
opt_specialflag= SPECIAL_ENGLISH;
@@ -4960,11 +4970,6 @@ static void mysql_init_variables(void)
/* Set default values for some option variables */
- global_system_variables.collation_server= default_charset_info;
- global_system_variables.collation_database= default_charset_info;
- global_system_variables.collation_connection= default_charset_info;
- global_system_variables.character_set_results= default_charset_info;
- global_system_variables.character_set_client= default_charset_info;
global_system_variables.table_type= DB_TYPE_MYISAM;
global_system_variables.tx_isolation= ISO_REPEATABLE_READ;
global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
@@ -4973,10 +4978,6 @@ static void mysql_init_variables(void)
max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
global_system_variables.old_passwords= 0;
- init_global_datetime_format(DATE_FORMAT_TYPE, 0);
- init_global_datetime_format(TIME_FORMAT_TYPE, 0);
- init_global_datetime_format(DATETIME_FORMAT_TYPE, 0);
-
/* Variables that depends on compile options */
#ifndef DBUG_OFF
default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace",
@@ -5578,7 +5579,7 @@ static void get_options(int argc,char **argv)
exit(ho_error);
if (argc > 0)
{
- fprintf(stderr, "%s: Too many arguments.\nUse --help to get a list of available options\n", my_progname);
+ fprintf(stderr, "%s: Too many arguments (first extra is '%s').\nUse --help to get a list of available options\n", my_progname, *argv);
exit(ho_error);
}
@@ -5639,6 +5640,14 @@ static void get_options(int argc,char **argv)
opt_specialflag|= SPECIAL_SHORT_LOG_FORMAT;
if (opt_log_queries_not_using_indexes)
opt_specialflag|= SPECIAL_LOG_QUERIES_NOT_USING_INDEXES;
+
+ if (init_global_datetime_format(TIMESTAMP_DATE,
+ &global_system_variables.date_format) ||
+ init_global_datetime_format(TIMESTAMP_TIME,
+ &global_system_variables.time_format) ||
+ init_global_datetime_format(TIMESTAMP_DATETIME,
+ &global_system_variables.datetime_format))
+ exit(1);
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 0fe759cff67..d7a745d371d 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -833,12 +833,17 @@ bool Protocol_simple::store(TIME *tm)
field_pos++;
#endif
char buff[40];
- String tmp((char*) buff,sizeof(buff),&my_charset_bin);
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (current_thd, DATETIME_FORMAT_TYPE).datetime_format);
- make_datetime(&tmp, tm, 1, tm->second_part,
- tmp_format->format, tmp_format->format_length, 1);
- return net_store_data((char*) tmp.ptr(), tmp.length());
+ uint length;
+ length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d",
+ (int) tm->year,
+ (int) tm->month,
+ (int) tm->day,
+ (int) tm->hour,
+ (int) tm->minute,
+ (int) tm->second));
+ if (tm->second_part)
+ length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
+ return net_store_data((char*) buff, length);
}
@@ -851,10 +856,7 @@ bool Protocol_simple::store_date(TIME *tm)
#endif
char buff[40];
String tmp((char*) buff,sizeof(buff),&my_charset_bin);
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (current_thd, DATE_FORMAT_TYPE).datetime_format);
- make_datetime(&tmp, tm, 1, 0,
- tmp_format->format, tmp_format->format_length, 1);
+ make_date((DATE_TIME_FORMAT *) 0, tm, &tmp);
return net_store_data((char*) tmp.ptr(), tmp.length());
}
@@ -873,14 +875,16 @@ bool Protocol_simple::store_time(TIME *tm)
field_pos++;
#endif
char buff[40];
- String tmp((char*) buff,sizeof(buff),&my_charset_bin);
- DATETIME_FORMAT *tmp_format= (&t_datetime_frm
- (current_thd, TIME_FORMAT_TYPE).datetime_format);
+ uint length;
uint day= (tm->year || tm->month) ? 0 : tm->day;
- tm->hour= (long) day*24L+(long) tm->hour;
- make_datetime(&tmp, tm, 0, tm->second_part,
- tmp_format->format, tmp_format->format_length, 1);
- return net_store_data((char*) tmp.ptr(), tmp.length());
+ length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d",
+ tm->neg ? "-" : "",
+ (long) day*24L+(long) tm->hour,
+ (int) tm->minute,
+ (int) tm->second));
+ if (tm->second_part)
+ length+= my_sprintf(buff+length,(buff+length, ".%06d", (int)tm->second_part));
+ return net_store_data((char*) buff, length);
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index d09544697ea..4d9fb1b6c27 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -289,14 +289,25 @@ sys_var_thd_ulong sys_tmp_table_size("tmp_table_size",
&SV::tmp_table_size);
sys_var_thd_ulong sys_net_wait_timeout("wait_timeout",
&SV::net_wait_timeout);
-
+
#ifdef HAVE_INNOBASE_DB
sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct",
&srv_max_buf_pool_modified_pct);
#endif
-/*
- Variables that are bits in THD
-*/
+
+/* Time/date/datetime formats */
+
+sys_var_thd_date_time_format sys_time_format("time_format",
+ &SV::time_format,
+ TIMESTAMP_TIME);
+sys_var_thd_date_time_format sys_date_format("date_format",
+ &SV::date_format,
+ TIMESTAMP_DATE);
+sys_var_thd_date_time_format sys_datetime_format("datetime_format",
+ &SV::datetime_format,
+ TIMESTAMP_DATETIME);
+
+/* Variables that are bits in THD */
static sys_var_thd_bit sys_autocommit("autocommit",
set_option_autocommit,
@@ -403,9 +414,8 @@ sys_var *sys_variables[]=
&sys_collation_server,
&sys_concurrent_insert,
&sys_connect_timeout,
- &g_datetime_frm(DATE_FORMAT_TYPE),
- &g_datetime_frm(DATETIME_FORMAT_TYPE),
- &g_datetime_frm(TIME_FORMAT_TYPE),
+ &sys_date_format,
+ &sys_datetime_format,
&sys_default_week_format,
&sys_delay_key_write,
&sys_delayed_insert_limit,
@@ -472,6 +482,7 @@ sys_var *sys_variables[]=
&sys_rand_seed1,
&sys_rand_seed2,
&sys_range_alloc_block_size,
+ &sys_readonly,
&sys_read_buff_size,
&sys_read_rnd_buff_size,
#ifdef HAVE_REPLICATION
@@ -487,7 +498,6 @@ sys_var *sys_variables[]=
&sys_slave_net_timeout,
&sys_slave_skip_counter,
#endif
- &sys_readonly,
&sys_slow_launch_time,
&sys_sort_buffer,
&sys_sql_big_tables,
@@ -498,6 +508,7 @@ sys_var *sys_variables[]=
&sys_table_cache_size,
&sys_table_type,
&sys_thread_cache_size,
+ &sys_time_format,
&sys_timestamp,
&sys_tmp_table_size,
&sys_trans_alloc_block_size,
@@ -543,9 +554,9 @@ struct show_var_st init_vars[]= {
{sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
{sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
{"datadir", mysql_real_data_home, SHOW_CHAR},
- {"date_format", (char*) &g_datetime_frm(DATE_FORMAT_TYPE), SHOW_SYS},
- {"datetime_format", (char*) &g_datetime_frm(DATETIME_FORMAT_TYPE), SHOW_SYS},
- {"default_week_format", (char*) &sys_default_week_format, SHOW_SYS},
+ {sys_date_format.name, (char*) &sys_date_format, SHOW_SYS},
+ {sys_datetime_format.name, (char*) &sys_datetime_format, SHOW_SYS},
+ {sys_default_week_format.name, (char*) &sys_default_week_format, SHOW_SYS},
{sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS},
{sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS},
{sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS},
@@ -701,7 +712,7 @@ struct show_var_st init_vars[]= {
#endif
{"thread_stack", (char*) &thread_stack, SHOW_LONG},
{sys_tx_isolation.name, (char*) &sys_tx_isolation, SHOW_SYS},
- {"time_format", (char*) &g_datetime_frm(TIME_FORMAT_TYPE), SHOW_SYS},
+ {sys_time_format.name, (char*) &sys_time_format, SHOW_SYS},
#ifdef HAVE_TZNAME
{"timezone", time_zone, SHOW_CHAR},
#endif
@@ -725,71 +736,6 @@ bool sys_var::check(THD *thd, set_var *var)
/*
Functions to check and update variables
*/
-char *update_datetime_format(THD *thd, enum enum_var_type type,
- enum datetime_format_types format_type,
- DATETIME_FORMAT *tmp_format)
-{
- char *old_value;
- if (type == OPT_GLOBAL)
- {
- pthread_mutex_lock(&LOCK_global_system_variables);
- old_value= g_datetime_frm(format_type).datetime_format.format;
- g_datetime_frm(format_type).datetime_format= *tmp_format;
- pthread_mutex_unlock(&LOCK_global_system_variables);
- }
- else
- {
- old_value= t_datetime_frm(thd,format_type).datetime_format.format;
- t_datetime_frm(thd, format_type).datetime_format= *tmp_format;
- }
- return old_value;
-}
-
-
-bool sys_var_datetime_format::update(THD *thd, set_var *var)
-{
- DATETIME_FORMAT tmp_format;
- char *old_value;
- uint new_length;
-
- if ((new_length= var->value->str_value.length()))
- {
- if (!make_format(&tmp_format, format_type,
- var->value->str_value.ptr(),
- new_length, 1))
- return 1;
- }
-
- old_value= update_datetime_format(thd, var->type, format_type, &tmp_format);
- my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
- return 0;
-}
-
-byte *sys_var_datetime_format::value_ptr(THD *thd, enum_var_type type,
- LEX_STRING *base)
-{
- if (type == OPT_GLOBAL)
- return (byte*) g_datetime_frm(format_type).datetime_format.format;
- return (byte*) t_datetime_frm(thd, format_type).datetime_format.format;
-}
-
-void sys_var_datetime_format::set_default(THD *thd, enum_var_type type)
-{
- DATETIME_FORMAT tmp_format;
- char *old_value;
- uint new_length;
-
- if ((new_length= strlen(opt_datetime_formats[format_type])))
- {
- if (!make_format(&tmp_format, format_type,
- opt_datetime_formats[format_type],
- new_length, 1))
- return;
- }
-
- old_value= update_datetime_format(thd, type, format_type, &tmp_format);
- my_free(old_value, MYF(MY_ALLOW_ZERO_PTR));
-}
/*
The following 3 functions need to be changed in 4.1 when we allow
@@ -1202,8 +1148,8 @@ bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names)
{
if (!(res=var->value->val_str(&str)) ||
((long) (var->save_result.ulong_value=
- (ulong) find_type(res->c_ptr(), enum_names, 3)-1))
- < 0)
+ (ulong) find_type(enum_names, res->ptr(),
+ res->length(),1)-1)) < 0)
{
value= res ? res->c_ptr() : "NULL";
goto err;
@@ -1317,8 +1263,12 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1);
case SHOW_CHAR:
{
+ Item_string *tmp;
+ pthread_mutex_lock(&LOCK_global_system_variables);
char *str= (char*) value_ptr(thd, var_type, base);
- return new Item_string(str, strlen(str), system_charset_info);
+ tmp= new Item_string(str, strlen(str), system_charset_info);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return tmp;
}
default:
net_printf(thd, ER_VAR_CANT_BE_READ, name);
@@ -1377,6 +1327,112 @@ byte *sys_var_thd_bit::value_ptr(THD *thd, enum_var_type type,
}
+/* Update a date_time format variable based on given value */
+
+void sys_var_thd_date_time_format::update2(THD *thd, enum_var_type type,
+ DATE_TIME_FORMAT *new_value)
+{
+ DATE_TIME_FORMAT *old;
+ DBUG_ENTER("sys_var_date_time_format::update2");
+ DBUG_DUMP("positions",(char*) new_value->positions,
+ sizeof(new_value->positions));
+
+ if (type == OPT_GLOBAL)
+ {
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ old= (global_system_variables.*offset);
+ (global_system_variables.*offset)= new_value;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ }
+ else
+ {
+ old= (thd->variables.*offset);
+ (thd->variables.*offset)= new_value;
+ }
+ my_free((char*) old, MYF(MY_ALLOW_ZERO_PTR));
+ DBUG_VOID_RETURN;
+}
+
+
+bool sys_var_thd_date_time_format::update(THD *thd, set_var *var)
+{
+ DATE_TIME_FORMAT *new_value;
+ /* We must make a copy of the last value to get it into normal memory */
+ new_value= date_time_format_copy((THD*) 0,
+ var->save_result.date_time_format);
+ if (!new_value)
+ return 1; // Out of memory
+ update2(thd, var->type, new_value); // Can't fail
+ return 0;
+}
+
+
+bool sys_var_thd_date_time_format::check(THD *thd, set_var *var)
+{
+ char buff[80];
+ String str(buff,sizeof(buff), system_charset_info), *res;
+ DATE_TIME_FORMAT *format;
+
+ if (!(res=var->value->val_str(&str)))
+ res= &my_empty_string;
+
+ if (!(format= date_time_format_make(date_time_type,
+ res->ptr(), res->length())))
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, res->c_ptr());
+ return 1;
+ }
+
+ /*
+ We must copy result to thread space to not get a memory leak if
+ update is aborted
+ */
+ var->save_result.date_time_format= date_time_format_copy(thd, format);
+ my_free((char*) format, MYF(0));
+ return var->save_result.date_time_format == 0;
+}
+
+
+void sys_var_thd_date_time_format::set_default(THD *thd, enum_var_type type)
+{
+ DATE_TIME_FORMAT *res= 0;
+
+ if (type == OPT_GLOBAL)
+ {
+ const char *format;
+ if ((format= opt_date_time_formats[date_time_type]))
+ res= date_time_format_make(date_time_type, format, strlen(format));
+ }
+ else
+ {
+ /* Make copy with malloc */
+ res= date_time_format_copy((THD *) 0, global_system_variables.*offset);
+ }
+
+ if (res) // Should always be true
+ update2(thd, type, res);
+}
+
+
+byte *sys_var_thd_date_time_format::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ if (type == OPT_GLOBAL)
+ {
+ char *res;
+ /*
+ We do a copy here just to be sure things will work even if someone
+ is modifying the original string while the copy is accessed
+ (Can't happen now in SQL SHOW, but this is a good safety for the future)
+ */
+ res= thd->strmake((global_system_variables.*offset)->format.str,
+ (global_system_variables.*offset)->format.length);
+ return (byte*) res;
+ }
+ return (byte*) (thd->variables.*offset)->format.str;
+}
+
+
typedef struct old_names_map_st
{
const char *old_name;
@@ -1385,17 +1441,17 @@ typedef struct old_names_map_st
static my_old_conv old_conv[]=
{
- { "cp1251_koi8" , "cp1251" },
- { "cp1250_latin2" , "cp1250" },
- { "kam_latin2" , "keybcs2" },
- { "mac_latin2" , "MacRoman" },
- { "macce_latin2" , "MacCE" },
- { "pc2_latin2" , "pclatin2" },
- { "vga_latin2" , "pclatin1" },
- { "koi8_cp1251" , "koi8r" },
- { "win1251ukr_koi8_ukr" , "win1251ukr" },
- { "koi8_ukr_win1251ukr" , "koi8u" },
- { NULL , NULL }
+ { "cp1251_koi8" , "cp1251" },
+ { "cp1250_latin2" , "cp1250" },
+ { "kam_latin2" , "keybcs2" },
+ { "mac_latin2" , "MacRoman" },
+ { "macce_latin2" , "MacCE" },
+ { "pc2_latin2" , "pclatin2" },
+ { "vga_latin2" , "pclatin1" },
+ { "koi8_cp1251" , "koi8r" },
+ { "win1251ukr_koi8_ukr" , "win1251ukr" },
+ { "koi8_ukr_win1251ukr" , "koi8u" },
+ { NULL , NULL }
};
CHARSET_INFO *get_old_charset_by_name(const char *name)
diff --git a/sql/set_var.h b/sql/set_var.h
index 752f275c9f2..3fcbd283833 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -49,8 +49,6 @@ public:
const char *name;
sys_after_update_func after_update;
- sys_var()
- {}
sys_var(const char *name_arg) :name(name_arg),after_update(0)
{}
sys_var(const char *name_arg,sys_after_update_func func)
@@ -190,9 +188,6 @@ public:
class sys_var_thd :public sys_var
{
public:
- sys_var_thd()
- :sys_var()
- {}
sys_var_thd(const char *name_arg)
:sys_var(name_arg)
{}
@@ -560,46 +555,26 @@ public:
};
-class sys_var_datetime_format :public sys_var_thd
+class sys_var_thd_date_time_format :public sys_var_thd
{
+ DATE_TIME_FORMAT *SV::*offset;
+ enum timestamp_type date_time_type;
public:
- enum datetime_format_types format_type;
- DATETIME_FORMAT datetime_format;
- sys_var_datetime_format(): sys_var_thd()
+ sys_var_thd_date_time_format(const char *name_arg,
+ DATE_TIME_FORMAT *SV::*offset_arg,
+ timestamp_type date_time_type_arg)
+ :sys_var_thd(name_arg), offset(offset_arg),
+ date_time_type(date_time_type_arg)
{}
-
- void clean()
- {
- my_free(datetime_format.format, MYF(MY_ALLOW_ZERO_PTR));
- datetime_format.format=0;
- }
-
- /*
- It's for copying of global_system_variables structure
- in THD constructor.
- */
- inline sys_var_datetime_format& operator= (sys_var_datetime_format& s)
- {
- if (&s != this)
- {
- name= s.name; name_length= s.name_length;
- datetime_format= s.datetime_format;
- datetime_format.format= (my_strdup_with_length
- (s.datetime_format.format,
- s.datetime_format.
- format_length, MYF(0)));
- format_type= s.format_type;
- }
- return *this;
- }
-
SHOW_TYPE type() { return SHOW_CHAR; }
bool check_update_type(Item_result type)
{
return type != STRING_RESULT; /* Only accept strings */
}
bool check_default(enum_var_type type) { return 0; }
+ bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
+ void update2(THD *thd, enum_var_type type, DATE_TIME_FORMAT *new_value);
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
void set_default(THD *thd, enum_var_type type);
};
@@ -657,6 +632,7 @@ public:
CHARSET_INFO *charset;
ulong ulong_value;
ulonglong ulonglong_value;
+ DATE_TIME_FORMAT *date_time_format;
} save_result;
LEX_STRING base; /* for structs */
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index bb7cd90b4c4..13015613f1e 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -291,4 +291,9 @@ character-set=latin2
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 48a4fee22f8..4f2d4a1f588 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -285,4 +285,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 98fb9278cc2..0a1fea43df4 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -293,4 +293,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 9a266c41669..ab11f776df6 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -259,9 +259,9 @@ character-set=latin1
"Slave is already running"
"Slave has already been stopped"
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)"
-"Z_MEM_ERROR: Not enough memory available for zlib"
-"Z_BUF_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)"
-"Z_DATA_ERROR: Input data was corrupted for zlib"
+"ZLIB: Not enough memory available for zlib"
+"ZLIB: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)"
+"ZLIB: Input data was corrupted for zlib"
"%d line(s) was(were) cut by group_concat()"
"Record count is fewer than the column count at row %ld";
"Record count is more than the column count at row %ld";
@@ -279,7 +279,12 @@ character-set=latin1
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
-"Wrong parameter or combination of parameters for START SLAVE UNTIL"
-"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
-"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL",
+"It is recommended to use --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL. Otherwise you will get problems if you get an unexpected slave's mysqld restart",
+"SQL thread is not to be started so UNTIL options are ignored",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index e596863907f..2a043deb1f8 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -287,4 +287,9 @@ character-set=latin7
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index a81b8859692..ea1fcf000ea 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -282,4 +282,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 9554822a5ff..f26b490183e 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -294,4 +294,9 @@ character-set=latin1
"Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL",
"Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet",
"SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 073289562b3..6dec7c063f2 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -282,4 +282,9 @@ character-set=greek
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index c62a7c7b1ae..7c71d8f06d6 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -284,4 +284,9 @@ character-set=latin2
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 004d7d00994..f34d78d6c00 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -282,4 +282,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 888ac449a8b..5b46d83b2cf 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -284,4 +284,9 @@ character-set=ujis
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index a72d6c3fdee..41ce2cb21ca 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -282,4 +282,9 @@ character-set=euckr
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 3c6dca27016..87dfbac750d 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -284,4 +284,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index bafc635a184..9ef8aef6217 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -284,4 +284,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 0aa25aabb44..c755eec5a32 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -286,4 +286,9 @@ character-set=latin2
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 33d8f68291d..7375ddd13ef 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -283,4 +283,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index ff46caf2c6c..46cd197f967 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -286,4 +286,9 @@ character-set=latin2
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index f8bdb8bf4a5..36599761936 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -284,4 +284,9 @@ character-set=koi8r
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index cede04e36ed..d971cc3297a 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -277,4 +277,9 @@ character-set=cp1250
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 0759f68a1bb..8721c9fe6c5 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -290,4 +290,9 @@ character-set=latin2
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index b9c1b297e43..cf50dfb6554 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -284,4 +284,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 456b93fbc4d..329b3b3636a 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -282,4 +282,9 @@ character-set=latin1
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index dba62fd60c8..965a1adb986 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -287,4 +287,9 @@ character-set=koi8u
"Wrong parameter or combination of parameters for START SLAVE UNTIL"
"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
"SQL thread is not to be started so UNTIL options are ignored"
-"Incorrect index name '%-.100s'",
+"Incorrect %s name '%-.100s'",
+"table",
+"database",
+"column",
+"index",
+"catalog",
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a926c6e66fe..3892ae4afac 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2082,7 +2082,8 @@ key_map get_key_map_from_key_list(TABLE *table,
uint pos;
while ((name=it++))
{
- if ((pos=find_type(name->c_ptr(), &table->keynames, 1+2)) <= 0)
+ if ((pos= find_type(&table->keynames, name->ptr(), name->length(), 1)) <=
+ 0)
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
table->real_name);
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index e5760dda8ae..15c9f8e8742 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -208,6 +208,12 @@ void THD::init(void)
{
pthread_mutex_lock(&LOCK_global_system_variables);
variables= global_system_variables;
+ variables.time_format= date_time_format_copy((THD*) 0,
+ variables.time_format);
+ variables.date_format= date_time_format_copy((THD*) 0,
+ variables.date_format);
+ variables.datetime_format= date_time_format_copy((THD*) 0,
+ variables.datetime_format);
pthread_mutex_unlock(&LOCK_global_system_variables);
server_status= SERVER_STATUS_AUTOCOMMIT;
options= thd_startup_options;
@@ -279,9 +285,9 @@ void THD::cleanup(void)
close_thread_tables(this);
}
close_temporary_tables(this);
- variables.datetime_formats[DATE_FORMAT_TYPE].clean();
- variables.datetime_formats[TIME_FORMAT_TYPE].clean();
- variables.datetime_formats[DATETIME_FORMAT_TYPE].clean();
+ my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR));
+ my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR));
delete_dynamic(&user_var_events);
hash_free(&user_vars);
if (global_read_lock)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 06bc29dbb2a..eafe6228ae3 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -421,7 +421,11 @@ struct system_variables
CHARSET_INFO *collation_server;
CHARSET_INFO *collation_database;
CHARSET_INFO *collation_connection;
- sys_var_datetime_format datetime_formats[3];
+
+ /* DATE, DATETIME and TIME formats */
+ DATE_TIME_FORMAT *date_format;
+ DATE_TIME_FORMAT *datetime_format;
+ DATE_TIME_FORMAT *time_format;
};
void free_tmp_table(THD *thd, TABLE *entry);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index b0f4b4ef574..b7d6c642398 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -609,7 +609,7 @@ bool mysql_change_db(THD *thd, const char *name)
}
if ((db_length > NAME_LEN) || check_db_name(dbname))
{
- net_printf(thd,ER_WRONG_DB_NAME, dbname);
+ net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), dbname);
x_free(dbname);
DBUG_RETURN(1);
}
@@ -675,7 +675,7 @@ int mysqld_show_create_db(THD *thd, char *dbname,
if (check_db_name(dbname))
{
- net_printf(thd,ER_WRONG_DB_NAME, dbname);
+ net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), dbname);
DBUG_RETURN(1);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 352a79843a9..cc9cedbfad6 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -40,10 +40,18 @@ LEX_STRING tmp_table_alias= {(char*) "tmp-table",8};
pthread_key(LEX*,THR_LEX);
+/* Longest standard keyword name */
#define TOCK_NAME_LENGTH 24
/*
- The following is based on the latin1 character set, and is only
+ Map to default keyword characters. This is used to test if an identifer
+ is 'simple', in which case we don't have to do any character set conversions
+ on it
+*/
+uchar *bin_ident_map= my_charset_bin.ident_map;
+
+/*
+ The following data is based on the latin1 character set, and is only
used when comparing keywords
*/
@@ -66,6 +74,7 @@ uchar to_upper_lex[] = {
208,209,210,211,212,213,214,247,216,217,218,219,220,221,222,255
};
+
inline int lex_casecmp(const char *s, const char *t, uint len)
{
while (len-- != 0 &&
@@ -410,15 +419,18 @@ inline static uint int_token(const char *str,uint length)
}
-// yylex remember the following states from the following yylex()
-// MY_LEX_EOQ ; found end of query
-// MY_LEX_OPERATOR_OR_IDENT ; last state was an ident, text or number
-// (which can't be followed by a signed number)
+/*
+ yylex remember the following states from the following yylex()
+
+ - MY_LEX_EOQ Found end of query
+ - MY_LEX_OPERATOR_OR_IDENT Last state was an ident, text or number
+ (which can't be followed by a signed number)
+*/
int yylex(void *arg, void *yythd)
{
reg1 uchar c;
- int tokval;
+ int tokval, result_state;
uint length;
enum my_lex_states state,prev_state;
LEX *lex= &(((THD *)yythd)->lex);
@@ -503,6 +515,7 @@ int yylex(void *arg, void *yythd)
#if defined(USE_MB) && defined(USE_MB_IDENT)
if (use_mb(cs))
{
+ result_state= IDENT_QUOTED;
if (my_mbcharlen(cs, yyGetLast()) > 1)
{
int l = my_ismbchar(cs,
@@ -529,7 +542,15 @@ int yylex(void *arg, void *yythd)
}
else
#endif
- while (ident_map[c=yyGet()]) ;
+ {
+ result_state= bin_ident_map[c] ? IDENT : IDENT_QUOTED;
+ while (ident_map[c=yyGet()])
+ {
+ /* If not simple character, mark that we must convert it */
+ if (!bin_ident_map[c])
+ result_state= IDENT_QUOTED;
+ }
+ }
length= (uint) (lex->ptr - lex->tok_start)-1;
if (lex->ignore_space)
{
@@ -560,8 +581,7 @@ int yylex(void *arg, void *yythd)
(lex->charset=get_charset_by_csname(yylval->lex_str.str+1,
MY_CS_PRIMARY,MYF(0))))
return(UNDERSCORE_CHARSET);
- else
- return(IDENT);
+ return(result_state); // IDENT or IDENT_QUOTED
case MY_LEX_IDENT_SEP: // Found ident and now '.'
yylval->lex_str.str=(char*) lex->ptr;
@@ -611,21 +631,11 @@ int yylex(void *arg, void *yythd)
}
// fall through
case MY_LEX_IDENT_START: // We come here after '.'
+ result_state= IDENT;
#if defined(USE_MB) && defined(USE_MB_IDENT)
if (use_mb(cs))
{
- if (my_mbcharlen(cs, yyGetLast()) > 1)
- {
- int l = my_ismbchar(cs,
- (const char *)lex->ptr-1,
- (const char *)lex->end_of_query);
- if (l == 0)
- {
- state = MY_LEX_CHAR;
- continue;
- }
- lex->ptr += l - 1;
- }
+ result_state= IDENT_QUOTED;
while (ident_map[c=yyGet()])
{
if (my_mbcharlen(cs, c) > 1)
@@ -641,15 +651,17 @@ int yylex(void *arg, void *yythd)
}
else
#endif
- while (ident_map[c = yyGet()]) ;
-
+ while (ident_map[c = yyGet()])
+ {
+ /* If not simple character, mark that we must convert it */
+ if (!bin_ident_map[c])
+ result_state= IDENT_QUOTED;
+ }
if (c == '.' && ident_map[yyPeek()])
lex->next_state=MY_LEX_IDENT_SEP;// Next is '.'
- // fall through
- case MY_LEX_FOUND_IDENT: // Complete ident
- yylval->lex_str=get_token(lex,yyLength());
- return(IDENT);
+ yylval->lex_str= get_token(lex,yyLength());
+ return(result_state);
case MY_LEX_USER_VARIABLE_DELIMITER:
{
@@ -699,7 +711,7 @@ int yylex(void *arg, void *yythd)
if (c == delim)
yySkip(); // Skip end `
lex->next_state= MY_LEX_START;
- return(IDENT);
+ return(IDENT_QUOTED);
}
case MY_LEX_INT_OR_REAL: // Compleat int or incompleat real
if (c != '.')
@@ -924,7 +936,13 @@ int yylex(void *arg, void *yythd)
We should now be able to handle:
[(global | local | session) .]variable_name
*/
- while (ident_map[c=yyGet()]) ;
+ result_state= IDENT;
+ while (ident_map[c=yyGet()])
+ {
+ /* If not simple character, mark that we must convert it */
+ if (!bin_ident_map[c])
+ result_state= IDENT_QUOTED;
+ }
if (c == '.')
lex->next_state=MY_LEX_IDENT_SEP;
length= (uint) (lex->ptr - lex->tok_start)-1;
@@ -934,7 +952,7 @@ int yylex(void *arg, void *yythd)
return(tokval); // Was keyword
}
yylval->lex_str=get_token(lex,length);
- return(IDENT);
+ return(result_state);
}
}
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 99f22993393..bef6209bd98 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1083,7 +1083,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
if (!db || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL");
goto err;
}
if (lower_case_table_names)
@@ -1424,7 +1424,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL");
break;
}
if (check_access(thd,CREATE_ACL,db,0,1,0))
@@ -1440,7 +1440,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db ? db : "NULL");
break;
}
if (check_access(thd,DROP_ACL,db,0,1,0))
@@ -2026,7 +2026,7 @@ mysql_execute_command(THD *thd)
#endif
if (strlen(tables->real_name) > NAME_LEN)
{
- net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
+ net_printf(thd,ER_WRONG_NAME, ER(ER_TABLE), tables->real_name);
break;
}
LOCK_ACTIVE_MI;
@@ -2071,7 +2071,7 @@ mysql_execute_command(THD *thd)
#endif
if (strlen(tables->real_name) > NAME_LEN)
{
- net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
+ net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), tables->alias);
res=0;
break;
}
@@ -2203,7 +2203,7 @@ mysql_execute_command(THD *thd)
ulong priv=0;
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{
- net_printf(thd,ER_WRONG_TABLE_NAME,lex->name);
+ net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), lex->name);
res=0;
break;
}
@@ -2777,7 +2777,7 @@ mysql_execute_command(THD *thd)
remove_escape(db); // Fix escaped '_'
if (check_db_name(db))
{
- net_printf(thd,ER_WRONG_DB_NAME, db);
+ net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), db);
goto error;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -2942,7 +2942,7 @@ mysql_execute_command(THD *thd)
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), lex->name);
break;
}
/*
@@ -2970,7 +2970,7 @@ mysql_execute_command(THD *thd)
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), lex->name);
break;
}
/*
@@ -3003,7 +3003,7 @@ mysql_execute_command(THD *thd)
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd, ER_WRONG_NAME, ER(ER_DATABASE), lex->name);
break;
}
if (check_access(thd,ALTER_ACL,lex->name,0,1,0))
@@ -3020,7 +3020,7 @@ mysql_execute_command(THD *thd)
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd,ER_WRONG_NAME, ER(ER_DATABASE), lex->name);
break;
}
if (check_access(thd,DROP_ACL,lex->name,0,1,0))
@@ -4086,7 +4086,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{
char *not_used;
uint not_used2;
- bool not_used3;
+ bool not_used3;
thd->cuted_fields=0;
String str,*res;
@@ -4116,7 +4116,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
{
String str,*res;
res=default_value->val_str(&str);
- if (!find_enum(interval,res->ptr(),res->length()))
+ res->strip_sp();
+ if (!find_type(interval, res->ptr(), res->length(), 0))
{
net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
@@ -4268,7 +4269,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
if (check_table_name(table->table.str,table->table.length) ||
table->db.str && check_db_name(table->db.str))
{
- net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
+ net_printf(thd, ER_WRONG_NAME, ER(ER_TABLE), table->table.str);
DBUG_RETURN(0);
}
@@ -4622,7 +4623,7 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
if (strlen(*filename_ptr)+strlen(table_name) >= FN_REFLEN-1 ||
!test_if_hard_path(*filename_ptr))
{
- my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr);
+ my_error(ER_WRONG_NAME, MYF(0), ER(ER_TABLE), *filename_ptr);
return 1;
}
/* Fix is using unix filename format on dos */
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 522879c863a..475c4824028 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -332,7 +332,7 @@ SETUP_PARAM_FUNCTION(setup_param_datetime)
tm.day= (uint) to[3];
tm.neg= 0;
- param->set_time(&tm, TIMESTAMP_FULL);
+ param->set_time(&tm, TIMESTAMP_DATETIME);
}
*pos+= length;
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 3d07c7e04de..ac36b5740fc 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -437,7 +437,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
if (check_column_name(sql_field->field_name))
{
- my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
+ my_error(ER_WRONG_NAME, MYF(0), ER(ER_COLUMN), sql_field->field_name);
DBUG_RETURN(-1);
}
@@ -863,7 +863,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
if (!key_info->name || check_column_name(key_info->name))
{
- my_error(ER_WRONG_INDEX_NAME, MYF(0), key_info->name);
+ my_error(ER_WRONG_NAME, MYF(0), ER(ER_INDEX), key_info->name);
DBUG_RETURN(-1);
}
if (!(key_info->flags & HA_NULL_PART_KEY))
@@ -1646,7 +1646,7 @@ int mysql_create_like_table(THD* thd, TABLE_LIST* table,
check_table_name(src_table,table_ident->table.length)) ||
table_ident->db.str && check_db_name((src_db= table_ident->db.str)))
{
- my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table);
+ my_error(ER_WRONG_NAME, MYF(0), ER(ER_TABLE), src_table);
DBUG_RETURN(-1);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index c7a27592a7b..c704ed2878c 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -78,7 +78,7 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B)
CHARSET_INFO *charset;
thr_lock_type lock_type;
interval_type interval;
- datetime_format_types datetime_format_type;
+ timestamp_type date_time_type;
st_select_lex *select_lex;
chooser_compare_func_creator boolfunc2creator;
}
@@ -245,6 +245,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token HIGH_PRIORITY
%token HOSTS_SYM
%token IDENT
+%token IDENT_QUOTED
%token IGNORE_SYM
%token IMPORT
%token INDEX
@@ -583,8 +584,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%right BINARY COLLATE_SYM
%type <lex_str>
- IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME
- ULONGLONG_NUM field_ident select_alias ident ident_or_text
+ IDENT IDENT_QUOTED TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM
+ LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component
@@ -646,7 +647,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC
UDA_CHAR_SUM UDA_FLOAT_SUM UDA_INT_SUM
-%type <datetime_format_type> datetime_format_type;
+%type <date_time_type> date_time_type;
%type <interval> interval
%type <db_type> table_types
@@ -2569,7 +2570,7 @@ simple_expr:
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbGeometryCollection,
Geometry::wkbPoint); }
- | GET_FORMAT '(' datetime_format_type ',' expr ')'
+ | GET_FORMAT '(' date_time_type ',' expr ')'
{ $$= new Item_func_get_format($3, $5); }
| HOUR_SYM '(' expr ')'
{ $$= new Item_func_hour($3); }
@@ -3184,10 +3185,10 @@ interval:
| YEAR_MONTH_SYM { $$=INTERVAL_YEAR_MONTH; }
| YEAR_SYM { $$=INTERVAL_YEAR; };
-datetime_format_type:
- DATE_SYM {$$=DATE_FORMAT_TYPE;}
- | TIME_SYM {$$=TIME_FORMAT_TYPE;}
- | DATETIME {$$=DATETIME_FORMAT_TYPE;};
+date_time_type:
+ DATE_SYM {$$=TIMESTAMP_DATE;}
+ | TIME_SYM {$$=TIMESTAMP_TIME;}
+ | DATETIME {$$=TIMESTAMP_DATETIME;};
table_alias:
/* empty */
@@ -4401,15 +4402,16 @@ table_ident:
/* For Delphi */;
IDENT_sys:
- IDENT
- {
- THD *thd= YYTHD;
- if (thd->charset_is_system_charset)
- $$= $1;
- else
- thd->convert_string(&$$, system_charset_info,
- $1.str, $1.length, thd->charset());
- }
+ IDENT { $$= $1; }
+ | IDENT_QUOTED
+ {
+ THD *thd= YYTHD;
+ if (thd->charset_is_system_charset)
+ $$= $1;
+ else
+ thd->convert_string(&$$, system_charset_info,
+ $1.str, $1.length, thd->charset());
+ }
;
TEXT_STRING_sys:
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
new file mode 100644
index 00000000000..1db2124bcee
--- /dev/null
+++ b/sql/strfunc.cc
@@ -0,0 +1,147 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Some useful string utility functions used by the MySQL server */
+
+#include "mysql_priv.h"
+
+/*
+ Return bitmap for strings used in a set
+
+ SYNOPSIS
+ find_set()
+ lib Strings in set
+ str Strings of set-strings separated by ','
+ err_pos If error, set to point to start of wrong set string
+ err_len If error, set to the length of wrong set string
+ set_warning Set to 1 if some string in set couldn't be used
+
+ NOTE
+ We delete all end space from str before comparison
+
+ RETURN
+ bitmap of all sets found in x.
+ set_warning is set to 1 if there was any sets that couldn't be set
+*/
+
+static const char field_separator=',';
+
+ulonglong find_set(TYPELIB *lib, const char *str, uint length, char **err_pos,
+ uint *err_len, bool *set_warning)
+{
+ const char *end= str + length;
+ *err_pos= 0; // No error yet
+ while (end > str && my_isspace(system_charset_info, end[-1]))
+ end--;
+
+ *err_len= 0;
+ ulonglong found= 0;
+ if (str != end)
+ {
+ const char *start= str;
+ for (;;)
+ {
+ const char *pos= start;
+ uint var_len;
+
+ for (; pos != end && *pos != field_separator; pos++) ;
+ var_len= (uint) (pos - start);
+ uint find= find_type(lib, start, var_len, 0);
+ if (!find)
+ {
+ *err_pos= (char*) start;
+ *err_len= var_len;
+ *set_warning= 1;
+ }
+ else
+ found|= ((longlong) 1 << (find - 1));
+ if (pos == end)
+ break;
+ start= pos + 1;
+ }
+ }
+ return found;
+}
+
+
+/*
+ Function to find a string in a TYPELIB
+ (Same format as mysys/typelib.c)
+
+ SYNOPSIS
+ find_type()
+ lib TYPELIB (struct of pointer to values + count)
+ find String to find
+ length Length of string to find
+ part_match Allow part matching of value
+
+ RETURN
+ 0 error
+ > 0 position in TYPELIB->type_names +1
+*/
+
+uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match)
+{
+ uint found_count=0, found_pos=0;
+ const char *end= find+length;
+ const char *i;
+ const char *j;
+ for (uint pos=0 ; (j=lib->type_names[pos++]) ; )
+ {
+ for (i=find ; i != end &&
+ my_toupper(system_charset_info,*i) ==
+ my_toupper(system_charset_info,*j) ; i++, j++) ;
+ if (i == end)
+ {
+ if (! *j)
+ return(pos);
+ found_count++;
+ found_pos= pos;
+ }
+ }
+ return(found_count == 1 && part_match ? found_count : 0);
+}
+
+
+/*
+ Check if the first word in a string is one of the ones in TYPELIB
+
+ SYNOPSIS
+ check_word()
+ lib TYPELIB
+ val String to check
+ end End of input
+ end_of_word Store value of last used byte here if we found word
+
+ RETURN
+ 0 No matching value
+ > 1 lib->type_names[#-1] matched
+ end_of_word will point to separator character/end in 'val'
+*/
+
+uint check_word(TYPELIB *lib, const char *val, const char *end,
+ const char **end_of_word)
+{
+ int res;
+ const char *ptr;
+
+ /* Fiend end of word */
+ for (ptr= val ; ptr < end && my_isalpha(&my_charset_latin1, *ptr) ; ptr++)
+ ;
+ if ((res=find_type(lib, val, (uint) (ptr - val), 1)) > 0)
+ *end_of_word= ptr;
+ return res;
+}
diff --git a/sql/structs.h b/sql/structs.h
index d9be230c049..352823cceb2 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -20,15 +20,19 @@
struct st_table;
class Field;
-typedef struct st_date_format { /* How to print date */
- uint pos[6]; /* Positions to YY.MM.DD HH:MM:SS */
-} DATE_FORMAT;
+typedef struct lex_string {
+ char *str;
+ uint length;
+} LEX_STRING;
+
+
+typedef struct st_date_time_format {
+ uchar positions[8];
+ char time_separator; /* Separator between hour and minute */
+ uint flag; /* For future */
+ LEX_STRING format;
+} DATE_TIME_FORMAT;
-typedef struct st_datetime_format {
- byte dt_pos[8];
- char *format;
- uint format_length;
-} DATETIME_FORMAT;
typedef struct st_keyfile_info { /* used with ha_info() */
byte ref[MAX_REFLENGTH]; /* Pointer to current row */
@@ -115,8 +119,17 @@ typedef struct st_read_record { /* Parameter to read_record */
bool print_error, ignore_not_found_rows;
} READ_RECORD;
-enum timestamp_type { TIMESTAMP_NONE, WRONG_TIMESTAMP_FULL, TIMESTAMP_DATE, TIMESTAMP_FULL,
- TIMESTAMP_TIME};
+
+enum timestamp_type
+{
+ TIMESTAMP_NONE= -2, TIMESTAMP_DATETIME_ERROR= -1,
+ TIMESTAMP_DATE= 0, TIMESTAMP_DATETIME= 1, TIMESTAMP_TIME= 2
+};
+
+/* Parameters to str_to_TIME */
+#define TIME_FUZZY_DATE 1
+#define TIME_DATETIME_ONLY 2
+
typedef struct st_time {
uint year,month,day,hour,minute,second;
@@ -125,12 +138,21 @@ typedef struct st_time {
timestamp_type time_type;
} TIME;
+
typedef struct {
long year,month,day,hour,minute,second,second_part;
bool neg;
} INTERVAL;
+typedef struct st_known_date_time_format {
+ const char *format_name;
+ const char *date_format;
+ const char *datetime_format;
+ const char *time_format;
+} KNOWN_DATE_TIME_FORMAT;
+
+
enum SHOW_TYPE
{
SHOW_UNDEF,
@@ -168,11 +190,6 @@ typedef struct show_var_st {
} SHOW_VAR;
-typedef struct lex_string {
- char *str;
- uint length;
-} LEX_STRING;
-
typedef struct st_lex_user {
LEX_STRING user, host, password;
} LEX_USER;
diff --git a/sql/time.cc b/sql/time.cc
index f2e41afa560..4f2a2a23910 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -23,14 +23,9 @@
static ulong const days_at_timestart=719528; /* daynr at 1970.01.01 */
uchar *days_in_month= (uchar*) "\037\034\037\036\037\036\037\037\036\037\036\037";
-
/* Init some variabels needed when using my_local_time */
/* Currently only my_time_zone is inited */
-bool parse_datetime_formats(datetime_format_types format_type,
- const char *format_str, uint format_length,
- byte *dt_pos);
-
static long my_time_zone=0;
void init_time(void)
@@ -282,6 +277,7 @@ ulong convert_period_to_month(ulong period)
return a*12+b-1;
}
+
ulong convert_month_to_period(ulong month)
{
ulong year;
@@ -295,6 +291,13 @@ ulong convert_month_to_period(ulong month)
}
+/* Position for YYYY-DD-MM HH-MM-DD.FFFFFF AM in default format */
+
+static uchar internal_format_positions[]=
+{0, 1, 2, 3, 4, 5, 6, (uchar) 255};
+
+static char time_separator=':';
+
/*
Convert a timestamp string to a TIME value.
@@ -303,7 +306,9 @@ ulong convert_month_to_period(ulong month)
str String to parse
length Length of string
l_time Date is stored here
- fuzzy_date 1 if we should allow dates where one part is zero
+ flags Bitmap of following items
+ TIME_FUZZY_DATE Set if we should allow partial dates
+ TIME_DATETIME_ONLY Set if we only allow full datetimes.
DESCRIPTION
At least the following formats are recogniced (based on number of digits)
@@ -312,161 +317,248 @@ ulong convert_month_to_period(ulong month)
YYYYMMDDTHHMMSS where T is a the character T (ISO8601)
Also dates where all parts are zero are allowed
+ The second part may have an optional .###### fraction part.
+
+ NOTES
+ This function should work with a format position vector as long as the
+ following things holds:
+ - All date are kept together and all time parts are kept together
+ - Date and time parts must be separated by blank
+ - Second fractions must come after second part and be separated
+ by a '.'. (The second fractions are optional)
+ - AM/PM must come after second fractions (or after seconds if no fractions)
+ - Year must always been specified.
+ - If time is before date, then we will use datetime format only if
+ the argument consist of two parts, separated by space.
+ Otherwise we will assume the argument is a date.
+ - The hour part must be specified in hour-minute-second order.
+
RETURN VALUES
TIMESTAMP_NONE String wasn't a timestamp, like
[DD [HH:[MM:[SS]]]].fraction
TIMESTAMP_DATE DATE string (YY MM and DD parts ok)
- TIMESTAMP_FULL Full timestamp
+ TIMESTAMP_DATETIME Full timestamp
+ TIMESTAMP_DATETIME_ERROR Timestamp with wrong values
*/
+#define MAX_DATE_PARTS 8
+
timestamp_type
-str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd)
+str_to_TIME(const char *str, uint length, TIME *l_time, uint flags)
{
- uint field_length= 0, year_length= 0, digits, i, number_of_fields;
- uint date[7], date_len[7];
- uint not_zero_date;
- bool is_internal_format= 0;
- const char *pos;
+ uint field_length, year_length, digits, i, number_of_fields;
+ uint date[MAX_DATE_PARTS], date_len[MAX_DATE_PARTS];
+ uint add_hours= 0, start_loop;
+ ulong not_zero_date, allow_space;
+ bool is_internal_format;
+ const char *pos, *last_field_pos;
const char *end=str+length;
- bool found_delimitier= 0;
+ const uchar *format_position;
+ bool found_delimitier= 0, found_space= 0;
+ DATE_TIME_FORMAT *format;
DBUG_ENTER("str_to_TIME");
- DBUG_PRINT("enter",("str: %.*s",length,str));
+ DBUG_PRINT("ENTER",("str: %.*s",length,str));
- // Skip garbage
- for (; str != end && !my_isdigit(&my_charset_latin1, *str) ; str++) ;
- if (str == end)
+ LINT_INIT(field_length);
+ LINT_INIT(year_length);
+ LINT_INIT(last_field_pos);
+
+ // Skip space at start
+ for (; str != end && my_isspace(&my_charset_latin1, *str) ; str++)
+ ;
+ if (str == end || ! my_isdigit(&my_charset_latin1, *str))
DBUG_RETURN(TIMESTAMP_NONE);
+
+ is_internal_format= 0;
+ /* This has to be changed if want to activate different timestamp formats */
+ format_position= internal_format_positions;
+
/*
- Calculate first number of digits.
+ Calculate number of digits in first part.
If length= 8 or >= 14 then year is of format YYYY.
(YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS)
*/
- for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++) ;
- /* Check for internal format */
- digits= (uint) (pos-str);
+ for (pos=str; pos != end && my_isdigit(&my_charset_latin1,*pos) ; pos++)
+ ;
- if (pos == end || digits>=12)
+ digits= (uint) (pos-str);
+ start_loop= 0; // Start of scan loop
+ date_len[format_position[0]]= 0; // Length of year field
+ if (pos == end)
{
- is_internal_format= 1;
+ /* Found date in internal format (only numbers like YYYYMMDD) */
year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
field_length=year_length-1;
- date_len[0]= year_length;
+ is_internal_format= 1;
+ format_position= internal_format_positions;
+ }
+ else
+ {
+ if (format_position[0] >= 3) // If year is after HHMMDD
+ {
+ /*
+ If year is not in first part then we have to determinate if we got
+ a date field or a datetime field.
+ We do this by checking if there is two numbers separated by
+ space in the input.
+ */
+ while (pos < end && !my_isspace(&my_charset_latin1, *pos))
+ pos++;
+ while (pos < end && !my_isdigit(&my_charset_latin1, *pos))
+ pos++;
+ if (pos == end)
+ {
+ if (flags & TIME_DATETIME_ONLY)
+ return TIMESTAMP_NONE; // Can't be a full datetime
+ /* Date field. Set hour, minutes and seconds to 0 */
+ date[0]= date[1]= date[2]= date[3]= 0;
+ start_loop= 5; // Start with first date part
+ }
+ }
}
+
+ /*
+ Only allow space in the first "part" of the datetime field and:
+ - after days, part seconds
+ - before and after AM/PM (handled by code later)
+
+ 2003-03-03 20:00:20 AM
+ 20:00:20.000000 AM 03-03-2000
+ */
+ i= max((uint) format_position[0], (uint) format_position[1]);
+ set_if_bigger(i, (uint) format_position[2]);
+ allow_space= ((1 << i) | (1 << format_position[6]));
+ allow_space&= (1 | 2 | 4 | 8);
+
not_zero_date= 0;
- for (i=0 ; i < 6 && str != end && my_isdigit(&my_charset_latin1,*str) ; i++)
+ for (i = start_loop;
+ i < MAX_DATE_PARTS-1 && str != end &&
+ my_isdigit(&my_charset_latin1,*str);
+ i++)
{
- if (!is_internal_format)
- date_len[i]= 1;
- uint tmp_value=(uint) (uchar) (*str++ - '0');
- while (str != end && my_isdigit(&my_charset_latin1,str[0])
- && (is_internal_format && field_length-- || !is_internal_format) )
+ const char *start= str;
+ ulong tmp_value= (uint) (uchar) (*str++ - '0');
+ while (str != end && my_isdigit(&my_charset_latin1,str[0]) &&
+ (!is_internal_format || field_length--))
{
- tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
+ tmp_value=tmp_value*10 + (ulong) (uchar) (*str - '0');
str++;
- if (!is_internal_format)
- date_len[i]+= 1;
}
- if (i == 2 && *str == '.')
+ date_len[i]+= (uint) (str - start);
+ if (tmp_value > 999999) // Impossible date part
DBUG_RETURN(TIMESTAMP_NONE);
date[i]=tmp_value;
not_zero_date|= tmp_value;
- if (i == 2 && str != end && *str == 'T')
+
+ /* Length-1 of next field */
+ field_length= format_position[i+1] == 0 ? 3 : 1;
+
+ if ((last_field_pos= str) == end)
+ {
+ i++; // Register last found part
+ break;
+ }
+ /* Allow a 'T' after day to allow CCYYMMDDT type of fields */
+ if (i == format_position[2] && *str == 'T')
+ {
str++; // ISO8601: CCYYMMDDThhmmss
- else if ( i != 5 ) // Skip inter-field delimiters
+ continue;
+ }
+ if (i == format_position[5]) // Seconds
{
- while (str != end &&
- (my_ispunct(&my_charset_latin1,*str) ||
- my_isspace(&my_charset_latin1,*str)))
+ if (*str == '.') // Followed by part seconds
{
- // Only allow space between days and hours
- if (my_isspace(&my_charset_latin1,*str) && i != 2)
- DBUG_RETURN(TIMESTAMP_NONE);
str++;
- found_delimitier=1; // Should be a 'normal' date
+ field_length= 5; // 5 digits after first (=6)
}
+ continue;
+
+ /* No part seconds */
+ date[++i]= 0;
}
- if (is_internal_format)
- field_length=1; // Rest fields can only be 2
- }
- /* Handle second fractions */
- if (i == 6 && (uint) (end-str) >= 2 && *str == '.' &&
- my_isdigit(&my_charset_latin1,str[1]))
- {
- str++;
- uint tmp_value=(uint) (uchar) (*str - '0');
- field_length=5;
- while (str++ != end && my_isdigit(&my_charset_latin1,str[0]) &&
- field_length--)
- tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
- date[6]=tmp_value;
- not_zero_date|= tmp_value;
+ while (str != end &&
+ (my_ispunct(&my_charset_latin1,*str) ||
+ my_isspace(&my_charset_latin1,*str)))
+ {
+ if (my_isspace(&my_charset_latin1,*str))
+ {
+ if (!(allow_space & (1 << i)))
+ DBUG_RETURN(TIMESTAMP_NONE);
+ found_space= 1;
+ }
+ str++;
+ found_delimitier= 1; // Should be a 'normal' date
+ }
+ /* Check if next position is AM/PM */
+ if (i == format_position[6]) // Seconds, time for AM/PM
+ {
+ i++; // Skip AM/PM part
+ if (format_position[7] != 255) // If using AM/PM
+ {
+ if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
+ {
+ if (str[1] == 'p' || str[1] == 'P')
+ add_hours= 12;
+ else if (str[1] != 'a' || str[1] != 'A')
+ continue; // Not AM/PM
+ str+= 2; // Skip AM/PM
+ /* Skip space after AM/PM */
+ while (str != end && my_isspace(&my_charset_latin1,*str))
+ str++;
+ }
+ }
+ }
+ last_field_pos= str;
}
- else
- date[6]=0;
-
- while (str != end && (my_ispunct(&my_charset_latin1,*str) ||
- my_isspace(&my_charset_latin1,*str)))
- str++;
+ if (found_delimitier && !found_space && (flags & TIME_DATETIME_ONLY))
+ DBUG_RETURN(TIMESTAMP_NONE); // Can't be a datetime
- uint add_hours= 0;
- if (!my_strnncoll(&my_charset_latin1,
- (const uchar *)str, 2,
- (const uchar *)"PM", 2))
- add_hours= 12;
+ str= last_field_pos;
- number_of_fields=i;
- while (i < 6)
+ number_of_fields= i - start_loop;
+ while (i < MAX_DATE_PARTS)
date[i++]=0;
if (!is_internal_format)
{
- byte *frm_pos;
+ year_length= date_len[(uint) format_position[0]];
+ if (!year_length) // Year must be specified
+ DBUG_RETURN(TIMESTAMP_NONE);
- if (number_of_fields <= 3)
- {
- frm_pos= t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format.dt_pos;
- l_time->hour= 0;
- l_time->minute= 0;
- l_time->second= 0;
- }
- else
+ l_time->year= date[(uint) format_position[0]];
+ l_time->month= date[(uint) format_position[1]];
+ l_time->day= date[(uint) format_position[2]];
+ l_time->hour= date[(uint) format_position[3]];
+ l_time->minute= date[(uint) format_position[4]];
+ l_time->second= date[(uint) format_position[5]];
+ l_time->second_part= date[(uint) format_position[6]];
+ if (format_position[7] != (uchar) 255)
{
- frm_pos= t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format.dt_pos;
- l_time->hour= date[(int) frm_pos[3]];
- l_time->minute=date[(int) frm_pos[4]];
- l_time->second=date[(int) frm_pos[5]];
- if (frm_pos[6] == 1)
- {
- if (l_time->hour > 12)
- DBUG_RETURN(WRONG_TIMESTAMP_FULL);
- l_time->hour= l_time->hour%12 + add_hours;
- }
+ if (l_time->hour > 12)
+ DBUG_RETURN(TIMESTAMP_DATETIME_ERROR);
+ l_time->hour= l_time->hour%12 + add_hours;
}
-
- l_time->year= date[(int) frm_pos[0]];
- l_time->month= date[(int) frm_pos[1]];
- l_time->day= date[(int) frm_pos[2]];
- year_length= date_len[(int) frm_pos[0]];
}
else
{
- l_time->year= date[0];
- l_time->month= date[1];
- l_time->day= date[2];
- l_time->hour= date[3];
- l_time->minute=date[4];
- l_time->second=date[5];
- }
- l_time->second_part=date[6];
+ l_time->year= date[0];
+ l_time->month= date[1];
+ l_time->day= date[2];
+ l_time->hour= date[3];
+ l_time->minute= date[4];
+ l_time->second= date[5];
+ l_time->second_part=date[6];
+ }
l_time->neg= 0;
- if (year_length == 2 && i >=2 && (l_time->month || l_time->day))
- l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
+ if (year_length == 2 && i >= format_position[1] && i >=format_position[2] &&
+ (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 ||
l_time->day > 31 || l_time->hour > 23 ||
l_time->minute > 59 || l_time->second > 59 ||
- (!fuzzy_date && (l_time->month == 0 || l_time->day == 0)))
+ (!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0)))
{
/* Only give warning for a zero date if there is some garbage after */
if (!not_zero_date) // If zero date
@@ -481,46 +573,46 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd)
}
}
if (not_zero_date)
- thd->cuted_fields++;
- DBUG_RETURN(WRONG_TIMESTAMP_FULL);
+ current_thd->cuted_fields++;
+ DBUG_RETURN(TIMESTAMP_DATETIME_ERROR);
}
- if (str != end && thd->count_cuted_fields)
+ if (str != end && current_thd->count_cuted_fields)
{
for (; str != end ; str++)
{
if (!my_isspace(&my_charset_latin1,*str))
{
- thd->cuted_fields++;
+ current_thd->cuted_fields++;
break;
}
}
}
DBUG_RETURN(l_time->time_type=
- (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL));
+ (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_DATETIME));
}
-time_t str_to_timestamp(const char *str,uint length, THD *thd)
+time_t str_to_timestamp(const char *str,uint length)
{
TIME l_time;
long not_used;
- if (str_to_TIME(str,length,&l_time,0,thd) <= WRONG_TIMESTAMP_FULL)
+ if (str_to_TIME(str,length,&l_time,0) <= TIMESTAMP_DATETIME_ERROR)
return(0);
if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR)
{
- thd->cuted_fields++;
+ current_thd->cuted_fields++;
return(0);
}
return(my_gmt_sec(&l_time, &not_used));
}
-longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd)
+longlong str_to_datetime(const char *str,uint length, uint fuzzy_date)
{
TIME l_time;
- if (str_to_TIME(str,length,&l_time,fuzzy_date,thd) <= WRONG_TIMESTAMP_FULL)
+ if (str_to_TIME(str,length,&l_time,fuzzy_date) <= TIMESTAMP_DATETIME_ERROR)
return(0);
return (longlong) (l_time.year*LL(10000000000) +
l_time.month*LL(100000000)+
@@ -542,22 +634,24 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd)
length Length of str
l_time Store result here
+ NOTES
+ Because of the extra days argument, this function can only
+ work with times where the time arguments are in the above order.
+
RETURN
0 ok
1 error
*/
-bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd)
+bool str_to_time(const char *str,uint length,TIME *l_time)
{
long date[5],value;
- const char *end=str+length;
+ const char *end=str+length, *end_of_days;
bool found_days,found_hours;
uint state;
- byte *frm_pos= t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format.dt_pos;
l_time->neg=0;
- for (; str != end &&
- !my_isdigit(&my_charset_latin1,*str) && *str != '-' ; str++)
+ for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++)
length--;
if (str != end && *str == '-')
{
@@ -571,37 +665,33 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd)
/* Check first if this is a full TIMESTAMP */
if (length >= 12)
{ // Probably full timestamp
- enum timestamp_type tres= str_to_TIME(str,length,l_time,1,thd);
- if (tres == TIMESTAMP_FULL)
- return 0;
- else if (tres == WRONG_TIMESTAMP_FULL)
- return 1;
+ enum timestamp_type res= str_to_TIME(str,length,l_time,
+ (TIME_FUZZY_DATE |
+ TIME_DATETIME_ONLY));
+ if ((int) res >= (int) TIMESTAMP_DATETIME_ERROR)
+ return res == TIMESTAMP_DATETIME_ERROR;
}
/* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
value=value*10L + (long) (*str - '0');
- /* Move to last space */
- if (str != end && *str == ' ')
- {
- while (++str != end && str[0] == ' ')
- {}
- str--;
- }
+ /* Skipp all space after 'days' */
+ end_of_days= str;
+ for (; str != end && my_isspace(&my_charset_latin1, str[0]) ; str++)
+ ;
LINT_INIT(state);
found_days=found_hours=0;
- if ((uint) (end-str) > 1 && (*str == ' ' &&
- my_isdigit(&my_charset_latin1,str[1])))
- { // days !
- date[0]=value;
- state=1; // Assume next is hours
- found_days=1;
- str++; // Skip space;
- }
- else if ((end-str) > 1 && *str == frm_pos[7] &&
- my_isdigit(&my_charset_latin1,str[1]))
+ if ((uint) (end-str) > 1 && str != end_of_days &&
+ my_isdigit(&my_charset_latin1, *str))
+ { // Found days part
+ date[0]= value;
+ state= 1; // Assume next is hours
+ found_days= 1;
+ }
+ else if ((end-str) > 1 && *str == time_separator &&
+ my_isdigit(&my_charset_latin1, str[1]))
{
date[0]=0; // Assume we found hours
date[1]=value;
@@ -626,10 +716,10 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd)
for (value=0; str != end && my_isdigit(&my_charset_latin1,*str) ; str++)
value=value*10L + (long) (*str - '0');
date[state++]=value;
- if (state == 4 || (end-str) < 2 || *str != frm_pos[7] ||
+ if (state == 4 || (end-str) < 2 || *str != time_separator ||
!my_isdigit(&my_charset_latin1,str[1]))
break;
- str++; // Skip ':'
+ str++; // Skip time_separator (':')
}
if (state != 4)
@@ -644,7 +734,8 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd)
else
bzero((char*) (date+state), sizeof(long)*(4-state));
}
- fractional:
+
+fractional:
/* Get fractional second part */
if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1]))
{
@@ -659,18 +750,21 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd)
else
date[4]=0;
- while (str != end && !my_isalpha(&my_charset_latin1,*str))
- str++;
-
- if ( (end-str)>= 2 &&
- !my_strnncoll(&my_charset_latin1,
- (const uchar *)str, 2,
- (const uchar *)"PM", 2) &&
- frm_pos[6] == 1)
+ if (internal_format_positions[7] != 255)
{
- uint days_i= date[1]/24;
- uint hours_i= date[1]%24;
- date[1]= hours_i%12 + 12 + 24*days_i;
+ /* Read a possible AM/PM */
+ while (str != end && my_isspace(&my_charset_latin1, *str))
+ str++;
+ if (str+2 <= end && (str[1] == 'M' || str[1] == 'm'))
+ {
+ if (str[1] == 'p' || str[1] == 'P')
+ {
+ str+= 2;
+ date[1]= date[1]%12 + 12;
+ }
+ else if (str[1] == 'a' || str[1] == 'A')
+ str+=2;
+ }
}
/* Some simple checks */
@@ -680,11 +774,11 @@ bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd)
return 1;
}
l_time->month=0;
- l_time->day=date[0];
- l_time->hour=date[frm_pos[3] + 1];
- l_time->minute=date[frm_pos[4] + 1];
- l_time->second=date[frm_pos[5] + 1];
- l_time->second_part=date[4];
+ l_time->day= date[0];
+ l_time->hour= date[1];
+ l_time->minute= date[2];
+ l_time->second= date[3];
+ l_time->second_part= date[4];
l_time->time_type= TIMESTAMP_TIME;
/* Check if there is garbage at end of the TIME specification */
@@ -730,163 +824,404 @@ void calc_time_from_sec(TIME *to, long seconds, long microseconds)
}
-DATETIME_FORMAT *make_format(DATETIME_FORMAT *datetime_format,
- datetime_format_types format_type,
- const char *format_str,
- uint format_length, bool is_alloc)
-{
- if (format_length &&
- !parse_datetime_formats(format_type, format_str,
- format_length,
- datetime_format->dt_pos))
- {
- if (is_alloc)
- {
- if (!(datetime_format->format= my_strdup_with_length(format_str,
- format_length,
- MYF(0))))
- return 0;
- }
- else
- datetime_format->format= (char *) format_str;
- datetime_format->format_length= format_length;
- return datetime_format;
- }
- return 0;
-}
+/*
+ Parse a format string specification
+ SYNOPSIS
+ parse_date_time_format()
+ format_type Format of string (time, date or datetime)
+ format_str String to parse
+ format_length Length of string
+ date_time_format Format to fill in
+
+ NOTES
+ Fills in date_time_format->positions for all date time parts.
+
+ positions marks the position for a datetime element in the format string.
+ The position array elements are in the following order:
+ YYYY-DD-MM HH-MM-DD.FFFFFF AM
+ 0 1 2 3 4 5 6 7
+
+ If positions[0]= 5, it means that year will be the forth element to
+ read from the parsed date string.
+
+ RETURN
+ 0 ok
+ 1 error
+*/
-bool parse_datetime_formats(datetime_format_types format_type,
- const char *format_str, uint format_length,
- byte *dt_pos)
+bool parse_date_time_format(timestamp_type format_type,
+ const char *format, uint format_length,
+ DATE_TIME_FORMAT *date_time_format)
{
- uint pos= 0;
- dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
- dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= -1;
+ uint offset= 0, separators= 0;
+ const char *ptr= format, *format_str;
+ const char *end= ptr+format_length;
+ uchar *dt_pos= date_time_format->positions;
+ /* need_p is set if we are using AM/PM format */
+ bool need_p= 0, allow_separator= 0;
+ ulong part_map= 0, separator_map= 0;
+ const char *parts[16];
+
+ date_time_format->time_separator= 0;
+ date_time_format->flag= 0; // For future
- const char *ptr=format_str;
- const char *end=ptr+format_length;
- bool need_p= 0;
+ /*
+ Fill position with 'dummy' arguments to found out if a format tag is
+ used twice (This limit's the format to 255 characters, but this is ok)
+ */
+ dt_pos[0]= dt_pos[1]= dt_pos[2]= dt_pos[3]=
+ dt_pos[4]= dt_pos[5]= dt_pos[6]= dt_pos[7]= 255;
for (; ptr != end; ptr++)
{
if (*ptr == '%' && ptr+1 != end)
{
+ uint position;
+ LINT_INIT(position);
switch (*++ptr) {
- case 'y':
+ case 'y': // Year
case 'Y':
- if (dt_pos[0] > -1)
- return 1;
- dt_pos[0]= pos;
+ position= 0;
break;
- case 'c':
+ case 'c': // Month
case 'm':
- if (dt_pos[1] > -1)
- return 1;
- dt_pos[1]= pos;
+ position= 1;
break;
case 'd':
case 'e':
- if (dt_pos[2] > -1)
- return 1;
- dt_pos[2]= pos;
+ position= 2;
break;
- case 'H':
- case 'k':
case 'h':
case 'I':
case 'l':
- if (dt_pos[3] > -1)
- return 1;
- dt_pos[3]= pos;
- need_p= (*ptr == 'h' || *ptr == 'l' || *ptr == 'I');
+ need_p= 1; // Need AM/PM
+ /* Fall through */
+ case 'k':
+ case 'H':
+ position= 3;
break;
case 'i':
- if (dt_pos[4] > -1)
- return 1;
- dt_pos[4]= pos;
+ position= 4;
break;
case 's':
case 'S':
- if (dt_pos[5] > -1)
- return 1;
- dt_pos[5]= pos;
+ position= 5;
+ break;
+ case 'f':
+ position= 6;
+ if (dt_pos[5] != offset-1 || ptr[-2] != '.')
+ return 1; // Wrong usage of %f
break;
- case 'p':
- if (dt_pos[6] > -1)
- return 1;
- /* %p should be last in format string */
- if (format_type == DATE_FORMAT_TYPE ||
- (pos != 6 && format_type == DATETIME_FORMAT_TYPE) ||
- (pos != 3 && format_type == TIME_FORMAT_TYPE))
- return 1;
- dt_pos[6]= 1;
+ case 'p': // AM/PM
+ if (offset == 0) // Can't be first
+ return 0;
+ position= 7;
break;
default:
- return 1;
+ return 1; // Unknown controll char
}
- if (dt_pos[6] == -1)
- pos++;
+ if (dt_pos[position] != 255) // Don't allow same tag twice
+ return 1;
+ parts[position]= ptr-1;
+
+ /*
+ If switching from time to date, ensure that all time parts
+ are used
+ */
+ if (part_map && position <= 2 && !(part_map & (1 | 2 | 4)))
+ offset=5;
+ part_map|= (ulong) 1 << position;
+ dt_pos[position]= offset++;
+ allow_separator= 1;
+ }
+ else
+ {
+ /*
+ Don't allow any characters in format as this could easily confuse
+ the date reader
+ */
+ if (!allow_separator)
+ return 1; // No separator here
+ allow_separator= 0; // Don't allow two separators
+ separators++;
+ /* Store in separator_map which parts are punct characters */
+ if (my_ispunct(&my_charset_latin1, *ptr))
+ separator_map|= (ulong) 1 << (offset-1);
+ else if (!my_isspace(&my_charset_latin1, *ptr))
+ return 1;
}
}
- if (pos > 5 && format_type == DATETIME_FORMAT_TYPE &&
- (dt_pos[0] + dt_pos[1] + dt_pos[2] +
- dt_pos[3] + dt_pos[4] + dt_pos[5] != 15) ||
- pos > 2 && format_type == DATE_FORMAT_TYPE &&
- (dt_pos[0] + dt_pos[1] + dt_pos[2] != 3) ||
- pos > 2 && format_type == TIME_FORMAT_TYPE &&
- (dt_pos[3] + dt_pos[4] + dt_pos[5] != 3) ||
- (need_p && dt_pos[6] != 1))
- return 1;
+ /* If no %f, specify it after seconds. Move %p up, if necessary */
+ if ((part_map & 32) && !(part_map & 64))
+ {
+ dt_pos[6]= dt_pos[5] +1;
+ parts[6]= parts[5]; // For later test in (need_p)
+ if (dt_pos[6] == dt_pos[7]) // Move %p one step up if used
+ dt_pos[7]++;
+ }
/*
- Check for valid separators between date/time parst
+ Check that we have not used a non legal format specifier and that all
+ format specifiers have been used
+
+ The last test is to ensure that %p is used if and only if
+ it's needed.
*/
- uint tmp_len= format_length;
- if (dt_pos[6] == 1)
+ if ((format_type == TIMESTAMP_DATETIME &&
+ !test_all_bits(part_map, (1 | 2 | 4 | 8 | 16 | 32))) ||
+ (format_type == TIMESTAMP_DATE && part_map != (1 | 2 | 4)) ||
+ (format_type == TIMESTAMP_TIME &&
+ !test_all_bits(part_map, 8 | 16 | 32)) ||
+ !allow_separator || // %option should be last
+ (need_p && dt_pos[6] +1 != dt_pos[7]) ||
+ (need_p ^ (dt_pos[7] != 255)))
+ return 1;
+
+ if (dt_pos[6] != 255) // If fractional seconds
{
- end= end - 2;
- if (my_ispunct(&my_charset_latin1, *end) || my_isspace(&my_charset_latin1, *end))
- end--;
- tmp_len= end - format_str;
+ /* remove fractional seconds from later tests */
+ uint pos= dt_pos[6] -1;
+ /* Remove separator before %f from sep map */
+ separator_map= ((separator_map & ((ulong) (1 << pos)-1)) |
+ ((separator_map & ~((ulong) (1 << pos)-1)) >> 1));
+ if (part_map & 64)
+ {
+ separators--; // There is always a separator
+ need_p= 1; // force use of separators
+ }
}
+
+ /*
+ Remove possible separator before %p from sep_map
+ (This can either be at position 3, 4, 6 or 7) h.m.d.%f %p
+ */
+ if (dt_pos[7] != 255)
+ {
+ if (need_p && parts[7] != parts[6]+2)
+ separators--;
+ }
+ /*
+ Calculate if %p is in first or last part of the datetime field
+
+ At this point we have either %H-%i-%s %p 'year parts' or
+ 'year parts' &H-%i-%s %p" as %f was removed above
+ */
+ offset= dt_pos[6] <= 3 ? 3 : 6;
+ /* Remove separator before %p from sep map */
+ separator_map= ((separator_map & ((ulong) (1 << offset)-1)) |
+ ((separator_map & ~((ulong) (1 << offset)-1)) >> 1));
+
+ format_str= 0;
switch (format_type) {
- case DATE_FORMAT_TYPE:
- case TIME_FORMAT_TYPE:
- if ((tmp_len == 6 &&
- !my_strnncoll(&my_charset_bin,
- (const uchar *) format_str, 6,
- (const uchar *) datetime_formats
- [format_type][INTERNAL_FORMAT], 6)) ||
- tmp_len == 8 &&
- my_ispunct(&my_charset_latin1, *(format_str+2)) &&
- my_ispunct(&my_charset_latin1, *(format_str+5)))
+ case TIMESTAMP_DATE:
+ format_str= known_date_time_formats[INTERNAL_FORMAT].date_format;
+ /* fall through */
+ case TIMESTAMP_TIME:
+ if (!format_str)
+ format_str=known_date_time_formats[INTERNAL_FORMAT].time_format;
+
+ /*
+ If there is no separators, allow the internal format as we can read
+ this. If separators are used, they must be between each part
+ */
+ if (format_length == 6 && !need_p &&
+ !my_strnncoll(&my_charset_bin,
+ (const uchar *) format, 6,
+ (const uchar *) format_str, 6))
+ return 0;
+ if (separator_map == (1 | 2))
{
- if (format_type == TIME_FORMAT_TYPE && tmp_len == 8)
+ if (format_type == TIMESTAMP_TIME)
{
- if (*(format_str+2) != *(format_str+5))
- return 1;
- dt_pos[7]= *(format_str+2);
+ if (*(format+2) != *(format+5))
+ break; // Error
+ /* Store the character used for time formats */
+ date_time_format->time_separator= *(format+2);
}
return 0;
}
break;
- case DATETIME_FORMAT_TYPE:
- if ((tmp_len == 12 &&
+ case TIMESTAMP_DATETIME:
+ /*
+ If there is no separators, allow the internal format as we can read
+ this. If separators are used, they must be between each part.
+ Between DATE and TIME we also allow space as separator
+ */
+ if ((format_length == 12 && !need_p &&
!my_strnncoll(&my_charset_bin,
- (const uchar *) format_str, 12,
- (const uchar *) datetime_formats
- [DATETIME_FORMAT_TYPE][INTERNAL_FORMAT], 12)) ||
- tmp_len == 17 &&
- my_ispunct(&my_charset_latin1, *(format_str+2)) &&
- my_ispunct(&my_charset_latin1, *(format_str+5)) &&
- my_ispunct(&my_charset_latin1, *(format_str+11)) &&
- my_ispunct(&my_charset_latin1, *(format_str+14)) &&
- (my_ispunct(&my_charset_latin1, *(format_str+8)) ||
- my_isspace(&my_charset_latin1, *(format_str+8))))
+ (const uchar *) format, 12,
+ (const uchar*) known_date_time_formats[INTERNAL_FORMAT].datetime_format,
+ 12)) ||
+ (separators == 5 && separator_map == (1 | 2 | 8 | 16)))
return 0;
break;
- }
- return 1;
+ default:
+ DBUG_ASSERT(1);
+ break;
+ }
+ return 1; // Error
+}
+
+
+/*
+ Create a DATE_TIME_FORMAT object from a format string specification
+
+ SYNOPSIS
+ date_time_format_make()
+ format_type Format to parse (time, date or datetime)
+ format_str String to parse
+ format_length Length of string
+
+ NOTES
+ The returned object should be freed with my_free()
+
+ RETURN
+ NULL ponter: Error
+ new object
+*/
+
+DATE_TIME_FORMAT
+*date_time_format_make(timestamp_type format_type,
+ const char *format_str, uint format_length)
+{
+ DATE_TIME_FORMAT tmp;
+
+ if (format_length && format_length < 255 &&
+ !parse_date_time_format(format_type, format_str,
+ format_length, &tmp))
+ {
+ tmp.format.str= (char*) format_str;
+ tmp.format.length= format_length;
+ return date_time_format_copy((THD *)0, &tmp);
+ }
+ return 0;
+}
+
+
+/*
+ Create a copy of a DATE_TIME_FORMAT object
+
+ SYNOPSIS
+ date_and_time_format_copy()
+ thd Set if variable should be allocated in thread mem
+ format format to copy
+
+ NOTES
+ The returned object should be freed with my_free()
+
+ RETURN
+ NULL ponter: Error
+ new object
+*/
+
+DATE_TIME_FORMAT *date_time_format_copy(THD *thd, DATE_TIME_FORMAT *format)
+{
+ DATE_TIME_FORMAT *new_format;
+ ulong length= sizeof(*format) + format->format.length + 1;
+
+ if (thd)
+ new_format= (DATE_TIME_FORMAT *) thd->alloc(length);
+ else
+ new_format= (DATE_TIME_FORMAT *) my_malloc(length, MYF(MY_WME));
+ if (new_format)
+ {
+ /* Put format string after current pos */
+ new_format->format.str= (char*) (new_format+1);
+ memcpy((char*) new_format->positions, (char*) format->positions,
+ sizeof(format->positions));
+ new_format->time_separator= format->time_separator;
+ /* We make the string null terminated for easy printf in SHOW VARIABLES */
+ memcpy((char*) new_format->format.str, format->format.str,
+ format->format.length);
+ new_format->format.str[format->format.length]= 0;
+ new_format->format.length= format->format.length;
+ }
+ return new_format;
+}
+
+
+KNOWN_DATE_TIME_FORMAT known_date_time_formats[6]=
+{
+ {"USA", "%m.%d.%Y", "%Y-%m-%d %H.%i.%s", "%h:%i:%s %p" },
+ {"JIS", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
+ {"ISO", "%Y-%m-%d", "%Y-%m-%d %H:%i:%s", "%H:%i:%s" },
+ {"EUR", "%d.%m.%Y", "%Y-%m-%d %H.%i.%s", "%H.%i.%s" },
+ {"INTERNAL", "%Y%m%d", "%Y%m%d%H%i%s", "%H%i%s" },
+ { 0, 0, 0, 0 }
+};
+
+
+/*
+ Return format string according format name.
+ If name is unknown, result is NULL
+*/
+
+const char *get_date_time_format_str(KNOWN_DATE_TIME_FORMAT *format,
+ timestamp_type type)
+{
+ switch (type) {
+ case TIMESTAMP_DATE:
+ return format->date_format;
+ case TIMESTAMP_DATETIME:
+ return format->datetime_format;
+ case TIMESTAMP_TIME:
+ return format->time_format;
+ default:
+ DBUG_ASSERT(0); // Impossible
+ return 0;
+ }
+}
+
+/****************************************************************************
+ Functions to create default time/date/datetime strings
+
+ NOTE:
+ For the moment the DATE_TIME_FORMAT argument is ignored becasue
+ MySQL doesn't support comparing of date/time/datetime strings that
+ are not in arbutary order as dates are compared as strings in some
+ context)
+****************************************************************************/
+
+void make_time(DATE_TIME_FORMAT *format, TIME *l_time, String *str)
+{
+ long length= my_sprintf((char*) str->ptr(),
+ ((char*) str->ptr(),
+ "%s%02d:%02d:%02d",
+ (l_time->neg ? "-" : ""),
+ l_time->hour,
+ l_time->minute,
+ l_time->second));
+ str->length(length);
+ str->set_charset(&my_charset_bin);
+}
+
+
+void make_date(DATE_TIME_FORMAT *format, TIME *l_time, String *str)
+{
+ long length= my_sprintf((char*) str->ptr(),
+ ((char*) str->ptr(),
+ "%04d-%02d-%02d",
+ l_time->year,
+ l_time->month,
+ l_time->day));
+ str->length(length);
+ str->set_charset(&my_charset_bin);
+}
+
+
+void make_datetime(DATE_TIME_FORMAT *format, TIME *l_time, String *str)
+{
+ long length= my_sprintf((char*) str->ptr(),
+ ((char*) str->ptr(),
+ "%04d-%02d-%02d %02d:%02d:%02d",
+ l_time->year,
+ l_time->month,
+ l_time->day,
+ l_time->hour,
+ l_time->minute,
+ l_time->second));
+ str->length(length);
+ str->set_charset(&my_charset_bin);
}
diff --git a/strings/Makefile.am b/strings/Makefile.am
index 7b2fdcccc55..61219c8abb9 100644
--- a/strings/Makefile.am
+++ b/strings/Makefile.am
@@ -21,20 +21,20 @@ pkglib_LIBRARIES = libmystrings.a
# Exact one of ASSEMBLER_X
if ASSEMBLER_x86
-ASRCS = strings-x86.s longlong2str-x86.s
+ASRCS = strings-x86.s longlong2str-x86.s my_strtoll10-x86.s
CSRCS = bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c
else
if ASSEMBLER_sparc32
# These file MUST all be on the same line!! Otherwise automake
# generats a very broken makefile
ASRCS = bmove_upp-sparc.s strappend-sparc.s strend-sparc.s strinstr-sparc.s strmake-sparc.s strmov-sparc.s strnmov-sparc.s strstr-sparc.s
-CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c
+CSRCS = strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c
else
#no assembler
ASRCS =
# These file MUST all be on the same line!! Otherwise automake
# generats a very broken makefile
-CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c
+CSRCS = strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c atof.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c ctype-mb.c ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c ctype-ucs2.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c xml.c ctype-extra.c my_strtoll10.c
endif
endif
@@ -47,6 +47,7 @@ EXTRA_DIST = ctype-big5.c ctype-czech.c ctype-euc_kr.c ctype-win1250ch.c \
ctype-ucs2.c ctype-tis620.c ctype-ujis.c \
xml.c strto.c strings-x86.s \
longlong2str.c longlong2str-x86.s \
+ my_strtoll10.c my_strtoll10-x86.s \
strxmov.c bmove_upp.c strappend.c strcont.c strend.c \
strfill.c strcend.c is_prefix.c strstr.c strinstr.c \
strmake.c strnmov.c strmov.c strnlen.c \
diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c
index ebf915398a8..42dd90ccb3c 100644
--- a/strings/ctype-bin.c
+++ b/strings/ctype-bin.c
@@ -35,12 +35,12 @@ static uchar ctype_bin[]=
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 16, 16, 16, 16, 32,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 72, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, 1, 1, 1, 1, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 16, 2, 2, 2, 2, 2, 2, 2, 2
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
diff --git a/strings/my_vsnprintf.c b/strings/my_vsnprintf.c
index deb9448857e..4fd288d257e 100644
--- a/strings/my_vsnprintf.c
+++ b/strings/my_vsnprintf.c
@@ -95,26 +95,32 @@ int my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
else if (*fmt == 'd' || *fmt == 'u') /* Integer parameter */
{
register int iarg;
- char *to_start= to;
- if ((uint) (end-to) < max(16,length))
- break;
+ uint res_length, to_length;
+ char *store_start= to, *store_end;
+ char buff[16];
+
+ if ((to_length= (uint) (end-to)) < 16 || length)
+ store_start= buff;
iarg = va_arg(ap, int);
if (*fmt == 'd')
- to=int10_to_str((long) iarg,to, -10);
+ store_end= int10_to_str((long) iarg, store_start, -10);
else
- to=int10_to_str((long) (uint) iarg,to,10);
+ store_end= int10_to_str((long) (uint) iarg, store_start, 10);
+ if ((res_length= (uint) (store_end - store_start)) > to_length)
+ break; /* num doesn't fit in output */
/* If %#d syntax was used, we have to pre-zero/pre-space the string */
- if (length)
+ if (store_start == buff)
{
- uint res_length= (uint) (to - to_start);
+ length= min(length, to_length);
if (res_length < length)
{
uint diff= (length- res_length);
- bmove_upp(to+diff, to, res_length);
- bfill(to-res_length, diff, pre_zero ? '0' : ' ');
+ bfill(to, diff, pre_zero ? '0' : ' ');
to+= diff;
}
+ bmove(to, store_start, res_length);
}
+ to+= res_length;
continue;
}
/* We come here on '%%', unknown code or too long parameter */