From 9b16dd8962408ac4483cd3a1bf4264b1e81d2780 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Aug 2003 14:39:54 +0300 Subject: [PATCH 1/6] fixed union unlocking problem (BUG#906) mysql-test/r/subselect.result: test of union unlocking problem mysql-test/t/subselect.test: test of union unlocking problem sql/sql_union.cc: prohibit unlocking all tables by fake select execution --- mysql-test/r/subselect.result | 12 ++++++++++++ mysql-test/t/subselect.test | 16 +++++++++++++++- sql/sql_union.cc | 3 ++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index bba86ff8891..fbf037d5147 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1225,3 +1225,15 @@ a (select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 an 2 2 1 2 drop table t1,t2,t3; +create table t1 (a int) type=innodb; +create table t2 (a int) type=innodb; +create table t3 (a int) type=innodb; +insert into t1 values (1),(2),(3),(4); +insert into t2 values (10),(20),(30),(40); +insert into t3 values (1),(2),(10),(50); +select a from t3 where t3.a in (select a from t1 where a <= 3 union select * from t2 where a <= 30); +a +1 +2 +10 +drop table t1,t2; diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 66d8dd2bc32..3896676f3ab 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -807,6 +807,7 @@ INSERT INTO t1 VALUES("2f6161e879db43c1a5b82c21ddc49089", "Default", "System", " INSERT INTO t1 VALUES("c373e9f5ad0791724315444553544200", "AddDocumentTest", "admin", "2003-06-09 10:51:25", "Movie Reviews", "0", "2003-06-09 10:51:25", "admin", "0", "2f6161e879db43c1a5b82c21ddc49089", "03eea05112b845949f3fd03278b5fe43", NULL); SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t1.FOLDERNAME = 'Level1'); drop table t1; + # # alloc_group_fields() working # @@ -817,4 +818,17 @@ insert into t1 values (0,100),(1,2), (1,3), (2,2), (2,7), (2,-1), (3,10); insert into t2 values (0,0), (1,1), (2,1), (3,1), (4,1); insert into t3 values (3,3), (2,2), (1,1); select a,(select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3; -drop table t1,t2,t3;s +drop table t1,t2,t3; + +# +# UNION unlocking test +# +create table t1 (a int) type=innodb; +create table t2 (a int) type=innodb; +create table t3 (a int) type=innodb; +insert into t1 values (1),(2),(3),(4); +insert into t2 values (10),(20),(30),(40); +insert into t3 values (1),(2),(10),(50); +select a from t3 where t3.a in (select a from t1 where a <= 3 union select * from t2 where a <= 30); +drop table t1,t2; + diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 724cc658b15..bbf0781bc19 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -351,7 +351,8 @@ int st_select_lex_unit::exec() global_parameters->order_list.elements, (ORDER*)global_parameters->order_list.first, (ORDER*) NULL, NULL, (ORDER*) NULL, - thd->options, result, this, fake_select, 0); + thd->options | SELECT_NO_UNLOCK, + result, this, fake_select, 0); if (found_rows_for_union && !res) thd->limit_found_rows = (ulonglong)table->file->records; fake_select->exclude(); From f3f6e5e9b2ecfef9bf6c5e7558af2481e30385ad Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 9 Aug 2003 17:10:58 +0300 Subject: [PATCH 2/6] test for BUG#969 --- mysql-test/r/derived.result | 32 ++++++++++++++++++++++++++++++++ mysql-test/t/derived.test | 16 ++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 61937ba9266..f3b09164dda 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -160,3 +160,35 @@ id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 3 2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary; Using filesort drop table t1; +create table t1 (mat_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, matintnum CHAR(6) NOT NULL, test MEDIUMINT UNSIGNED NULL); +create table t2 (mat_id MEDIUMINT UNSIGNED NOT NULL, pla_id MEDIUMINT UNSIGNED NOT NULL); +insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd', 4), (NULL, 'e', 5), (NULL, 'f', 6), (NULL, 'g', 7), (NULL, 'h', 8), (NULL, 'i', 9); +insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); +SELECT d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +pla_id mat_id +100 1 +101 1 +102 1 +103 2 +104 2 +105 3 +SELECT d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +pla_id test +100 1 +101 1 +102 1 +103 2 +104 2 +105 3 +explain SELECT d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY m2 ALL NULL NULL NULL NULL 9 +1 PRIMARY ALL NULL NULL NULL NULL 6 Using where +2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort +2 DERIVED m2 index NULL PRIMARY 3 NULL 9 Using index +explain SELECT d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY m2 ALL NULL NULL NULL NULL 9 +1 PRIMARY ALL NULL NULL NULL NULL 6 Using where +2 DERIVED mp ALL NULL NULL NULL NULL 9 Using temporary; Using filesort +2 DERIVED m2 index NULL PRIMARY 3 NULL 9 Using index diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 4f0af1edbaa..c998de7ae6e 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -74,3 +74,19 @@ create table t1 (id int); insert into t1 values (1),(2),(3); describe select * from (select * from t1 group by id) bar; drop table t1; + +# +# test->used_keys test for derived tables +# +create table t1 (mat_id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, matintnum CHAR(6) NOT NULL, test MEDIUMINT UNSIGNED NULL); +create table t2 (mat_id MEDIUMINT UNSIGNED NOT NULL, pla_id MEDIUMINT UNSIGNED NOT NULL); +insert into t1 values (NULL, 'a', 1), (NULL, 'b', 2), (NULL, 'c', 3), (NULL, 'd', 4), (NULL, 'e', 5), (NULL, 'f', 6), (NULL, 'g', 7), (NULL, 'h', 8), (NULL, 'i', 9); +insert into t2 values (1, 100), (1, 101), (1, 102), (2, 100), (2, 103), (2, 104), (3, 101), (3, 102), (3, 105); + +SELECT d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +SELECT d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; + +explain SELECT d.pla_id, m2.mat_id FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; +explain SELECT d.pla_id, m2.test FROM t1 m2 INNER JOIN (SELECT mp.pla_id, MIN(m1.matintnum) AS matintnum FROM t2 mp INNER JOIN t1 m1 ON mp.mat_id=m1.mat_id GROUP BY mp.pla_id) d ON d.matintnum=m2.matintnum; + +drop table t1,t2 From 0960c3eb26861238d9102845d370f3eb66d91290 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Aug 2003 18:18:34 +0500 Subject: [PATCH 3/6] Fix: create table t1 (a char(10) character set cp1251) SELECT _koi8r'blabla' as a The above query created a field of koi8r charset, not cp1251 Change: CREATE TABLE a (a CHAR(1) CHARACTER SET utf8) Length now means character length, not byte length. The above creates a field that guarantees can store a multibyte value 1 character long. For utf8 the above creates a field that can store 3 bytes. --- mysql-test/r/ctype_mb.result | 21 +++++++++++++ mysql-test/r/ctype_recoding.result | 14 +++++++++ mysql-test/r/func_system.result | 6 ++-- mysql-test/t/ctype_mb.test | 8 +++++ mysql-test/t/ctype_recoding.test | 7 +++++ sql/field.cc | 24 +++++++++++++-- sql/field.h | 1 + sql/item.h | 4 +-- sql/sql_parse.cc | 16 ++++++++-- sql/sql_table.cc | 47 +++++++++++++++++++----------- sql/unireg.h | 7 ++++- 11 files changed, 127 insertions(+), 28 deletions(-) create mode 100644 mysql-test/r/ctype_mb.result create mode 100644 mysql-test/t/ctype_mb.test diff --git a/mysql-test/r/ctype_mb.result b/mysql-test/r/ctype_mb.result new file mode 100644 index 00000000000..4b3b464dea1 --- /dev/null +++ b/mysql-test/r/ctype_mb.result @@ -0,0 +1,21 @@ +CREATE TABLE t1 SELECT _utf8'test' as c1, _utf8'тест' as c2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` char(4) character set utf8 NOT NULL default '', + `c2` char(4) character set utf8 NOT NULL default '' +) TYPE=MyISAM CHARSET=latin1 +DELETE FROM t1; +ALTER TABLE t1 ADD c3 CHAR(4) CHARACTER SET utf8; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` char(4) character set utf8 NOT NULL default '', + `c2` char(4) character set utf8 NOT NULL default '', + `c3` char(4) character set utf8 default NULL +) TYPE=MyISAM CHARSET=latin1 +INSERT INTO t1 VALUES ('aaaabbbbccccdddd','aaaabbbbccccdddd','aaaabbbbccccdddd'); +SELECT * FROM t1; +c1 c2 c3 +aaaabbbbcccc aaaabbbbcccc aaaabbbbcccc +DROP TABLE t1; diff --git a/mysql-test/r/ctype_recoding.result b/mysql-test/r/ctype_recoding.result index b89a90cc6ba..624eab4cf0b 100644 --- a/mysql-test/r/ctype_recoding.result +++ b/mysql-test/r/ctype_recoding.result @@ -1,5 +1,19 @@ SET CHARACTER SET koi8r; DROP TABLE IF EXISTS ; +SET CHARACTER SET koi8r; +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp1251) SELECT _koi8r'' AS a; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` char(10) character set cp1251 default NULL +) TYPE=MyISAM CHARSET=latin1 +SELECT a FROM t1; +a + +SELECT HEX(a) FROM t1; +HEX(a) +EFF0EEE1E0 +DROP TABLE t1; CREATE TABLE ( CHAR(32) CHARACTER SET koi8r NOT NULL diff --git a/mysql-test/r/func_system.result b/mysql-test/r/func_system.result index cde21ead33c..a52d5613c04 100644 --- a/mysql-test/r/func_system.result +++ b/mysql-test/r/func_system.result @@ -41,9 +41,9 @@ create table t1 (version char(40)) select database(), user(), version() as 'vers show create table t1; Table Create Table t1 CREATE TABLE `t1` ( - `database()` char(102) character set utf8 NOT NULL default '', - `user()` char(231) character set utf8 NOT NULL default '', - `version` char(40) character set utf8 default NULL + `database()` char(34) character set utf8 NOT NULL default '', + `user()` char(77) character set utf8 NOT NULL default '', + `version` char(40) default NULL ) TYPE=MyISAM CHARSET=latin1 drop table t1; select TRUE,FALSE,NULL; diff --git a/mysql-test/t/ctype_mb.test b/mysql-test/t/ctype_mb.test new file mode 100644 index 00000000000..5c3e67eec01 --- /dev/null +++ b/mysql-test/t/ctype_mb.test @@ -0,0 +1,8 @@ +CREATE TABLE t1 SELECT _utf8'test' as c1, _utf8'тест' as c2; +SHOW CREATE TABLE t1; +DELETE FROM t1; +ALTER TABLE t1 ADD c3 CHAR(4) CHARACTER SET utf8; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES ('aaaabbbbccccdddd','aaaabbbbccccdddd','aaaabbbbccccdddd'); +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/t/ctype_recoding.test b/mysql-test/t/ctype_recoding.test index 8fa31b1f17b..25df9c0a86b 100644 --- a/mysql-test/t/ctype_recoding.test +++ b/mysql-test/t/ctype_recoding.test @@ -4,6 +4,13 @@ SET CHARACTER SET koi8r; DROP TABLE IF EXISTS ; --enable_warnings +SET CHARACTER SET koi8r; +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp1251) SELECT _koi8r'' AS a; +SHOW CREATE TABLE t1; +SELECT a FROM t1; +SELECT HEX(a) FROM t1; +DROP TABLE t1; + CREATE TABLE ( CHAR(32) CHARACTER SET koi8r NOT NULL diff --git a/sql/field.cc b/sql/field.cc index 2f89dd43c3f..c25f1170b00 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4012,7 +4012,7 @@ void Field_string::sql_type(String &res) const (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? "varchar" : "char"), - (int) field_length); + (int) field_length / charset()->mbmaxlen); res.length(length); } @@ -4178,7 +4178,7 @@ void Field_varstring::sql_type(String &res) const CHARSET_INFO *cs=res.charset(); ulong length= cs->cset->snprintf(cs,(char*) res.ptr(), res.alloced_length(),"varchar(%u)", - field_length); + field_length / charset()->mbmaxlen); res.length(length); } @@ -5267,6 +5267,26 @@ bool Field_num::eq_def(Field *field) ** Handling of field and create_field *****************************************************************************/ +void create_field::create_length_to_internal_length(void) +{ + switch (sql_type) + { + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_VAR_STRING: + case MYSQL_TYPE_STRING: + length*= charset->mbmaxlen; + pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ? + FIELD_TYPE_STRING : sql_type, length); + break; + default: + /* do nothing */ + break; + } +} + /* Make a field from the .frm file info */ diff --git a/sql/field.h b/sql/field.h index 79c45a99a43..794b4a89542 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1066,6 +1066,7 @@ public: uint offset,pack_flag; create_field() :after(0) {} create_field(Field *field, Field *orig_field); + void create_length_to_internal_length(void); }; diff --git a/sql/item.h b/sql/item.h index 621dc017d25..3412b43da44 100644 --- a/sql/item.h +++ b/sql/item.h @@ -419,7 +419,7 @@ public: { collation.set(cs, dv); str_value.set(str,length,cs); - max_length=length; + max_length= str_value.numchars()*cs->mbmaxlen; set_name(str, length, cs); decimals=NOT_FIXED_DEC; } @@ -428,7 +428,7 @@ public: { collation.set(cs, dv); str_value.set(str,length,cs); - max_length=length; + max_length= str_value.numchars()*cs->mbmaxlen; set_name(name_par,0,cs); decimals=NOT_FIXED_DEC; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5880a9d4c8a..ed68f487924 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2078,10 +2078,20 @@ mysql_execute_command(THD *thd) res= mysql_create_like_table(thd, tables, &lex->create_info, (Table_ident *)lex->name); else + { + List_iterator fields(lex->create_list); + create_field *field; + while ((field= fields++)) + { + if (!field->charset) + field->charset= lex->create_info.table_charset; + field->create_length_to_internal_length(); + } res= mysql_create_table(thd,tables->db ? tables->db : thd->db, tables->real_name, &lex->create_info, lex->create_list, lex->key_list,0,0,0); // do logging + } if (!res) send_ok(thd); } @@ -3791,7 +3801,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, break; case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: - if (new_field->length < MAX_FIELD_WIDTH || default_value) + if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value) break; /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */ new_field->sql_type= FIELD_TYPE_BLOB; @@ -3957,13 +3967,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, } } - if (new_field->length >= MAX_FIELD_WIDTH || + if (new_field->length > MAX_FIELD_CHARLENGTH || (!new_field->length && !(new_field->flags & BLOB_FLAG) && type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY)) { net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name, - MAX_FIELD_WIDTH-1); /* purecov: inspected */ + MAX_FIELD_CHARLENGTH); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } type_modifier&= AUTO_INCREMENT_FLAG; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e16d7a0067d..7cb8dfaae0d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -457,12 +457,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, else { /* Field redefined */ + sql_field->sql_type= dup_field->sql_type; + sql_field->charset= dup_field->charset ? dup_field->charset : create_info->table_charset; sql_field->length= dup_field->length; + sql_field->pack_length= dup_field->pack_length; + sql_field->create_length_to_internal_length(); sql_field->decimals= dup_field->decimals; sql_field->flags= dup_field->flags; - sql_field->pack_length= dup_field->pack_length; sql_field->unireg_check= dup_field->unireg_check; - sql_field->sql_type= dup_field->sql_type; it2.remove(); // Remove first (create) definition select_field_pos--; break; @@ -480,10 +482,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, while ((sql_field=it++)) { if (!sql_field->charset) - sql_field->charset = create_info->table_charset ? - create_info->table_charset : - thd->variables.character_set_database; - + sql_field->charset = create_info->table_charset; switch (sql_field->sql_type) { case FIELD_TYPE_BLOB: case FIELD_TYPE_MEDIUM_BLOB: @@ -1891,18 +1890,42 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } /* Full alter table */ + + /* let new create options override the old ones */ + if (!(used_fields & HA_CREATE_USED_MIN_ROWS)) + create_info->min_rows=table->min_rows; + if (!(used_fields & HA_CREATE_USED_MAX_ROWS)) + create_info->max_rows=table->max_rows; + if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH)) + create_info->avg_row_length=table->avg_row_length; + if (!(used_fields & HA_CREATE_USED_CHARSET)) + create_info->table_charset=table->table_charset; + restore_record(table,default_values); // Empty record for DEFAULT List_iterator drop_it(drop_list); List_iterator def_it(fields); List_iterator alter_it(alter_list); List create_list; // Add new fields here List key_list; // Add new keys here + create_field *def; + + /* + For each column set charset to the table + default if the column charset hasn't been specified + explicitely. Change CREATE length into internal length + */ + def_it.rewind(); + while ((def= def_it++)) + { + if (!def->charset) + def->charset= create_info->table_charset; + def->create_length_to_internal_length(); + } /* First collect all fields from table which isn't in drop_list */ - create_field *def; Field **f_ptr,*field; for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++) { @@ -2121,16 +2144,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if (!create_info->comment) create_info->comment=table->comment; - /* let new create options override the old ones */ - if (!(used_fields & HA_CREATE_USED_MIN_ROWS)) - create_info->min_rows=table->min_rows; - if (!(used_fields & HA_CREATE_USED_MAX_ROWS)) - create_info->max_rows=table->max_rows; - if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH)) - create_info->avg_row_length=table->avg_row_length; - if (!(used_fields & HA_CREATE_USED_CHARSET)) - create_info->table_charset=table->table_charset; - table->file->update_create_info(create_info); if ((create_info->table_options & (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) || diff --git a/sql/unireg.h b/sql/unireg.h index 4bbfa8b0fae..4920d4b609a 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -58,7 +58,12 @@ #endif #define MAX_HOSTNAME 61 /* len+1 in mysql.user */ -#define MAX_FIELD_WIDTH 256 /* Max column width +1 */ +#define MAX_MBWIDTH 3 /* Max multibyte sequence */ +#define MAX_FIELD_CHARLENGTH 255 +/* Max column width +1 */ +#define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1) + + #define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */ #define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2)) #define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1)) From 2ad06dc68e3ca572d2abbe89b470f2a510466ad3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 11 Aug 2003 23:43:01 +0400 Subject: [PATCH 4/6] Implemented UTC_TIME, UTC_DATE and UTC_TIMESTAMP functions (WL#345) configure.in: ./configure now tests if gmtime_r is present include/config-os2.h: Supposing that OS/2 have gmtime_r include/my_pthread.h: Use our imeplementation of gmtime_r if system lacks one mysql-test/r/func_time.result: Added UTC_* functions to test mysql-test/t/func_time.test: Added UTC_* functions to test mysys/my_pthread.c: Our implementation of gmtime_r mysys/my_thr_init.c: Now we also need LOCK_locktime_r if gmtime_r is absent sql/item_timefunc.cc: Generalized classes for CURDATE, CURTIME and NOW, abstracted them from timezone. Added new children classes for implementing these and UTC_* functions. sql/item_timefunc.h: Generalized classes for CURDATE, CURTIME and NOW, abstracted them from timezone. Added new children classes for implementing these and UTC_* functions. sql/lex.h: Added tokens for UTC_TIME, UTC_DATE and UTC_TIMESTAMP sql/sql_yacc.yy: Added UTC_* functions to grammar. Current functions are using classes now. --- configure.in | 2 +- include/config-os2.h | 3 + include/my_pthread.h | 9 +++ mysql-test/r/func_time.result | 18 +++++ mysql-test/t/func_time.test | 9 +++ mysys/my_pthread.c | 21 ++++- mysys/my_thr_init.c | 6 +- sql/item_timefunc.cc | 148 ++++++++++++++++++++++++---------- sql/item_timefunc.h | 80 ++++++++++++++++-- sql/lex.h | 3 + sql/sql_yacc.yy | 19 +++-- 11 files changed, 260 insertions(+), 58 deletions(-) diff --git a/configure.in b/configure.in index 63b33e391b2..12615a49f8f 100644 --- a/configure.in +++ b/configure.in @@ -1812,7 +1812,7 @@ AC_CHECK_FUNCS(alarm bmove \ gethostbyaddr_r gethostbyname_r getpwnam \ bfill bzero bcmp strstr strpbrk strerror \ tell atod memcpy memmove \ - setupterm strcasecmp sighold vidattr lrand48 localtime_r \ + setupterm strcasecmp sighold vidattr lrand48 localtime_r gmtime_r \ sigset sigthreadmask pthread_sigmask pthread_setprio pthread_setprio_np \ pthread_setschedparam pthread_attr_setprio pthread_attr_setschedparam \ pthread_attr_create pthread_getsequence_np pthread_attr_setstacksize \ diff --git a/include/config-os2.h b/include/config-os2.h index 7e9684ae3f5..0402074acc0 100644 --- a/include/config-os2.h +++ b/include/config-os2.h @@ -463,6 +463,9 @@ typedef unsigned long long os_off_t; /* Define if you have the getwd function. */ #define HAVE_GETWD 1 +/* Define to 1 if you have the `gmtime_r' function. */ +#define HAVE_GMTIME_R 1 + /* Define if you have the index function. */ #define HAVE_INDEX 1 diff --git a/include/my_pthread.h b/include/my_pthread.h index bff82ef7320..d8374cad314 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -100,6 +100,8 @@ int pthread_attr_setstacksize(pthread_attr_t *connect_att,DWORD stack); int pthread_attr_setprio(pthread_attr_t *connect_att,int priority); int pthread_attr_destroy(pthread_attr_t *connect_att); struct tm *localtime_r(const time_t *timep,struct tm *tmp); +struct tm *gmtime_r(const time_t *timep,struct tm *tmp); + void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ @@ -109,6 +111,7 @@ void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/ #endif #define pthread_self() win_pthread_self #define HAVE_LOCALTIME_R 1 +#define HAVE_GMTIME_R 1 #define _REENTRANT 1 #define HAVE_PTHREAD_ATTR_SETSTACKSIZE 1 @@ -276,6 +279,8 @@ extern int my_pthread_create_detached; #define USE_ALARM_THREAD #undef HAVE_LOCALTIME_R #define HAVE_LOCALTIME_R +#undef HAVE_GMTIME_R +#define HAVE_GMTIME_R #undef HAVE_PTHREAD_ATTR_SETSCOPE #define HAVE_PTHREAD_ATTR_SETSCOPE #undef HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE /* If we are running linux */ @@ -376,6 +381,10 @@ void *my_pthread_getspecific_imp(pthread_key_t key); struct tm *localtime_r(const time_t *clock, struct tm *res); #endif +#ifndef HAVE_GMTIME_R +struct tm *gmtime_r(const time_t *clock, struct tm *res); +#endif + #ifdef HAVE_PTHREAD_CONDATTR_CREATE /* DCE threads on HPUX 10.20 */ #define pthread_condattr_init pthread_condattr_create diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index 38fe97a79a6..c65dbbb926f 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -465,3 +465,21 @@ select date_add(time,INTERVAL 1 SECOND) from t1; date_add(time,INTERVAL 1 SECOND) 2006-07-08 00:00:01 drop table t1; +select strcmp(date_sub(localtimestamp(), interval 3 hour), utc_timestamp())=0; +strcmp(date_sub(localtimestamp(), interval 3 hour), utc_timestamp())=0 +1 +select strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%T"), utc_time())=0; +strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%T"), utc_time())=0 +1 +select strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%Y-%m-%d"), utc_date())=0; +strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%Y-%m-%d"), utc_date())=0 +1 +select strcmp(date_format(utc_timestamp(),"%T"), utc_time())=0; +strcmp(date_format(utc_timestamp(),"%T"), utc_time())=0 +1 +select strcmp(date_format(utc_timestamp(),"%Y-%m-%d"), utc_date())=0; +strcmp(date_format(utc_timestamp(),"%Y-%m-%d"), utc_date())=0 +1 +select strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0; +strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0 +1 diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index af222b0b3cc..4be6570d410 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -220,3 +220,12 @@ select date_add(date,INTERVAL "1 1:1:1" DAY_SECOND) from t1; # The following is not as one would expect... select date_add(time,INTERVAL 1 SECOND) from t1; drop table t1; + +# Test SAPDB UTC_% functions. This part is TZ dependant (It is supposed that +# TZ variable set to GMT-3 +select strcmp(date_sub(localtimestamp(), interval 3 hour), utc_timestamp())=0; +select strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%T"), utc_time())=0; +select strcmp(date_format(date_sub(localtimestamp(), interval 3 hour),"%Y-%m-%d"), utc_date())=0; +select strcmp(date_format(utc_timestamp(),"%T"), utc_time())=0; +select strcmp(date_format(utc_timestamp(),"%Y-%m-%d"), utc_date())=0; +select strcmp(concat(utc_date(),' ',utc_time()),utc_timestamp())=0; diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c index 4f472f61593..32528707480 100644 --- a/mysys/my_pthread.c +++ b/mysys/my_pthread.c @@ -133,10 +133,13 @@ int my_sigwait(const sigset_t *set,int *sig) /* localtime_r for SCO 3.2V4.2 */ -#ifndef HAVE_LOCALTIME_R +#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) extern pthread_mutex_t LOCK_localtime_r; +#endif + +#if !defined(HAVE_LOCALTIME_R) struct tm *localtime_r(const time_t *clock, struct tm *res) { struct tm *tmp; @@ -148,6 +151,22 @@ struct tm *localtime_r(const time_t *clock, struct tm *res) } #endif +#if !defined(HAVE_GMTIME_R) +/* + Reentrant version of standard gmtime() function. + Needed on some systems which don't implement it. +*/ + +struct tm *gmtime_r(const time_t *clock, struct tm *res) +{ + struct tm *tmp; + pthread_mutex_lock(&LOCK_localtime_r); + tmp= gmtime(clock); + *res= *tmp; + pthread_mutex_unlock(&LOCK_localtime_r); + return res; +} +#endif /**************************************************************************** ** Replacement of sigwait if the system doesn't have one (like BSDI 3.0) diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index 59466083b28..32bc8ea3724 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -31,7 +31,7 @@ pthread_key(struct st_my_thread_var, THR_KEY_mysys); pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,THR_LOCK_keycache, THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap, THR_LOCK_net, THR_LOCK_charset; -#ifndef HAVE_LOCALTIME_R +#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) pthread_mutex_t LOCK_localtime_r; #endif #ifndef HAVE_GETHOSTBYNAME_R @@ -73,7 +73,7 @@ my_bool my_thread_global_init(void) #if defined( __WIN__) || defined(OS2) win_pthread_init(); #endif -#ifndef HAVE_LOCALTIME_R +#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) pthread_mutex_init(&LOCK_localtime_r,MY_MUTEX_INIT_SLOW); #endif #ifndef HAVE_GETHOSTBYNAME_R @@ -103,7 +103,7 @@ void my_thread_global_end(void) pthread_mutex_destroy(&THR_LOCK_heap); pthread_mutex_destroy(&THR_LOCK_net); pthread_mutex_destroy(&THR_LOCK_charset); -#ifndef HAVE_LOCALTIME_R +#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) pthread_mutex_destroy(&LOCK_localtime_r); #endif #ifndef HAVE_GETHOSTBYNAME_R diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 62d8afd7ec0..2948438d76f 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -571,21 +571,21 @@ longlong Item_func_from_days::val_int() void Item_func_curdate::fix_length_and_dec() { - struct tm tm_tmp,*start; - time_t query_start=current_thd->query_start(); + struct tm start; collation.set(default_charset()); decimals=0; max_length=10*default_charset()->mbmaxlen; - localtime_r(&query_start,&tm_tmp); - start=&tm_tmp; - value=(longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+ - ((uint) start->tm_mon+1)*100+ - (uint) start->tm_mday); + + store_now_in_tm(current_thd->query_start(),&start); + + value=(longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ + ((uint) start.tm_mon+1)*100+ + (uint) start.tm_mday); /* For getdate */ - ltime.year= start->tm_year+1900; - ltime.month= start->tm_mon+1; - ltime.day= start->tm_mday; + ltime.year= start.tm_year+1900; + ltime.month= start.tm_mon+1; + ltime.day= start.tm_mday; ltime.hour= 0; ltime.minute= 0; ltime.second= 0; @@ -594,6 +594,7 @@ void Item_func_curdate::fix_length_and_dec() ltime.time_type=TIMESTAMP_DATE; } + bool Item_func_curdate::get_date(TIME *res, bool fuzzy_date __attribute__((unused))) { @@ -601,6 +602,27 @@ bool Item_func_curdate::get_date(TIME *res, return 0; } + +/* + Converts time in time_t to struct tm represenatation for local timezone. + Defines timezone (local) used for whole CURDATE function +*/ +void Item_func_curdate_local::store_now_in_tm(time_t now, struct tm *now_tm) +{ + localtime_r(&now,now_tm); +} + + +/* + Converts time in time_t to struct tm represenatation for UTC + Defines timezone (UTC) used for whole UTC_DATE function +*/ +void Item_func_curdate_utc::store_now_in_tm(time_t now, struct tm *now_tm) +{ + gmtime_r(&now,now_tm); +} + + String *Item_func_curtime::val_str(String *str) { str_value.set(buff,buff_length,default_charset()); @@ -609,23 +631,43 @@ String *Item_func_curtime::val_str(String *str) void Item_func_curtime::fix_length_and_dec() { - struct tm tm_tmp,*start; - time_t query_start=current_thd->query_start(); - CHARSET_INFO *cs=default_charset(); + struct tm start; + CHARSET_INFO *cs= default_charset(); decimals=0; max_length=8*cs->mbmaxlen; - localtime_r(&query_start,&tm_tmp); - start=&tm_tmp; collation.set(cs); - value=(longlong) ((ulong) ((uint) start->tm_hour)*10000L+ - (ulong) (((uint) start->tm_min)*100L+ - (uint) start->tm_sec)); + + store_now_in_tm(current_thd->query_start(),&start); + + value=(longlong) ((ulong) ((uint) start.tm_hour)*10000L+ + (ulong) (((uint) start.tm_min)*100L+ + (uint) start.tm_sec)); buff_length=cs->cset->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d", - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); + (int) start.tm_hour, + (int) start.tm_min, + (int) start.tm_sec); +} + + +/* + Converts time in time_t to struct tm represenatation for local timezone. + Defines timezone (local) used for whole CURTIME function +*/ +void Item_func_curtime_local::store_now_in_tm(time_t now, struct tm *now_tm) +{ + localtime_r(&now,now_tm); +} + + +/* + Converts time in time_t to struct tm represenatation for UTC. + Defines timezone (UTC) used for whole UTC_TIME function +*/ +void Item_func_curtime_utc::store_now_in_tm(time_t now, struct tm *now_tm) +{ + gmtime_r(&now,now_tm); } @@ -638,37 +680,37 @@ String *Item_func_now::val_str(String *str) void Item_func_now::fix_length_and_dec() { - struct tm tm_tmp,*start; - time_t query_start=current_thd->query_start(); + struct tm start; CHARSET_INFO *cs= &my_charset_bin; decimals=0; max_length=19*cs->mbmaxlen; collation.set(cs); - localtime_r(&query_start,&tm_tmp); - start=&tm_tmp; - value=((longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+ - (((uint) start->tm_mon+1)*100+ - (uint) start->tm_mday))*(longlong) 1000000L+ - (longlong) ((ulong) ((uint) start->tm_hour)*10000L+ - (ulong) (((uint) start->tm_min)*100L+ - (uint) start->tm_sec))); + + store_now_in_tm(current_thd->query_start(),&start); + + value=((longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+ + (((uint) start.tm_mon+1)*100+ + (uint) start.tm_mday))*(longlong) 1000000L+ + (longlong) ((ulong) ((uint) start.tm_hour)*10000L+ + (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); + ((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; - ltime.day= start->tm_mday; - ltime.hour= start->tm_hour; - ltime.minute= start->tm_min; - ltime.second= start->tm_sec; + 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; ltime.time_type=TIMESTAMP_FULL; @@ -690,6 +732,26 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions) } +/* + Converts time in time_t to struct tm represenatation for local timezone. + Defines timezone (local) used for whole CURRENT_TIMESTAMP function +*/ +void Item_func_now_local::store_now_in_tm(time_t now, struct tm *now_tm) +{ + localtime_r(&now,now_tm); +} + + +/* + Converts time in time_t to struct tm represenatation for UTC. + Defines timezone (UTC) used for whole UTC_TIMESTAMP function +*/ +void Item_func_now_utc::store_now_in_tm(time_t now, struct tm *now_tm) +{ + gmtime_r(&now,now_tm); +} + + String *Item_func_sec_to_time::val_str(String *str) { char buff[23*2]; diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index a6fb9b11de4..2196f83884a 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -350,6 +350,8 @@ public: }; +/* Abstract CURTIME function. Children should define what timezone is used */ + class Item_func_curtime :public Item_func { longlong value; @@ -363,29 +365,77 @@ public: double val() { return (double) value; } longlong val_int() { return value; } String *val_str(String *str); - const char *func_name() const { return "curtime"; } void fix_length_and_dec(); Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg) { return (new Field_time(maybe_null, name, t_arg, default_charset())); - } + } + /* + Abstract method that defines which time zone is used for conversion. + Converts time from time_t representation to broken down representation + in struct tm using gmtime_r or localtime_r functions. + */ + virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0; }; +class Item_func_curtime_local :public Item_func_curtime +{ +public: + Item_func_curtime_local() :Item_func_curtime() {} + Item_func_curtime_local(Item *a) :Item_func_curtime(a) {} + const char *func_name() const { return "curtime"; } + void store_now_in_tm(time_t now, struct tm *now_tm); +}; + + +class Item_func_curtime_utc :public Item_func_curtime +{ +public: + Item_func_curtime_utc() :Item_func_curtime() {} + Item_func_curtime_utc(Item *a) :Item_func_curtime(a) {} + const char *func_name() const { return "utc_time"; } + void store_now_in_tm(time_t now, struct tm *now_tm); +}; + + +/* Abstract CURDATE function. See also Item_func_curtime. */ + class Item_func_curdate :public Item_date { longlong value; TIME ltime; public: Item_func_curdate() :Item_date() {} + void set_result_from_tm(struct tm *now); longlong val_int() { return (value) ; } - const char *func_name() const { return "curdate"; } - void fix_length_and_dec(); /* Retrieves curtime */ + void fix_length_and_dec(); bool get_date(TIME *res,bool fuzzy_date); + virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0; }; +class Item_func_curdate_local :public Item_func_curdate +{ +public: + Item_func_curdate_local() :Item_func_curdate() {} + const char *func_name() const { return "curdate"; } + void store_now_in_tm(time_t now, struct tm *now_tm); +}; + + +class Item_func_curdate_utc :public Item_func_curdate +{ +public: + Item_func_curdate_utc() :Item_func_curdate() {} + const char *func_name() const { return "utc_date"; } + void store_now_in_tm(time_t now, struct tm *now_tm); +}; + + +/* Abstract CURRENT_TIMESTAMP function. See also Item_func_curtime */ + class Item_func_now :public Item_date_func { longlong value; @@ -400,9 +450,29 @@ public: longlong val_int() { return value; } int save_in_field(Field *to, bool no_conversions); String *val_str(String *str); - const char *func_name() const { return "now"; } void fix_length_and_dec(); bool get_date(TIME *res,bool fuzzy_date); + virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0; +}; + + +class Item_func_now_local :public Item_func_now +{ +public: + Item_func_now_local() :Item_func_now() {} + Item_func_now_local(Item *a) :Item_func_now(a) {} + const char *func_name() const { return "now"; } + void store_now_in_tm(time_t now, struct tm *now_tm); +}; + + +class Item_func_now_utc :public Item_func_now +{ +public: + Item_func_now_utc() :Item_func_now() {} + Item_func_now_utc(Item *a) :Item_func_now(a) {} + const char *func_name() const { return "utc_timestamp"; } + void store_now_in_tm(time_t now, struct tm *now_tm); }; diff --git a/sql/lex.h b/sql/lex.h index c2860f4551a..35c4d990b32 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -404,6 +404,9 @@ static SYMBOL symbols[] = { { "USE_FRM", SYM(USE_FRM),0,0}, { "USER", SYM(USER),0,0}, { "USING", SYM(USING),0,0}, + { "UTC_DATE", SYM(UTC_DATE_SYM),0,0}, + { "UTC_TIME", SYM(UTC_TIME_SYM),0,0}, + { "UTC_TIMESTAMP", SYM(UTC_TIMESTAMP_SYM),0,0}, { "UPDATE", SYM(UPDATE_SYM),0,0}, { "USAGE", SYM(USAGE),0,0}, { "VALUE", SYM(VALUE_SYM),0,0}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index aef58e6cb94..856cc3842fc 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -526,6 +526,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token UNIQUE_USERS %token UNIX_TIMESTAMP %token USER +%token UTC_DATE_SYM +%token UTC_TIME_SYM +%token UTC_TIMESTAMP_SYM %token WEEK_SYM %token WHEN_SYM %token WORK_SYM @@ -2372,12 +2375,12 @@ simple_expr: | CONCAT_WS '(' expr ',' expr_list ')' { $$= new Item_func_concat_ws($3, *$5); } | CURDATE optional_braces - { $$= new Item_func_curdate(); Lex->safe_to_cache_query=0; } + { $$= new Item_func_curdate_local(); Lex->safe_to_cache_query=0; } | CURTIME optional_braces - { $$= new Item_func_curtime(); Lex->safe_to_cache_query=0; } + { $$= new Item_func_curtime_local(); Lex->safe_to_cache_query=0; } | CURTIME '(' expr ')' { - $$= new Item_func_curtime($3); + $$= new Item_func_curtime_local($3); Lex->safe_to_cache_query=0; } | DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')' @@ -2539,9 +2542,9 @@ simple_expr: { $$= new Item_func_spatial_collection(* $3, Geometry::wkbMultiPolygon, Geometry::wkbPolygon ); } | NOW_SYM optional_braces - { $$= new Item_func_now(); Lex->safe_to_cache_query=0;} + { $$= new Item_func_now_local(); Lex->safe_to_cache_query=0;} | NOW_SYM '(' expr ')' - { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;} + { $$= new Item_func_now_local($3); Lex->safe_to_cache_query=0;} | PASSWORD '(' expr ')' { $$= new Item_func_password($3); } | PASSWORD '(' expr ',' expr ')' @@ -2669,6 +2672,12 @@ simple_expr: { $$= new Item_func_unix_timestamp($3); } | USER '(' ')' { $$= new Item_func_user(); Lex->safe_to_cache_query=0; } + | UTC_DATE_SYM optional_braces + { $$= new Item_func_curdate_utc(); Lex->safe_to_cache_query=0;} + | UTC_TIME_SYM optional_braces + { $$= new Item_func_curtime_utc(); Lex->safe_to_cache_query=0;} + | UTC_TIMESTAMP_SYM optional_braces + { $$= new Item_func_now_utc(); Lex->safe_to_cache_query=0;} | WEEK_SYM '(' expr ')' { $$= new Item_func_week($3,new Item_int((char*) "0", From 2338e2eaf9392ece5faea1f19147d4402590314d Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Aug 2003 16:42:52 +0500 Subject: [PATCH 5/6] LIKE didn't work with non-default charset --- mysql-test/r/func_like.result | 67 +++++++++++++++++++++++++++++++++++ mysql-test/t/func_like.test | 20 +++++++++++ sql/item_cmpfunc.cc | 2 +- 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result index f90e694f5f0..cf07ba88477 100644 --- a/mysql-test/r/func_like.result +++ b/mysql-test/r/func_like.result @@ -37,3 +37,70 @@ select * from t1 where a like "%abc\d%"; a abcd drop table t1; +SET NAMES koi8r; +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET koi8r); +INSERT INTO t1 VALUES (''),(''),(''),(''),(''),(''); +INSERT INTO t1 VALUES (''),(''),(''),(''); +INSERT INTO t1 VALUES (''),(''),(''),(''); +INSERT INTO t1 VALUES (''),(''),(''),(''); +SELECT * FROM t1 WHERE a LIKE '%%'; +a + + + + + + + + + + + + + + + + + + +SELECT * FROM t1 WHERE a LIKE '%%'; +a + + + + + + + + + + + + + + + + + + +SELECT * FROM t1 WHERE a LIKE '%'; +a + + + + + + + + + + + + + + + + + + +DROP TABLE t1; diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index 90b376e34df..0cd85385df4 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -24,3 +24,23 @@ select * from t1 where a like "%abcd%"; select * from t1 where a like "%abc\d%"; drop table t1; + + +# +# Test like with non-default character set +# + +SET NAMES koi8r; + +CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET koi8r); + +INSERT INTO t1 VALUES (''),(''),(''),(''),(''),(''); +INSERT INTO t1 VALUES (''),(''),(''),(''); +INSERT INTO t1 VALUES (''),(''),(''),(''); +INSERT INTO t1 VALUES (''),(''),(''),(''); + +SELECT * FROM t1 WHERE a LIKE '%%'; +SELECT * FROM t1 WHERE a LIKE '%%'; +SELECT * FROM t1 WHERE a LIKE '%'; + +DROP TABLE t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7d8da16338b..642be5491aa 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2139,7 +2139,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const int shift = pattern_len; int j = 0; int u = 0; - CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed + CHARSET_INFO *cs= cmp.cmp_collation.collation; // QQ Needs to be fixed const int plm1= pattern_len - 1; const int tlmpl= text_len - pattern_len; From abbcc4ffbba233a9a7eeeb037655de2bd92e7914 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 12 Aug 2003 17:40:11 +0300 Subject: [PATCH 6/6] fixed layout --- sql/sql_yacc.yy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 856cc3842fc..c484a2d6f19 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1918,7 +1918,8 @@ select: LEX *lex= Lex; lex->sql_command= SQLCOM_SELECT; lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE; - }; + } + ; /* Need select_init2 for subselects. */ select_init: