diff options
32 files changed, 650 insertions, 279 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 5cf95b9fc2a..e6bfe0ceb36 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -43,6 +43,7 @@ jani@janikt.pp.saunalahti.fi jani@rhols221.adsl.netsonic.fi jani@rhols221.arenanet.fi jani@ua126d19.elisa.omakaista.fi +jani@ua141d10.elisa.omakaista.fi jcole@abel.spaceapes.com jcole@main.burghcom.com jcole@mugatu.spaceapes.com @@ -98,6 +99,7 @@ ranger@regul.home.lan root@x3.internalnet salle@geopard.(none) salle@geopard.online.bg +salle@vafla.home salle@vafla.online.bg sasha@mysql.sashanet.com serg@build.mysql2.com diff --git a/include/my_sys.h b/include/my_sys.h index e1656cfc626..75e22629a19 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -740,6 +740,8 @@ extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size, extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size); extern void free_root(MEM_ROOT *root, myf MyFLAGS); extern void set_prealloc_root(MEM_ROOT *root, char *ptr); +extern void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, + uint prealloc_size); extern char *strdup_root(MEM_ROOT *root,const char *str); extern char *strmake_root(MEM_ROOT *root,const char *str,uint len); extern char *memdup_root(MEM_ROOT *root,const char *str,uint len); diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index dc7acfcba36..87505656d5a 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -52,7 +52,7 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve hash table fixed size in bytes */ #define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data dictionary varying size in bytes */ - + /************************************************************************** Adds a column to the data dictionary hash table. */ static @@ -2109,6 +2109,68 @@ dict_accept( } /************************************************************************* +Scans an id. For the lexical definition of an 'id', see the code below. +Strips backquotes or double quotes from around the id. */ +static +char* +dict_scan_id( +/*=========*/ + /* out: scanned to */ + char* ptr, /* in: scanned to */ + char** start, /* out: start of the id; NULL if no id was + scannable */ + ulint* len, /* out: length of the id */ + ibool accept_also_dot)/* in: TRUE if also a dot can appear in a + non-quoted id; in a quoted id it can appear + always */ +{ + char quote = '\0'; + + *start = NULL; + + while (isspace(*ptr)) { + ptr++; + } + + if (*ptr == '\0') { + + return(ptr); + } + + if (*ptr == '`' || *ptr == '"') { + quote = *ptr++; + } + + *start = ptr; + + if (quote) { + while (*ptr != quote && *ptr != '\0') { + ptr++; + } + } else { + while (!isspace(*ptr) && *ptr != '(' && *ptr != ')' + && (accept_also_dot || *ptr != '.') + && *ptr != ',' && *ptr != '\0') { + + ptr++; + } + } + + *len = (ulint) (ptr - *start); + + if (quote) { + if (*ptr == quote) { + ptr++; + } else { + /* Syntax error */ + *start = NULL; + } + } + + return(ptr); +} + +/************************************************************************* Tries to scan a column name. */ static char* @@ -2124,64 +2186,29 @@ dict_scan_col( ulint* column_name_len)/* out: column name length */ { dict_col_t* col; - char* old_ptr; ulint i; *success = FALSE; - while (isspace(*ptr)) { - ptr++; - } + ptr = dict_scan_id(ptr, column_name, column_name_len, TRUE); - if (*ptr == '\0') { + if (column_name == NULL) { - return(ptr); - } - - if (*ptr == '`' || *ptr == '"') { - /* - The identifier is quoted. Search for end quote. - We can't use the general code here as the name may contain - special characters like space. - */ - char quote= *ptr++; - - old_ptr= ptr; - /* - The colum name should always end with 'quote' but we check for - end zero just to be safe if this is called outside of MySQL - */ - while (*ptr && *ptr != quote) - ptr++; - *column_name_len = (ulint)(ptr - old_ptr); - - if (*ptr) /* Skip end quote */ - ptr++; - } - else - { - old_ptr = ptr; - - while (!isspace(*ptr) && *ptr != ',' && *ptr != ')' - && *ptr != '\0') { - ptr++; - } - *column_name_len = (ulint)(ptr - old_ptr); + return(ptr); /* Syntax error */ } - if (table == NULL) { *success = TRUE; *column = NULL; - *column_name = old_ptr; } else { for (i = 0; i < dict_table_get_n_cols(table); i++) { col = dict_table_get_nth_col(table, i); if (ut_strlen(col->name) == *column_name_len - && 0 == ut_cmp_in_lower_case(col->name, old_ptr, - *column_name_len)) { + && 0 == ut_cmp_in_lower_case(col->name, + *column_name, + *column_name_len)) { /* Found */ *success = TRUE; @@ -2211,147 +2238,117 @@ dict_scan_table_name( the referenced table name; must be at least 2500 bytes */ { - char* dot_ptr = NULL; - char* old_ptr; + char* database_name = NULL; + ulint database_name_len = 999999999; /* init to a dummy value to + suppress a compiler warning */ + char* table_name = NULL; + ulint table_name_len; + char* scanned_id; + ulint scanned_id_len; ulint i; - char quote = 0; *success = FALSE; *table = NULL; + + ptr = dict_scan_id(ptr, &scanned_id, &scanned_id_len, FALSE); - while (isspace(*ptr)) { - ptr++; + if (scanned_id == NULL) { + + return(ptr); /* Syntax error */ } - if (*ptr == '\0') { + if (*ptr == '.') { + /* We scanned the database name; scan also the table name */ - return(ptr); - } + ptr++; - if (*ptr == '`' || *ptr == '"') { - quote= *ptr++; - } + database_name = scanned_id; + database_name_len = scanned_id_len; - old_ptr = ptr; - - while (*ptr != quote && - (quote || (!isspace(*ptr) && *ptr != '(')) && - *ptr != '\0') { - if (!quote && *ptr == '.') { - dot_ptr = ptr; - } + ptr = dict_scan_id(ptr, &table_name, &table_name_len, FALSE); - ptr++; - } + if (table_name == NULL) { - if (ptr - old_ptr > 2000) { - return(old_ptr); - } - - if (dot_ptr == NULL) { - /* Copy the database name from 'name' to the start */ - for (i = 0;; i++) { - second_table_name[i] = name[i]; - if (name[i] == '/') { - i++; - break; - } - } -#ifdef __WIN__ - ut_cpy_in_lower_case(second_table_name + i, old_ptr, - ptr - old_ptr); -#else - if (srv_lower_case_table_names) { - ut_cpy_in_lower_case(second_table_name + i, old_ptr, - ptr - old_ptr); - } else { - ut_memcpy(second_table_name + i, old_ptr, - ptr - old_ptr); + return(ptr); /* Syntax error */ } -#endif - second_table_name[i + (ptr - old_ptr)] = '\0'; } else { -#ifdef __WIN__ - ut_cpy_in_lower_case(second_table_name, old_ptr, - ptr - old_ptr); -#else - if (srv_lower_case_table_names) { - ut_cpy_in_lower_case(second_table_name, old_ptr, - ptr - old_ptr); - } else { - ut_memcpy(second_table_name, old_ptr, ptr - old_ptr); + /* To be able to read table dumps made with InnoDB-4.0.17 or + earlier, we must allow the dot separator between the database + name and the table name also to appear within a quoted + identifier! InnoDB used to print a constraint as: + ... REFERENCES `databasename.tablename` ... + starting from 4.0.18 it is + ... REFERENCES `databasename`.`tablename` ... */ + + for (i = 0; i < scanned_id_len; i++) { + if (scanned_id[i] == '.') { + database_name = scanned_id; + database_name_len = i; + + scanned_id = scanned_id + i + 1; + scanned_id_len -= i + 1; + } } -#endif - second_table_name[dot_ptr - old_ptr] = '/'; - second_table_name[ptr - old_ptr] = '\0'; - } - *success = TRUE; - - *table = dict_table_get_low(second_table_name); - - if (*ptr && *ptr == quote) { - ptr++; + table_name = scanned_id; + table_name_len = scanned_id_len; } - return(ptr); -} + if (database_name == NULL) { + /* Use the database name of the foreign key table */ -/************************************************************************* -Scans an id. For the lexical definition of an 'id', see the code below. -Strips backquotes from around the id. */ -static -char* -dict_scan_id( -/*=========*/ - /* out: scanned to */ - char* ptr, /* in: scanned to */ - char** start, /* out: start of the id; NULL if no id was - scannable */ - ulint* len) /* out: length of the id */ -{ - char quote = 0; - - *start = NULL; + database_name = name; + + i = 0; + while (name[i] != '/') { + i++; + } - while (isspace(*ptr)) { - ptr++; + database_name_len = i; } - if (*ptr == '\0') { + if (table_name_len + database_name_len > 2000) { - return(ptr); - } - - if (*ptr == '`' || *ptr == '"') { - quote = *ptr++; + return(ptr); /* Too long name */ } - *start = ptr; - - while (*ptr != quote && - (!quote || (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && - *ptr != ')')) - && *ptr != '\0') { - ptr++; +#ifdef __WIN__ + ut_cpy_in_lower_case(second_table_name, database_name, + database_name_len); +#else + if (srv_lower_case_table_names) { + ut_cpy_in_lower_case(second_table_name, database_name, + database_name_len); + } else { + ut_memcpy(second_table_name, database_name, + database_name_len); } +#endif + second_table_name[database_name_len] = '/'; - *len = (ulint) (ptr - *start); - - if (quote) { - if (*ptr == quote) { - ptr++; - } else { - /* Syntax error */ - *start = NULL; - } +#ifdef __WIN__ + ut_cpy_in_lower_case(second_table_name + database_name_len + 1, + table_name, table_name_len); +#else + if (srv_lower_case_table_names) { + ut_cpy_in_lower_case(second_table_name + database_name_len + 1, + table_name, table_name_len); + } else { + ut_memcpy(second_table_name + database_name_len + 1, + table_name, table_name_len); } +#endif + second_table_name[database_name_len + 1 + table_name_len] = '\0'; + + *success = TRUE; + + *table = dict_table_get_low(second_table_name); return(ptr); } /************************************************************************* -Skips one id. */ +Skips one id. The id is allowed to contain also '.'. */ static char* dict_skip_word( @@ -2366,7 +2363,7 @@ dict_skip_word( *success = FALSE; - ptr = dict_scan_id(ptr, &start, &len); + ptr = dict_scan_id(ptr, &start, &len, TRUE); if (start) { *success = TRUE; @@ -3064,7 +3061,7 @@ loop: goto syntax_error; } - ptr = dict_scan_id(ptr, &start, &len); + ptr = dict_scan_id(ptr, &start, &len, TRUE); if (start == NULL) { @@ -3899,6 +3896,7 @@ dict_print_info_on_foreign_key_in_create_format( char* buf) /* in: buffer of at least 5000 bytes */ { char* buf2 = buf; + ulint cpy_len; ulint i; buf2 += sprintf(buf2, ",\n CONSTRAINT `%s` FOREIGN KEY (", @@ -3918,24 +3916,31 @@ dict_print_info_on_foreign_key_in_create_format( if (dict_tables_have_same_db(foreign->foreign_table_name, foreign->referenced_table_name)) { - /* Do not print the database name of the referenced - table */ + /* Do not print the database name of the referenced table */ buf2 += sprintf(buf2, ") REFERENCES `%.500s` (", dict_remove_db_name( foreign->referenced_table_name)); } else { - buf2 += sprintf(buf2, ") REFERENCES `%.500s` (", - foreign->referenced_table_name); - /* Change the '/' in the table name to '.' */ - - for (i = ut_strlen(buf); i > 0; i--) { - if (buf[i] == '/') { + buf2 += sprintf(buf2, ") REFERENCES `"); + + /* Look for the '/' in the table name */ - buf[i] = '.'; + i = 0; + while (foreign->referenced_table_name[i] != '/') { + i++; + } + + cpy_len = i; - break; - } + if (cpy_len > 500) { + cpy_len = 500; } + + memcpy(buf2, foreign->referenced_table_name, cpy_len); + buf2 += cpy_len; + + buf2 += sprintf(buf2, "`.`%.500s` (", + foreign->referenced_table_name + i + 1); } for (i = 0; i < foreign->n_fields; i++) { diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 468404268f4..257756ff8aa 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1804,6 +1804,7 @@ row_drop_table_for_mysql( char* name, /* in: table name */ trx_t* trx) /* in: transaction handle */ { + dict_foreign_t* foreign; dict_table_t* table; que_thr_t* thr; que_t* graph; @@ -1996,6 +1997,31 @@ row_drop_table_for_mysql( goto funct_exit; } + foreign = UT_LIST_GET_FIRST(table->referenced_list); + + if (foreign && trx->check_foreigns) { + char* buf = dict_foreign_err_buf; + + /* We only allow dropping a referenced table if + FOREIGN_KEY_CHECKS is set to 0 */ + + err = DB_CANNOT_DROP_CONSTRAINT; + + mutex_enter(&dict_foreign_err_mutex); + ut_sprintf_timestamp(buf); + + sprintf(buf + strlen(buf), + " Cannot drop table %.500s\n", name); + sprintf(buf + strlen(buf), +"because it is referenced by %.500s\n", foreign->foreign_table_name); + + ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN); + + mutex_exit(&dict_foreign_err_mutex); + + goto funct_exit; + } + if (table->n_mysql_handles_opened > 0) { ut_print_timestamp(stderr); diff --git a/mysql-test/r/bigint.result b/mysql-test/r/bigint.result index 308adc881f2..f96da579bce 100644 --- a/mysql-test/r/bigint.result +++ b/mysql-test/r/bigint.result @@ -81,3 +81,6 @@ quantity 10000000000000000000 10000000000000000000 drop table t1; +SELECT '0x8000000000000001'+0; +'0x8000000000000001'+0 +0 diff --git a/mysql-test/r/ctype_tis620.result b/mysql-test/r/ctype_tis620.result new file mode 100644 index 00000000000..d939fd12e60 --- /dev/null +++ b/mysql-test/r/ctype_tis620.result @@ -0,0 +1,17 @@ +DROP TABLE IF EXISTS t620; +CREATE TABLE t620 ( +recid int(11) NOT NULL auto_increment, +dyninfo text, +PRIMARY KEY (recid) +) TYPE=MyISAM; +INSERT INTO t620 VALUES (1,'color=\"STB,NPG\"\r\nengine=\"J30A13\"\r\nframe=\"MRHCG1640YP4\"\r\ngrade=\"V6\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CG164YEN\"\r\ntype=\"VT6\"\r\n'); +INSERT INTO t620 VALUES (2,'color=\"HTM,NPG,DEG,RGS\"\r\nengine=\"F23A5YP1\"\r\nframe=\"MRHCF8640YP3\"\r\ngrade=\"EXi AT\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CF864YE\"\r\ntype=\"EXA\"\r\n'); +SELECT DISTINCT +(IF( LOCATE( 'year=\"', dyninfo ) = 1, +SUBSTRING( dyninfo, 6+1, LOCATE('\"\r',dyninfo) - 6 -1), +IF( LOCATE( '\nyear=\"', dyninfo ), +SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) + 7, +LOCATE( '\"\r', SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) +7 )) - 1), '' ))) AS year +FROM t620 +HAVING year != '' ORDER BY year; +year diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index ca4a49fea4e..416c583a8d7 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1004,7 +1004,7 @@ select * from t1; id select * from t2; id t1_id -drop table t1,t2; +drop table t2,t1; DROP TABLE IF EXISTS t1,t2; CREATE TABLE t1(id INT NOT NULL, PRIMARY KEY (id)) TYPE=INNODB; CREATE TABLE t2(id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id) ) TYPE=INNODB; @@ -1245,4 +1245,4 @@ a drop table t1; CREATE TABLE t1 (`id 1` INT NOT NULL, PRIMARY KEY (`id 1`)) TYPE=INNODB; CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (`t1_id`) REFERENCES `t1`(`id 1`) ON DELETE CASCADE ) TYPE=INNODB; -drop table t1,t2; +drop table t2,t1; diff --git a/mysql-test/r/rpl_insert_id.result b/mysql-test/r/rpl_insert_id.result index 889e7891770..d2dfbb05675 100644 --- a/mysql-test/r/rpl_insert_id.result +++ b/mysql-test/r/rpl_insert_id.result @@ -39,8 +39,8 @@ select * from t2; b c 5 0 6 11 -drop table t1; drop table t2; +drop table t1; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); insert into t1 values (10); diff --git a/mysql-test/r/timezone.result b/mysql-test/r/timezone.result index 20706408075..15f0d4121c7 100644 --- a/mysql-test/r/timezone.result +++ b/mysql-test/r/timezone.result @@ -32,3 +32,9 @@ ts from_unixtime(ts) 1048989599 2003-03-30 03:59:59 1048989601 2003-03-30 04:00:01 DROP TABLE t1; +select unix_timestamp('1970-01-01 01:00:00'), +unix_timestamp('1970-01-01 01:00:01'), +unix_timestamp('2038-01-01 00:59:59'), +unix_timestamp('2038-01-01 01:00:00'); +unix_timestamp('1970-01-01 01:00:00') unix_timestamp('1970-01-01 01:00:01') unix_timestamp('2038-01-01 00:59:59') unix_timestamp('2038-01-01 01:00:00') +0 1 2145916799 0 diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result index b513f958787..cd45bcf911d 100644 --- a/mysql-test/r/type_timestamp.result +++ b/mysql-test/r/type_timestamp.result @@ -122,5 +122,48 @@ t2 t4 t6 t8 t10 t12 t14 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 0000-00-00 00:00:00 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 1997-12-31 23:47:59 drop table t1; -create table t1 (a timestamp default 1); -Invalid default value for 'a' +create table t1 (t1 timestamp default '2003-01-01 00:00:00', +t2 timestamp default '2003-01-01 00:00:00'); +set TIMESTAMP=1000000000; +insert into t1 values(); +select * from t1; +t1 t2 +2001-09-09 04:46:40 2003-01-01 00:00:00 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t1` timestamp(14) NOT NULL, + `t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00' +) TYPE=MyISAM +show columns from t1; +Field Type Null Key Default Extra +t1 timestamp(14) YES NULL +t2 timestamp(14) YES 2003-01-01 00:00:00 +show columns from t1 like 't2'; +Field Type Null Key Default Extra +t2 timestamp(14) YES 2003-01-01 00:00:00 +create table t2 (select * from t1); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `t1` timestamp(14) NOT NULL, + `t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00' +) TYPE=MyISAM +alter table t1 add column t0 timestamp first; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `t0` timestamp(14) NOT NULL, + `t1` timestamp(14) NOT NULL default '2003-01-01 00:00:00', + `t2` timestamp(14) NOT NULL default '2003-01-01 00:00:00' +) TYPE=MyISAM +drop table t1,t2; +create table t1 (ts1 timestamp, ts2 timestamp); +set TIMESTAMP=1000000000; +insert into t1 values (); +insert into t1 values (DEFAULT, DEFAULT); +select * from t1; +ts1 ts2 +2001-09-09 04:46:40 0000-00-00 00:00:00 +2001-09-09 04:46:40 0000-00-00 00:00:00 +drop table t1; diff --git a/mysql-test/t/bigint.test b/mysql-test/t/bigint.test index f21f821e45c..0092317dc5e 100644 --- a/mysql-test/t/bigint.test +++ b/mysql-test/t/bigint.test @@ -60,3 +60,5 @@ insert into t1 values ('10000000000000000000'); select * from t1; drop table t1; +SELECT '0x8000000000000001'+0; + diff --git a/mysql-test/t/ctype_tis620-master.opt b/mysql-test/t/ctype_tis620-master.opt new file mode 100644 index 00000000000..69d47c06e42 --- /dev/null +++ b/mysql-test/t/ctype_tis620-master.opt @@ -0,0 +1 @@ +--default-character-set=tis620 diff --git a/mysql-test/t/ctype_tis620.test b/mysql-test/t/ctype_tis620.test new file mode 100644 index 00000000000..7a0555515e1 --- /dev/null +++ b/mysql-test/t/ctype_tis620.test @@ -0,0 +1,18 @@ +DROP TABLE IF EXISTS t620; +CREATE TABLE t620 ( + recid int(11) NOT NULL auto_increment, + dyninfo text, + PRIMARY KEY (recid) +) TYPE=MyISAM; + +INSERT INTO t620 VALUES (1,'color=\"STB,NPG\"\r\nengine=\"J30A13\"\r\nframe=\"MRHCG1640YP4\"\r\ngrade=\"V6\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CG164YEN\"\r\ntype=\"VT6\"\r\n'); +INSERT INTO t620 VALUES (2,'color=\"HTM,NPG,DEG,RGS\"\r\nengine=\"F23A5YP1\"\r\nframe=\"MRHCF8640YP3\"\r\ngrade=\"EXi AT\"\r\nmodel=\"ACCORD\"\r\nmodelcode=\"CF864YE\"\r\ntype=\"EXA\"\r\n'); + +SELECT DISTINCT + (IF( LOCATE( 'year=\"', dyninfo ) = 1, + SUBSTRING( dyninfo, 6+1, LOCATE('\"\r',dyninfo) - 6 -1), + IF( LOCATE( '\nyear=\"', dyninfo ), + SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) + 7, + LOCATE( '\"\r', SUBSTRING( dyninfo, LOCATE( '\nyear=\"', dyninfo ) +7 )) - 1), '' ))) AS year +FROM t620 +HAVING year != '' ORDER BY year; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 51fadccdc1c..ec9aa83ae16 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -692,7 +692,7 @@ insert into t2 set id=1, t1_id=1; delete t1,t2 from t1,t2 where t1.id=t2.t1_id; select * from t1; select * from t2; -drop table t1,t2; +drop table t2,t1; DROP TABLE IF EXISTS t1,t2; CREATE TABLE t1(id INT NOT NULL, PRIMARY KEY (id)) TYPE=INNODB; CREATE TABLE t2(id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id) ) TYPE=INNODB; @@ -877,4 +877,4 @@ drop table t1; CREATE TABLE t1 (`id 1` INT NOT NULL, PRIMARY KEY (`id 1`)) TYPE=INNODB; CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (`t1_id`) REFERENCES `t1`(`id 1`) ON DELETE CASCADE ) TYPE=INNODB; #show create table t2; -drop table t1,t2; +drop table t2,t1; diff --git a/mysql-test/t/rpl_insert_id.test b/mysql-test/t/rpl_insert_id.test index 49fefae72b8..a6da44de456 100644 --- a/mysql-test/t/rpl_insert_id.test +++ b/mysql-test/t/rpl_insert_id.test @@ -42,8 +42,8 @@ connection master; # check if INSERT SELECT in auto_increment is well replicated (bug #490) -drop table t1; drop table t2; +drop table t1; create table t1(a int auto_increment, key(a)); create table t2(b int auto_increment, c int, key(b)); insert into t1 values (10); diff --git a/mysql-test/t/timezone.test b/mysql-test/t/timezone.test index ab732c11a34..ba65eb72fe6 100644 --- a/mysql-test/t/timezone.test +++ b/mysql-test/t/timezone.test @@ -38,3 +38,10 @@ INSERT INTO t1 (ts) VALUES (Unix_timestamp('2003-03-30 04:00:01')); SELECT ts,from_unixtime(ts) FROM t1; DROP TABLE t1; +# +# Test for fix for Bug#2523 +# +select unix_timestamp('1970-01-01 01:00:00'), + unix_timestamp('1970-01-01 01:00:01'), + unix_timestamp('2038-01-01 00:59:59'), + unix_timestamp('2038-01-01 01:00:00'); diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test index 17f7b7c487f..3483227376e 100644 --- a/mysql-test/t/type_timestamp.test +++ b/mysql-test/t/type_timestamp.test @@ -73,8 +73,35 @@ select * from t1; drop table t1; # -# Bug #1885 +# Bug #1885, bug #2539. +# Not perfect but still sensible attitude towards defaults for TIMESTAMP +# We will ignore default value for first TIMESTAMP column. # +create table t1 (t1 timestamp default '2003-01-01 00:00:00', + t2 timestamp default '2003-01-01 00:00:00'); +set TIMESTAMP=1000000000; +insert into t1 values(); +select * from t1; +show create table t1; +show columns from t1; +show columns from t1 like 't2'; +create table t2 (select * from t1); +show create table t2; + +# Ugly, but we can't do anything about this in 4.0 +alter table t1 add column t0 timestamp first; +show create table t1; ---error 1067 -create table t1 (a timestamp default 1); +drop table t1,t2; + +# +# Test for bug 2464, DEFAULT keyword in INSERT statement should return +# default value for column. +# + +create table t1 (ts1 timestamp, ts2 timestamp); +set TIMESTAMP=1000000000; +insert into t1 values (); +insert into t1 values (DEFAULT, DEFAULT); +select * from t1; +drop table t1; diff --git a/mysys/my_alloc.c b/mysys/my_alloc.c index 4d3b0604984..d03ec5841af 100644 --- a/mysys/my_alloc.c +++ b/mysys/my_alloc.c @@ -47,6 +47,72 @@ void init_alloc_root(MEM_ROOT *mem_root, uint block_size, #endif } +/* + SYNOPSIS + reset_root_defaults() + mem_root memory root to change defaults of + block_size new value of block size. Must be + greater than ~68 bytes (the exact value depends on + platform and compilation flags) + pre_alloc_size new size of preallocated block. If not zero, + must be equal to or greater than block size, + otherwise means 'no prealloc'. + DESCRIPTION + Function aligns and assigns new value to block size; then it tries to + reuse one of existing blocks as prealloc block, or malloc new one of + requested size. If no blocks can be reused, all unused blocks are freed + before allocation. + */ + +void reset_root_defaults(MEM_ROOT *mem_root, uint block_size, + uint pre_alloc_size) +{ + mem_root->block_size= block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8; +#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG)) + if (pre_alloc_size) + { + uint size= pre_alloc_size + ALIGN_SIZE(sizeof(USED_MEM)); + if (!mem_root->pre_alloc || mem_root->pre_alloc->size != size) + { + USED_MEM *mem, **prev= &mem_root->free; + /* + Free unused blocks, so that consequent calls + to reset_root_defaults won't eat away memory. + */ + while (*prev) + { + mem= *prev; + if (mem->size == size) + { + /* We found a suitable block, no need to do anything else */ + mem_root->pre_alloc= mem; + return; + } + if (mem->left + ALIGN_SIZE(sizeof(USED_MEM)) == mem->size) + { + /* remove block from the list and free it */ + *prev= mem->next; + my_free((gptr) mem, MYF(0)); + } + else + prev= &mem->next; + } + /* Allocate new prealloc block and add it to the end of free list */ + if ((mem= (USED_MEM *) my_malloc(size, MYF(0)))) + { + mem->size= size; + mem->left= pre_alloc_size; + mem->next= *prev; + *prev= mem_root->pre_alloc= mem; + } + } + } + else +#endif + mem_root->pre_alloc= 0; +} + + gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size) { #if defined(HAVE_purify) && defined(EXTRA_DEBUG) diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index 662e33a3a5a..a8c57b4cd1d 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -298,9 +298,11 @@ int handle_options(int *argc, char ***argv, --enable-'option-name'. *optend was set to '0' if one used --disable-option */ - *((my_bool*) optp->value)= (my_bool) (!optend || *optend == '1'); - (*argc)--; - get_one_option(optp->id, optp, argument); + my_bool tmp= (my_bool) (!optend || *optend == '1'); + *((my_bool*) optp->value)= tmp; + (*argc)--; + get_one_option(optp->id, optp, + tmp ? (char*) "1" : disabled_my_option); continue; } argument= optend; diff --git a/sql/field.cc b/sql/field.cc index 8bcbf8ecc56..ac3ebb4bfc7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -2583,22 +2583,18 @@ static longlong fix_datetime(longlong nr, TIME *time_res) void Field_timestamp::store(longlong nr) { TIME l_time; - time_t timestamp; + time_t timestamp= 0; if ((nr= fix_datetime(nr, &l_time))) { long not_used; - if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1) - { + timestamp= my_gmt_sec(&l_time, ¬_used); + + if (!timestamp) current_thd->cuted_fields++; - timestamp=0; - } - else - timestamp=my_gmt_sec(&l_time, ¬_used); } - else - timestamp=0; + #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -5124,8 +5120,7 @@ create_field::create_field(Field *old_field,Field *orig_field) interval=0; def=0; if (!old_field->is_real_null() && ! (flags & BLOB_FLAG) && - old_field->type() != FIELD_TYPE_TIMESTAMP && old_field->ptr && - orig_field) + old_field->ptr && orig_field) { char buff[MAX_FIELD_WIDTH],*pos; String tmp(buff,sizeof(buff)); diff --git a/sql/field.h b/sql/field.h index 413a08f08d4..6f049e3809e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -564,7 +564,10 @@ public: void set_time(); virtual void set_default() { - set_time(); + if (table->timestamp_field == this) + set_time(); + else + Field::set_default(); } inline long get_timestamp() { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index bcd1130dcdb..68052014f57 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -276,7 +276,7 @@ convert_error_code_to_mysql( } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) { - return(HA_WRONG_CREATE_OPTION); + return(HA_ERR_ROW_IS_REFERENCED); } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { @@ -3572,6 +3572,7 @@ ha_innobase::delete_table( int error; trx_t* parent_trx; trx_t* trx; + THD *thd= current_thd; char norm_name[1000]; DBUG_ENTER("ha_innobase::delete_table"); @@ -3597,6 +3598,14 @@ ha_innobase::delete_table( trx->mysql_thd = current_thd; trx->mysql_query_str = &((*current_thd).query); + if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { + trx->check_foreigns = FALSE; + } + + if (thd->options & OPTION_RELAXED_UNIQUE_CHECKS) { + trx->check_unique_secondary = FALSE; + } + name_len = strlen(name); assert(name_len < 1000); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index acb7005c26c..b3c3c5648bf 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -116,6 +116,9 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); /* Time handling defaults */ #define TIMESTAMP_MAX_YEAR 2038 #define YY_PART_YEAR 70 +#define TIMESTAMP_MIN_YEAR (1900 + YY_PART_YEAR - 1) +#define TIMESTAMP_MAX_VALUE 2145916799 +#define TIMESTAMP_MIN_VALUE 1 #define PRECISION_FOR_DOUBLE 53 #define PRECISION_FOR_FLOAT 24 @@ -708,7 +711,7 @@ extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_safe_show_db, opt_local_infile; extern my_bool opt_slave_compressed_protocol, use_temp_pool; extern my_bool opt_readonly; -extern my_bool opt_enable_named_pipe; +extern my_bool opt_enable_named_pipe, opt_sync_frm; extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log; extern FILE *bootstrap_file; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c3931eccc0c..b0ab59b49e6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -140,7 +140,7 @@ int initgroups(const char *,unsigned int); typedef fp_except fp_except_t; #endif - /* We can't handle floating point expections with threads, so disable + /* We can't handle floating point exceptions with threads, so disable this on freebsd */ @@ -308,7 +308,7 @@ static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; my_bool opt_log_slave_updates= 0, opt_console= 0; -my_bool opt_readonly = 0; +my_bool opt_readonly = 0, opt_sync_bdb_logs, opt_sync_frm; volatile bool mqh_used = 0; FILE *bootstrap_file=0; @@ -1689,7 +1689,7 @@ static void start_signal_handler(void) (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR); - pthread_attr_setstacksize(&thr_attr,32768); + pthread_attr_setstacksize(&thr_attr,thread_stack); #endif (void) pthread_mutex_lock(&LOCK_thread_count); @@ -3158,7 +3158,7 @@ enum options_mysqld { OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG, OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR, OPT_BDB_HOME, OPT_BDB_LOG, - OPT_BDB_TMP, OPT_BDB_NOSYNC, + OPT_BDB_TMP, OPT_BDB_SYNC, OPT_BDB_LOCK, OPT_BDB_SKIP, OPT_BDB_NO_RECOVER, OPT_BDB_SHARED, OPT_MASTER_HOST, OPT_MASTER_USER, @@ -3251,7 +3251,8 @@ enum options_mysqld { 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_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE, + OPT_SYNC_FRM, OPT_BDB_NOSYNC }; @@ -3277,8 +3278,14 @@ struct my_option my_long_options[] = {"bdb-no-recover", OPT_BDB_NO_RECOVER, "Don't try to recover Berkeley DB tables on start", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"bdb-no-sync", OPT_BDB_NOSYNC, "Don't synchronously flush logs", 0, 0, 0, - GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"bdb-no-sync", OPT_BDB_NOSYNC, + "Disable synchronously flushing logs. This option is deprecated, use --skip-sync-bdb-logs or sync-bdb-logs=0 instead", + // (gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL, + 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"sync-bdb-logs", OPT_BDB_SYNC, + "Synchronously flush logs. Enabled by default", + (gptr*) &opt_sync_bdb_logs, (gptr*) &opt_sync_bdb_logs, 0, GET_BOOL, + NO_ARG, 1, 0, 0, 0, 0, 0}, {"bdb-shared-data", OPT_BDB_SHARED, "Start Berkeley DB in multi-process mode", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -3286,6 +3293,9 @@ struct my_option my_long_options[] = (gptr*) &berkeley_tmpdir, (gptr*) &berkeley_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif /* HAVE_BERKELEY_DB */ + {"sync-frm", OPT_SYNC_FRM, "Sync .frm to disk on create. Enabled by default", + (gptr*) &opt_sync_frm, (gptr*) &opt_sync_frm, 0, GET_BOOL, NO_ARG, 1, 0, + 0, 0, 0, 0}, {"skip-bdb", OPT_BDB_SKIP, "Don't use berkeley db (will save memory)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"big-tables", OPT_BIG_TABLES, @@ -4044,7 +4054,7 @@ this value; if zero (the default): when the size exceeds max_binlog_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", + "Make all tables readonly, with the exception for replication (slave) threads and users with the SUPER privilege", (gptr*) &opt_readonly, (gptr*) &opt_readonly, 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, @@ -4729,7 +4739,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } #ifdef HAVE_BERKELEY_DB case OPT_BDB_NOSYNC: - berkeley_env_flags|=DB_TXN_NOSYNC; + /* Deprecated option */ + opt_sync_bdb_logs= 0; + /* Fall through */ + case OPT_BDB_SYNC: + if (!opt_sync_bdb_logs) + berkeley_env_flags|= DB_TXN_NOSYNC; + else + berkeley_env_flags&= ~DB_TXN_NOSYNC; + printf("berkeley_env_flags: %d, arg '%s'\n", berkeley_env_flags, argument); break; case OPT_BDB_NO_RECOVER: berkeley_init_flags&= ~(DB_RECOVER); diff --git a/sql/set_var.cc b/sql/set_var.cc index 693d8e4c958..475beb798e6 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -88,6 +88,8 @@ 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 void fix_thd_mem_root(THD *thd, enum_var_type type); +static void fix_trans_mem_root(THD *thd, enum_var_type type); /* Variable definition list @@ -209,13 +211,17 @@ sys_var_long_ptr sys_query_cache_size("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); + &SV::query_alloc_block_size, + fix_thd_mem_root); sys_var_thd_ulong sys_query_prealloc_size("query_prealloc_size", - &SV::query_prealloc_size); + &SV::query_prealloc_size, + fix_thd_mem_root); sys_var_thd_ulong sys_trans_alloc_block_size("transaction_alloc_block_size", - &SV::trans_alloc_block_size); + &SV::trans_alloc_block_size, + fix_trans_mem_root); sys_var_thd_ulong sys_trans_prealloc_size("transaction_prealloc_size", - &SV::trans_prealloc_size); + &SV::trans_prealloc_size, + fix_trans_mem_root); #ifdef HAVE_QUERY_CACHE sys_var_long_ptr sys_query_cache_limit("query_cache_limit", @@ -763,6 +769,24 @@ static void fix_max_connections(THD *thd, enum_var_type type) } +static void fix_thd_mem_root(THD *thd, enum_var_type type) +{ + if (type != OPT_GLOBAL) + reset_root_defaults(&thd->mem_root, + thd->variables.query_alloc_block_size, + thd->variables.query_prealloc_size); +} + + +static void fix_trans_mem_root(THD *thd, enum_var_type type) +{ + if (type != OPT_GLOBAL) + reset_root_defaults(&thd->transaction.mem_root, + thd->variables.trans_alloc_block_size, + thd->variables.trans_prealloc_size); +} + + bool sys_var_long_ptr::update(THD *thd, set_var *var) { ulonglong tmp= var->value->val_int(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f97b1b8f8be..ac3ccd4fc62 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3040,12 +3040,12 @@ bool add_field_to_list(char *field_name, enum_field_types type, if (default_value) { - if (type == FIELD_TYPE_TIMESTAMP) - { - net_printf(&thd->net, ER_INVALID_DEFAULT, field_name); - DBUG_RETURN(1); - } - else if (default_value->type() == Item::NULL_ITEM) + /* + We allow specifying value for first TIMESTAMP column + altough it is silently ignored. This should be fixed in 4.1 + (by proper warning or real support for default values) + */ + if (default_value->type() == Item::NULL_ITEM) { default_value=0; if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == diff --git a/sql/sql_show.cc b/sql/sql_show.cc index addea958ff6..f62853ce9d6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -503,6 +503,12 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, field->sql_type(type); net_store_data(packet,convert,type.ptr(),type.length()); + /* + Altough TIMESTAMP fields can't contain NULL as its value they + will accept NULL if you will try to insert such value and will + convert it to current TIMESTAMP. So YES here means that NULL + is allowed for assignment but can't be returned. + */ pos=(byte*) ((flags & NOT_NULL_FLAG) && field->type() != FIELD_TYPE_TIMESTAMP ? "" : "YES"); @@ -512,7 +518,11 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); net_store_data(packet,convert,(char*) pos); - if (field->type() == FIELD_TYPE_TIMESTAMP || + /* + We handle first TIMESTAMP column in special way because its + default value is ignored and current timestamp used instead. + */ + if (table->timestamp_field == field || field->unireg_check == Field::NEXT_NUMBER) null_default_value=1; if (!null_default_value && !field->is_null()) @@ -883,7 +893,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append(type.ptr(),type.length()); has_default= (field->type() != FIELD_TYPE_BLOB && - field->type() != FIELD_TYPE_TIMESTAMP && + table->timestamp_field != field && field->unireg_check != Field::NEXT_NUMBER); if (flags & NOT_NULL_FLAG) packet->append(" NOT NULL", 9); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7fa973eb60f..774801c094a 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -167,7 +167,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, String wrong_tables; db_type table_type; int error; - bool some_tables_deleted=0, tmp_table_deleted=0; + bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0; DBUG_ENTER("mysql_rm_table_part2"); if (lock_table_names(thd, tables)) @@ -212,6 +212,9 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, error=ha_delete_table(table_type, path); if (error == ENOENT && if_exists) error = 0; + if (error == HA_ERR_ROW_IS_REFERENCED) + foreign_key_error=1; /* the table is referenced by a foreign key + constraint */ if (!error || error == ENOENT) { /* Delete the table definition file */ @@ -247,7 +250,10 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, error= 0; if (wrong_tables.length()) { - my_error(ER_BAD_TABLE_ERROR,MYF(0),wrong_tables.c_ptr()); + if (!foreign_key_error) + my_error(ER_BAD_TABLE_ERROR,MYF(0),wrong_tables.c_ptr()); + else + my_error(ER_ROW_IS_REFERENCED,MYF(0)); error= 1; } DBUG_RETURN(error); diff --git a/sql/time.cc b/sql/time.cc index 5dc229b1d88..0363d764100 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -63,6 +63,9 @@ long my_gmt_sec(TIME *t, long *my_timezone) struct tm *l_time,tm_tmp; long diff, current_timezone; + if (t->year > TIMESTAMP_MAX_YEAR || t->year < TIMESTAMP_MIN_YEAR) + return 0; + if (t->hour >= 24) { /* Fix for time-loop */ t->day+=t->hour/24; @@ -125,8 +128,10 @@ long my_gmt_sec(TIME *t, long *my_timezone) tmp-=t->minute*60 + t->second; // Move to previous hour } *my_timezone= current_timezone; - if (tmp < 0 && t->year <= 1900+YY_PART_YEAR) + + if (tmp < TIMESTAMP_MIN_VALUE || tmp > TIMESTAMP_MAX_VALUE) tmp= 0; + return (long) tmp; } /* my_gmt_sec */ @@ -444,15 +449,13 @@ time_t str_to_timestamp(const char *str,uint length) { TIME l_time; long not_used; + time_t timestamp= 0; - if (str_to_TIME(str,length,&l_time,0) == TIMESTAMP_NONE) - return(0); - if (l_time.year >= TIMESTAMP_MAX_YEAR || l_time.year < 1900+YY_PART_YEAR-1) - { + if (str_to_TIME(str,length,&l_time,0) != TIMESTAMP_NONE && + !(timestamp= my_gmt_sec(&l_time, ¬_used))) current_thd->cuted_fields++; - return(0); - } - return(my_gmt_sec(&l_time, ¬_used)); + + return timestamp; } diff --git a/sql/unireg.cc b/sql/unireg.cc index ff42bfae0f0..955e5cfda8a 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -150,7 +150,7 @@ int rea_create_table(my_string file_name, my_free((gptr) screen_buff,MYF(0)); my_afree((gptr) keybuff); - if (my_sync(file, MYF(MY_WME))) + if (opt_sync_frm && my_sync(file, MYF(MY_WME))) goto err2; if (my_close(file,MYF(MY_WME)) || ha_create_table(file_name,create_info,0)) diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index 7ffc83ea005..5cd718f5944 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -15,6 +15,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* + Copyright (C) 2003 by Sathit Jittanupat <jsat66@hotmail.com,jsat66@yahoo.com> + * solving bug crash with long text field string + * sorting with different number of space or sign char. within string + Copyright (C) 2001 by Korakot Chaovavanich <korakot@iname.com> and Apisilp Trunganont <apisilp@pantip.inet.co.th> Copyright (C) 1998, 1999 by Pruet Boonma <pruet@eng.cmu.ac.th> @@ -49,10 +53,6 @@ #include "m_ctype.h" #include "t_ctype.h" -static uchar* thai2sortable(const uchar *tstr,int len); - -#define BUFFER_MULTIPLY 4 -#define buffsize(s) (BUFFER_MULTIPLY * (strlen(s) + 1)) #define M L_MIDDLE #define U L_UPPER #define L L_LOWER @@ -453,13 +453,77 @@ uchar NEAR sort_order_tis620[]= Arg: const source string and length of converted string Ret: Sortable string */ +static void _thai2sortable(uchar *tstr) +{ + uchar *p ; + int len,tlen ; + uchar c,l2bias ; + + tlen= len = strlen (tstr) ; + l2bias = 256 - 8 ; + for (p=tstr; tlen > 0; p++,tlen--) + { + c = *p ; + + if (isthai(c)) + { + int *t_ctype0 = t_ctype[c] ; + + if (isconsnt(c)) + l2bias -= 8 ; + if (isldvowel(c) && isconsnt(p[1])) + { + /* + simply swap between leading-vowel and consonant + */ + *p = p[1]; + p[1]= c ; + tlen-- ; + p++; + continue ; + } + + // if found level 2 char (L2_GARAN,L2_TONE*,L2_TYKHU) move to last + if (t_ctype0[1]>= L2_GARAN) + { + // l2bias use to control position weight of l2char + // example (*=l2char) XX*X must come before X*XX + strcpy (p,p+1) ; + tstr[len-1] = l2bias + t_ctype0[1]- L2_GARAN +1 ; + p-- ; + continue ; + } + } + else + { + l2bias -= 8 ; + *p = to_lower_tis620[c]; + } + /* + this routine skip non-printable char + but not necessary, leave it like raw ascii 8 bits + */ + /* + t_ctype0 = t_ctype[p[0]]; + if ((t_ctype0[0]|t_ctype0[1]|t_ctype0[2])==IGNORE) + { + strcpy(p,p+1); + p-- ; + } + */ + } +} + /* NOTE: isn't it faster to alloc buffer in calling function? - */ +*/ +/* +Sathit's NOTE: we don't use this function anymore static uchar* thai2sortable(const uchar * tstr,int len) { +*/ /* We use only 3 levels (neglect capitalization). */ - +/* const uchar* p= tstr; uchar *outBuf; uchar *pRight1, *pRight2, *pRight3; @@ -526,6 +590,7 @@ static uchar* thai2sortable(const uchar * tstr,int len) memcpy(pRight1, pLeft3, pRight3 - pLeft3); return outBuf; } +*/ /* strncoll() replacement, compare 2 string, both are conveted to sortable string Arg: 2 Strings and it compare length @@ -533,16 +598,27 @@ static uchar* thai2sortable(const uchar * tstr,int len) */ int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2) { - uchar *tc1, *tc2; - int i; - tc1= thai2sortable(s1, len1); - tc2= thai2sortable(s2, len2); - i= strcmp((char*)tc1, (char*)tc2); - if (tc1 != s1) - free(tc1); - if (tc2 != s2) - free(tc2); - return i; + uchar buf[80] ; + uchar *tc1, *tc2; + int i; + + len1= (int) strnlen((char*) s1,len1); + len2= (int) strnlen((char*) s2,len2); + if ((len1 + len2 +2) > (int) sizeof(buf)) + tc1 = (uchar *)malloc(len1+len2) ; + else + tc1 = buf ; + tc2 = tc1 + len1+1 ; + strncpy((char *)tc1,(char *)s1,len1) ; + tc1[len1] = 0; // if s1's length > len1, need to put 'end of string' + strncpy((char *)tc2,(char *)s2,len2) ; + tc2[len2] = 0; // put end of string + _thai2sortable(tc1); + _thai2sortable(tc2); + i= strcmp((char*)tc1, (char*)tc2); + if (tc1 != buf ) + free(tc1); + return i; } /* strnxfrm replacment, convert Thai string to sortable string @@ -551,15 +627,12 @@ int my_strnncoll_tis620(const uchar * s1, int len1, const uchar * s2, int len2) */ int my_strnxfrm_tis620(uchar * dest, const uchar * src, int len, int srclen) { - uint bufSize; - uchar *tmp; - bufSize= (uint) buffsize((char*)src); - tmp= thai2sortable(src,srclen); - set_if_smaller(bufSize,(uint) len); - memcpy((uchar *)dest, tmp, bufSize); - if (tmp != src) - free(tmp); - return (int)bufSize; + if (len > srclen) + len = srclen ; + strncpy (dest,src,len) ; + dest[len] = 0; // if src's length > len, need to put 'end of string' + _thai2sortable(dest); + return strlen(dest); } /* strcoll replacment, compare 2 strings @@ -568,16 +641,7 @@ int my_strnxfrm_tis620(uchar * dest, const uchar * src, int len, int srclen) */ int my_strcoll_tis620(const uchar * s1, const uchar * s2) { - uchar *tc1, *tc2; - int i; - tc1= thai2sortable(s1, (int) strlen((char*)s1)); - tc2= thai2sortable(s2, (int) strlen((char*)s2)); - i= strcmp((char*)tc1, (char*)tc2); - if (tc1 != s1) - free(tc1); - if (tc2 != s2) - free(tc2); - return i; + return my_strnncoll_tis620(s1, strlen((char *)s1),s2,strlen((char *)s2)); } /* strxfrm replacment, convert Thai string to sortable string @@ -586,15 +650,7 @@ int my_strcoll_tis620(const uchar * s1, const uchar * s2) */ int my_strxfrm_tis620(uchar * dest, const uchar * src, int len) { - uint bufSize; - uchar *tmp; - - bufSize= (uint)buffsize((char*) src); - tmp= thai2sortable(src, len); - memcpy((uchar *)dest, tmp, bufSize); - if (tmp != src) - free(tmp); - return bufSize; + return my_strnxfrm_tis620(dest,src,len,strlen((char *)src)); } /* Convert SQL like string to C string @@ -658,20 +714,31 @@ void ThNormalize(uchar* ptr, uint field_length, const uchar* from, uint length) { const uchar* fr= from; uchar* p= ptr; + uint i; if (length > field_length) length= field_length; - while (length--) - if ((istone(*fr) || isdiacrt1(*fr)) && - (islwrvowel(fr[1]) || isuprvowel(fr[1]))) - { - *p= fr[1]; - p[1]= *fr; - fr+= 2; - p+= 2; - length--; + for (i=0;i<length;i++,p++,fr++) + { + *p = *fr ; + +/* Sathit's NOTE: it's better idea not to do any normalize +*/ + if (istone(*fr) || isdiacrt1(*fr)) + { + if (i > 0 && (islwrvowel(fr[-1]) || isuprvowel(fr[-1]))) + continue ; + if(islwrvowel(fr[1]) || isuprvowel(fr[1])) + { + *p= fr[1]; + p[1]= *fr; + fr++; + p++; + i++ ; + } } - else - *p++ = *fr++; + + } + } diff --git a/support-files/mysql.server.sh b/support-files/mysql.server.sh index d55068db64e..7f4987be3a8 100644 --- a/support-files/mysql.server.sh +++ b/support-files/mysql.server.sh @@ -59,6 +59,12 @@ export PATH mode=$1 # start or stop +case `echo "testing\c"`,`echo -n testing` in + *c*,-n*) echo_n= echo_c= ;; + *c*,*) echo_n=-n echo_c= ;; + *) echo_n= echo_c='\c' ;; +esac + parse_arguments() { for arg do case "$arg" in @@ -169,7 +175,7 @@ case "$mode" in sleep 1 while [ -s $pid_file -a "$flags" != aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ] do - [ -z "$flags" ] && echo "Wait for mysqld to exit\c" || echo ".\c" + [ -z "$flags" ] && echo $echo_n "Wait for mysqld to exit$echo_c" || echo $echo_n ".$echo_c" flags=a$flags sleep 1 done |