diff options
125 files changed, 2707 insertions, 792 deletions
diff --git a/.bzrignore b/.bzrignore index 339dc8f33ee..920522c7592 100644 --- a/.bzrignore +++ b/.bzrignore @@ -515,6 +515,7 @@ scripts/fill_func_tables.sql scripts/fill_help_tables scripts/fill_help_tables.sql scripts/make_binary_distribution +scripts/make_sharedlib_distribution scripts/make_win_src_distribution scripts/msql2mysql scripts/mysql_config diff --git a/client/client_priv.h b/client/client_priv.h index eede1a0a39d..d655619516d 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -26,7 +26,7 @@ /* We have to define 'enum options' identical in all files to keep OS2 happy */ -enum options { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET, +enum options_client { OPT_CHARSETS_DIR=256, OPT_DEFAULT_CHARSET, OPT_PAGER, OPT_NOPAGER, OPT_TEE, OPT_NOTEE, OPT_LOW_PRIORITY, OPT_AUTO_REPAIR, OPT_COMPRESS, OPT_DROP, OPT_LOCKS, OPT_KEYWORDS, OPT_DELAYED, OPT_OPTIMIZE, diff --git a/configure.in b/configure.in index f098a3d39a8..207404a89c5 100644 --- a/configure.in +++ b/configure.in @@ -1821,7 +1821,7 @@ AC_CHECK_FUNCS(alarm bmove \ cuserid fcntl fconvert poll \ getrusage getpwuid getcwd getrlimit getwd index stpcpy locking longjmp \ perror pread realpath readlink rename \ - socket strnlen madvise mkstemp \ + socket strnlen madvise mallinfo mkstemp \ strtol strtoul strtoll strtoull snprintf tempnam thr_setconcurrency \ gethostbyaddr_r gethostbyname_r getpwnam \ bfill bzero bcmp strstr strpbrk strerror \ diff --git a/include/m_ctype.h b/include/m_ctype.h index f39cbf8b659..a896afe750a 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -123,8 +123,8 @@ typedef struct my_collation_handler_st int (*strcasecmp)(struct charset_info_st *, const char *, const char *); uint (*instr)(struct charset_info_st *, - const char *big, uint b_length, - const char *small, uint s_length, + const char *b, uint b_length, + const char *s, uint s_length, my_match_t *match, uint nmatch); /* Hash calculation */ @@ -257,8 +257,8 @@ extern void my_hash_sort_simple(CHARSET_INFO *cs, extern uint my_lengthsp_8bit(CHARSET_INFO *cs, const char *ptr, uint length); extern uint my_instr_simple(struct charset_info_st *, - const char *big, uint b_length, - const char *small, uint s_length, + const char *b, uint b_length, + const char *s, uint s_length, my_match_t *match, uint nmatch); @@ -327,8 +327,8 @@ int my_wildcmp_mb(CHARSET_INFO *, uint my_numchars_mb(CHARSET_INFO *, const char *b, const char *e); uint my_charpos_mb(CHARSET_INFO *, const char *b, const char *e, uint pos); uint my_instr_mb(struct charset_info_st *, - const char *big, uint b_length, - const char *small, uint s_length, + const char *b, uint b_length, + const char *s, uint s_length, my_match_t *match, uint nmatch); diff --git a/include/my_base.h b/include/my_base.h index e36f73afe75..5af8a968cd0 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -49,20 +49,24 @@ /* The following is parameter to ha_rkey() how to use key */ -/* We define a complete-field prefix of a key value as a prefix where the -last included field in the prefix contains the full field, not just some bytes -from the start of the field. A partial-field prefix is allowed to -contain only a few first bytes from the last included field. - -Below HA_READ_KEY_EXACT, ..., HA_READ_BEFORE_KEY can take a -complete-field prefix of a key value as the search key. HA_READ_PREFIX -and HA_READ_PREFIX_LAST could also take a partial-field prefix, but -currently (4.0.10) they are only used with complete-field prefixes. MySQL uses -a padding trick to implement LIKE 'abc%' queries. - -NOTE that in InnoDB HA_READ_PREFIX_LAST will NOT work with a partial-field -prefix because InnoDB currently strips spaces from the end of varchar -fields! */ +/* + We define a complete-field prefix of a key value as a prefix where + the last included field in the prefix contains the full field, not + just some bytes from the start of the field. A partial-field prefix + is allowed to contain only a few first bytes from the last included + field. + + Below HA_READ_KEY_EXACT, ..., HA_READ_BEFORE_KEY can take a + complete-field prefix of a key value as the search + key. HA_READ_PREFIX and HA_READ_PREFIX_LAST could also take a + partial-field prefix, but currently (4.0.10) they are only used with + complete-field prefixes. MySQL uses a padding trick to implement + LIKE 'abc%' queries. + + NOTE that in InnoDB HA_READ_PREFIX_LAST will NOT work with a + partial-field prefix because InnoDB currently strips spaces from the + end of varchar fields! +*/ enum ha_rkey_function { HA_READ_KEY_EXACT, /* Find first record else error */ diff --git a/include/mysql.h b/include/mysql.h index a8ced90f414..f44d515478c 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -66,6 +66,9 @@ typedef int my_socket; extern unsigned int mysql_port; extern char *mysql_unix_port; +#define CLIENT_NET_READ_TIMEOUT 365*24*3600 /* Timeout on read */ +#define CLIENT_NET_WRITE_TIMEOUT 365*24*3600 /* Timeout on write */ + #ifdef __NETWARE__ #pragma pack(push, 8) /* 8 byte alignment */ #endif diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 8a75ccffe8c..34184f5ba97 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -295,5 +295,6 @@ #define ER_BAD_SLAVE_UNTIL_COND 1276 #define ER_MISSING_SKIP_SLAVE 1277 #define ER_UNTIL_COND_IGNORED 1278 -#define ER_BAD_FT_COLUMN 1279 -#define ER_ERROR_MESSAGES 280 +#define ER_WRONG_INDEX_NAME 1279 +#define ER_BAD_FT_COLUMN 1280 +#define ER_ERROR_MESSAGES 281 diff --git a/include/queues.h b/include/queues.h index 699705d0869..ac15b09719b 100644 --- a/include/queues.h +++ b/include/queues.h @@ -49,6 +49,7 @@ int init_queue(QUEUE *queue,uint max_elements,uint offset_to_key, int reinit_queue(QUEUE *queue,uint max_elements,uint offset_to_key, pbool max_at_top, queue_compare compare, void *first_cmp_arg); +int resize_queue(QUEUE *queue, uint max_elements); void delete_queue(QUEUE *queue); void queue_insert(QUEUE *queue,byte *element); byte *queue_remove(QUEUE *queue,uint idx); diff --git a/include/sql_state.h b/include/sql_state.h index c0b7cf97ea5..222636d3bec 100644 --- a/include/sql_state.h +++ b/include/sql_state.h @@ -159,3 +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", "", diff --git a/include/thr_alarm.h b/include/thr_alarm.h index 8ff4472f700..0dbb700b4fc 100644 --- a/include/thr_alarm.h +++ b/include/thr_alarm.h @@ -60,9 +60,10 @@ typedef my_bool ALARM; #define thr_end_alarm(A) #define thr_alarm(A,B,C) ((*(A)=1)-1) /* The following should maybe be (*(A)) */ -#define thr_got_alarm(A) 0 +#define thr_got_alarm(A) 0 #define init_thr_alarm(A) #define thr_alarm_kill(A) +#define resize_thr_alarm(N) #define end_thr_alarm() #else @@ -100,6 +101,7 @@ typedef struct st_alarm { #define thr_alarm_init(A) (*(A))=0 #define thr_alarm_in_use(A) (*(A)!= 0) void init_thr_alarm(uint max_alarm); +void resize_thr_alarm(uint max_alarms); my_bool thr_alarm(thr_alarm_t *alarmed, uint sec, ALARM *buff); void thr_alarm_kill(pthread_t thread_id); void thr_end_alarm(thr_alarm_t *alarmed); diff --git a/innobase/include/os0thread.h b/innobase/include/os0thread.h index 491d8866af4..554ca0563e4 100644 --- a/innobase/include/os0thread.h +++ b/innobase/include/os0thread.h @@ -15,14 +15,9 @@ Created 9/8/1995 Heikki Tuuri /* Maximum number of threads which can be created in the program; this is also the size of the wait slot array for MySQL threads which can wait inside InnoDB */ -#if defined(__WIN__) || defined(__NETWARE__) -/* Create less event semaphores because Win 98/ME had difficult creating -40000 event semaphores */ -/* TODO: these just take a lot of memory on NetWare. should netware move up? */ -#define OS_THREAD_MAX_N 1000 -#else -#define OS_THREAD_MAX_N 10000 -#endif + +#define OS_THREAD_MAX_N srv_max_n_threads + /* Possible fixed priorities for threads */ #define OS_THREAD_PRIORITY_NONE 100 diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 094b95e68d3..6e47c468d26 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -87,6 +87,8 @@ extern ulint srv_max_dirty_pages_pct; extern ulint srv_force_recovery; extern ulint srv_thread_concurrency; +extern ulint srv_max_n_threads; + extern lint srv_conc_n_threads; extern ibool srv_fast_shutdown; diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index e16073c171c..2f3502f99ad 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -180,6 +180,12 @@ the user from forgetting the innodb_force_recovery keyword to my.cnf */ ulint srv_force_recovery = 0; /*-----------------------*/ +/* We are prepared for a situation that we have this many threads waiting for +a semaphore inside InnoDB. innobase_start_or_create_for_mysql() sets the +value. */ + +ulint srv_max_n_threads = 0; + /* The following controls how many threads we let inside InnoDB concurrently: threads waiting for locks are not counted into the number because otherwise we could get a deadlock. MySQL creates a thread for each user session, and @@ -219,7 +225,7 @@ struct srv_conc_slot_struct{ UT_LIST_BASE_NODE_T(srv_conc_slot_t) srv_conc_queue; /* queue of threads waiting to get in */ -srv_conc_slot_t srv_conc_slots[OS_THREAD_MAX_N]; /* array of wait +srv_conc_slot_t* srv_conc_slots; /* array of wait slots */ /* Number of times a thread is allowed to enter InnoDB within the same @@ -1712,6 +1718,8 @@ srv_init(void) UT_LIST_INIT(srv_conc_queue); + srv_conc_slots = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_conc_slot_t)); + for (i = 0; i < OS_THREAD_MAX_N; i++) { conc_slot = srv_conc_slots + i; conc_slot->reserved = FALSE; @@ -1758,7 +1766,7 @@ srv_conc_enter_innodb( thread */ { ibool has_slept = FALSE; - srv_conc_slot_t* slot; + srv_conc_slot_t* slot = NULL; ulint i; char err_buf[1000]; @@ -1835,6 +1843,7 @@ retry: slot = srv_conc_slots + i; if (!slot->reserved) { + break; } } diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 5de87038bde..83cde6e6589 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1138,10 +1138,32 @@ innobase_start_or_create_for_mysql(void) srv_file_flush_method_str); return(DB_ERROR); } - + + /* Set the maximum number of threads which can wait for a semaphore + inside InnoDB */ +#if defined(__WIN__) || defined(__NETWARE__) + +/* Create less event semaphores because Win 98/ME had difficulty creating +40000 event semaphores. +Comment from Novell, Inc.: also, these just take a lot of memory on +NetWare. */ + srv_max_n_threads = 1000; +#else + if (srv_pool_size >= 8 * 1024) { + /* Here we still have srv_pool_size counted + in kilobytes, srv_boot converts the value to + pages; if buffer pool is less than 8 MB, + assume fewer threads. */ + srv_max_n_threads = 10000; + } else { + srv_max_n_threads = 1000; /* saves several MB of memory, + especially in 64-bit + computers */ + } +#endif /* Note that the call srv_boot() also changes the values of srv_pool_size etc. to the units used by InnoDB internally */ - + err = srv_boot(); if (err != DB_SUCCESS) { diff --git a/innobase/thr/thr0loc.c b/innobase/thr/thr0loc.c index fbf3e3a1dad..839cb024f25 100644 --- a/innobase/thr/thr0loc.c +++ b/innobase/thr/thr0loc.c @@ -14,6 +14,7 @@ Created 10/5/1995 Heikki Tuuri #include "sync0sync.h" #include "hash0hash.h" #include "mem0mem.h" +#include "srv0srv.h" /* IMPLEMENTATION OF THREAD LOCAL STORAGE diff --git a/libmysql/client_settings.h b/libmysql/client_settings.h index b9c47c1dd55..582f9613ee0 100644 --- a/libmysql/client_settings.h +++ b/libmysql/client_settings.h @@ -52,9 +52,9 @@ void STDCALL cli_mysql_close(MYSQL *mysql); MYSQL_FIELD * STDCALL cli_list_fields(MYSQL *mysql); my_bool STDCALL cli_read_prepare_result(MYSQL *mysql, MYSQL_STMT *stmt); -MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, - uint fields); +MYSQL_DATA * STDCALL cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + uint fields); int STDCALL cli_stmt_execute(MYSQL_STMT *stmt); -MYSQL_DATA *cli_read_binary_rows(MYSQL_STMT *stmt); +MYSQL_DATA * STDCALL cli_read_binary_rows(MYSQL_STMT *stmt); int STDCALL cli_unbuffered_fetch(MYSQL *mysql, char **row); const char * STDCALL cli_read_statistic(MYSQL *mysql); diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c index 08ea9deb11e..1cad02948e1 100644 --- a/libmysql/libmysql.c +++ b/libmysql/libmysql.c @@ -65,8 +65,8 @@ ulong net_buffer_length=8192; ulong max_allowed_packet= 1024L*1024L*1024L; -ulong net_read_timeout= NET_READ_TIMEOUT; -ulong net_write_timeout= NET_WRITE_TIMEOUT; +ulong net_read_timeout= CLIENT_NET_READ_TIMEOUT; +ulong net_write_timeout= CLIENT_NET_WRITE_TIMEOUT; #ifdef EMBEDDED_LIBRARY @@ -3098,7 +3098,7 @@ no_data: Read all rows of data from server (binary format) */ -MYSQL_DATA *cli_read_binary_rows(MYSQL_STMT *stmt) +MYSQL_DATA * STDCALL cli_read_binary_rows(MYSQL_STMT *stmt) { ulong pkt_len; uchar *cp; diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def index 1abc924e9c0..787aa645017 100644 --- a/libmysql/libmysql.def +++ b/libmysql/libmysql.def @@ -81,7 +81,7 @@ EXPORTS mysql_param_result mysql_ping mysql_prepare - mysql_prepare_result + mysql_get_metadata mysql_query mysql_read_query_result mysql_real_connect diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index b2fdb2ccf3f..76d3205dc01 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -146,7 +146,7 @@ int main(int argc, char **argv) #endif } /* main */ -enum options { +enum options_mc { OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS, OPT_CORRECT_CHECKSUM, OPT_KEY_BUFFER_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE, diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 277ae9e0b8d..d61614180b3 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -16,6 +16,8 @@ b drop table t1; +create table t1 (a int not null auto_increment,primary key (a)) type=heap; +drop table t1; create table t2 type=heap select * from t1; ERROR 42S02: Table 'test.t1' doesn't exist create table t2 select auto+1 from t1; @@ -26,10 +28,11 @@ Note 1051 Unknown table 't1' Note 1051 Unknown table 't2' create table t1 (b char(0) not null, index(b)); ERROR 42000: The used storage engine can't index column 'b' -create table t1 (a int not null auto_increment,primary key (a)) type=heap; create table t1 (a int not null,b text) type=heap; ERROR 42000: The used table type doesn't support BLOB/TEXT columns drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap; ERROR 42000: Incorrect table definition; There can only be one auto column and it must be defined as a key create table not_existing_database.test (a int); @@ -66,9 +69,8 @@ drop table if exists ``; ERROR 42000: Incorrect table name '' create table t1 (`` int); ERROR 42000: Incorrect column name '' -drop table if exists t1; -Warnings: -Note 1051 Unknown table 't1' +create table t1 (i int, index `` (i)); +ERROR 42000: Incorrect index name '' create table t1 (a int auto_increment not null primary key, B CHAR(20)); insert into t1 (b) values ("hello"),("my"),("world"); create table t2 (key (b)) select * from t1; @@ -220,6 +222,46 @@ ERROR 23000: Column 'k1' cannot be null insert into t1 values (NULL, NULL); ERROR 23000: Column 'k1' cannot be null drop table t1; +create table t1 select x'4132'; +drop table t1; +create table t1 select 1,2,3; +create table if not exists t1 select 1,2; +create table if not exists t1 select 1,2,3,4; +ERROR 21S01: Column count doesn't match value count at row 1 +create table if not exists t1 select 1; +select * from t1; +1 2 3 +1 2 3 +0 1 2 +0 0 1 +drop table t1; +create table t1 select 1,2,3; +create table if not exists t1 select 1,2; +create table if not exists t1 select 1,2,3,4; +ERROR 21S01: Column count doesn't match value count at row 1 +create table if not exists t1 select 1; +select * from t1; +1 2 3 +1 2 3 +0 1 2 +0 0 1 +drop table t1; +create table t1 (a int not null, b int, primary key (a)); +insert into t1 values (1,1); +create table if not exists t1 select 2; +select * from t1; +a b +1 1 +0 2 +create table if not exists t1 select 3 as 'a',4 as 'b'; +create table if not exists t1 select 3 as 'a',3 as 'b'; +ERROR 23000: Duplicate entry '3' for key 1 +select * from t1; +a b +1 1 +0 2 +3 4 +drop table t1; create table t1 (a int, key(a)); create table t2 (b int, foreign key(b) references t1(a), key(b)); drop table if exists t1,t2; @@ -320,8 +362,6 @@ t1 CREATE TABLE `t1` ( ) TYPE=MyISAM CHARSET=latin1 SET SESSION table_type=default; drop table t1; -create table t1 select x'4132'; -drop table t1; create table t1(a int,b int,c int unsigned,d date,e char,f datetime,g time,h blob); insert into t1(a)values(1); insert into t1(a,b,c,d,e,f,g,h) diff --git a/mysql-test/r/ctype_mb.result b/mysql-test/r/ctype_mb.result index 298e774186d..ce4a4f98b42 100644 --- a/mysql-test/r/ctype_mb.result +++ b/mysql-test/r/ctype_mb.result @@ -1,3 +1,4 @@ +drop table if exists t1; CREATE TABLE t1 SELECT _utf8'test' as c1, _utf8'теÑÑ‚' as c2; SHOW CREATE TABLE t1; Table Create Table @@ -15,6 +16,10 @@ t1 CREATE TABLE `t1` ( `c3` char(4) character set utf8 default NULL ) TYPE=MyISAM CHARSET=latin1 INSERT INTO t1 VALUES ('aaaabbbbccccdddd','aaaabbbbccccdddd','aaaabbbbccccdddd'); +Warnings: +Warning 1264 Data truncated for column 'c1' at row 1 +Warning 1264 Data truncated for column 'c2' at row 1 +Warning 1264 Data truncated for column 'c3' at row 1 SELECT * FROM t1; c1 c2 c3 aaaabbbbcccc aaaabbbbcccc aaaabbbbcccc diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result new file mode 100644 index 00000000000..590a1d6904b --- /dev/null +++ b/mysql-test/r/date_formats.result @@ -0,0 +1,157 @@ +SHOW GLOBAL VARIABLES LIKE "%_format%"; +Variable_name Value +date_format %d.%m.%Y +datetime_format %Y/%d/%m-%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 +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 date_format='%d.%m.%d'; +ERROR HY000: Unknown error +SET datetime_format="%d.%m.%y %h.%i.%s"; +ERROR HY000: Unknown error +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 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 get_format(DATE, 'USA') as a; +a +%m.%d.%Y +select get_format(TIME, 'internal') as a; +a +%H%i%s +select get_format(DATETIME, 'eur') as a; +a +%Y-%m-%d-%H.%i.%s diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index d24ac5e898a..12d8bbaf8ae 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -215,3 +215,18 @@ ERROR 42000: You have an error in your SQL syntax. Check the manual that corres insert into (select * from t1) values (5); ERROR 42000: You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '(select * from t1) values (5)' at line 1 drop table t1; +create table t1 (E1 INTEGER UNSIGNED NOT NULL, E2 INTEGER UNSIGNED NOT NULL, E3 INTEGER UNSIGNED NOT NULL, PRIMARY KEY(E1) +); +insert into t1 VALUES(1,1,1), (2,2,1); +select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +count(*) +2 +explain select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 2 +1 PRIMARY t1 eq_ref PRIMARY PRIMARY 4 THEMAX.E2 1 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 2 Using where +3 DEPENDENT SUBQUERY B ALL NULL NULL NULL NULL 2 Using where +Warnings: +Note 1275 Field or reference 'A.E2' of SELECT #3 was resolved in SELECT #2 +drop table t1; diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result index 479a7f049d9..2ef1f0c86f9 100644 --- a/mysql-test/r/null.result +++ b/mysql-test/r/null.result @@ -75,6 +75,8 @@ NULL this is null drop table t1; CREATE TABLE t1 (a varchar(16) NOT NULL, b smallint(6) NOT NULL, c datetime NOT NULL, d smallint(6) NOT NULL); INSERT INTO t1 SET a = "", d= "2003-01-14 03:54:55"; +Warnings: +Warning 1264 Data truncated for column 'd' at row 1 UPDATE t1 SET d=1/NULL; Warnings: Warning 1264 Data truncated for column 'd' at row 1 diff --git a/mysql-test/r/select_found.result b/mysql-test/r/select_found.result index c8991696b5e..d79f45a9334 100644 --- a/mysql-test/r/select_found.result +++ b/mysql-test/r/select_found.result @@ -136,7 +136,7 @@ email104 email105 email106 email107 -INSERT INTO `t1` (`id`, `kid`) VALUES ('', '150'); +INSERT INTO `t1` (`id`, `kid`) VALUES ('0', '150'); SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; email email1 diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result index 9b80b965d10..06451b8ac34 100644 --- a/mysql-test/r/sql_mode.result +++ b/mysql-test/r/sql_mode.result @@ -71,10 +71,10 @@ t1 CREATE TABLE `t1` ( PRIMARY KEY (`a`), UNIQUE KEY `email` (`email`) ) TYPE=HEAP ROW_FORMAT=DYNAMIC -set sql_mode="postgresql,oracle,mssql,db2,sapdb"; +set sql_mode="postgresql,oracle,mssql,db2,maxdb"; select @@sql_mode; @@sql_mode -PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,POSTGRESQL,ORACLE,MSSQL,DB2,SAPDB,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS +PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,POSTGRESQL,ORACLE,MSSQL,DB2,MAXDB,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS show create table t1; Table Create Table t1 CREATE TABLE "t1" ( diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 6e35b6e78c1..14a132531ca 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1438,4 +1438,4 @@ explain select * from t3 where a > all (select max(b) from t2 group by a); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t3 ALL NULL NULL NULL NULL 3 Using where 2 SUBQUERY t2 ALL NULL NULL NULL NULL 4 Using temporary; Using filesort -drop table if exists t2, t3; +drop table t2, t3; diff --git a/mysql-test/r/type_float.result b/mysql-test/r/type_float.result index 987fa9d5685..2a461942853 100644 --- a/mysql-test/r/type_float.result +++ b/mysql-test/r/type_float.result @@ -70,6 +70,12 @@ select min(a) from t1; min(a) -0.010 drop table t1; +create table t1 (a float); +insert into t1 values (1); +select max(a),min(a),avg(a) from t1; +max(a) min(a) avg(a) +1 1 1 +drop table t1; create table t1 (f float, f2 float(24), f3 float(6,2), d double, d2 float(53), d3 double(10,3), de decimal, de2 decimal(6), de3 decimal(5,2), n numeric, n2 numeric(8), n3 numeric(5,6)); show full columns from t1; Field Type Collation Null Key Default Extra Privileges Comment diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index ead09cc6ed7..d65b44e7846 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -163,6 +163,38 @@ set @@rand_seed1=10000000,@@rand_seed2=1000000; select ROUND(RAND(),5); ROUND(RAND(),5) 0.02887 +show variables like '%alloc%'; +Variable_name Value +query_alloc_block_size 8192 +query_prealloc_size 8192 +range_alloc_block_size 2048 +transaction_alloc_block_size 8192 +transaction_prealloc_size 4096 +set @@range_alloc_block_size=1024*16; +set @@query_alloc_block_size=1024*17+2; +set @@query_prealloc_size=1024*18; +set @@transaction_alloc_block_size=1024*20-1; +set @@transaction_prealloc_size=1024*21-1; +select @@query_alloc_block_size; +@@query_alloc_block_size +17408 +show variables like '%alloc%'; +Variable_name Value +query_alloc_block_size 17408 +query_prealloc_size 18432 +range_alloc_block_size 16384 +transaction_alloc_block_size 19456 +transaction_prealloc_size 20480 +set @@range_alloc_block_size=default; +set @@query_alloc_block_size=default, @@query_prealloc_size=default; +set transaction_alloc_block_size=default, @@transaction_prealloc_size=default; +show variables like '%alloc%'; +Variable_name Value +query_alloc_block_size 8192 +query_prealloc_size 8192 +range_alloc_block_size 2048 +transaction_alloc_block_size 8192 +transaction_prealloc_size 4096 set big_tables=OFFF; ERROR 42000: Variable 'big_tables' can't be set to the value of 'OFFF' set big_tables="OFFF"; @@ -202,6 +234,8 @@ set myisam_max_sort_file_size=100; ERROR HY000: Variable 'myisam_max_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL set myisam_max_extra_sort_file_size=100; ERROR HY000: Variable 'myisam_max_extra_sort_file_size' is a GLOBAL variable and should be set with SET GLOBAL +set @@SQL_WARNINGS=NULL; +ERROR 42000: Variable 'sql_warnings' can't be set to the value of 'NULL' set autocommit=1; set big_tables=1; select @@autocommit, @@big_tables; diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index 9d4710ff729..26353785733 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -92,6 +92,8 @@ Warning 1264 Data truncated for column 'b' at row 3 Warning 1262 Data truncated, NULL supplied to NOT NULL column 'a' at row 4 Warning 1264 Data truncated for column 'b' at row 4 insert into t2(b) values('mysqlab'); +Warnings: +Warning 1264 Data truncated for column 'b' at row 1 set sql_warnings=1; insert into t2(b) values('mysqlab'); Warnings: diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index d57fd3bb193..059808161a3 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -17,25 +17,35 @@ insert into t1 values (""),(null); select * from t1; drop table t1; +create table t1 (a int not null auto_increment,primary key (a)) type=heap; +drop table t1; + # # Test of some CREATE TABLE'S that should fail # -!$1146 create table t2 type=heap select * from t1; -!$1146 create table t2 select auto+1 from t1; +--error 1146 +create table t2 type=heap select * from t1; +--error 1146 +create table t2 select auto+1 from t1; drop table if exists t1,t2; -!$1167 create table t1 (b char(0) not null, index(b)); -create table t1 (a int not null auto_increment,primary key (a)) type=heap; -!$1163 create table t1 (a int not null,b text) type=heap; +--error 1167 +create table t1 (b char(0) not null, index(b)); +--error 1163 +create table t1 (a int not null,b text) type=heap; drop table if exists t1; -!$1075 create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap; +--error 1075 +create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) type=heap; -- error 1044,1 create table not_existing_database.test (a int); -!$1103 create table `a/a` (a int); -!$1103 create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int); -!$1059 create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int); +--error 1103 +create table `a/a` (a int); +--error 1103 +create table `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa int); +--error 1059 +create table a (`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` int); # # test of dummy table names @@ -62,7 +72,8 @@ create table `` (a int); drop table if exists ``; --error 1166 create table t1 (`` int); -drop table if exists t1; +--error 1279 +create table t1 (i int, index `` (i)); # # Test of CREATE ... SELECT with indexes @@ -167,6 +178,46 @@ insert into t1 values (NULL, NULL); drop table t1; # +# Bug # 801 +# + +create table t1 select x'4132'; +drop table t1; + +# +# bug #1434 +# + +create table t1 select 1,2,3; +create table if not exists t1 select 1,2; +--error 1136 +create table if not exists t1 select 1,2,3,4; +create table if not exists t1 select 1; +select * from t1; +drop table t1; +create table t1 select 1,2,3; +create table if not exists t1 select 1,2; +--error 1136 +create table if not exists t1 select 1,2,3,4; +create table if not exists t1 select 1; +select * from t1; +drop table t1; + +# +# Test create table if not exists with duplicate key error +# + +create table t1 (a int not null, b int, primary key (a)); +insert into t1 values (1,1); +create table if not exists t1 select 2; +select * from t1; +create table if not exists t1 select 3 as 'a',4 as 'b'; +--error 1062 +create table if not exists t1 select 3 as 'a',3 as 'b'; +select * from t1; +drop table t1; + +# # Test create with foreign keys # @@ -230,12 +281,6 @@ SET SESSION table_type=default; drop table t1; # -# Bug # 801 -# -create table t1 select x'4132'; -drop table t1; - -# # Test types of data for create select with functions # diff --git a/mysql-test/t/ctype_mb.test b/mysql-test/t/ctype_mb.test index 96bb634deb3..b0ccab8e345 100644 --- a/mysql-test/t/ctype_mb.test +++ b/mysql-test/t/ctype_mb.test @@ -1,3 +1,10 @@ +# +# Test of alter table +# +--disable_warnings +drop table if exists t1; +--enable_warnings + CREATE TABLE t1 SELECT _utf8'test' as c1, _utf8'теÑÑ‚' as c2; SHOW CREATE TABLE t1; DELETE FROM t1; diff --git a/mysql-test/t/date_formats-master.opt b/mysql-test/t/date_formats-master.opt new file mode 100644 index 00000000000..7977a601dd7 --- /dev/null +++ b/mysql-test/t/date_formats-master.opt @@ -0,0 +1 @@ +--date_format=%d.%m.%Y --time_format=%H.%i.%s --datetime_format=%Y/%d/%m-%H:%i:%s diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test new file mode 100644 index 00000000000..9551efaa648 --- /dev/null +++ b/mysql-test/t/date_formats.test @@ -0,0 +1,82 @@ +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 +SET date_format='%d.%m.%d'; +--error 1105 +SET datetime_format="%d.%m.%y %h.%i.%s"; + +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 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"); + +select get_format(DATE, 'USA') as a; +select get_format(TIME, 'internal') as a; +select get_format(DATETIME, 'eur') as a; + diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index a8583aa5ea3..80b131ac6fe 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -122,3 +122,13 @@ delete from (select * from t1); -- error 1064 insert into (select * from t1) values (5); drop table t1; + +# +# deived tables with subquery inside all by one table +# +create table t1 (E1 INTEGER UNSIGNED NOT NULL, E2 INTEGER UNSIGNED NOT NULL, E3 INTEGER UNSIGNED NOT NULL, PRIMARY KEY(E1) +); +insert into t1 VALUES(1,1,1), (2,2,1); +select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +explain select count(*) from t1 INNER JOIN (SELECT A.E1, A.E2, A.E3 FROM t1 AS A WHERE A.E3 = (SELECT MAX(B.E3) FROM t1 AS B WHERE A.E2 = B.E2)) AS THEMAX ON t1.E1 = THEMAX.E2 AND t1.E1 = t1.E2; +drop table t1; diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 8c43ce1937f..5dceb2b4598 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -34,6 +34,7 @@ create table t1 (a tinyint not null auto_increment, b blob not null, primary key let $1=100; disable_query_log; +--disable_warnings SET SQL_WARNINGS=0; while ($1) { @@ -41,6 +42,7 @@ while ($1) dec $1; } SET SQL_WARNINGS=1; +--enable_warnings enable_query_log; check table t1; repair table t1; diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test index 956afb3e7ca..c71ffb21354 100644 --- a/mysql-test/t/mysqlbinlog.test +++ b/mysql-test/t/mysqlbinlog.test @@ -39,28 +39,28 @@ select "--- Local --" as ""; # --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ $MYSQL_TEST_DIR/var/log/master-bin.000001 # this should not fail but shouldn't produce any working statements --disable_query_log select "--- Broken LOAD DATA --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form $MYSQL_TEST_DIR/var/log/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ $MYSQL_TEST_DIR/var/log/master-bin.000002 # this should show almost nothing --disable_query_log select "--- --database --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form --database=nottest $MYSQL_TEST_DIR/var/log/master-bin.000001 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --database=nottest $MYSQL_TEST_DIR/var/log/master-bin.000001 # this test for position option --disable_query_log select "--- --position --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form --position=27 $MYSQL_TEST_DIR/var/log/master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --position=27 $MYSQL_TEST_DIR/var/log/master-bin.000002 # These are tests for remote binlog. # They should return the same as previous test. @@ -76,28 +76,28 @@ select "--- Remote --" as ""; # This is broken now # By the way it seems that remote version fetches all events with name >= master-bin.000001 --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 # This is broken too --disable_query_log select "--- Broken LOAD DATA --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 # And this too ! (altough it is documented) --disable_query_log select "--- --database --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT --database=nottest master-bin.000001 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT --database=nottest master-bin.000001 # Strangely but this works --disable_query_log select "--- --position --" as ""; --enable_query_log --replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR ---exec $MYSQL_BINLOG --short-form --read-from-remote-server --position=27 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 +--exec $MYSQL_BINLOG --short-form --local-load=$MYSQL_TEST_DIR/var/tmp/ --read-from-remote-server --position=27 --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000002 # clean up drop table t1; diff --git a/mysql-test/t/select_found.test b/mysql-test/t/select_found.test index 06624d50a43..e8be902606c 100644 --- a/mysql-test/t/select_found.test +++ b/mysql-test/t/select_found.test @@ -64,7 +64,7 @@ SELECT FOUND_ROWS(); SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; SELECT DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL ORDER BY email LIMIT 10; -INSERT INTO `t1` (`id`, `kid`) VALUES ('', '150'); +INSERT INTO `t1` (`id`, `kid`) VALUES ('0', '150'); SELECT SQL_CALC_FOUND_ROWS DISTINCT email FROM t2 LEFT JOIN t1 ON kid = t2.id WHERE t1.id IS NULL LIMIT 10; SELECT FOUND_ROWS(); diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test index d3531f0c440..d96fd030207 100644 --- a/mysql-test/t/sql_mode.test +++ b/mysql-test/t/sql_mode.test @@ -24,7 +24,7 @@ show create table t1; set @@sql_mode="no_field_options,mysql323,mysql40"; show variables like 'sql_mode'; show create table t1; -set sql_mode="postgresql,oracle,mssql,db2,sapdb"; +set sql_mode="postgresql,oracle,mssql,db2,maxdb"; select @@sql_mode; show create table t1; drop table t1; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 9ba91c7e0a6..8c0b3fb3919 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -964,4 +964,4 @@ explain select * from t3 where a >= all (select b from t2); insert into t2 values (2,2), (2,1), (3,3), (3,1); select * from t3 where a > all (select max(b) from t2 group by a); explain select * from t3 where a > all (select max(b) from t2 group by a); -drop table if exists t2, t3; +drop table t2, t3; diff --git a/mysql-test/t/type_float.test b/mysql-test/t/type_float.test index f6281ca6c21..caccf31b32a 100644 --- a/mysql-test/t/type_float.test +++ b/mysql-test/t/type_float.test @@ -31,6 +31,15 @@ select a from t1 order by a; select min(a) from t1; drop table t1; +# Bug #1022: When a table contains a 'float' field, +# and one of the functions MAX, MIN, or AVG is used on that field, +# the system crashes. + +create table t1 (a float); +insert into t1 values (1); +select max(a),min(a),avg(a) from t1; +drop table t1; + # # FLOAT/DOUBLE/DECIMAL handling # diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 22f8406cba5..396fb3ac722 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -98,6 +98,18 @@ select @@timestamp>0; set @@rand_seed1=10000000,@@rand_seed2=1000000; select ROUND(RAND(),5); +show variables like '%alloc%'; +set @@range_alloc_block_size=1024*16; +set @@query_alloc_block_size=1024*17+2; +set @@query_prealloc_size=1024*18; +set @@transaction_alloc_block_size=1024*20-1; +set @@transaction_prealloc_size=1024*21-1; +select @@query_alloc_block_size; +show variables like '%alloc%'; +set @@range_alloc_block_size=default; +set @@query_alloc_block_size=default, @@query_prealloc_size=default; +set transaction_alloc_block_size=default, @@transaction_prealloc_size=default; +show variables like '%alloc%'; # The following should give errors @@ -138,6 +150,8 @@ select @@global.sql_auto_is_null; set myisam_max_sort_file_size=100; --error 1229 set myisam_max_extra_sort_file_size=100; +--error 1231 +set @@SQL_WARNINGS=NULL; # Test setting all variables diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c index 8e46b0808c0..653ea569172 100644 --- a/mysys/my_chsize.c +++ b/mysys/my_chsize.c @@ -51,16 +51,17 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags) #if defined(HAVE_SETFILEPOINTER) /* This is for the moment only true on windows */ { + long is_success; HANDLE win_file= (HANDLE) _get_osfhandle(fd); long length_low, length_high; length_low= (long) (ulong) newlength; length_high= (long) ((ulonglong) newlength >> 32); - if (SetFilePointer(win_file, length_low, &length_high, FILE_BEGIN)) - { - if (SetEndOfFile(win_file)) - DBUG_RETURN(0); - } - my_errno= errno; + is_success= SetFilePointer(win_file, length_low, &length_high, FILE_BEGIN); + if (is_success == -1 && (my_errno= GetLastError()) != NO_ERROR) + goto err; + if (SetEndOfFile(win_file)) + DBUG_RETURN(0); + my_errno= GetLastError(); goto err; } #elif defined(HAVE_FTRUNCATE) diff --git a/mysys/queues.c b/mysys/queues.c index f077b38ca0b..ecf1058af41 100644 --- a/mysys/queues.c +++ b/mysys/queues.c @@ -64,7 +64,7 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key, /* - Reinitialize queue for other usage (deletes all elements) + Reinitialize queue for other usage SYNOPSIS reinit_queue() @@ -77,8 +77,8 @@ int init_queue(QUEUE *queue, uint max_elements, uint offset_to_key, first_cmp_arg First argument to compare function NOTES - You can't currently resize the number of elements! If you need this, - fix it :) + This will delete all elements from the queue. If you don't want this, + use resize_queue() instead. RETURN 0 ok @@ -90,15 +90,46 @@ int reinit_queue(QUEUE *queue, uint max_elements, uint offset_to_key, void *first_cmp_arg) { DBUG_ENTER("reinit_queue"); - if (queue->max_elements < max_elements) - /* It's real easy to do realloc here, just don't want to bother */ - DBUG_RETURN(my_errno=EE_OUTOFMEMORY); - queue->elements=0; queue->compare=compare; queue->first_cmp_arg=first_cmp_arg; queue->offset_to_key=offset_to_key; queue->max_at_top= max_at_top ? (-1 ^ 1) : 0; + resize_queue(queue, max_elements); + DBUG_RETURN(0); +} + + +/* + Resize queue + + SYNOPSIS + resize_queue() + queue Queue + max_elements New max size for queue + + NOTES + If you resize queue to be less than the elements you have in it, + the extra elements will be deleted + + RETURN + 0 ok + 1 Error. In this case the queue is unchanged +*/ + +int resize_queue(QUEUE *queue, uint max_elements) +{ + byte **new_root; + DBUG_ENTER("resize_queue"); + if (queue->max_elements == max_elements) + DBUG_RETURN(0); + if ((new_root= (byte **) my_realloc((void *)queue->root, + (max_elements+1)*sizeof(void*), + MYF(MY_WME))) == 0) + DBUG_RETURN(1); + set_if_smaller(queue->elements, max_elements); + queue->max_elements= max_elements; + queue->root= new_root; DBUG_RETURN(0); } diff --git a/mysys/thr_alarm.c b/mysys/thr_alarm.c index 2289f8208bc..36bbac16fef 100644 --- a/mysys/thr_alarm.c +++ b/mysys/thr_alarm.c @@ -120,6 +120,20 @@ void init_thr_alarm(uint max_alarms) DBUG_VOID_RETURN; } + +void resize_thr_alarm(uint max_alarms) +{ + pthread_mutex_lock(&LOCK_alarm); + /* + It's ok not to shrink the queue as there may be more pending alarms than + than max_alarms + */ + if (alarm_queue.elements < max_alarms) + resize_queue(&alarm_queue,max_alarms+1); + pthread_mutex_unlock(&LOCK_alarm); +} + + /* Request alarm after sec seconds. diff --git a/netware/BUILD/apply-patch b/netware/BUILD/apply-patch new file mode 100755 index 00000000000..3fe5a077f9a --- /dev/null +++ b/netware/BUILD/apply-patch @@ -0,0 +1,41 @@ +#! /bin/sh + +# debug +#set -x + +# stop on errors +set -e + +# repository directory +repo_dir=`pwd` + +# show usage +show_usage() +{ + cat << EOF + +usage: apply-patch + +Imports netware/current-changes.patch so that current changes +for the platform are present on the local repository. + +Use from the root directory of the repository, with BitKeeper +installed. + +EOF + exit 0; +} + +if test $1 || test -z $BK_USER +then + show_usage +fi + +echo "starting patch..." + +echo "user: $BK_USER" + +# import patch +# Note: In future this should be changed to check whether +# the repo already has this patch +bk import -tpatch $repo_dir/netware/current-changes.patch $repo_dir diff --git a/netware/BUILD/save-patch b/netware/BUILD/save-patch new file mode 100755 index 00000000000..9f9979ace5b --- /dev/null +++ b/netware/BUILD/save-patch @@ -0,0 +1,56 @@ +#! /bin/sh + +# debug +#set -x + +# stop on errors +set -e + +# repository directory +repo_dir=`pwd` + +# show usage +show_usage() +{ + cat << EOF + +usage: save-patch + +Creates a patch file between the latest revision of the current tree +and the latest revision not created by \$BK_USER and places it in +the tree as netware/current-changes.patch + +EOF + exit 0; +} + +if test $1 || test -z $BK_USER +then + show_usage +fi + +echo "starting patch..." + +echo "user: $BK_USER" + +# check for bk and repo_dir +bk help > /dev/null +repo_dir=`bk root $repo_dir` +cd $repo_dir + +# determine version +version=`grep -e "AM_INIT_AUTOMAKE(mysql, .*)" < configure.in | sed -e "s/AM_INIT_AUTOMAKE(mysql, \(.*\))/\1/"` +echo "version: $version" + +# user revision +user_rev=`bk changes -e -n -d':REV:' | head -1` +echo "latest revision: $user_rev" + +# tree revision +tree_rev=`bk changes -e -n -d':REV:' -U$BK_USER | head -1` +echo "latest non-$BK_USER revision: $tree_rev" + +# create patch +patch="$repo_dir/netware/current-changes.patch" +echo "creating \"$patch\"..." +bk export -tpatch -r$tree_rev..$user_rev -xnetware/current-changes.patch > $patch diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 4782c763447..48592d2ff00 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -37,6 +37,7 @@ bin_SCRIPTS = @server_scripts@ \ mysql_create_system_tables EXTRA_SCRIPTS = make_binary_distribution.sh \ + make_sharedlib_distribution.sh \ make_win_src_distribution.sh \ msql2mysql.sh \ mysql_config.sh \ @@ -69,6 +70,7 @@ dist_pkgdata_DATA = fill_help_tables.sql mysql_fix_privilege_tables.sql # failures with it. CLEANFILES = @server_scripts@ \ make_binary_distribution \ + make_sharedlib_distribution \ msql2mysql \ mysql_config \ mysql_fix_privilege_tables \ @@ -141,7 +143,7 @@ SUFFIXES = .sh # Don't update the files from bitkeeper %::SCCS/s.% -all: fill_help_tables.sql make_win_src_distribution make_binary_distribution +all: fill_help_tables.sql make_win_src_distribution make_binary_distribution make_sharedlib_distribution fill_help_tables.sql: fill_help_tables ../Docs/manual.texi ./fill_help_tables < ../Docs/manual.texi > fill_help_tables.sql diff --git a/scripts/fill_help_tables.sh b/scripts/fill_help_tables.sh index 8ba05910596..cb5437f7178 100644 --- a/scripts/fill_help_tables.sh +++ b/scripts/fill_help_tables.sh @@ -112,6 +112,7 @@ sub add_topic_to_category $categories{$current_category}->{$topic_name}= $topics{$topic_name}; my $category= $categories{$current_category}; + $category->{__name__}= $current_category; if (exists($category->{__parent_category__})) { @@ -132,7 +133,7 @@ sub add_topic_to_category my $old_category= $topics{$topic_name}->{category}; if ($old_category ne $category) { - print_error "wrong category for $topic_name\n"; + print_error "wrong category for $topic_name (first one's \"$old_category->{__name__}\" second one's \"$current_category\")\n"; } } diff --git a/scripts/make_sharedlib_distribution.sh b/scripts/make_sharedlib_distribution.sh new file mode 100644 index 00000000000..4104a315296 --- /dev/null +++ b/scripts/make_sharedlib_distribution.sh @@ -0,0 +1,117 @@ +#!/bin/sh +# The default path should be /usr/local + +# Get some info from configure +# chmod +x ./scripts/setsomevars + +machine=@MACHINE_TYPE@ +system=@SYSTEM_TYPE@ +version=@VERSION@ +export machine system version +SOURCE=`pwd` +CP="cp -p" +MV="mv" + +STRIP=1 +DEBUG=0 +SILENT=0 +TMP=/tmp +SUFFIX="" + +parse_arguments() { + for arg do + case "$arg" in + --debug) DEBUG=1;; + --tmp=*) TMP=`echo "$arg" | sed -e "s;--tmp=;;"` ;; + --suffix=*) SUFFIX=`echo "$arg" | sed -e "s;--suffix=;;"` ;; + --no-strip) STRIP=0 ;; + --silent) SILENT=1 ;; + *) + echo "Unknown argument '$arg'" + exit 1 + ;; + esac + done +} + +parse_arguments "$@" + +BASE=$TMP/my_dist$SUFFIX + +if [ -d $BASE ] ; then + rm -r -f $BASE +fi + +mkdir -p $BASE/lib + +for i in \ + libmysql/.libs/libmysqlclient.so* \ + libmysql_r/.libs/libmysqlclient_r.so* +do + if [ -f $i ] + then + $CP $i $BASE/lib + fi +done + +# Change the distribution to a long descriptive name +NEW_NAME=mysql-shared-$version-$system-$machine$SUFFIX +BASE2=$TMP/$NEW_NAME +rm -r -f $BASE2 +mv $BASE $BASE2 +BASE=$BASE2 + +#if we are debugging, do not do tar/gz +if [ x$DEBUG = x1 ] ; then + exit +fi + +# This is needed to prefer GNU tar instead of tar because tar can't +# always handle long filenames + +PATH_DIRS=`echo $PATH | sed -e 's/^:/. /' -e 's/:$/ ./' -e 's/::/ . /g' -e 's/:/ /g' ` +which_1 () +{ + for cmd + do + for d in $PATH_DIRS + do + for file in $d/$cmd + do + if test -x $file -a ! -d $file + then + echo $file + exit 0 + fi + done + done + done + exit 1 +} + +# +# Create the result tar file +# + +tar=`which_1 gnutar gtar` +if test "$?" = "1" -o "$tar" = "" +then + tar=tar +fi + +echo "Using $tar to create archive" +cd $TMP + +OPT=cvf +if [ x$SILENT = x1 ] ; then + OPT=cf +fi + +$tar $OPT $SOURCE/$NEW_NAME.tar $NEW_NAME +cd $SOURCE +echo "Compressing archive" +gzip -9 $NEW_NAME.tar +echo "Removing temporary directory" +rm -r -f $BASE + +echo "$NEW_NAME.tar.gz created" diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index 52284104636..6b543bf4a07 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -62,7 +62,7 @@ get_full_path () { case $1 in /*) echo "$1";; - ./*) tmp=`pwd`/$1; echo $tmp | sed -e 's;/./;/;' ;; + ./*) tmp=`pwd`/$1; echo $tmp | sed -e 's;/\./;/;' ;; *) which $1 ;; esac } diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh index 1c056e963cb..ece4ba098f4 100644 --- a/scripts/mysqld_safe.sh +++ b/scripts/mysqld_safe.sh @@ -51,9 +51,9 @@ parse_arguments() { ;; # these two might have been set in a [mysqld_safe] section of my.cnf - # they get passed via environment variables to mysqld_safe - --socket=*) MYSQL_UNIX_PORT=`echo "$arg" | sed -e "s;--socket=;;"` ;; - --port=*) MYSQL_TCP_PORT=`echo "$arg" | sed -e "s;--port=;;"` ;; + # they are added to mysqld command line to override settings from my.cnf + --socket=*) mysql_unix_port=`echo "$arg" | sed -e "s;--socket=;;"` ;; + --port=*) mysql_tcp_port=`echo "$arg" | sed -e "s;--port=;;"` ;; # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! --ledir=*) ledir=`echo "$arg" | sed -e "s;--ledir=;;"` ;; @@ -114,8 +114,7 @@ else ledir=@libexecdir@ fi -MYSQL_UNIX_PORT=${MYSQL_UNIX_PORT:-@MYSQL_UNIX_ADDR@} -MYSQL_TCP_PORT=${MYSQL_TCP_PORT:-@MYSQL_TCP_PORT@} +safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-@MYSQL_UNIX_ADDR@}} user=@MYSQLD_USER@ niceness=0 @@ -171,9 +170,14 @@ else fi test -z "$err_log" && err_log=$DATADIR/`@HOSTNAME@`.err -export MYSQL_UNIX_PORT -export MYSQL_TCP_PORT - +if test -n "$mysql_unix_port" +then + args="--socket=$mysql_unix_port $args" +fi +if test -n "$mysql_tcp_port" +then + args="--port=$mysql_tcp_port $args" +fi if test $niceness -eq 0 then @@ -296,7 +300,7 @@ echo "Starting $MYSQLD daemon with databases from $DATADIR" echo "`date +'%y%m%d %H:%M:%S mysqld started'`" >> $err_log while true do - rm -f $MYSQL_UNIX_PORT $pid_file # Some extra safety + rm -f $safe_mysql_unix_port $pid_file # Some extra safety if test -z "$args" then $NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ >> $err_log 2>&1 diff --git a/sql-common/client.c b/sql-common/client.c index 80a5a719376..15f906f4e34 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1137,8 +1137,8 @@ unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, /* Read all rows (fields or data) from server */ -MYSQL_DATA *cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, - unsigned int fields) +MYSQL_DATA * STDCALL cli_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, + unsigned int fields) { uint field; ulong pkt_len; diff --git a/sql/field.cc b/sql/field.cc index bb651835194..98eb0e01f56 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -278,7 +278,8 @@ bool Field::get_date(TIME *ltime,bool 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) == TIMESTAMP_NONE) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate,current_thd)<= + WRONG_TIMESTAMP_FULL) return 1; return 0; } @@ -288,7 +289,7 @@ 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)) + str_to_time(res->ptr(),res->length(),ltime,current_thd)) return 1; return 0; } @@ -298,28 +299,29 @@ bool Field::get_time(TIME *ltime) 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: store("",0,&my_charset_bin); // Probably an error - break; + return; case TIMESTAMP_DATE: - sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day); - store(buff,10,&my_charset_bin); + tmp_format= &t_datetime_frm(current_thd, DATE_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_FULL: - 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); + tmp_format=&t_datetime_frm(current_thd,DATETIME_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_TIME: - { - ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d", - ltime->hour,ltime->minute,ltime->second)); - store(buff,(uint) length, &my_charset_bin); + tmp_format= &t_datetime_frm(current_thd, TIME_FORMAT_TYPE).datetime_format; + is_time_only= 1; 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); } @@ -2690,7 +2692,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); + long tmp=(long) str_to_timestamp(from,len,current_thd); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -3024,7 +3026,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,<ime)) + if (str_to_time(from,len,<ime,current_thd)) { tmp=0L; error= 1; @@ -3133,19 +3135,25 @@ longlong Field_time::val_int(void) String *Field_time::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { + TIME ltime; val_buffer->alloc(16); long tmp=(long) sint3korr(ptr); const char *sign=""; + ltime.neg= 0; if (tmp < 0) { tmp= -tmp; - sign= "-"; - } - long length= my_sprintf((char*) val_buffer->ptr(), - ((char*) val_buffer->ptr(),"%s%02d:%02d:%02d", - sign,(int) (tmp/10000), (int) (tmp/100 % 100), - (int) (tmp % 100))); - val_buffer->length(length); + 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, <ime, 0, 0, + tmp_format->format, + tmp_format->format_length, 1); return val_buffer; } @@ -3311,7 +3319,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) == TIMESTAMP_NONE) + if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) { tmp=0; error= 1; @@ -3421,6 +3429,7 @@ longlong Field_date::val_int(void) String *Field_date::val_str(String *val_buffer, String *val_ptr __attribute__((unused))) { + TIME ltime; val_buffer->alloc(field_length); val_buffer->length(field_length); int32 tmp; @@ -3430,9 +3439,15 @@ String *Field_date::val_str(String *val_buffer, else #endif longget(tmp,ptr); - sprintf((char*) val_buffer->ptr(),"%04d-%02d-%02d", - (int) ((uint32) tmp/10000L % 10000), (int) ((uint32) tmp/100 % 100), - (int) ((uint32) tmp % 100)); + 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, <ime, 0, 0, + tmp_format->format, + tmp_format->format_length, 1); return val_buffer; } @@ -3491,7 +3506,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) == TIMESTAMP_NONE) + if (str_to_TIME(from,len,&l_time,1,current_thd) <= WRONG_TIMESTAMP_FULL) { tmp=0L; error= 1; @@ -3660,7 +3675,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); + longlong tmp=str_to_datetime(from,len,1,current_thd); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 6510a03f5a6..5f08c91372b 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -119,7 +119,7 @@ set_field_to_null(Field *field) return 0; } field->reset(); - if (current_thd->count_cuted_fields) + if (current_thd->count_cuted_fields == CHECK_FIELD_WARN) { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,ER_WARN_DATA_TRUNCATED); return 0; @@ -176,7 +176,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= false; return 0; // field is set in handler.cc } - if (current_thd->count_cuted_fields) + if (current_thd->count_cuted_fields == CHECK_FIELD_WARN) { field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,ER_WARN_NULL_TO_NOTNULL); return 0; diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index bac037dcfc7..3e5dc38e864 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -238,7 +238,8 @@ int berkeley_show_logs(Protocol *protocol) MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); DBUG_ENTER("berkeley_show_logs"); - init_alloc_root(&show_logs_root, 1024, 1024); + init_sql_alloc(&show_logs_root, BDB_LOG_ALLOC_BLOCK_SIZE, + BDB_LOG_ALLOC_BLOCK_SIZE); my_pthread_setspecific_ptr(THR_MALLOC,&show_logs_root); if ((error= db_env->log_archive(db_env, &all_logs, diff --git a/sql/handler.h b/sql/handler.h index 5fc63cf30f5..638125e23d0 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -169,10 +169,10 @@ typedef struct st_ha_create_information SQL_LIST merge_list; enum db_type db_type; enum row_type row_type; - uint options; /* OR of HA_CREATE_ options */ + uint options; /* OR of HA_CREATE_ options */ uint raid_type,raid_chunks; uint merge_insert_method; - bool if_not_exists; + bool table_existed; /* 1 in create if table existed */ } HA_CREATE_INFO; diff --git a/sql/item.cc b/sql/item.cc index 69082fab4c2..e610453e981 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -46,7 +46,7 @@ Item::Item(): collation.set(default_charset(), DERIVATION_COERCIBLE); name= 0; decimals= 0; max_length= 0; - THD *thd= current_thd; + thd= current_thd; next= thd->free_list; // Put in free list thd->free_list= this; /* @@ -69,7 +69,7 @@ Item::Item(): Used for duplicating lists in processing queries with temporary tables */ -Item::Item(THD *thd, Item &item): +Item::Item(THD *c_thd, Item &item): str_value(item.str_value), name(item.name), max_length(item.max_length), @@ -82,7 +82,8 @@ Item::Item(THD *thd, Item &item): fixed(item.fixed), collation(item.collation) { - next=thd->free_list; // Put in free list + next=c_thd->free_list; // Put in free list + thd= c_thd; thd->free_list= this; } @@ -174,7 +175,8 @@ bool Item::get_date(TIME *ltime,bool 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) == TIMESTAMP_NONE) + str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate, thd) <= + WRONG_TIMESTAMP_FULL) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -192,7 +194,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)) + str_to_time(res->ptr(),res->length(),ltime, thd)) { bzero((char*) ltime,sizeof(*ltime)); return 1; @@ -272,11 +274,13 @@ Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name) } // Constructor need to process subselect with temporary tables (see Item) -Item_field::Item_field(THD *thd, Item_field &item): - Item_ident(thd, item), - field(item.field), - result_field(item.result_field) -{ collation.set(DERIVATION_IMPLICIT); } +Item_field::Item_field(THD *thd, Item_field &item) + :Item_ident(thd, item), + field(item.field), + result_field(item.result_field) +{ + collation.set(DERIVATION_IMPLICIT); +} void Item_field::set_field(Field *field_par) { @@ -673,30 +677,28 @@ String *Item_param::query_val_str(String* str) } else { - char buff[25]; + DATETIME_FORMAT *tmp_format= 0; + bool is_time_only= 0; switch (ltime.time_type) { case TIMESTAMP_NONE: + case WRONG_TIMESTAMP_FULL: break; case TIMESTAMP_DATE: - sprintf(buff, "%04d-%02d-%02d", - ltime.year,ltime.month,ltime.day); - str->append(buff, 10); + tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_FULL: - sprintf(buff, "%04d-%02d-%02d %02d:%02d:%02d", - ltime.year,ltime.month,ltime.day, - ltime.hour,ltime.minute,ltime.second); - str->append(buff, 19); + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; break; case TIMESTAMP_TIME: { - sprintf(buff, "%02d:%02d:%02d", - ltime.hour,ltime.minute,ltime.second); - str->append(buff, 8); + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + is_time_only= 1; break; - } + } } + make_datetime(str, <ime, is_time_only, 0, + tmp_format->format, tmp_format->format_length, 0); } str->append("'"); } @@ -1296,6 +1298,14 @@ bool Item::send(Protocol *protocol, String *buffer) result= protocol->store_longlong(nr, unsigned_flag); break; } + case MYSQL_TYPE_FLOAT: + { + float nr; + nr= val(); + if (!null_value) + result= protocol->store(nr, decimals, buffer); + break; + } case MYSQL_TYPE_DOUBLE: { double nr; diff --git a/sql/item.h b/sql/item.h index a126a61e32e..c738f92124f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -113,6 +113,14 @@ public: my_bool with_sum_func; 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(); @@ -124,7 +132,7 @@ public: top AND/OR ctructure of WHERE clause to protect it of optimisation changes in prepared statements */ - Item(THD *thd, Item &item); + Item(THD *c_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); @@ -322,7 +330,7 @@ public: bool long_data_supplied; uint pos_in_query; - Item_param::Item_param(uint position) + Item_param(uint position) { name= (char*) "?"; pos_in_query= position; diff --git a/sql/item_create.cc b/sql/item_create.cc index b1173b9c7b8..fce59d68c1f 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -701,3 +701,8 @@ Item *create_func_maketime(Item* a,Item* b,Item* c) { return new Item_func_maketime(a, b, c); } + +Item *create_func_str_to_date(Item* a,Item* b) +{ + return new Item_func_str_to_date(a, b); +} diff --git a/sql/item_create.h b/sql/item_create.h index c75f4404bad..5d6cbe1d58f 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -149,3 +149,4 @@ Item *create_func_addtime(Item* a,Item* b); Item *create_func_subtime(Item* a,Item* b); Item *create_func_timediff(Item* a,Item* b); Item *create_func_maketime(Item* a,Item* b,Item* c); +Item *create_func_str_to_date(Item* a,Item* b); diff --git a/sql/item_func.cc b/sql/item_func.cc index dde830b61c9..5a7aada8c1d 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2200,6 +2200,9 @@ double user_var_entry::val(my_bool *null_value) return (double) *(longlong*) value; case STRING_RESULT: return atof(value); // This is null terminated + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; } return 0.0; // Impossible } @@ -2219,6 +2222,9 @@ longlong user_var_entry::val_int(my_bool *null_value) return *(longlong*) value; case STRING_RESULT: return strtoull(value,NULL,10); // String is null terminated + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; } return LL(0); // Impossible } @@ -2242,6 +2248,9 @@ String *user_var_entry::val_str(my_bool *null_value, String *str, case STRING_RESULT: if (str->copy(value, length, collation.collation)) str= 0; // EOM error + case ROW_RESULT: + DBUG_ASSERT(1); // Impossible + break; } return(str); } diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 55a20908894..99dd06c566c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -33,7 +33,9 @@ #include "md5.h" #include "sha1.h" #include "my_aes.h" +C_MODE_START #include "../mysys/my_static.h" // For soundex_map +C_MODE_END String my_empty_string("",default_charset_info); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 9a36f8a60a6..4009256ee17 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -57,82 +57,544 @@ static String day_names[] = String("Sunday", &my_charset_latin1) }; -enum date_time_format_types +uint check_names(String *arr,int item_count,const char *val_ptr, + const char *val_end, uint *val, bool check_part) { - TIME_ONLY= 0, TIME_MICROSECOND, - DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND -}; + 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; + } -struct date_time_format -{ - const char* format_str; - uint length; -}; + 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; +} -static struct date_time_format date_time_formats[]= +uint check_val_is_digit(const char *ptr, uint val_len, uint digit_count) { - {"%s%02d:%02d:%02d", 10}, - {"%s%02d:%02d:%02d.%06d", 17}, - {"%04d-%02d-%02d", 10}, - {"%04d-%02d-%02d %02d:%02d:%02d", 19}, - {"%04d-%02d-%02d %02d:%02d:%02d.%06d", 26} -}; + 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++; + } + return digit_found; +} /* - 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. + Extract datetime value to TIME struct from string value + according to format string. */ - -String *make_datetime(String *str, TIME *ltime, - enum date_time_format_types format) +bool extract_datetime(const char *str_val, uint str_val_len, + const char *str_format, uint str_format_len, + TIME *l_time) { - char *buff; + 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; - uint length= date_time_formats[format].length + 32; - const char* format_str= date_time_formats[format].format_str; + int err= 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; + + DBUG_ENTER("extract_datetime"); + for (; ptr != end && val_ptr != val_end; ptr++) + { + if (*ptr == '%' && ptr+1 != end) + { + val_len= val_end - val_ptr; + char *val_end1= (char *) val_end; + 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; + 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; + 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; + l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900); + val_ptr+=2; + break; + 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; + break; + 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; + 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; + break; + 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; + break; + 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; + 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; + 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; + break; + 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; + break; + case 'w': + weekday= my_strntoll(cs, val_ptr, 1, 10, &val_end1, &err); + if (err) + return 1; + val_ptr++; + 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; + } + 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; + 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; + break; + default: + if (*val_ptr != *ptr) + return 1; + val_ptr++; + } + } + else + { + if (*val_ptr != *ptr) + return 1; + val_ptr++; + } + } + if (usa_time) + { + if (l_time->hour > 12 || l_time->hour < 1) + return 1; + l_time->hour= l_time->hour%12+daypart; + } - if (str->alloc(length)) - return 0; + 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); + } + } - buff= (char*) str->ptr(); - switch (format) { - case TIME_ONLY: - length= cs->cset->snprintf(cs, buff, length, format_str, ltime->neg ? "-" : "", - ltime->hour, ltime->minute, ltime->second); - break; - case TIME_MICROSECOND: - length= cs->cset->snprintf(cs, buff, length, format_str, ltime->neg ? "-" : "", - ltime->hour, ltime->minute, ltime->second, - ltime->second_part); - break; - case DATE_ONLY: - length= cs->cset->snprintf(cs, buff, length, format_str, - ltime->year, ltime->month, ltime->day); - break; - case DATE_TIME: - length= cs->cset->snprintf(cs, buff, length, format_str, - ltime->year, ltime->month, ltime->day, - ltime->hour, ltime->minute, ltime->second); - break; - case DATE_TIME_MICROSECOND: - length= cs->cset->snprintf(cs, buff, length, format_str, - ltime->year, ltime->month, ltime->day, - ltime->hour, ltime->minute, ltime->second, - ltime->second_part); - break; - default: - return 0; + if (week_number >= 0 && weekday) + { + int days= calc_daynr(l_time->year,1,1); + uint weekday_b; + + if (weekday > 7 || weekday < 0) + return 1; + if (sunday_first) + weekday = weekday%7; + + if (week_number == 53) + { + days+= (week_number - 1)*7; + weekday_b= calc_weekday(days, sunday_first); + weekday = weekday - weekday_b - !sunday_first; + days+= weekday; + } + else if (week_number == 0) + { + weekday_b= calc_weekday(days, sunday_first); + weekday = weekday - weekday_b - !sunday_first; + days+= weekday; + } + else + { + days+= (week_number - !sunday_first)*7; + weekday_b= calc_weekday(days, sunday_first); + 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); + } } - str->length(length); - str->set_charset(cs); + if (l_time->month > 12 || l_time->day > 31 || l_time->hour > 23 || + l_time->minute > 59 || l_time->second > 59) + return 1; + + DBUG_RETURN(0); +} + + + +/* + Print datetime string from TIME struct + according to format 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) +{ + char intbuff[15]; + uint days_i; + uint hours_i; + uint weekday; + ulong length; + if (set_len_to_zero) + str->length(0); + if (l_time->neg) + str->append("-", 1); + const char *end=ptr+format_length; + for (; ptr != end ; ptr++) + { + if (*ptr != '%' || ptr+1 == end) + str->append(*ptr); + else + { + switch (*++ptr) { + case 'M': + if (!l_time->month) + return 0; + 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); + break; + case 'W': + 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]); + 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); + break; + case 'D': + if (is_time_only) + return 0; + 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) + str->append("th"); + else + { + switch (l_time->day %10) { + case 1: + str->append("st",2); + break; + case 2: + str->append("nd",2); + break; + case 3: + str->append("rd",2); + break; + default: + str->append("th",2); + break; + } + } + break; + case 'Y': + length= int10_to_str(l_time->year, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 4, '0'); + break; + case 'y': + length= int10_to_str(l_time->year%100, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'm': + length= int10_to_str(l_time->month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'c': + length= int10_to_str(l_time->month, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'd': + length= int10_to_str(l_time->day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'e': + length= int10_to_str(l_time->day, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'f': + length= int10_to_str(l_time->second_part, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 6, '0'); + break; + case 'H': + length= int10_to_str(l_time->hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'h': + case 'I': + days_i= l_time->hour/24; + hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i; + length= int10_to_str(hours_i, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + break; + case 'i': /* minutes */ + length= int10_to_str(l_time->minute, intbuff, 10) - intbuff; + 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) - + calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 3, '0'); + break; + case 'k': + length= int10_to_str(l_time->hour, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'l': + days_i= l_time->hour/24; + hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i; + length= int10_to_str(hours_i, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + case 'p': + hours_i= l_time->hour%24; + str->append(hours_i < 12 ? "AM" : "PM",2); + break; + case 'r': + length= my_sprintf(intbuff, + (intbuff, + (l_time->hour < 12) ? "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM", + (l_time->hour+11)%12+1, + l_time->minute, + l_time->second)); + str->append(intbuff, length); + break; + case 'S': + 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, + (intbuff, + "%02d:%02d:%02d", + l_time->hour, + l_time->minute, + l_time->second)); + str->append(intbuff, length); + break; + case 'U': + case 'u': + { + uint year; + if (is_time_only) + return 0; + length= int10_to_str(calc_week(l_time, 0, (*ptr) == 'U', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + } + break; + case 'v': + case 'V': + { + uint year; + if (is_time_only) + return 0; + length= int10_to_str(calc_week(l_time, 1, (*ptr) == 'V', &year), + intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 2, '0'); + } + break; + case 'x': + case 'X': + { + uint year; + if (is_time_only) + return 0; + (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); + length= int10_to_str(weekday, intbuff, 10) - intbuff; + str->append_with_prefill(intbuff, length, 1, '0'); + break; + default: + str->append(*ptr); + break; + } + } + } return str; } + /* ** Get a array of positive numbers from a string object. ** Each number is separated by 1 non digit character @@ -346,7 +808,7 @@ longlong Item_func_year::val_int() longlong Item_func_unix_timestamp::val_int() { if (arg_count == 0) - return (longlong) current_thd->query_start(); + return (longlong) thd->query_start(); if (args[0]->type() == FIELD_ITEM) { // Optimize timestamp field Field *field=((Item_field*) args[0])->field; @@ -358,7 +820,7 @@ longlong Item_func_unix_timestamp::val_int() { return 0; /* purecov: inspected */ } - return (longlong) str_to_timestamp(str->ptr(),str->length()); + return (longlong) str_to_timestamp(str->ptr(),str->length(), thd); } @@ -522,22 +984,26 @@ 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) - return (String*) 0; - if (!value) // zero daynr - { - str->copy("0000-00-00",10,&my_charset_latin1,default_charset()); + goto null_date; + + ltime.year= (value/10000L) % 10000; + ltime.month= (value/100)%100; + ltime.day= (value%100); + ltime.neg=0; + ltime.time_type=TIMESTAMP_DATE; + + tmp_format= &t_datetime_frm(thd, DATE_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1)) return str; - } - - char tmpbuff[11]; - sprintf(tmpbuff,"%04d-%02d-%02d", - (int) (value/10000L) % 10000, - (int) (value/100)%100, - (int) (value%100)); - str->copy(tmpbuff,10,&my_charset_latin1,default_charset()); - return str; + + null_value= 1; +null_date: + return 0; } @@ -577,7 +1043,7 @@ void Item_func_curdate::fix_length_and_dec() decimals=0; max_length=10*default_charset()->mbmaxlen; - store_now_in_tm(current_thd->query_start(),&start); + store_now_in_tm(thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ ((uint) start.tm_mon+1)*100+ @@ -632,22 +1098,27 @@ String *Item_func_curtime::val_str(String *str) void Item_func_curtime::fix_length_and_dec() { struct tm start; - CHARSET_INFO *cs= default_charset(); + DATETIME_FORMAT *tmp_format; + String tmp((char*) buff,sizeof(buff),default_charset()); + TIME ltime; decimals=0; - max_length=8*cs->mbmaxlen; - collation.set(cs); - - store_now_in_tm(current_thd->query_start(),&start); - + store_now_in_tm(thd->query_start(),&start); value=(longlong) ((ulong) ((uint) start.tm_hour)*10000L+ (ulong) (((uint) start.tm_min)*100L+ (uint) start.tm_sec)); - - buff_length=cs->cset->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d", - (int) start.tm_hour, - (int) start.tm_min, - (int) start.tm_sec); + ltime.day= 0; + ltime.hour= start.tm_hour; + ltime.minute= start.tm_min; + 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, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1); + buff_length= tmp.length(); + max_length= buff_length; } @@ -681,14 +1152,11 @@ String *Item_func_now::val_str(String *str) void Item_func_now::fix_length_and_dec() { struct tm start; - CHARSET_INFO *cs= &my_charset_bin; + DATETIME_FORMAT *tmp_format; + String tmp((char*) buff,sizeof(buff),&my_charset_bin); decimals=0; - max_length=19*cs->mbmaxlen; - collation.set(cs); - - store_now_in_tm(current_thd->query_start(),&start); - + store_now_in_tm(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+ @@ -696,14 +1164,6 @@ void Item_func_now::fix_length_and_dec() (ulong) (((uint) start.tm_min)*100L+ (uint) start.tm_sec))); - buff_length= (uint) cs->cset->snprintf(cs,buff, sizeof(buff), - "%04d-%02d-%02d %02d:%02d:%02d", - ((int) (start.tm_year+1900)) % 10000, - (int) start.tm_mon+1, - (int) start.tm_mday, - (int) start.tm_hour, - (int) start.tm_min, - (int) start.tm_sec); /* For getdate */ ltime.year= start.tm_year+1900; ltime.month= start.tm_mon+1; @@ -711,9 +1171,15 @@ void Item_func_now::fix_length_and_dec() ltime.hour= start.tm_hour; ltime.minute= start.tm_min; ltime.second= start.tm_sec; - ltime.second_part=0; - ltime.neg=0; - ltime.time_type=TIMESTAMP_FULL; + ltime.second_part= 0; + ltime.neg= 0; + ltime.time_type= TIMESTAMP_FULL; + + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; + make_datetime(&tmp, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1); + buff_length= tmp.length(); + max_length= buff_length; } bool Item_func_now::get_date(TIME *res, @@ -754,22 +1220,36 @@ void Item_func_now_utc::store_now_in_tm(time_t now, struct tm *now_tm) String *Item_func_sec_to_time::val_str(String *str) { - char buff[23*2]; - const char *sign=""; longlong seconds=(longlong) args[0]->val_int(); - ulong length; + uint sec; + + DATETIME_FORMAT *tmp_format; + TIME ltime; + if ((null_value=args[0]->null_value)) - return (String*) 0; + goto null_date; + + ltime.neg= 0; if (seconds < 0) { seconds= -seconds; - sign= "-"; + ltime.neg= 1; } - uint sec= (uint) ((ulonglong) seconds % 3600); - length= my_sprintf(buff,(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600), - sec/60, sec % 60)); - str->copy(buff, length, &my_charset_latin1, default_charset()); - return str; + + sec= (uint) ((ulonglong) seconds % 3600); + ltime.day= 0; + ltime.hour= seconds/3600; + ltime.minute= sec/60; + ltime.second= sec % 60; + + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1)) + return str; + + null_value= 1; +null_date: + return (String*) 0; } @@ -879,9 +1359,7 @@ String *Item_func_date_format::val_str(String *str) { String *format; TIME l_time; - char intbuff[15]; uint size,weekday; - ulong length; if (!date_or_time) { @@ -892,24 +1370,17 @@ String *Item_func_date_format::val_str(String *str) { String *res; if (!(res=args[0]->val_str(str))) - { - null_value=1; - return 0; - } - if (str_to_time(res->ptr(),res->length(),&l_time)) - { - null_value=1; - return 0; - } + goto null_date; + + if (str_to_time(res->ptr(),res->length(),&l_time, thd)) + goto null_date; + l_time.year=l_time.month=l_time.day=0; null_value=0; } if (!(format = args[1]->val_str(str)) || !format->length()) - { - null_value=1; - return 0; - } + goto null_date; if (fixed_length) size=max_length; @@ -918,237 +1389,53 @@ String *Item_func_date_format::val_str(String *str) if (format == str) str= &value; // Save result here if (str->alloc(size)) - { - null_value=1; - return 0; - } - str->length(0); + goto null_date; + /* Create the result string */ - const char *ptr=format->ptr(); - const char *end=ptr+format->length(); - for (; ptr != end ; ptr++) - { - if (*ptr != '%' || ptr+1 == end) - str->append(*ptr); - else - { - switch (*++ptr) { - case 'M': - if (!l_time.month) - { - null_value=1; - return 0; - } - str->append(month_names[l_time.month-1]); - break; - case 'b': - if (!l_time.month) - { - null_value=1; - return 0; - } - str->append(month_names[l_time.month-1].ptr(),3); - break; - case 'W': - if (date_or_time) - { - null_value=1; - return 0; - } - weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),0); - str->append(day_names[weekday]); - break; - case 'a': - if (date_or_time) - { - null_value=1; - return 0; - } - weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),0); - str->append(day_names[weekday].ptr(),3); - break; - case 'D': - if (date_or_time) - { - null_value=1; - return 0; - } - 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) - str->append("th"); - else - { - switch (l_time.day %10) { - case 1: - str->append("st",2); - break; - case 2: - str->append("nd",2); - break; - case 3: - str->append("rd",2); - break; - default: - str->append("th",2); - break; - } - } - break; - case 'Y': - length= int10_to_str(l_time.year, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 4, '0'); - break; - case 'y': - length= int10_to_str(l_time.year%100, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'm': - length= int10_to_str(l_time.month, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'c': - length= int10_to_str(l_time.month, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'd': - length= int10_to_str(l_time.day, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'e': - length= int10_to_str(l_time.day, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'f': - length= int10_to_str(l_time.second_part, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 6, '0'); - break; - case 'H': - length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'h': - case 'I': - length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'i': /* minutes */ - length= int10_to_str(l_time.minute, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'j': - if (date_or_time) - { - null_value=1; - return 0; - } - 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; - case 'k': - length= int10_to_str(l_time.hour, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'l': - length= int10_to_str((l_time.hour+11)%12+1, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 1, '0'); - break; - case 'p': - str->append(l_time.hour < 12 ? "AM" : "PM",2); - break; - case 'r': - length= my_sprintf(intbuff, - (intbuff, - (l_time.hour < 12) ? "%02d:%02d:%02d AM" : "%02d:%02d:%02d PM", - (l_time.hour+11)%12+1, - l_time.minute, - l_time.second)); - str->append(intbuff, length); - break; - case 'S': - case 's': - length= int10_to_str(l_time.second, intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - break; - case 'T': - length= my_sprintf(intbuff, - (intbuff, - "%02d:%02d:%02d", - l_time.hour, - l_time.minute, - l_time.second)); - str->append(intbuff, length); - break; - case 'U': - case 'u': - { - uint year; - length= int10_to_str(calc_week(&l_time, 0, (*ptr) == 'U', &year), - intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - } - break; - case 'v': - case 'V': - { - uint year; - length= int10_to_str(calc_week(&l_time, 1, (*ptr) == 'V', &year), - intbuff, 10) - intbuff; - str->append_with_prefill(intbuff, length, 2, '0'); - } - break; - case 'x': - case 'X': - { - uint year; - (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': - 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'); + if (make_datetime(str, &l_time, 0, 0, + format->ptr(), format->length(), 1)) + return str; - break; - default: - str->append(*ptr); - break; - } - } - } - return str; +null_date: + null_value=1; + return 0; } 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(); + TIME ltime; if ((null_value=args[0]->null_value)) - return 0; + goto null_date; + localtime_r(&tmp,&tm_tmp); start=&tm_tmp; - + + ltime.year= start->tm_year+1900; + ltime.month= start->tm_mon+1; + ltime.day= start->tm_mday; + ltime.hour= start->tm_hour; + ltime.minute= start->tm_min; + ltime.second= start->tm_sec; + ltime.second_part= 0; + ltime.neg=0; + l=20*cs->mbmaxlen+32; - if (str->alloc(l)) - return str; /* purecov: inspected */ - l=cs->cset->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d", - (int) start->tm_year+1900, - (int) start->tm_mon+1, - (int) start->tm_mday, - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); - str->length(l); - str->set_charset(cs); - return str; + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; + if (str->alloc(l) && make_datetime(str, <ime, 1, 0, + tmp_format->format, + tmp_format->format_length, 1)) + return str; + null_value= 1; +null_date: + return 0; } @@ -1229,7 +1516,7 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool 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)) goto null_date; @@ -1329,19 +1616,17 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_add_interval::val_str(String *str) { TIME ltime; - enum date_time_format_types format; + DATETIME_FORMAT *tmp_format; if (Item_date_add_interval::get_date(<ime,0)) return 0; if (ltime.time_type == TIMESTAMP_DATE) - format= DATE_ONLY; - else if (ltime.second_part) - format= DATE_TIME_MICROSECOND; - else - format= DATE_TIME; - - if (make_datetime(str, <ime, format)) + 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, <ime, 1, ltime.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_value=1; @@ -1400,7 +1685,7 @@ longlong Item_extract::val_int() else { String *res= args[0]->val_str(&value); - if (!res || str_to_time(res->ptr(),res->length(),<ime)) + if (!res || str_to_time(res->ptr(),res->length(),<ime, thd)) { null_value=1; return 0; @@ -1408,7 +1693,6 @@ longlong Item_extract::val_int() neg= ltime.neg ? -1 : 1; null_value=0; } - switch (int_type) { case INTERVAL_YEAR: return ltime.year; case INTERVAL_YEAR_MONTH: return ltime.year*100L+ltime.month; @@ -1530,10 +1814,12 @@ void Item_char_typecast::fix_length_and_dec() 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(<ime,1) && - make_datetime(str, <ime, ltime.second_part ? - DATE_TIME_MICROSECOND : DATE_TIME)) + make_datetime(str, <ime, 1, ltime.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1553,9 +1839,12 @@ 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(<ime) && - make_datetime(str, <ime, ltime.second_part ? TIME_MICROSECOND : TIME_ONLY)) + make_datetime(str, <ime, 0, ltime.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_value=1; @@ -1574,9 +1863,12 @@ 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(<ime,1) && - make_datetime(str, <ime, DATE_ONLY)) + make_datetime(str, <ime, 1, 0, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1605,7 +1897,11 @@ String *Item_func_makedate::val_str(String *str) { null_value=0; get_date_from_daynr(days,&l_time.year,&l_time.month,&l_time.day); - if (make_datetime(str, &l_time, DATE_ONLY)) + + 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; } @@ -1656,6 +1952,7 @@ 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; @@ -1720,19 +2017,21 @@ 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, - l_time1.second_part || l_time2.second_part ? - DATE_TIME_MICROSECOND : DATE_TIME)) + make_datetime(str, &l_time3, 1, + l_time1.second_part || l_time2.second_part, + tmp_format->format, tmp_format->format_length, 1)) 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, - l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY)) + if (make_datetime(str, &l_time3, 0, + l_time1.second_part || l_time2.second_part, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1755,6 +2054,7 @@ 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) || @@ -1800,9 +2100,11 @@ String *Item_func_timediff::val_str(String *str) l_time3.neg= l_time3.neg ? 0 : 1; calc_time_from_sec(&l_time3, seconds, microseconds); - if (make_datetime(str, &l_time3, - l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY)) + + 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)) return str; null_date: @@ -1819,6 +2121,7 @@ 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(); @@ -1840,7 +2143,9 @@ String *Item_func_maketime::val_str(String *str) ltime.hour= (ulong)hour; ltime.minute= (ulong)minute; ltime.second= (ulong)second; - if (make_datetime(str, <ime, TIME_ONLY)) + tmp_format= &t_datetime_frm(thd, TIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, + tmp_format->format, tmp_format->format_length, 1)) return str; null_date: @@ -1860,3 +2165,79 @@ longlong Item_func_microsecond::val_int() return ltime.second_part; 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]; + + if (!args[0]->null_value) + { + const char *val_ptr= val->ptr(); + uint val_len= val->length(); + for (int i= 0; i < 5; i++) + { + 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; + } + } + } + + null_value= 0; + str->length(0); + str->append(format_str); + return str; +} + + +String *Item_func_str_to_date::val_str(String *str) +{ + TIME ltime; + bzero((char*) <ime, 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(), + <ime)) + goto null_date; + + tmp_format= &t_datetime_frm(thd, DATETIME_FORMAT_TYPE).datetime_format; + if (make_datetime(str, <ime, 0, 0, tmp_format->format, + tmp_format->format_length, 1)) + return str; + +null_date: + null_value=1; + return 0; +} diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 6dcf7d00ce1..b7bf294b83d 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -763,3 +763,46 @@ public: maybe_null=1; } }; + + +enum datetime_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; +public: + Item_func_get_format(datetime_format_types type_arg1, Item *a) + :Item_str_func(a), tm_format(type_arg1) {} + String *val_str(String *str); + const char *func_name() const { return "get_format"; } + void fix_length_and_dec() + { + decimals=0; + max_length=17*MY_CHARSET_BIN_MB_MAXLEN; + } +}; + + +class Item_func_str_to_date :public Item_str_func +{ +public: + Item_func_str_to_date(Item *a, Item *b) + :Item_str_func(a, b) {} + String *val_str(String *str); + const char *func_name() const { return "str_to_date"; } + void fix_length_and_dec() + { + decimals=0; + max_length=29*MY_CHARSET_BIN_MB_MAXLEN; + } +}; diff --git a/sql/lex.h b/sql/lex.h index f8bb34c5c5b..5d79e378d4f 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -177,6 +177,7 @@ static SYMBOL symbols[] = { { "FUNCTION", SYM(UDF_SYM),0,0}, { "GEOMETRY", SYM(GEOMETRY_SYM),0,0}, { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),0,0}, + { "GET_FORMAT", SYM(GET_FORMAT),0,0}, { "GLOBAL", SYM(GLOBAL_SYM),0,0}, { "GRANT", SYM(GRANT),0,0}, { "GRANTS", SYM(GRANTS),0,0}, @@ -640,6 +641,7 @@ static SYMBOL sql_functions[] = { { "STARTPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_startpoint)}, { "STD", SYM(STD_SYM),0,0}, { "STDDEV", SYM(STD_SYM),0,0}, + { "STR_TO_DATE", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_str_to_date)}, { "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)}, { "SUBSTR", SYM(SUBSTRING),0,0}, { "SUBSTRING", SYM(SUBSTRING),0,0}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 72e9bbf5bb7..dd5c4837663 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -190,6 +190,19 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MYSQLD_NET_RETRY_COUNT 10 // Abort read after this many int. #endif #define TEMP_POOL_SIZE 128 + +#define QUERY_ALLOC_BLOCK_SIZE 8192 +#define QUERY_ALLOC_PREALLOC_SIZE 8192 +#define TRANS_ALLOC_BLOCK_SIZE 4096 +#define TRANS_ALLOC_PREALLOC_SIZE 4096 +#define RANGE_ALLOC_BLOCK_SIZE 2048 +#define ACL_ALLOC_BLOCK_SIZE 1024 +#define UDF_ALLOC_BLOCK_SIZE 1024 +#define TABLE_ALLOC_BLOCK_SIZE 1024 +#define BDB_LOG_ALLOC_BLOCK_SIZE 1024 +#define WARN_ALLOC_BLOCK_SIZE 2048 +#define WARN_ALLOC_PREALLOC_SIZE 1024 + /* The following parameters is to decide when to use an extra cache to optimise seeks when reading a big table in sorted order @@ -319,7 +332,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define MODE_ORACLE 512 #define MODE_MSSQL 1024 #define MODE_DB2 2048 -#define MODE_SAPDB 4096 +#define MODE_MAXDB 4096 #define MODE_NO_KEY_OPTIONS 8192 #define MODE_NO_TABLE_OPTIONS 16384 #define MODE_NO_FIELD_OPTIONS 32768 @@ -914,7 +927,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_system_variables, LOCK_user_conn; -extern rw_lock_t LOCK_grant; +extern rw_lock_t LOCK_grant; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_attr_t connection_attrib; extern I_List<THD> threads; @@ -931,6 +944,14 @@ extern SHOW_COMP_OPTION have_berkeley_db; 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 String null_string; extern HASH open_cache; extern TABLE *unused_tables; @@ -1001,14 +1022,24 @@ 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); -bool str_to_time(const char *str,uint length,TIME *l_time); -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date); +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); timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time, - bool fuzzy_date); + bool fuzzy_date, THD *thd); 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); + int test_if_number(char *str,int *res,bool allow_wildcards); void change_byte(byte *,uint,char,char); extern "C" void unireg_abort(int exit_code); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1bfb8e8cbf1..6cd61536944 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -217,7 +217,7 @@ const char *sql_mode_names[] = "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", "?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", "NO_DIR_IN_CREATE", - "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS", + "POSTGRESQL", "ORACLE", "MSSQL", "DB2", "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI", "NO_AUTO_VALUE_ON_ZERO", NullS }; @@ -319,6 +319,12 @@ char* log_error_file_ptr= log_error_file; 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"}; + char *language_ptr, *default_collation_name, *default_character_set_name; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; char server_version[SERVER_VERSION_LENGTH]=MYSQL_SERVER_VERSION; @@ -906,6 +912,9 @@ 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(); if (defaults_argv) free_defaults(defaults_argv); free_tmpdir(&mysql_tmpdir_list); @@ -1998,6 +2007,36 @@ bool open_log(MYSQL_LOG *log, const char *hostname, } +int init_global_datetime_format(datetime_format_types format_type, bool is_alloc) +{ + const char *format_str= opt_datetime_formats[format_type]; + uint format_length= 0; + DATETIME_FORMAT *tmp_format= &g_datetime_frm(format_type).datetime_format; + + if (format_str) + { + format_str= opt_datetime_formats[format_type]; + format_length= strlen(format_str); + } + else + { + format_str= datetime_formats[format_type][ISO_FORMAT]; + format_length= strlen(datetime_formats[format_type][ISO_FORMAT]); + opt_datetime_formats[format_type]= format_str; + } + if (make_format(tmp_format, format_type, format_str, + format_length, is_alloc)) + { + 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; + } + return 1; +} + + static int init_common_variables(const char *conf_file_name, int argc, char **argv, const char **groups) { @@ -2113,6 +2152,12 @@ static int init_common_variables(const char *conf_file_name, int argc, 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; if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1)) return 1; @@ -3453,10 +3498,10 @@ error: Handle start options ******************************************************************************/ -enum options +enum options_mysqld { - OPT_ISAM_LOG=256, OPT_SKIP_NEW, - OPT_SKIP_GRANT, OPT_SKIP_LOCK, + OPT_ISAM_LOG=256, OPT_SKIP_NEW, + OPT_SKIP_GRANT, OPT_SKIP_LOCK, OPT_ENABLE_LOCK, OPT_USE_LOCKING, OPT_SOCKET, OPT_UPDATE_LOG, OPT_BIN_LOG, OPT_SKIP_RESOLVE, @@ -3567,14 +3612,20 @@ enum options OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, OPT_ERROR_LOG_FILE, + OPT_DEFAULT_WEEK_FORMAT, + OPT_RANGE_ALLOC_BLOCK_SIZE, + OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE, + OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE, OPT_ENABLE_SHARED_MEMORY, OPT_SHARED_MEMORY_BASE_NAME, OPT_OLD_PASSWORDS, OPT_EXPIRE_LOGS_DAYS, - OPT_DEFAULT_WEEK_FORMAT, OPT_GROUP_CONCAT_MAX_LEN, OPT_DEFAULT_COLLATION, OPT_SECURE_AUTH, + OPT_DATE_FORMAT, + OPT_TIME_FORMAT, + OPT_DATETIME_FORMAT, OPT_LOG_QUERIES_NOT_USING_INDEXES }; @@ -4392,6 +4443,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.preload_buff_size, (gptr*) &max_system_variables.preload_buff_size, 0, GET_ULONG, REQUIRED_ARG, 32*1024L, 1024, 1024*1024*1024L, 0, 1, 0}, + {"query_alloc_block_size", OPT_QUERY_ALLOC_BLOCK_SIZE, + "Allocation block size for query parsing and execution", + (gptr*) &global_system_variables.query_alloc_block_size, + (gptr*) &max_system_variables.query_alloc_block_size, 0, GET_ULONG, + REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, #ifdef HAVE_QUERY_CACHE {"query_cache_limit", OPT_QUERY_CACHE_LIMIT, "Don't cache results that are bigger than this.", @@ -4413,6 +4469,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.query_cache_type, (gptr*) &max_system_variables.query_cache_type, 0, GET_ULONG, REQUIRED_ARG, 1, 0, 2, 0, 1, 0}, + {"query_prealloc_size", OPT_QUERY_PREALLOC_SIZE, + "Persistent buffer for query parsing and execution", + (gptr*) &global_system_variables.query_prealloc_size, + (gptr*) &max_system_variables.query_prealloc_size, 0, GET_ULONG, + REQUIRED_ARG, QUERY_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, #endif /*HAVE_QUERY_CACHE*/ {"read_buffer_size", OPT_RECORD_BUFFER, "Each thread that does a sequential scan allocates a buffer of this size for each table it scans. If you do many sequential scans, you may want to increase this value.", @@ -4451,6 +4512,11 @@ The minimum value for this variable is 4096.", (gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0, GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0}, #endif /* HAVE_REPLICATION */ + {"range_alloc_block_size", OPT_RANGE_ALLOC_BLOCK_SIZE, + "Allocation block size for storing ranges during optimization", + (gptr*) &global_system_variables.range_alloc_block_size, + (gptr*) &max_system_variables.range_alloc_block_size, 0, GET_ULONG, + REQUIRED_ARG, RANGE_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, {"read-only", OPT_READONLY, "Make all tables readonly, with the expections for replications (slave) threads and users with the SUPER privilege.", (gptr*) &opt_readonly, @@ -4487,6 +4553,16 @@ The minimum value for this variable is 4096.", "The stack size for each thread.", (gptr*) &thread_stack, (gptr*) &thread_stack, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK, 1024*32, ~0L, 0, 1024, 0}, + {"transaction_alloc_block_size", OPT_TRANS_ALLOC_BLOCK_SIZE, + "Allocation block size for transactions to be stored in binary log", + (gptr*) &global_system_variables.trans_alloc_block_size, + (gptr*) &max_system_variables.trans_alloc_block_size, 0, GET_ULONG, + REQUIRED_ARG, QUERY_ALLOC_BLOCK_SIZE, 1024, ~0L, 0, 1024, 0}, + {"transaction_prealloc_size", OPT_TRANS_PREALLOC_SIZE, + "Persistent buffer for transactions to be stored in binary log", + (gptr*) &global_system_variables.trans_prealloc_size, + (gptr*) &max_system_variables.trans_prealloc_size, 0, GET_ULONG, + REQUIRED_ARG, TRANS_ALLOC_PREALLOC_SIZE, 1024, ~0L, 0, 1024, 0}, {"wait_timeout", OPT_WAIT_TIMEOUT, "The number of seconds the server waits for activity on a connection before closing it.", (gptr*) &global_system_variables.net_wait_timeout, @@ -4502,6 +4578,21 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.default_week_format, (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], + 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], + 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], + 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} }; @@ -4879,6 +4970,10 @@ 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", diff --git a/sql/opt_ft.cc b/sql/opt_ft.cc index b35b3230a39..74349819937 100644 --- a/sql/opt_ft.cc +++ b/sql/opt_ft.cc @@ -26,11 +26,11 @@ ** Create a FT or QUICK RANGE based on a key ****************************************************************************/ -QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab) +QUICK_SELECT *get_ft_or_quick_select_for_ref(THD *thd, TABLE *table, + JOIN_TAB *tab) { if (tab->type == JT_FT) - return new FT_SELECT(table, &tab->ref); - else - return get_quick_select_for_ref(table, &tab->ref); + return new FT_SELECT(thd, table, &tab->ref); + return get_quick_select_for_ref(thd, table, &tab->ref); } diff --git a/sql/opt_ft.h b/sql/opt_ft.h index b055edc107c..69b6b72f3fc 100644 --- a/sql/opt_ft.h +++ b/sql/opt_ft.h @@ -28,13 +28,14 @@ class FT_SELECT: public QUICK_SELECT { public: TABLE_REF *ref; - FT_SELECT(TABLE *table, TABLE_REF *tref) : - QUICK_SELECT (table,tref->key,1), ref(tref) { init(); } + FT_SELECT(THD *thd, TABLE *table, TABLE_REF *tref) : + QUICK_SELECT (thd, table, tref->key, 1), ref(tref) { init(); } int init() { return error=file->ft_init(); } int get_next() { return error=file->ft_read(record); } }; -QUICK_SELECT *get_ft_or_quick_select_for_ref(TABLE *table, JOIN_TAB *tab); +QUICK_SELECT *get_ft_or_quick_select_for_ref(THD *thd, TABLE *table, + JOIN_TAB *tab); #endif diff --git a/sql/opt_range.cc b/sql/opt_range.cc index a8ea50beafc..cf1838489d0 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -279,6 +279,7 @@ public: typedef struct st_qsel_param { + THD *thd; TABLE *table; KEY_PART *key_parts,*key_parts_end,*key[MAX_KEY]; MEM_ROOT *mem_root; @@ -377,13 +378,14 @@ SQL_SELECT::~SQL_SELECT() #undef index // Fix for Unixware 7 -QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc) +QUICK_SELECT::QUICK_SELECT(THD *thd, TABLE *table, uint key_nr, bool no_alloc) :dont_free(0),error(0),index(key_nr),max_used_key_length(0), used_key_parts(0), head(table), it(ranges),range(0) { if (!no_alloc) { - init_sql_alloc(&alloc,1024,0); // Allocates everything here + // Allocates everything through the internal memroot + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); my_pthread_setspecific_ptr(THR_MALLOC,&alloc); } else @@ -455,17 +457,17 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) SEL_ARG *tmp; if (type != KEY_RANGE) { - if (!(tmp=new SEL_ARG(type))) - return 0; // out of memory + if (!(tmp= new SEL_ARG(type))) + return 0; // out of memory tmp->prev= *next_arg; // Link into next/prev chain (*next_arg)->next=tmp; (*next_arg)= tmp; } else { - if (!(tmp=new SEL_ARG(field,part, min_value,max_value, - min_flag, max_flag, maybe_flag))) - return 0; // out of memory + if (!(tmp= new SEL_ARG(field,part, min_value,max_value, + min_flag, max_flag, maybe_flag))) + return 0; // OOM tmp->parent=new_parent; tmp->next_key_part=next_key_part; if (left != &null_element) @@ -476,7 +478,8 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg) (*next_arg)= tmp; if (right != &null_element) - tmp->right=right->clone(tmp,next_arg); + if (!(tmp->right= right->clone(tmp,next_arg))) + return 0; // OOM } increment_use_count(1); return tmp; @@ -555,10 +558,11 @@ SEL_ARG *SEL_ARG::clone_tree() { SEL_ARG tmp_link,*next_arg,*root; next_arg= &tmp_link; - root=clone((SEL_ARG *) 0, &next_arg); + root= clone((SEL_ARG *) 0, &next_arg); next_arg->next=0; // Fix last link tmp_link.next->prev=0; // Fix first link - root->use_count=0; + if (root) // If not OOM + root->use_count= 0; return root; } @@ -576,7 +580,8 @@ SEL_ARG *SEL_ARG::clone_tree() ** quick_rows ; How many rows the key matches *****************************************************************************/ -int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, +int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, + table_map prev_tables, ha_rows limit, bool force_quick_range) { uint basflag; @@ -617,9 +622,9 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, SEL_TREE *tree; KEY_PART *key_parts; PARAM param; - THD *thd= current_thd; - + /* set up parameter that is passed to all functions */ + param.thd= thd; param.baseflag=basflag; param.prev_tables=prev_tables | const_tables; param.read_tables=read_tables; @@ -629,7 +634,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, param.mem_root= &alloc; thd->no_errors=1; // Don't warn about NULL - init_sql_alloc(&alloc,2048,0); + init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0); if (!(param.key_parts = (KEY_PART*) alloc_root(&alloc, sizeof(KEY_PART)* head->key_parts))) @@ -764,7 +769,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) while ((item=li++)) { SEL_TREE *new_tree=get_mm_tree(param,item); - if (current_thd->is_fatal_error) + if (param->thd->is_fatal_error) DBUG_RETURN(0); // out of memory tree=tree_and(param,tree,new_tree); if (tree && tree->type == SEL_TREE::IMPOSSIBLE) @@ -905,7 +910,7 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, { SEL_ARG *sel_arg=0; if (!tree && !(tree=new SEL_TREE())) - DBUG_RETURN(0); // out of memory + DBUG_RETURN(0); // OOM if (!value || !(value->used_tables() & ~param->read_tables)) { sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value); @@ -917,10 +922,11 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type, DBUG_RETURN(tree); } } - else { + else + { // This key may be used later - if (!(sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY))) - DBUG_RETURN(0); // out of memory + if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY))) + DBUG_RETURN(0); // OOM } sel_arg->part=(uchar) key_part->part; tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg); @@ -1125,8 +1131,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, ******************************************************************************/ /* -** Add a new key test to a key when scanning through all keys -** This will never be called for same key parts. + Add a new key test to a key when scanning through all keys + This will never be called for same key parts. */ static SEL_ARG * @@ -1310,7 +1316,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) // key1->part < key2->part key1->use_count--; if (key1->use_count > 0) - key1=key1->clone_tree(); + if (!(key1= key1->clone_tree())) + return 0; // OOM return and_all_keys(key1,key2,clone_flag); } @@ -1329,7 +1336,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) if (key1->use_count > 1) { key1->use_count--; - key1=key1->clone_tree(); + if (!(key1=key1->clone_tree())) + return 0; // OOM key1->use_count++; } if (key1->type == SEL_ARG::MAYBE_KEY) @@ -1373,6 +1381,8 @@ key_and(SEL_ARG *key1,SEL_ARG *key2,uint clone_flag) if (!next || next->type != SEL_ARG::IMPOSSIBLE) { SEL_ARG *new_arg= e1->clone_and(e2); + if (!new_arg) + return &null_element; // End of memory new_arg->next_key_part=next; if (!new_tree) { @@ -1460,8 +1470,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) { swap(SEL_ARG *,key1,key2); } - else - key1=key1->clone_tree(); + else if (!(key1=key1->clone_tree())) + return 0; // OOM } // Add tree at key2 to tree at key1 @@ -1529,7 +1539,10 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) SEL_ARG *next=key2->next; // Keys are not overlapping if (key2_shared) { - key1=key1->insert(new SEL_ARG(*key2)); // Must make copy + SEL_ARG *tmp= new SEL_ARG(*key2); // Must make copy + if (!tmp) + return 0; // OOM + key1=key1->insert(tmp); key2->increment_use_count(key1->use_count+1); } else @@ -1575,6 +1588,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) if (cmp >= 0 && tmp->cmp_min_to_min(key2) < 0) { // tmp.min <= x < key2.min SEL_ARG *new_arg=tmp->clone_first(key2); + if (!new_arg) + return 0; // OOM if ((new_arg->next_key_part= key1->next_key_part)) new_arg->increment_use_count(key1->use_count+1); tmp->copy_min_to_min(key2); @@ -1588,6 +1603,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) if (tmp->cmp_min_to_min(&key) > 0) { // key.min <= x < tmp.min SEL_ARG *new_arg=key.clone_first(tmp); + if (!new_arg) + return 0; // OOM if ((new_arg->next_key_part=key.next_key_part)) new_arg->increment_use_count(key1->use_count+1); key1=key1->insert(new_arg); @@ -1602,19 +1619,27 @@ key_or(SEL_ARG *key1,SEL_ARG *key2) key.copy_max_to_min(tmp); if (!(tmp=tmp->next)) { - key1=key1->insert(new SEL_ARG(key)); + SEL_ARG *tmp2= new SEL_ARG(key); + if (!tmp2) + return 0; // OOM + key1=key1->insert(tmp2); key2=key2->next; goto end; } if (tmp->cmp_min_to_max(&key) > 0) { - key1=key1->insert(new SEL_ARG(key)); + SEL_ARG *tmp2= new SEL_ARG(key); + if (!tmp2) + return 0; // OOM + key1=key1->insert(tmp2); break; } } else { SEL_ARG *new_arg=tmp->clone_last(&key); // tmp.min <= x <= key.max + if (!new_arg) + return 0; // OOM tmp->copy_max_to_min(&key); tmp->increment_use_count(key1->use_count+1); new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part); @@ -1631,8 +1656,11 @@ end: SEL_ARG *next=key2->next; if (key2_shared) { + SEL_ARG *tmp=new SEL_ARG(*key2); // Must make copy + if (!tmp) + return 0; key2->increment_use_count(key1->use_count+1); - key1=key1->insert(new SEL_ARG(*key2)); // Must make copy + key1=key1->insert(tmp); } else key1=key1->insert(key2); // Will destroy key2_root @@ -2221,7 +2249,8 @@ get_quick_select(PARAM *param,uint idx,SEL_ARG *key_tree) { QUICK_SELECT *quick; DBUG_ENTER("get_quick_select"); - if ((quick=new QUICK_SELECT(param->table,param->real_keynr[idx]))) + if ((quick=new QUICK_SELECT(param->thd, param->table, + param->real_keynr[idx]))) { if (quick->error || get_quick_keys(param,quick,param->key[idx],key_tree,param->min_key,0, @@ -2333,10 +2362,10 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, /* Get range for retrieving rows in QUICK_SELECT::get_next */ if (!(range= new QUICK_RANGE(param->min_key, - (uint) (tmp_min_key - param->min_key), - param->max_key, - (uint) (tmp_max_key - param->max_key), - flag))) + (uint) (tmp_min_key - param->min_key), + param->max_key, + (uint) (tmp_max_key - param->max_key), + flag))) return 1; // out of memory set_if_bigger(quick->max_used_key_length,range->min_length); @@ -2393,10 +2422,10 @@ static bool null_part_in_key(KEY_PART *key_part, const char *key, uint length) ** Create a QUICK RANGE based on a key ****************************************************************************/ -QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref) +QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) { table->file->index_end(); // Remove old cursor - QUICK_SELECT *quick=new QUICK_SELECT(table, ref->key, 1); + QUICK_SELECT *quick=new QUICK_SELECT(thd, table, ref->key, 1); KEY *key_info = &table->key_info[ref->key]; KEY_PART *key_part; uint part; @@ -2405,7 +2434,7 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref) return 0; /* no ranges found */ if (cp_buffer_from_ref(ref)) { - if (current_thd->is_fatal_error) + if (thd->is_fatal_error) return 0; // out of memory return quick; // empty range } diff --git a/sql/opt_range.h b/sql/opt_range.h index 4931f6f007e..b4d855c0faa 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -83,7 +83,7 @@ public: ha_rows records; double read_time; - QUICK_SELECT(TABLE *table,uint index_arg,bool no_alloc=0); + QUICK_SELECT(THD *thd, TABLE *table,uint index_arg,bool no_alloc=0); virtual ~QUICK_SELECT(); void reset(void) { next=0; it.rewind(); } int init() { return error=file->index_init(index); } @@ -127,13 +127,14 @@ class SQL_SELECT :public Sql_alloc { SQL_SELECT(); ~SQL_SELECT(); - bool check_quick(bool force_quick_range=0, ha_rows limit = HA_POS_ERROR) - { return test_quick_select(key_map(~0),0,limit, force_quick_range) < 0; } + bool check_quick(THD *thd, bool force_quick_range, ha_rows limit) + { return test_quick_select(thd, key_map(~0L),0,limit, force_quick_range) < 0; } inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; } - int test_quick_select(key_map keys,table_map prev_tables,ha_rows limit, - bool force_quick_range=0); + int test_quick_select(THD *thd, key_map keys, table_map prev_tables, + ha_rows limit, bool force_quick_range=0); }; -QUICK_SELECT *get_quick_select_for_ref(TABLE *table, struct st_table_ref *ref); +QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, + struct st_table_ref *ref); #endif diff --git a/sql/protocol.cc b/sql/protocol.cc index 79420fb71d5..0fe759cff67 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -833,17 +833,12 @@ bool Protocol_simple::store(TIME *tm) field_pos++; #endif char buff[40]; - 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); + 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()); } @@ -855,12 +850,12 @@ bool Protocol_simple::store_date(TIME *tm) field_pos++; #endif char buff[40]; - uint length; - length= my_sprintf(buff,(buff, "%04d-%02d-%02d", - (int) tm->year, - (int) tm->month, - (int) tm->day)); - return net_store_data((char*) buff, length); + 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); + return net_store_data((char*) tmp.ptr(), tmp.length()); } @@ -878,16 +873,14 @@ bool Protocol_simple::store_time(TIME *tm) field_pos++; #endif char buff[40]; - uint length; + String tmp((char*) buff,sizeof(buff),&my_charset_bin); + DATETIME_FORMAT *tmp_format= (&t_datetime_frm + (current_thd, TIME_FORMAT_TYPE).datetime_format); uint day= (tm->year || tm->month) ? 0 : tm->day; - 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); + 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()); } diff --git a/sql/set_var.cc b/sql/set_var.cc index eb456b0745f..48580960399 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -51,6 +51,7 @@ #include "slave.h" #include "sql_acl.h" #include <my_getopt.h> +#include <thr_alarm.h> #include <myisam.h> #ifdef HAVE_BERKELEY_DB #include "ha_berkeley.h" @@ -90,6 +91,7 @@ static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static void fix_max_binlog_size(THD *thd, enum_var_type type); static void fix_max_relay_log_size(THD *thd, enum_var_type type); +static void fix_max_connections(THD *thd, enum_var_type type); static KEY_CACHE *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); @@ -162,11 +164,13 @@ sys_var_long_ptr sys_max_binlog_size("max_binlog_size", &max_binlog_size, fix_max_binlog_size); sys_var_long_ptr sys_max_connections("max_connections", - &max_connections); + &max_connections, + fix_max_connections); sys_var_long_ptr sys_max_connect_errors("max_connect_errors", &max_connect_errors); sys_var_long_ptr sys_max_delayed_threads("max_delayed_threads", - &max_insert_delayed_threads); + &max_insert_delayed_threads, + fix_max_connections); sys_var_thd_ulong sys_max_error_count("max_error_count", &SV::max_error_count); sys_var_thd_ulong sys_max_heap_table_size("max_heap_table_size", @@ -235,6 +239,18 @@ sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", sys_var_long_ptr sys_query_cache_size("query_cache_size", &query_cache_size, fix_query_cache_size); + +sys_var_thd_ulong sys_range_alloc_block_size("range_alloc_block_size", + &SV::range_alloc_block_size); +sys_var_thd_ulong sys_query_alloc_block_size("query_alloc_block_size", + &SV::query_alloc_block_size); +sys_var_thd_ulong sys_query_prealloc_size("query_prealloc_size", + &SV::query_prealloc_size); +sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size", + &SV::trans_alloc_block_size); +sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size", + &SV::trans_prealloc_size); + #ifdef HAVE_QUERY_CACHE sys_var_long_ptr sys_query_cache_limit("query_cache_limit", &query_cache.query_cache_limit); @@ -387,6 +403,9 @@ 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_default_week_format, &sys_delay_key_write, &sys_delayed_insert_limit, @@ -441,7 +460,9 @@ sys_var *sys_variables[]= &sys_old_passwords, &sys_preload_buff_size, &sys_pseudo_thread_id, + &sys_query_alloc_block_size, &sys_query_cache_size, + &sys_query_prealloc_size, #ifdef HAVE_QUERY_CACHE &sys_query_cache_limit, &sys_query_cache_min_res_unit, @@ -450,6 +471,7 @@ sys_var *sys_variables[]= &sys_quote_show_create, &sys_rand_seed1, &sys_rand_seed2, + &sys_range_alloc_block_size, &sys_read_buff_size, &sys_read_rnd_buff_size, #ifdef HAVE_REPLICATION @@ -478,6 +500,8 @@ sys_var *sys_variables[]= &sys_thread_cache_size, &sys_timestamp, &sys_tmp_table_size, + &sys_trans_alloc_block_size, + &sys_trans_prealloc_size, &sys_tx_isolation, #ifdef HAVE_INNOBASE_DB &sys_innodb_max_dirty_pages_pct, @@ -519,6 +543,8 @@ 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_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS}, {sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS}, @@ -629,6 +655,8 @@ struct show_var_st init_vars[]= { {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, {sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS}, + {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, + SHOW_SYS}, #ifdef HAVE_QUERY_CACHE {sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS}, {sys_query_cache_min_res_unit.name, (char*) &sys_query_cache_min_res_unit, @@ -637,6 +665,9 @@ struct show_var_st init_vars[]= { {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS}, {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, #endif /* HAVE_QUERY_CACHE */ + {sys_query_prealloc_size.name, (char*) &sys_query_prealloc_size, SHOW_SYS}, + {sys_range_alloc_block_size.name, (char*) &sys_range_alloc_block_size, + SHOW_SYS}, {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS}, {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS}, @@ -670,19 +701,89 @@ 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}, #ifdef HAVE_TZNAME {"timezone", time_zone, SHOW_CHAR}, #endif {sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS}, {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR}, + {sys_trans_alloc_block_size.name, (char*) &sys_trans_alloc_block_size, + SHOW_SYS}, + {sys_trans_prealloc_size.name, (char*) &sys_trans_prealloc_size, SHOW_SYS}, {"version", server_version, SHOW_CHAR}, {sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS}, {NullS, NullS, SHOW_LONG} }; + /* 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 @@ -748,7 +849,7 @@ static void fix_max_join_size(THD *thd, enum_var_type type) thd->options&= ~OPTION_BIG_SELECTS; } } - + /* If one doesn't use the SESSION modifier, the isolation level @@ -816,7 +917,7 @@ static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type) #endif -void fix_delay_key_write(THD *thd, enum_var_type type) +extern void fix_delay_key_write(THD *thd, enum_var_type type) { switch ((enum_delay_key_write) delay_key_write_options) { case DELAY_KEY_WRITE_NONE: @@ -832,7 +933,7 @@ void fix_delay_key_write(THD *thd, enum_var_type type) } } -void fix_max_binlog_size(THD *thd, enum_var_type type) +static void fix_max_binlog_size(THD *thd, enum_var_type type) { DBUG_ENTER("fix_max_binlog_size"); DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu", @@ -845,7 +946,7 @@ void fix_max_binlog_size(THD *thd, enum_var_type type) DBUG_VOID_RETURN; } -void fix_max_relay_log_size(THD *thd, enum_var_type type) +static void fix_max_relay_log_size(THD *thd, enum_var_type type) { DBUG_ENTER("fix_max_relay_log_size"); DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu", @@ -857,6 +958,13 @@ void fix_max_relay_log_size(THD *thd, enum_var_type type) DBUG_VOID_RETURN; } + +static void fix_max_connections(THD *thd, enum_var_type type) +{ + resize_thr_alarm(max_connections + max_insert_delayed_threads + 10); +} + + bool sys_var_long_ptr::update(THD *thd, set_var *var) { ulonglong tmp= var->value->val_int(); @@ -1082,7 +1190,8 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type, bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { - char buff[80], *value; + char buff[80]; + const char *value; String str(buff, sizeof(buff), system_charset_info), *res; if (var->value->result_type() == STRING_RESULT) @@ -1092,7 +1201,7 @@ bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) (ulong) find_type(res->c_ptr(), enum_names, 3)-1)) < 0) { - value=res->c_ptr(); + value= res ? res->c_ptr() : "NULL"; goto err; } } @@ -2050,7 +2159,7 @@ int set_var::check(THD *thd) { my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name); return -1; - } + } return var->check(thd, this) ? -1 : 0; } @@ -2205,7 +2314,7 @@ ulong fix_sql_mode(ulong sql_mode) MODE_IGNORE_SPACE | MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | MODE_NO_FIELD_OPTIONS); - if (sql_mode & MODE_SAPDB) + if (sql_mode & MODE_MAXDB) sql_mode|= (MODE_PIPES_AS_CONCAT | MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_NO_KEY_OPTIONS | MODE_NO_TABLE_OPTIONS | diff --git a/sql/set_var.h b/sql/set_var.h index 812bd6c9420..4c67c5ccc59 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -49,6 +49,8 @@ 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) @@ -188,6 +190,9 @@ 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) {} @@ -555,6 +560,51 @@ public: }; +class sys_var_datetime_format :public sys_var_thd +{ +public: + enum datetime_format_types format_type; + DATETIME_FORMAT datetime_format; + sys_var_datetime_format(): sys_var_thd() + {} + + 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 update(THD *thd, set_var *var); + byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base); + void set_default(THD *thd, enum_var_type type); +}; + + /* Variable that you can only read from */ class sys_var_readonly: public sys_var @@ -693,7 +743,7 @@ public: uint name_length_arg, gptr data_arg) :name_length(name_length_arg), data(data_arg) { - name= my_memdup(name_arg, name_length, MYF(MY_WME)); + name= my_memdup((byte*) name_arg, name_length, MYF(MY_WME)); links->push_back(this); } inline bool cmp(const char *name_cmp, uint length) diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 74027e78c31..bb7cd90b4c4 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -291,4 +291,4 @@ 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'", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index aa93758bc8b..48a4fee22f8 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -285,4 +285,4 @@ 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'", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 963f040ae86..98fb9278cc2 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -293,4 +293,4 @@ 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'", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 7fb93e70e04..5ccfb39478a 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -282,5 +282,5 @@ 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'", "Column '%-.64s' cannot be part of FULLTEXT index" - diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 91f530585de..e596863907f 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -287,4 +287,4 @@ 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'", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 6ab9529e88d..a81b8859692 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -282,4 +282,4 @@ 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'", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 7750b5292fd..9554822a5ff 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -294,4 +294,4 @@ 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'", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 46fb9ab2425..073289562b3 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -282,4 +282,4 @@ 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'", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index ddf6b3b5347..c62a7c7b1ae 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -284,4 +284,4 @@ 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'", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 9043bd009c6..004d7d00994 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -282,4 +282,4 @@ 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'", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 35e8529070b..888ac449a8b 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -284,4 +284,4 @@ 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'", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 84e1030c188..a72d6c3fdee 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -282,4 +282,4 @@ 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'", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 12c697c7019..3c6dca27016 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -284,4 +284,4 @@ 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'", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 916f44b10be..bafc635a184 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -284,4 +284,4 @@ 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'", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index a9ee2b490ed..0aa25aabb44 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -286,4 +286,4 @@ 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'", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index b2de951fa31..33d8f68291d 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -283,4 +283,4 @@ 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'", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 217743e2542..ff46caf2c6c 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -286,4 +286,4 @@ 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'", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 6456a585585..f8bdb8bf4a5 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -284,4 +284,4 @@ 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'", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index a350ab82a98..cede04e36ed 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -277,4 +277,4 @@ 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'", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 711a7ec2fb9..0759f68a1bb 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -290,4 +290,4 @@ 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'", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 9c8cf5fceab..b9c1b297e43 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -284,4 +284,4 @@ 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'", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 95b44366fdf..456b93fbc4d 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -282,4 +282,4 @@ 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'", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 38d0b05a37f..dba62fd60c8 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -287,4 +287,4 @@ 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'", diff --git a/sql/slave.cc b/sql/slave.cc index 2aea1056ac8..415969a2955 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1086,11 +1086,12 @@ static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi) BINLOG_FORMAT_323_GEQ_57 ; break; case '4': - case '5': mi->old_format = BINLOG_FORMAT_CURRENT; break; default: - errmsg = "Master reported unrecognized MySQL version"; + /* 5.0 is not supported */ + errmsg = "Master reported an unrecognized MySQL version. Note that 4.0 \ +slaves can't replicate a 5.0 or newer master."; break; } @@ -3165,6 +3166,8 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff)); err: + /* Free temporary tables etc */ + thd->cleanup(); VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query = thd->db = 0; // extra safety VOID(pthread_mutex_unlock(&LOCK_thread_count)); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index a47a38f2376..7b79d1aa1b5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -186,7 +186,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) thd->net.last_error); goto end; } - init_sql_alloc(&mem,1024,0); + init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0); init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0); VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50)); while (!(read_record_info.read_record(&read_record_info))) @@ -2450,7 +2450,7 @@ my_bool grant_init(THD *org_thd) (void) hash_init(&column_priv_hash,&my_charset_latin1, 0,0,0, (hash_get_key) get_grant_table, (hash_free_key) free_grant_table,0); - init_sql_alloc(&memex,1024,0); + init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); /* Don't do anything if running with --skip-grant */ if (!initialized) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c7d77c67236..588031643d4 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -90,8 +90,9 @@ THD::THD():user_time(0), is_fatal_error(0), { host=user=priv_user=db=query=ip=0; host_or_ip= "connecting host"; - locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password= + locked=killed=some_tables_deleted=no_errors=password= query_start_used=prepare_command=0; + count_cuted_fields= CHECK_FIELD_IGNORE; db_length=query_length=col_access=0; query_error= tmp_table_used= 0; next_insert_id=last_insert_id=0; @@ -147,7 +148,7 @@ THD::THD():user_time(0), is_fatal_error(0), bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root)); bzero((char*) &con_root,sizeof(con_root)); bzero((char*) &warn_root,sizeof(warn_root)); - init_alloc_root(&warn_root, 1024, 0); + init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); user_connect=(USER_CONN *)0; hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, (hash_get_key) get_var_key, @@ -230,9 +231,11 @@ void THD::init(void) void THD::init_for_queries() { - init_sql_alloc(&mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); + init_sql_alloc(&mem_root, variables.query_alloc_block_size, + variables.query_prealloc_size); init_sql_alloc(&transaction.mem_root, - TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC); + variables.trans_alloc_block_size, + variables.trans_prealloc_size); } @@ -276,6 +279,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(); 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 146ee18e3e2..06bc29dbb2a 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -34,6 +34,9 @@ enum enum_log_type { LOG_CLOSED, LOG_TO_BE_OPENED, LOG_NORMAL, LOG_NEW, LOG_BIN} enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON, DELAY_KEY_WRITE_ALL }; +enum enum_check_fields { CHECK_FIELD_IGNORE, CHECK_FIELD_WARN, + CHECK_FIELD_ERROR_FOR_NULL }; + extern char internal_table_name[2]; /* log info errors */ @@ -389,10 +392,15 @@ struct system_variables ulong table_type; ulong tmp_table_size; ulong tx_isolation; - /* Determines if which non-standard SQL behaviour should be enabled */ + /* Determines which non-standard SQL behaviour should be enabled */ ulong sql_mode; ulong default_week_format; ulong max_seeks_for_key; + ulong range_alloc_block_size; + ulong query_alloc_block_size; + ulong query_prealloc_size; + ulong trans_alloc_block_size; + ulong trans_prealloc_size; ulong group_concat_max_len; /* In slave thread we need to know in behalf of which @@ -413,6 +421,7 @@ struct system_variables CHARSET_INFO *collation_server; CHARSET_INFO *collation_database; CHARSET_INFO *collation_connection; + sys_var_datetime_format datetime_formats[3]; }; void free_tmp_table(THD *thd, TABLE *entry); @@ -569,6 +578,7 @@ public: uint select_number; //number of select (used for EXPLAIN) /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; + enum_check_fields count_cuted_fields; /* for user variables replication*/ DYNAMIC_ARRAY user_var_events; @@ -576,7 +586,7 @@ public: char scramble[SCRAMBLE_LENGTH+1]; bool slave_thread; - bool set_query_id,locked,count_cuted_fields,some_tables_deleted; + bool set_query_id,locked,some_tables_deleted; bool last_cuted_field; bool no_errors, allow_sum_func, password, is_fatal_error; bool query_start_used,last_insert_id_used,insert_id_used,rand_used; @@ -858,8 +868,7 @@ public: List<Item> &select_fields,enum_duplicates duplic) :select_insert (NULL, &select_fields, duplic), db(db_name), name(table_name), extra_fields(&fields_par),keys(&keys_par), - create_info(create_info_par), - lock(0) + create_info(create_info_par), lock(0) {} int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &values); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index bd76cbd5f36..2985f7e04a0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -90,7 +90,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, select=make_select(table,0,0,conds,&error); if (error) DBUG_RETURN(-1); - if ((select && select->check_quick(safe_update, limit)) || !limit) + if ((select && select->check_quick(thd, safe_update, limit)) || !limit) { delete select; free_underlaid_joins(thd, &thd->lex.select_lex); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 13d3cc27376..7fd2b751c1d 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -220,7 +220,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, } } else - unit->exclude_level(); + unit->exclude_tree(); org_table_list->db= (char *)""; #ifndef DBUG_OFF /* Try to catch errors if this is accessed */ diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 93ab332bcd5..bce1022d5c0 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -33,7 +33,7 @@ The second is to be freeed only on thread end. mysql_ha_open should then do { handler_items=concat(handler_items, free_list); free_list=0; } - But !!! do_cammand calls free_root at the end of every query and frees up + But !!! do_command calls free_root at the end of every query and frees up all the sql_alloc'ed memory. It's harder to work around... */ @@ -72,7 +72,11 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) if (*ptr) { VOID(pthread_mutex_lock(&LOCK_open)); - close_thread_table(thd, ptr); + if (close_thread_table(thd, ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } VOID(pthread_mutex_unlock(&LOCK_open)); } else @@ -89,8 +93,11 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) int mysql_ha_closeall(THD *thd, TABLE_LIST *tables) { TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->real_name, 0); - if (*ptr) - close_thread_table(thd, ptr); + if (*ptr && close_thread_table(thd, ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } return 0; } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 02fc8591370..6af4ffde0e1 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -599,7 +599,7 @@ SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables, { cond->fix_fields(thd, tables, &cond); // can never fail SQL_SELECT *res= make_select(table,0,0,cond,error); - return (*error || (res && res->check_quick(0, HA_POS_ERROR))) ? 0 : res; + return (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR))) ? 0 : res; } /* @@ -627,6 +627,8 @@ SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, Item *cond= new Item_func_like(new Item_field(pfname), new Item_string(mask,mlen,pfname->charset()), (char*) "\\"); + if (thd->is_fatal_error) + return 0; // OOM return prepare_simple_select(thd,cond,tables,table,error); } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 0ad66beec2e..9077d4c6a2d 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -240,9 +240,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, info.handle_duplicates=duplic; info.update_fields=&update_fields; info.update_values=&update_values; - // Don't count warnings for simple inserts - if (values_list.elements > 1 || (thd->options & OPTION_WARNINGS)) - thd->count_cuted_fields = 1; + /* + Count warnings for all inserts. + For single line insert, generate an error if try to set a NOT NULL field + to NULL + */ + thd->count_cuted_fields= ((values_list.elements == 1) ? + CHECK_FIELD_ERROR_FOR_NULL : + CHECK_FIELD_WARN); thd->cuted_fields = 0L; table->next_number_field=table->found_next_number_field; @@ -394,7 +399,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, } thd->proc_info="end"; table->next_number_field=0; - thd->count_cuted_fields=0; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; thd->next_insert_id=0; // Reset this if wrongly used if (duplic != DUP_ERROR) table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); @@ -1391,7 +1396,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) restore_record(table,default_values); // Get empty record table->next_number_field=table->found_next_number_field; - thd->count_cuted_fields=1; // calc cuted fields + thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0; if (info.handle_duplicates != DUP_REPLACE) table->file->extra(HA_EXTRA_WRITE_CACHE); @@ -1409,7 +1414,7 @@ select_insert::~select_insert() table->next_number_field=0; table->file->extra(HA_EXTRA_RESET); } - thd->count_cuted_fields=0; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; } @@ -1548,6 +1553,14 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) if (!table) DBUG_RETURN(-1); // abort() deletes table + if (table->fields < values.elements) + { + my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, + ER(ER_WRONG_VALUE_COUNT_ON_ROW), + MYF(0),1); + DBUG_RETURN(-1); + } + /* First field to copy */ field=table->field+table->fields - values.elements; @@ -1559,7 +1572,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) table->next_number_field=table->found_next_number_field; restore_record(table,default_values); // Get empty record - thd->count_cuted_fields=1; // count warnings + thd->count_cuted_fields= CHECK_FIELD_WARN; // count warnings thd->cuted_fields=0; if (info.handle_duplicates == DUP_IGNORE || info.handle_duplicates == DUP_REPLACE) @@ -1606,7 +1619,7 @@ bool select_create::send_eof() */ if (!table->tmp_table) hash_delete(&open_cache,(byte*) table); - lock=0; + lock=0; table=0; VOID(pthread_mutex_unlock(&LOCK_open)); } @@ -1627,7 +1640,8 @@ void select_create::abort() enum db_type table_type=table->db_type; if (!table->tmp_table) hash_delete(&open_cache,(byte*) table); - quick_rm_table(table_type,db,name); + if (!create_info->table_existed) + quick_rm_table(table_type,db,name); table=0; } VOID(pthread_mutex_unlock(&LOCK_open)); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 80d698dfc26..5b05bf096cb 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1097,6 +1097,16 @@ void st_select_lex_node::exclude() */ } + +/* + Exclude level of current unit from tree of SELECTs + + SYNOPSYS + st_select_lex_unit::exclude_level() + + NOTE: units which belong to current will be brought up on level of + currernt unit +*/ void st_select_lex_unit::exclude_level() { SELECT_LEX_UNIT *units= 0, **units_last= &units; @@ -1125,6 +1135,30 @@ void st_select_lex_unit::exclude_level() (*prev)= next; } + +/* + Exclude subtree of current unit from tree of SELECTs + + SYNOPSYS + st_select_lex_unit::exclude_tree() +*/ +void st_select_lex_unit::exclude_tree() +{ + SELECT_LEX_UNIT *units= 0, **units_last= &units; + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + if (sl->link_prev && (*sl->link_prev= sl->link_next)) + sl->link_next->link_prev= sl->link_prev; + + for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit()) + { + u->exclude_level(); + } + } + (*prev)= next; +} + + /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from this to 'last' as dependent @@ -1135,7 +1169,6 @@ void st_select_lex_unit::exclude_level() NOTE 'last' should be reachable from this st_select_lex_node - */ void st_select_lex::mark_as_dependent(SELECT_LEX *last) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0166951ab9d..7545f525082 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -321,6 +321,7 @@ public: st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; } st_select_lex* return_after_parsing() { return return_to; } void exclude_level(); + void exclude_tree(); /* UNION methods */ int prepare(THD *thd, select_result *result, bool tables_and_fields_initied); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 0a5c544c2e7..0e7895689b5 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -252,7 +252,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, restore_record(table,default_values); - thd->count_cuted_fields=1; /* calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ thd->cuted_fields=0L; if (ex->line_term->length() && field_term->length()) { @@ -293,7 +293,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (file >= 0) my_close(file,MYF(0)); free_blobs(table); /* if pack_blob was used */ table->copy_blobs=0; - thd->count_cuted_fields=0; /* Don`t calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* We must invalidate the table in query cache before binlog writing and diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 248dfc0e47a..e8870b20d99 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3407,7 +3407,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, /* grant_option is set if there exists a single table or column grant */ if (db_access == want_access || ((grant_option && !dont_check_global_grants) && - !(want_access & ~TABLE_ACLS))) + !(want_access & ~(db_access | TABLE_ACLS)))) DBUG_RETURN(FALSE); /* Ok */ if (!no_errors) net_printf(thd,ER_DBACCESS_DENIED_ERROR, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index dd8d5613880..522879c863a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -888,12 +888,15 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) { MEM_ROOT thd_root= thd->mem_root; PREP_STMT stmt; + SELECT_LEX *sl; DBUG_ENTER("mysql_stmt_prepare"); bzero((char*) &stmt, sizeof(stmt)); stmt.stmt_id= ++thd->current_stmt_id; - init_sql_alloc(&stmt.mem_root, 8192, 8192); + init_sql_alloc(&stmt.mem_root, + thd->variables.query_alloc_block_size, + thd->variables.query_prealloc_size); stmt.thd= thd; stmt.thd->mem_root= stmt.mem_root; @@ -908,7 +911,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) my_pthread_setprio(pthread_self(),WAIT_PRIOR); // save WHERE clause pointers to avoid damaging they by optimisation - for (SELECT_LEX *sl= thd->lex.all_selects_list; + for (sl= thd->lex.all_selects_list; sl; sl= sl->next_select_in_list()) { @@ -943,8 +946,9 @@ err: void mysql_stmt_execute(THD *thd, char *packet) { - ulong stmt_id= uint4korr(packet); - PREP_STMT *stmt; + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + SELECT_LEX *sl; DBUG_ENTER("mysql_stmt_execute"); if (!(stmt=find_prepared_statement(thd, stmt_id, "execute"))) @@ -963,11 +967,13 @@ void mysql_stmt_execute(THD *thd, char *packet) LEX thd_lex= thd->lex; thd->lex= stmt->lex; - for (SELECT_LEX *sl= stmt->lex.all_selects_list; + for (sl= stmt->lex.all_selects_list; sl; sl= sl->next_select_in_list()) { - // copy WHERE clause pointers to avoid damaging they by optimisation + /* + Copy WHERE clause pointers to avoid damaging they by optimisation + */ if (sl->prep_where) sl->where= sl->prep_where->copy_andor_structure(thd); DBUG_ASSERT(sl->join == 0); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5bd494c723d..f25b012a0fa 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1577,7 +1577,8 @@ err: Approximate how many records will be used in each table *****************************************************************************/ -static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table, +static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select, + TABLE *table, const key_map& keys,ha_rows limit) { int error; @@ -1586,7 +1587,7 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table, { select->head=table; table->reginfo.impossible_range=0; - if ((error=select->test_quick_select(keys,(table_map) 0,limit)) + if ((error=select->test_quick_select(thd, keys,(table_map) 0,limit)) == 1) DBUG_RETURN(select->quick->records); if (error == -1) @@ -1874,8 +1875,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, found_const_table_map, s->on_expr ? s->on_expr : conds, &error); - records= get_quick_record_count(select,s->table, s->const_keys, - join->row_limit); + records= get_quick_record_count(join->thd, select, s->table, + s->const_keys, join->row_limit); s->quick=select->quick; s->needed_reg=select->needed_reg; select->quick=0; @@ -3226,9 +3227,9 @@ store_val_in_field(Field *field,Item *item) bool error; THD *thd=current_thd; ha_rows cuted_fields=thd->cuted_fields; - thd->count_cuted_fields=1; + thd->count_cuted_fields= CHECK_FIELD_WARN; error= item->save_in_field(field, 1); - thd->count_cuted_fields=0; + thd->count_cuted_fields= CHECK_FIELD_IGNORE; return error || cuted_fields != thd->cuted_fields; } @@ -3386,7 +3387,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) /* Join with outer join condition */ COND *orig_cond=sel->cond; sel->cond=and_conds(sel->cond,tab->on_expr); - if (sel->test_quick_select(tab->keys, + if (sel->test_quick_select(join->thd, tab->keys, used_tables & ~ current_map, (join->select_options & OPTION_FOUND_ROWS ? @@ -3399,7 +3400,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) */ sel->cond=orig_cond; if (!tab->on_expr || - sel->test_quick_select(tab->keys, + sel->test_quick_select(join->thd, tab->keys, used_tables & ~ current_map, (join->select_options & OPTION_FOUND_ROWS ? @@ -4882,6 +4883,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, recinfo->type=FIELD_NORMAL; if (!--hidden_field_count) null_count=(null_count+7) & ~7; // move to next byte + + // fix table name in field entry + field->table_name= table->table_name; } param->copy_field_end=copy; @@ -5845,7 +5849,8 @@ test_if_quick_select(JOIN_TAB *tab) { delete tab->select->quick; tab->select->quick=0; - return tab->select->test_quick_select(tab->keys,(table_map) 0,HA_POS_ERROR); + return tab->select->test_quick_select(tab->join->thd, tab->keys, + (table_map) 0, HA_POS_ERROR); } @@ -6949,7 +6954,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order, For impossible ranges (like when doing a lookup on NULL on a NOT NULL field, quick will contain an empty record set. */ - if (!(select->quick=get_ft_or_quick_select_for_ref(table, tab))) + if (!(select->quick=get_ft_or_quick_select_for_ref(tab->join->thd, + table, tab))) goto err; } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a026bd5276d..3be829acbda 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1073,7 +1073,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) MODE_ORACLE | MODE_MSSQL | MODE_DB2 | - MODE_SAPDB | + MODE_MAXDB | MODE_ANSI)) != 0; my_bool limited_mysql_mode= (thd->variables.sql_mode & (MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 | diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5112dfb59cd..7559f2a86e2 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -886,6 +886,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, key_info->name=(char*) key_name; } } + if (!key_info->name || check_column_name(key_info->name)) + { + my_error(ER_WRONG_INDEX_NAME, MYF(0), key_info->name); + DBUG_RETURN(-1); + } if (!(key_info->flags & HA_NULL_PART_KEY)) unique_key=1; key_info->key_length=(uint16) key_length; @@ -926,7 +931,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, && find_temporary_table(thd,db,table_name)) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + create_info->table_existed= 1; // Mark that table existed DBUG_RETURN(0); + } my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); DBUG_RETURN(-1); } @@ -938,14 +946,18 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, if (!access(path,F_OK)) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + create_info->table_existed= 1; // Mark that table existed error= 0; + } else - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto end; } } thd->proc_info="creating table"; + create_info->table_existed= 0; // Mark that table is created if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) create_info->data_file_name= create_info->index_file_name= 0; @@ -2330,7 +2342,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (use_timestamp) new_table->time_stamp=0; new_table->next_number_field=new_table->found_next_number_field; - thd->count_cuted_fields=1; // calc cuted fields + thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0L; thd->proc_info="copy to tmp table"; next_insert_id=thd->next_insert_id; // Remember for loggin @@ -2340,7 +2352,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, handle_duplicates, order_num, order, &copied, &deleted); thd->last_insert_id=next_insert_id; // Needed for correct log - thd->count_cuted_fields=0; // Don`t calc cuted fields + thd->count_cuted_fields= CHECK_FIELD_IGNORE; new_table->time_stamp=save_time_stamp; if (table->tmp_table) @@ -2749,9 +2761,9 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) while (!t->file->rnd_next(t->record[0])) { ha_checksum row_crc= 0; - if (t->record[0] != t->field[0]->ptr) + if (t->record[0] != (byte*) t->field[0]->ptr) row_crc= my_checksum(row_crc, t->record[0], - t->field[0]->ptr - t->record[0]); + ((byte*) t->field[0]->ptr) - t->record[0]); for (uint i= 0; i < t->fields; i++ ) { @@ -2760,10 +2772,11 @@ int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) { String tmp; f->val_str(&tmp,&tmp); - row_crc= my_checksum(row_crc, tmp.ptr(), tmp.length()); + row_crc= my_checksum(row_crc, (byte*) tmp.ptr(), tmp.length()); } else - row_crc= my_checksum(row_crc, f->ptr, f->pack_length()); + row_crc= my_checksum(row_crc, (byte*) f->ptr, + f->pack_length()); } crc+= row_crc; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 006a324f16d..d8d6d716abe 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -22,6 +22,7 @@ #include "sql_select.h" #include <hash.h> #include <thr_alarm.h> +#include <malloc.h> /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; @@ -301,6 +302,8 @@ void mysql_print_status(THD *thd) printf("\nStatus information:\n\n"); my_getwd(current_dir, sizeof(current_dir),MYF(0)); printf("Current dir: %s\n", current_dir); + printf("Running threads: %d Stack size: %ld\n", thread_count, + (long) thread_stack); if (thd) thd->proc_info="locks"; thr_print_locks(); // Write some debug info @@ -366,6 +369,34 @@ Next alarm time: %lu\n", thd->proc_info="malloc"; my_checkmalloc(); TERMINATE(stdout); // Write malloc information + +#ifdef HAVE_MALLINFO + struct mallinfo info= mallinfo(); + printf("\nMemory status:\n\ +Non-mmapped space allocated from system: %d\n\ +Number of free chunks: %d\n\ +Number of fastbin blocks: %d\n\ +Number of mmapped regions: %d\n\ +Space in mmapped regions: %d\n\ +Maximum total allocated space: %d\n\ +Space available in freed fastbin blocks: %d\n\ +Total allocated space: %d\n\ +Total free space: %d\n\ +Top-most, releasable space: %d\n\ +Estimated memory (with thread stack): %ld\n", + (int) info.arena , + (int) info.ordblks, + (int) info.smblks, + (int) info.hblks, + (int) info.hblkhd, + (int) info.usmblks, + (int) info.fsmblks, + (int) info.uordblks, + (int) info.fordblks, + (int) info.keepcost, + (long) (thread_count * thread_stack + info.hblkhd + info.arena)); +#endif + puts(""); if (thd) thd->proc_info=0; } diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index c237b023e7b..337f2540a39 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -128,7 +128,7 @@ void udf_init() my_rwlock_init(&THR_LOCK_udf,NULL); - init_sql_alloc(&mem, 1024,0); + init_sql_alloc(&mem, UDF_ALLOC_BLOCK_SIZE, 0); THD *new_thd = new THD; if (!new_thd || hash_init(&udf_hash,system_charset_info,32,0,0,get_hash_key, NULL, 0)) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4cf5f740d17..9214894e214 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -152,7 +152,7 @@ int mysql_update(THD *thd, table->used_keys.clear_all(); select=make_select(table,0,0,conds,&error); if (error || - (select && select->check_quick(safe_update, limit)) || !limit) + (select && select->check_quick(thd, safe_update, limit)) || !limit) { delete select; free_underlaid_joins(thd, &thd->lex.select_lex); @@ -295,7 +295,7 @@ int mysql_update(THD *thd, init_read_record(&info,thd,table,select,0,1); updated= found= 0; - thd->count_cuted_fields=1; /* calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_WARN; /* calc cuted fields */ thd->cuted_fields=0L; thd->proc_info="Updating"; query_id=thd->query_id; @@ -386,7 +386,7 @@ int mysql_update(THD *thd, thd->insert_id_used ? thd->insert_id() : 0L,buff); DBUG_PRINT("info",("%d records updated",updated)); } - thd->count_cuted_fields=0; /* calc cuted fields */ + thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ free_io_cache(table); DBUG_RETURN(0); @@ -492,7 +492,7 @@ int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *unit) uint i, max_fields; DBUG_ENTER("multi_update::prepare"); - thd->count_cuted_fields=1; + thd->count_cuted_fields= CHECK_FIELD_WARN; thd->cuted_fields=0L; thd->proc_info="updating main table"; @@ -732,7 +732,7 @@ multi_update::~multi_update() } if (copy_field) delete [] copy_field; - thd->count_cuted_fields=0; // Restore this setting + thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting if (!trans_safe) thd->options|=OPTION_STATUS_NO_TRANS_UPDATE; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f7cd22545c5..04f5043839f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -78,6 +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; st_select_lex *select_lex; chooser_compare_func_creator boolfunc2creator; } @@ -482,6 +483,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token GEOMETRYCOLLECTION %token GROUP_CONCAT_SYM %token GROUP_UNIQUE_USERS +%token GET_FORMAT %token HOUR_MICROSECOND_SYM %token HOUR_MINUTE_SYM %token HOUR_SECOND_SYM @@ -644,6 +646,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 <interval> interval %type <db_type> table_types @@ -1254,7 +1257,7 @@ type: | TIME_SYM { $$=FIELD_TYPE_TIME; } | TIMESTAMP { - if (YYTHD->variables.sql_mode & MODE_SAPDB) + if (YYTHD->variables.sql_mode & MODE_MAXDB) $$=FIELD_TYPE_DATETIME; else $$=FIELD_TYPE_TIMESTAMP; @@ -2583,6 +2586,8 @@ simple_expr: { $$= new Item_func_spatial_collection(* $3, Geometry::wkbGeometryCollection, Geometry::wkbPoint); } + | GET_FORMAT '(' datetime_format_type ',' expr ')' + { $$= new Item_func_get_format($3, $5); } | HOUR_SYM '(' expr ')' { $$= new Item_func_hour($3); } | IF '(' expr ',' expr ',' expr ')' @@ -3196,6 +3201,11 @@ 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;}; + table_alias: /* empty */ | AS @@ -4543,6 +4553,7 @@ keyword: | FLUSH_SYM {} | GEOMETRY_SYM {} | GEOMETRYCOLLECTION {} + | GET_FORMAT {} | GRANTS {} | GLOBAL_SYM {} | HANDLER_SYM {} diff --git a/sql/structs.h b/sql/structs.h index 05ebdba7a37..d9be230c049 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -24,6 +24,11 @@ typedef struct st_date_format { /* How to print date */ uint pos[6]; /* Positions to YY.MM.DD HH:MM:SS */ } DATE_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 */ @@ -110,8 +115,8 @@ typedef struct st_read_record { /* Parameter to read_record */ bool print_error, ignore_not_found_rows; } READ_RECORD; -enum timestamp_type { TIMESTAMP_NONE, TIMESTAMP_DATE, TIMESTAMP_FULL, - TIMESTAMP_TIME }; +enum timestamp_type { TIMESTAMP_NONE, WRONG_TIMESTAMP_FULL, TIMESTAMP_DATE, TIMESTAMP_FULL, + TIMESTAMP_TIME}; typedef struct st_time { uint year,month,day,hour,minute,second; diff --git a/sql/table.cc b/sql/table.cc index 0281046f6a0..24c5b941c0b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -90,7 +90,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->db_stat = db_stat; error=1; - init_sql_alloc(&outparam->mem_root,1024,0); + init_sql_alloc(&outparam->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root); diff --git a/sql/time.cc b/sql/time.cc index 70ae8dcd8ed..f2e41afa560 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -27,6 +27,10 @@ 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) @@ -316,10 +320,12 @@ ulong convert_month_to_period(ulong month) */ timestamp_type -str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) +str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date,THD *thd) { - uint field_length,year_length,digits,i,number_of_fields,date[7]; + 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; const char *end=str+length; bool found_delimitier= 0; @@ -336,24 +342,32 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) (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); - year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; - field_length=year_length-1; + + if (pos == end || digits>=12) + { + is_internal_format= 1; + year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2; + field_length=year_length-1; + date_len[0]= year_length; + } not_zero_date= 0; for (i=0 ; i < 6 && 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]) && - field_length--) + while (str != end && my_isdigit(&my_charset_latin1,str[0]) + && (is_internal_format && field_length-- || !is_internal_format) ) { tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0'); str++; + if (!is_internal_format) + date_len[i]+= 1; } - if (found_delimitier && (int) field_length < 0) - { - /* The number can't match any valid date or datetime string */ + if (i == 2 && *str == '.') DBUG_RETURN(TIMESTAMP_NONE); - } date[i]=tmp_value; not_zero_date|= tmp_value; if (i == 2 && str != end && *str == 'T') @@ -371,7 +385,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) found_delimitier=1; // Should be a 'normal' date } } - field_length=1; // Rest fields can only be 2 + if (is_internal_format) + field_length=1; // Rest fields can only be 2 } /* Handle second fractions */ if (i == 6 && (uint) (end-str) >= 2 && *str == '.' && @@ -389,14 +404,69 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) else date[6]=0; - if (year_length == 2 && i >=2 && (date[1] || date[2])) - date[0]+= (date[0] < YY_PART_YEAR ? 2000 : 1900); + while (str != end && (my_ispunct(&my_charset_latin1,*str) || + my_isspace(&my_charset_latin1,*str))) + str++; + + uint add_hours= 0; + if (!my_strnncoll(&my_charset_latin1, + (const uchar *)str, 2, + (const uchar *)"PM", 2)) + add_hours= 12; + number_of_fields=i; while (i < 6) date[i++]=0; - if (number_of_fields < 3 || date[1] > 12 || - date[2] > 31 || date[3] > 23 || date[4] > 59 || date[5] > 59 || - (!fuzzy_date && (date[1] == 0 || date[2] == 0))) + + if (!is_internal_format) + { + byte *frm_pos; + + 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 + { + 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; + } + } + + 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->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 (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))) { /* Only give warning for a zero date if there is some garbage after */ if (!not_zero_date) // If zero date @@ -411,53 +481,46 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) } } if (not_zero_date) - current_thd->cuted_fields++; - DBUG_RETURN(TIMESTAMP_NONE); + thd->cuted_fields++; + DBUG_RETURN(WRONG_TIMESTAMP_FULL); } - if (str != end && current_thd->count_cuted_fields) + if (str != end && thd->count_cuted_fields) { for (; str != end ; str++) { if (!my_isspace(&my_charset_latin1,*str)) { - current_thd->cuted_fields++; + thd->cuted_fields++; break; } } } - 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; + DBUG_RETURN(l_time->time_type= (number_of_fields <= 3 ? TIMESTAMP_DATE : TIMESTAMP_FULL)); } -time_t str_to_timestamp(const char *str,uint length) +time_t str_to_timestamp(const char *str,uint length, THD *thd) { TIME l_time; long not_used; - if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE) + if (str_to_TIME(str,length,&l_time,0,thd) <= WRONG_TIMESTAMP_FULL) return(0); if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR) { - current_thd->cuted_fields++; + thd->cuted_fields++; return(0); } return(my_gmt_sec(&l_time, ¬_used)); } -longlong str_to_datetime(const char *str,uint length,bool fuzzy_date) +longlong str_to_datetime(const char *str,uint length,bool fuzzy_date, THD *thd) { TIME l_time; - if (str_to_TIME(str,length,&l_time,fuzzy_date) == TIMESTAMP_NONE) + if (str_to_TIME(str,length,&l_time,fuzzy_date,thd) <= WRONG_TIMESTAMP_FULL) return(0); return (longlong) (l_time.year*LL(10000000000) + l_time.month*LL(100000000)+ @@ -484,12 +547,13 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date) 1 error */ -bool str_to_time(const char *str,uint length,TIME *l_time) +bool str_to_time(const char *str,uint length,TIME *l_time, THD *thd) { long date[5],value; const char *end=str+length; 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 && @@ -507,8 +571,11 @@ bool str_to_time(const char *str,uint length,TIME *l_time) /* Check first if this is a full TIMESTAMP */ if (length >= 12) { // Probably full timestamp - if (str_to_TIME(str,length,l_time,1) == TIMESTAMP_FULL) - return 0; // Was an ok 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; } /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ @@ -533,7 +600,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time) found_days=1; str++; // Skip space; } - else if ((end-str) > 1 && *str == ':' && + else if ((end-str) > 1 && *str == frm_pos[7] && my_isdigit(&my_charset_latin1,str[1])) { date[0]=0; // Assume we found hours @@ -559,8 +626,8 @@ bool str_to_time(const char *str,uint length,TIME *l_time) 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 != ':' || - !my_isdigit(&my_charset_latin1,str[1])) + if (state == 4 || (end-str) < 2 || *str != frm_pos[7] || + !my_isdigit(&my_charset_latin1,str[1])) break; str++; // Skip ':' } @@ -577,7 +644,6 @@ bool str_to_time(const char *str,uint length,TIME *l_time) else bzero((char*) (date+state), sizeof(long)*(4-state)); } - fractional: /* Get fractional second part */ if ((end-str) >= 2 && *str == '.' && my_isdigit(&my_charset_latin1,str[1])) @@ -593,6 +659,20 @@ bool str_to_time(const char *str,uint length,TIME *l_time) 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) + { + uint days_i= date[1]/24; + uint hours_i= date[1]%24; + date[1]= hours_i%12 + 12 + 24*days_i; + } + /* Some simple checks */ if (date[2] >= 60 || date[3] >= 60) { @@ -601,9 +681,9 @@ bool str_to_time(const char *str,uint length,TIME *l_time) } l_time->month=0; l_time->day=date[0]; - l_time->hour=date[1]; - l_time->minute=date[2]; - l_time->second=date[3]; + 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->time_type= TIMESTAMP_TIME; @@ -648,3 +728,165 @@ void calc_time_from_sec(TIME *to, long seconds, long microseconds) to->second= t_seconds%60L; to->second_part= 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; +} + + +bool parse_datetime_formats(datetime_format_types format_type, + const char *format_str, uint format_length, + byte *dt_pos) +{ + 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; + + const char *ptr=format_str; + const char *end=ptr+format_length; + bool need_p= 0; + + for (; ptr != end; ptr++) + { + if (*ptr == '%' && ptr+1 != end) + { + switch (*++ptr) { + case 'y': + case 'Y': + if (dt_pos[0] > -1) + return 1; + dt_pos[0]= pos; + break; + case 'c': + case 'm': + if (dt_pos[1] > -1) + return 1; + dt_pos[1]= pos; + break; + case 'd': + case 'e': + if (dt_pos[2] > -1) + return 1; + dt_pos[2]= pos; + 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'); + break; + case 'i': + if (dt_pos[4] > -1) + return 1; + dt_pos[4]= pos; + break; + case 's': + case 'S': + if (dt_pos[5] > -1) + return 1; + dt_pos[5]= pos; + 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; + break; + default: + return 1; + } + if (dt_pos[6] == -1) + pos++; + } + } + + 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; + + /* + Check for valid separators between date/time parst + */ + uint tmp_len= format_length; + if (dt_pos[6] == 1) + { + end= end - 2; + if (my_ispunct(&my_charset_latin1, *end) || my_isspace(&my_charset_latin1, *end)) + end--; + tmp_len= end - format_str; + } + 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))) + { + if (format_type == TIME_FORMAT_TYPE && tmp_len == 8) + { + if (*(format_str+2) != *(format_str+5)) + return 1; + dt_pos[7]= *(format_str+2); + } + return 0; + } + break; + case DATETIME_FORMAT_TYPE: + if ((tmp_len == 12 && + !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)))) + return 0; + break; + } + return 1; +} diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index cd1b1399506..5a785552b45 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -270,9 +270,9 @@ static int my_strnxfrm_bin(CHARSET_INFO *cs __attribute__((unused)), static uint my_instr_bin(CHARSET_INFO *cs __attribute__((unused)), - const char *big, uint b_length, - const char *small, uint s_length, - my_match_t *match, uint nmatch) + const char *b, uint b_length, + const char *s, uint s_length, + my_match_t *match, uint nmatch) { register const uchar *str, *search, *end, *search_end; @@ -289,10 +289,10 @@ uint my_instr_bin(CHARSET_INFO *cs __attribute__((unused)), return 1; /* Empty string is always found */ } - str= (const uchar*) big; - search= (const uchar*) small; - end= (const uchar*) big+b_length-s_length+1; - search_end= (const uchar*) small + s_length; + str= (const uchar*) b; + search= (const uchar*) s; + end= (const uchar*) b+b_length-s_length+1; + search_end= (const uchar*) s + s_length; skipp: while (str != end) @@ -311,7 +311,7 @@ skipp: if (nmatch > 0) { match[0].beg= 0; - match[0].end= str- (const uchar*)big-1; + match[0].end= str- (const uchar*)b-1; match[0].mblen= match[0].end; if (nmatch > 1) diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index 813a33fd229..271c56b8a0a 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -275,11 +275,11 @@ uint my_charpos_mb(CHARSET_INFO *cs __attribute__((unused)), } uint my_instr_mb(CHARSET_INFO *cs, - const char *big, uint b_length, - const char *small, uint s_length, + const char *b, uint b_length, + const char *s, uint s_length, my_match_t *match, uint nmatch) { - register const char *end, *big0; + register const char *end, *b0; int res= 0; if (s_length <= b_length) @@ -295,20 +295,20 @@ uint my_instr_mb(CHARSET_INFO *cs, return 1; /* Empty string is always found */ } - big0= big; - end= big+b_length-s_length+1; + b0= b; + end= b+b_length-s_length+1; - while (big < end) + while (b < end) { int mblen; - if (!cs->coll->strnncoll(cs, (unsigned char*) big, s_length, - (unsigned char*) small, s_length)) + if (!cs->coll->strnncoll(cs, (unsigned char*) b, s_length, + (unsigned char*) s, s_length)) { if (nmatch) { match[0].beg= 0; - match[0].end= big-big0; + match[0].end= b-b0; match[0].mblen= res; if (nmatch > 1) { @@ -319,8 +319,8 @@ uint my_instr_mb(CHARSET_INFO *cs, } return 2; } - mblen= (mblen= my_ismbchar(cs, big, end)) ? mblen : 1; - big+= mblen; + mblen= (mblen= my_ismbchar(cs, b, end)) ? mblen : 1; + b+= mblen; b_length-= mblen; res++; } diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index ed1d2c77049..6f77d6f3e16 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -1031,8 +1031,8 @@ uint my_lengthsp_8bit(CHARSET_INFO *cs __attribute__((unused)), uint my_instr_simple(CHARSET_INFO *cs, - const char *big, uint b_length, - const char *small, uint s_length, + const char *b, uint b_length, + const char *s, uint s_length, my_match_t *match, uint nmatch) { register const uchar *str, *search, *end, *search_end; @@ -1050,10 +1050,10 @@ uint my_instr_simple(CHARSET_INFO *cs, return 1; /* Empty string is always found */ } - str= (const uchar*) big; - search= (const uchar*) small; - end= (const uchar*) big+b_length-s_length+1; - search_end= (const uchar*) small + s_length; + str= (const uchar*) b; + search= (const uchar*) s; + end= (const uchar*) b+b_length-s_length+1; + search_end= (const uchar*) s + s_length; skipp: while (str != end) @@ -1072,7 +1072,7 @@ skipp: if (nmatch > 0) { match[0].beg= 0; - match[0].end= str- (const uchar*)big-1; + match[0].end= str- (const uchar*)b-1; match[0].mblen= match[0].end; if (nmatch > 1) |