diff --git a/.bzrignore b/.bzrignore index 835e4b2c357..25056b86642 100644 --- a/.bzrignore +++ b/.bzrignore @@ -278,6 +278,7 @@ bkpush.log bkpush.log* build.log build_tags.sh +client/#mysql.cc# client/*.ds? client/*.vcproj client/completion_hash.cpp @@ -1181,7 +1182,9 @@ sql/pack.c sql/safe_to_cache_query.txt sql/share/*.sys sql/share/charsets/gmon.out +sql/share/fixerrmsg.pl sql/share/gmon.out +sql/share/iso639-2.txt sql/share/mysql sql/share/norwegian-ny/errmsg.sys sql/share/norwegian/errmsg.sys diff --git a/client/mysql.cc b/client/mysql.cc index 96df1fafc3b..ab1f4bdc8c5 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -852,6 +852,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case OPT_NOPAGER: printf("WARNING: option deprecated; use --disable-pager instead.\n"); opt_nopager= 1; + break; case OPT_MYSQL_PROTOCOL: { if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index ccd6932e25b..18a31117c08 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -35,9 +35,10 @@ /* Global Thread counter */ -int counter= 0; +int counter; #ifdef HAVE_LIBPTHREAD pthread_mutex_t counter_mutex; +pthread_cond_t count_threshhold; #endif static void db_error_with_table(MYSQL *mysql, char *table); @@ -556,6 +557,7 @@ error: pthread_mutex_lock(&counter_mutex); counter--; + pthread_cond_signal(&count_threshhold); pthread_mutex_unlock(&counter_mutex); my_thread_end(); @@ -584,28 +586,26 @@ int main(int argc, char **argv) { pthread_t mainthread; /* Thread descriptor */ pthread_attr_t attr; /* Thread attributes */ - VOID(pthread_mutex_init(&counter_mutex, NULL)); + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_DETACHED); - for (; *argv != NULL; argv++) /* Loop through tables */ + VOID(pthread_mutex_init(&counter_mutex, NULL)); + VOID(pthread_cond_init(&count_threshhold, NULL)); + + for (counter= 0; *argv != NULL; argv++) /* Loop through tables */ { - /* - If we hit thread count limit we loop until some threads exit. - We sleep for a second, so that we don't chew up a lot of - CPU in the loop. - */ -sanity_label: - if (counter == opt_use_threads) - { - sleep(1); - goto sanity_label; - } pthread_mutex_lock(&counter_mutex); + while (counter == opt_use_threads) + { + struct timespec abstime; + + set_timespec(abstime, 3); + pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime); + } + /* Before exiting the lock we set ourselves up for the next thread */ counter++; pthread_mutex_unlock(&counter_mutex); - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, - PTHREAD_CREATE_DETACHED); - /* now create the thread */ if (pthread_create(&mainthread, &attr, worker_thread, (void *)*argv) != 0) @@ -621,13 +621,18 @@ sanity_label: /* We loop until we know that all children have cleaned up. */ -loop_label: - if (counter) + pthread_mutex_lock(&counter_mutex); + while (counter) { - sleep(1); - goto loop_label; + struct timespec abstime; + + set_timespec(abstime, 3); + pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime); } + pthread_mutex_unlock(&counter_mutex); VOID(pthread_mutex_destroy(&counter_mutex)); + VOID(pthread_cond_destroy(&count_threshhold)); + pthread_attr_destroy(&attr); } else #endif diff --git a/extra/yassl/README b/extra/yassl/README index 62209723f66..a5ff70aa6f6 100644 --- a/extra/yassl/README +++ b/extra/yassl/README @@ -1,4 +1,14 @@ -yaSSL Release notes, version 1.3.0 (04/26/06) +yaSSL Release notes, version 1.3.5 (06/01/06) + + + This release of yaSSL contains bug fixes, portability enhancements, + better libcurl support, and improved non-blocking I/O. + +See normal build instructions below under 1.0.6. +See libcurl build instructions below under 1.3.0. + + +********************yaSSL Release notes, version 1.3.0 (04/26/06) This release of yaSSL contains minor bug fixes, portability enhancements, @@ -17,8 +27,8 @@ See normal build instructions below under 1.0.6. make make openssl-links - (then go to your libcurl home and tell libcurl about yaSSL) - ./configure --with-ssl=/yaSSL-HomeDir + (then go to your libcurl home and tell libcurl about yaSSL build dir) + ./configure --with-ssl=/yaSSL-BuildDir LDFLAGS=-lm make diff --git a/extra/yassl/include/openssl/engine.h b/extra/yassl/include/openssl/engine.h new file mode 100644 index 00000000000..39952fcae84 --- /dev/null +++ b/extra/yassl/include/openssl/engine.h @@ -0,0 +1,5 @@ +/* engine.h for libcurl */ + +#undef HAVE_OPENSSL_ENGINE_H + + diff --git a/extra/yassl/include/openssl/pkcs12.h b/extra/yassl/include/openssl/pkcs12.h new file mode 100644 index 00000000000..e452fc879c4 --- /dev/null +++ b/extra/yassl/include/openssl/pkcs12.h @@ -0,0 +1,5 @@ +/* pkcs12.h for libcurl */ + + +#undef HAVE_OPENSSL_PKCS12_H + diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp index 2b099af930c..12b62f26e14 100644 --- a/extra/yassl/src/handshake.cpp +++ b/extra/yassl/src/handshake.cpp @@ -458,6 +458,11 @@ void ProcessOldClientHello(input_buffer& input, SSL& ssl) uint16 sz = ((b0 & 0x7f) << 8) | b1; + if (sz > input.get_remaining()) { + ssl.SetError(bad_input); + return; + } + // hashHandShake manually const opaque* buffer = input.get_buffer() + input.get_current(); ssl.useHashes().use_MD5().update(buffer, sz); @@ -681,25 +686,38 @@ DoProcessReply(SSL& ssl, mySTL::auto_ptr buffered) // old style sslv2 client hello? if (ssl.getSecurity().get_parms().entity_ == server_end && ssl.getStates().getServer() == clientNull) - if (buffer.peek() != handshake) + if (buffer.peek() != handshake) { ProcessOldClientHello(buffer, ssl); + if (ssl.GetError()) { + buffered.reset(0); + return buffered; + } + } while(!buffer.eof()) { // each record RecordLayerHeader hdr; + bool needHdr = false; + + if (static_cast(RECORD_HEADER) > buffer.get_remaining()) + needHdr = true; + else { buffer >> hdr; ssl.verifyState(hdr); + } // make sure we have enough input in buffer to process this record - if (hdr.length_ > buffer.get_remaining()) { - uint sz = buffer.get_remaining() + RECORD_HEADER; + if (needHdr || hdr.length_ > buffer.get_remaining()) { + // put header in front for next time processing + uint extra = needHdr ? 0 : RECORD_HEADER; + uint sz = buffer.get_remaining() + extra; buffered.reset(NEW_YS input_buffer(sz, buffer.get_buffer() + - buffer.get_current() - RECORD_HEADER, sz)); + buffer.get_current() - extra, sz)); break; } while (buffer.get_current() < hdr.length_ + RECORD_HEADER + offset) { - // each message in record + // each message in record, can be more than 1 if not encrypted if (ssl.getSecurity().get_parms().pending_ == false) // cipher on decrypt_message(ssl, buffer, hdr.length_); mySTL::auto_ptr msg(mf.CreateObject(hdr.type_), ysDelete); @@ -717,7 +735,7 @@ DoProcessReply(SSL& ssl, mySTL::auto_ptr buffered) } offset += hdr.length_ + RECORD_HEADER; } - return buffered; // done, don't call again + return buffered; } diff --git a/include/config-win.h b/include/config-win.h index aa372762191..00d2fa0dea6 100644 --- a/include/config-win.h +++ b/include/config-win.h @@ -400,6 +400,7 @@ inline double ulonglong2double(ulonglong value) #define FN_LIBCHAR '\\' #define FN_ROOTDIR "\\" +#define FN_DEVCHAR ':' #define FN_NETWORK_DRIVES /* Uses \\ to indicate network drives */ #define FN_NO_CASE_SENCE /* Files are not case-sensitive */ #define OS_FILE_LIMIT 2048 diff --git a/include/my_global.h b/include/my_global.h index f2ad3af0b6f..f3f3825957f 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -681,7 +681,6 @@ typedef SOCKET_SIZE_TYPE size_socket; #define FN_HOMELIB '~' /* ~/ is used as abbrev for home dir */ #define FN_CURLIB '.' /* ./ is used as abbrev for current dir */ #define FN_PARENTDIR ".." /* Parent directory; Must be a string */ -#define FN_DEVCHAR ':' #ifndef FN_LIBCHAR #define FN_LIBCHAR '/' diff --git a/mysql-test/r/create_not_windows.result b/mysql-test/r/create_not_windows.result new file mode 100644 index 00000000000..b975c98c2b1 --- /dev/null +++ b/mysql-test/r/create_not_windows.result @@ -0,0 +1,14 @@ +drop table if exists `about:text`; +create table `about:text` ( +_id int not null auto_increment, +`about:text` varchar(255) not null default '', +primary key (_id) +); +show create table `about:text`; +Table Create Table +about:text CREATE TABLE `about:text` ( + `_id` int(11) NOT NULL auto_increment, + `about:text` varchar(255) NOT NULL default '', + PRIMARY KEY (`_id`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table `about:text`; diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 2d11f739717..1731146f901 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1,5 +1,10 @@ drop table if exists t1; create table t1 (a int) +engine = csv +partition by list (a) +(partition p0 values in (null)); +ERROR HY000: CSV handler cannot be used in partitioned tables +create table t1 (a int) partition by key(a) (partition p0 engine = MEMORY); drop table t1; @@ -344,25 +349,25 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) alter table t1; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) alter table t1 engine=myisam; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) alter table t1 engine=heap; show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) alter table t1 remove partitioning; show create table t1; Table Create Table @@ -379,7 +384,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) alter table t1 add column b int remove partitioning; show create table t1; Table Create Table @@ -396,7 +401,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) alter table t1 engine=heap partition by key(a) @@ -406,7 +411,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) alter table t1 engine=myisam, add column c int remove partitioning; show create table t1; Table Create Table @@ -425,7 +430,7 @@ t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, `c` int(11) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) alter table t1 partition by key (a) (partition p0, partition p1); @@ -435,7 +440,7 @@ t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, `c` int(11) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) alter table t1 engine=heap partition by key (a) @@ -446,7 +451,7 @@ t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, `c` int(11) DEFAULT NULL -) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) +) ENGINE=MEMORY DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MEMORY, PARTITION p1 ENGINE = MEMORY) alter table t1 partition by key(a) (partition p0, partition p1 engine=heap); @@ -598,7 +603,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) (PARTITION p0 VALUES LESS THAN (100) (SUBPARTITION p0sp0 ENGINE = MyISAM), PARTITION p1 VALUES LESS THAN (200) (SUBPARTITION subpart21 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a) (PARTITION p0 VALUES LESS THAN (100) (SUBPARTITION p0sp0 ENGINE = MyISAM), PARTITION p1 VALUES LESS THAN (200) (SUBPARTITION subpart21 ENGINE = MyISAM)) drop table t1; create table t1 (a int) partition by key (a); @@ -612,7 +617,7 @@ show create table t1; Table Create Table t1 CREATE TABLE `t1` ( `a` int(11) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY KEY (a) (PARTITION p0 ENGINE = MyISAM, PARTITION p1 ENGINE = MyISAM) drop table t1; create table t1 (a int, b int) partition by range (a) @@ -909,6 +914,28 @@ insert into t1 values (1); create index inx1 on t1(a); drop table t1; create table t1 (a int) +PARTITION BY KEY (a) +(PARTITION p0); +set session sql_mode='no_table_options'; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) PARTITION BY KEY (a) (PARTITION p0) +set session sql_mode=''; +drop table t1; +create table t1 (a int) +partition by key (a) +(partition p1 engine = innodb); +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +drop table t1; +create table t1 (a int) partition by key (a) (partition p0 engine = MERGE); ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables diff --git a/mysql-test/r/partition_02myisam.result b/mysql-test/r/partition_02myisam.result index 147e705f861..35ee0fe22ee 100644 --- a/mysql-test/r/partition_02myisam.result +++ b/mysql-test/r/partition_02myisam.result @@ -147,7 +147,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -205,7 +205,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -260,7 +260,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -313,7 +313,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -371,7 +371,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -429,7 +429,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -489,7 +489,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -547,7 +547,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -603,7 +603,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -661,7 +661,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -721,7 +721,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -833,7 +833,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -891,7 +891,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (200) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM), PARTITION part3 VALUES LESS THAN (2147483647) (SUBPARTITION subpart31 ENGINE = MyISAM, SUBPARTITION subpart32 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (100) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (200) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM), PARTITION part3 VALUES LESS THAN (2147483647) (SUBPARTITION subpart31 ENGINE = MyISAM, SUBPARTITION subpart32 ENGINE = MyISAM)) SELECT COUNT(*) = 0 AS my_value FROM t1; my_value 1 @@ -1304,7 +1304,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) DROP TABLE t1; CREATE TABLE t1 ( f1 INTEGER, f2 char(20)) PARTITION BY RANGE(f1) PARTITIONS 2 @@ -1319,7 +1319,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (1000) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (f1) SUBPARTITION BY HASH (f1) (PARTITION part1 VALUES LESS THAN (1000) (SUBPARTITION subpart11 ENGINE = MyISAM, SUBPARTITION subpart12 ENGINE = MyISAM), PARTITION part2 VALUES LESS THAN (2147483647) (SUBPARTITION subpart21 ENGINE = MyISAM, SUBPARTITION subpart22 ENGINE = MyISAM)) DROP TABLE t1; # 3.3.2 (positive) number of partition/subpartition , # 0 (= no) named partition/subpartition @@ -1454,7 +1454,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION p0 ENGINE = MyISAM, PARTITION part1 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION p0 ENGINE = MyISAM, PARTITION part1 ENGINE = MyISAM) INSERT INTO t1 SELECT * FROM t0_template WHERE f1 BETWEEN 100 AND 200; SELECT (COUNT(*) = 200) AND (MIN(f1) = 1) AND (MAX(f1) = 200) AS my_value FROM t1; @@ -1502,7 +1502,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM) INSERT INTO t1 SELECT * FROM t0_template WHERE f1 BETWEEN 1 AND 100 - 1; ALTER TABLE t1 ADD PARTITION (PARTITION part0); SHOW CREATE TABLE t1; @@ -1510,7 +1510,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM, PARTITION part0 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM, PARTITION part0 ENGINE = MyISAM) INSERT INTO t1 SELECT * FROM t0_template WHERE f1 BETWEEN 100 AND 200; SELECT (COUNT(*) = 200) AND (MIN(f1) = 1) AND (MAX(f1) = 200) AS my_value FROM t1; @@ -1557,7 +1557,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM, PARTITION part0 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM, PARTITION part0 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) INSERT INTO t1 SELECT * FROM t0_template WHERE f1 BETWEEN 100 AND 200; SELECT (COUNT(*) = 200) AND (MIN(f1) = 1) AND (MAX(f1) = 200) AS my_value FROM t1; @@ -1603,7 +1603,7 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM, PARTITION part0 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM, PARTITION part0 ENGINE = MyISAM, PARTITION part2 ENGINE = MyISAM) INSERT INTO t1 SELECT * FROM t0_template WHERE f1 BETWEEN 100 AND 200; SELECT (COUNT(*) = 200) AND (MIN(f1) = 1) AND (MAX(f1) = 200) AS my_value FROM t1; @@ -1651,14 +1651,14 @@ Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM) INSERT INTO t1 SELECT * FROM t0_template WHERE f1 BETWEEN 1 AND 100 - 1; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `f1` int(11) DEFAULT NULL, `f2` char(20) DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (f1) (PARTITION part1 ENGINE = MyISAM, PARTITION part3 ENGINE = MyISAM) INSERT INTO t1 SELECT * FROM t0_template WHERE f1 BETWEEN 100 AND 200; SELECT (COUNT(*) = 200) AND (MIN(f1) = 1) AND (MAX(f1) = 200) AS my_value FROM t1; diff --git a/mysql-test/r/partition_mgm.result b/mysql-test/r/partition_mgm.result new file mode 100644 index 00000000000..48bbdf57b93 --- /dev/null +++ b/mysql-test/r/partition_mgm.result @@ -0,0 +1,16 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30)) +PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f_date` date DEFAULT NULL, + `f_varchar` varchar(30) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 2 +ALTER TABLE t1 COALESCE PARTITION 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f_date` date DEFAULT NULL, + `f_varchar` varchar(30) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 1 diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result index c7257db4910..518d3a8e1d4 100644 --- a/mysql-test/r/partition_range.result +++ b/mysql-test/r/partition_range.result @@ -143,7 +143,7 @@ t1 CREATE TABLE `t1` ( `b` int(11) NOT NULL, `c` int(11) NOT NULL, PRIMARY KEY (`a`,`b`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a+b) (PARTITION x1 VALUES LESS THAN (1) (SUBPARTITION x11 ENGINE = MyISAM, SUBPARTITION x12 ENGINE = MyISAM), PARTITION x2 VALUES LESS THAN (5) (SUBPARTITION x21 ENGINE = MyISAM, SUBPARTITION x22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a+b) (PARTITION x1 VALUES LESS THAN (1) (SUBPARTITION x11 ENGINE = MyISAM, SUBPARTITION x12 ENGINE = MyISAM), PARTITION x2 VALUES LESS THAN (5) (SUBPARTITION x21 ENGINE = MyISAM, SUBPARTITION x22 ENGINE = MyISAM)) ALTER TABLE t1 ADD COLUMN d int; show create table t1; Table Create Table @@ -153,7 +153,7 @@ t1 CREATE TABLE `t1` ( `c` int(11) NOT NULL, `d` int(11) DEFAULT NULL, PRIMARY KEY (`a`,`b`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a+b) (PARTITION x1 VALUES LESS THAN (1) (SUBPARTITION x11 ENGINE = MyISAM, SUBPARTITION x12 ENGINE = MyISAM), PARTITION x2 VALUES LESS THAN (5) (SUBPARTITION x21 ENGINE = MyISAM, SUBPARTITION x22 ENGINE = MyISAM)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY RANGE (a) SUBPARTITION BY HASH (a+b) (PARTITION x1 VALUES LESS THAN (1) (SUBPARTITION x11 ENGINE = MyISAM, SUBPARTITION x12 ENGINE = MyISAM), PARTITION x2 VALUES LESS THAN (5) (SUBPARTITION x21 ENGINE = MyISAM, SUBPARTITION x22 ENGINE = MyISAM)) drop table t1; CREATE TABLE t1 ( a int not null, @@ -387,3 +387,108 @@ ALTER TABLE t1 DROP PARTITION p0; ALTER TABLE t1 DROP PARTITION p1; ALTER TABLE t1 DROP PARTITION p2; drop table t1; +create table t1 (a int DEFAULT NULL, +b varchar(30) DEFAULT NULL, +c date DEFAULT NULL) +ENGINE=MYISAM DEFAULT CHARSET=latin1; +insert into t1 values (1, 'abc', '1995-01-01'); +insert into t1 values (1, 'abc', '1995-01-02'); +insert into t1 values (1, 'abc', '1995-01-03'); +insert into t1 values (1, 'abc', '1995-01-04'); +insert into t1 values (1, 'abc', '1995-01-05'); +insert into t1 values (1, 'abc', '1995-01-06'); +insert into t1 values (1, 'abc', '1995-01-07'); +insert into t1 values (1, 'abc', '1995-01-08'); +insert into t1 values (1, 'abc', '1995-01-09'); +insert into t1 values (1, 'abc', '1995-01-10'); +insert into t1 values (1, 'abc', '1995-01-11'); +insert into t1 values (1, 'abc', '1995-01-12'); +insert into t1 values (1, 'abc', '1995-01-13'); +insert into t1 values (1, 'abc', '1995-01-14'); +insert into t1 values (1, 'abc', '1995-01-15'); +insert into t1 values (1, 'abc', '1997-01-01'); +insert into t1 values (1, 'abc', '1997-01-02'); +insert into t1 values (1, 'abc', '1997-01-03'); +insert into t1 values (1, 'abc', '1997-01-04'); +insert into t1 values (1, 'abc', '1997-01-05'); +insert into t1 values (1, 'abc', '1997-01-06'); +insert into t1 values (1, 'abc', '1997-01-07'); +insert into t1 values (1, 'abc', '1997-01-08'); +insert into t1 values (1, 'abc', '1997-01-09'); +insert into t1 values (1, 'abc', '1997-01-10'); +insert into t1 values (1, 'abc', '1997-01-11'); +insert into t1 values (1, 'abc', '1997-01-12'); +insert into t1 values (1, 'abc', '1997-01-13'); +insert into t1 values (1, 'abc', '1997-01-14'); +insert into t1 values (1, 'abc', '1997-01-15'); +insert into t1 values (1, 'abc', '1998-01-01'); +insert into t1 values (1, 'abc', '1998-01-02'); +insert into t1 values (1, 'abc', '1998-01-03'); +insert into t1 values (1, 'abc', '1998-01-04'); +insert into t1 values (1, 'abc', '1998-01-05'); +insert into t1 values (1, 'abc', '1998-01-06'); +insert into t1 values (1, 'abc', '1998-01-07'); +insert into t1 values (1, 'abc', '1998-01-08'); +insert into t1 values (1, 'abc', '1998-01-09'); +insert into t1 values (1, 'abc', '1998-01-10'); +insert into t1 values (1, 'abc', '1998-01-11'); +insert into t1 values (1, 'abc', '1998-01-12'); +insert into t1 values (1, 'abc', '1998-01-13'); +insert into t1 values (1, 'abc', '1998-01-14'); +insert into t1 values (1, 'abc', '1998-01-15'); +insert into t1 values (1, 'abc', '1999-01-01'); +insert into t1 values (1, 'abc', '1999-01-02'); +insert into t1 values (1, 'abc', '1999-01-03'); +insert into t1 values (1, 'abc', '1999-01-04'); +insert into t1 values (1, 'abc', '1999-01-05'); +insert into t1 values (1, 'abc', '1999-01-06'); +insert into t1 values (1, 'abc', '1999-01-07'); +insert into t1 values (1, 'abc', '1999-01-08'); +insert into t1 values (1, 'abc', '1999-01-09'); +insert into t1 values (1, 'abc', '1999-01-10'); +insert into t1 values (1, 'abc', '1999-01-11'); +insert into t1 values (1, 'abc', '1999-01-12'); +insert into t1 values (1, 'abc', '1999-01-13'); +insert into t1 values (1, 'abc', '1999-01-14'); +insert into t1 values (1, 'abc', '1999-01-15'); +insert into t1 values (1, 'abc', '2000-01-01'); +insert into t1 values (1, 'abc', '2000-01-02'); +insert into t1 values (1, 'abc', '2000-01-03'); +insert into t1 values (1, 'abc', '2000-01-04'); +insert into t1 values (1, 'abc', '2000-01-05'); +insert into t1 values (1, 'abc', '2000-01-06'); +insert into t1 values (1, 'abc', '2000-01-07'); +insert into t1 values (1, 'abc', '2000-01-08'); +insert into t1 values (1, 'abc', '2000-01-09'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2000-01-11'); +insert into t1 values (1, 'abc', '2000-01-12'); +insert into t1 values (1, 'abc', '2000-01-13'); +insert into t1 values (1, 'abc', '2000-01-14'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2001-01-01'); +insert into t1 values (1, 'abc', '2001-01-02'); +insert into t1 values (1, 'abc', '2001-01-03'); +insert into t1 values (1, 'abc', '2001-01-04'); +insert into t1 values (1, 'abc', '2001-01-05'); +insert into t1 values (1, 'abc', '2001-01-06'); +insert into t1 values (1, 'abc', '2001-01-07'); +insert into t1 values (1, 'abc', '2001-01-08'); +insert into t1 values (1, 'abc', '2001-01-09'); +insert into t1 values (1, 'abc', '2001-01-15'); +insert into t1 values (1, 'abc', '2001-01-11'); +insert into t1 values (1, 'abc', '2001-01-12'); +insert into t1 values (1, 'abc', '2001-01-13'); +insert into t1 values (1, 'abc', '2001-01-14'); +insert into t1 values (1, 'abc', '2001-01-15'); +alter table t1 +partition by range (year(c)) +(partition p5 values less than (2000), partition p10 values less than (2010)); +alter table t1 +reorganize partition p5 into +(partition p1 values less than (1996), +partition p2 values less than (1997), +partition p3 values less than (1998), +partition p4 values less than (1999), +partition p5 values less than (2000)); +drop table t1; diff --git a/mysql-test/t/create_not_windows.test b/mysql-test/t/create_not_windows.test new file mode 100644 index 00000000000..71ad9ccd7fe --- /dev/null +++ b/mysql-test/t/create_not_windows.test @@ -0,0 +1,20 @@ +# Non-windows specific create tests. + +--source include/not_windows.inc + +# +# Bug#19479:mysqldump creates invalid dump +# +--disable_warnings +drop table if exists `about:text`; +--enable_warnings +create table `about:text` ( +_id int not null auto_increment, +`about:text` varchar(255) not null default '', +primary key (_id) +); + +show create table `about:text`; +drop table `about:text`; + +# End of 5.0 tests diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index 90cd27ded55..6e5ea515710 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -9,6 +9,17 @@ drop table if exists t1; --enable_warnings +# +# Bug 19307: CSV engine crashes +# +--error ER_PARTITION_MERGE_ERROR +create table t1 (a int) +engine = csv +partition by list (a) +(partition p0 values in (null)); + +# +# create table t1 (a int) partition by key(a) (partition p0 engine = MEMORY); @@ -1030,6 +1041,34 @@ insert into t1 values (1); create index inx1 on t1(a); drop table t1; +# +# Bug 19695 Partitions: SHOW CREATE TABLE shows table options even when it +# shouldn't +# +create table t1 (a int) +PARTITION BY KEY (a) +(PARTITION p0); +set session sql_mode='no_table_options'; +show create table t1; +set session sql_mode=''; +drop table t1; + +# +# BUG 19122 Crash after ALTER TABLE t1 REBUILD PARTITION p1 +# +create table t1 (a int) +partition by key (a) +(partition p1 engine = innodb); + +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +alter table t1 rebuild partition p1; +drop table t1; + # # BUG 19304 Partitions: MERGE handler not allowed in partitioned tables # diff --git a/mysql-test/t/partition_mgm.test b/mysql-test/t/partition_mgm.test new file mode 100644 index 00000000000..67c0619f28c --- /dev/null +++ b/mysql-test/t/partition_mgm.test @@ -0,0 +1,15 @@ +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30)) +PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 2; +SHOW CREATE TABLE t1; + +#--exec ls $MYSQLTEST_VARDIR/master-data/test/t1* +ALTER TABLE t1 COALESCE PARTITION 1; +SHOW CREATE TABLE t1; +#--exec ls $MYSQLTEST_VARDIR/master-data/test/t1* + + + + diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test index ef539e2001f..42ce4e0d879 100644 --- a/mysql-test/t/partition_range.test +++ b/mysql-test/t/partition_range.test @@ -416,3 +416,117 @@ ALTER TABLE t1 DROP PARTITION p0; ALTER TABLE t1 DROP PARTITION p1; ALTER TABLE t1 DROP PARTITION p2; drop table t1; + +# +# Bug 19830: ALTER TABLE t1 REORGANIZE PARTITION crashes +# +create table t1 (a int DEFAULT NULL, + b varchar(30) DEFAULT NULL, + c date DEFAULT NULL) +ENGINE=MYISAM DEFAULT CHARSET=latin1; + +insert into t1 values (1, 'abc', '1995-01-01'); +insert into t1 values (1, 'abc', '1995-01-02'); +insert into t1 values (1, 'abc', '1995-01-03'); +insert into t1 values (1, 'abc', '1995-01-04'); +insert into t1 values (1, 'abc', '1995-01-05'); +insert into t1 values (1, 'abc', '1995-01-06'); +insert into t1 values (1, 'abc', '1995-01-07'); +insert into t1 values (1, 'abc', '1995-01-08'); +insert into t1 values (1, 'abc', '1995-01-09'); +insert into t1 values (1, 'abc', '1995-01-10'); +insert into t1 values (1, 'abc', '1995-01-11'); +insert into t1 values (1, 'abc', '1995-01-12'); +insert into t1 values (1, 'abc', '1995-01-13'); +insert into t1 values (1, 'abc', '1995-01-14'); +insert into t1 values (1, 'abc', '1995-01-15'); +insert into t1 values (1, 'abc', '1997-01-01'); +insert into t1 values (1, 'abc', '1997-01-02'); +insert into t1 values (1, 'abc', '1997-01-03'); +insert into t1 values (1, 'abc', '1997-01-04'); +insert into t1 values (1, 'abc', '1997-01-05'); +insert into t1 values (1, 'abc', '1997-01-06'); +insert into t1 values (1, 'abc', '1997-01-07'); +insert into t1 values (1, 'abc', '1997-01-08'); +insert into t1 values (1, 'abc', '1997-01-09'); +insert into t1 values (1, 'abc', '1997-01-10'); +insert into t1 values (1, 'abc', '1997-01-11'); +insert into t1 values (1, 'abc', '1997-01-12'); +insert into t1 values (1, 'abc', '1997-01-13'); +insert into t1 values (1, 'abc', '1997-01-14'); +insert into t1 values (1, 'abc', '1997-01-15'); +insert into t1 values (1, 'abc', '1998-01-01'); +insert into t1 values (1, 'abc', '1998-01-02'); +insert into t1 values (1, 'abc', '1998-01-03'); +insert into t1 values (1, 'abc', '1998-01-04'); +insert into t1 values (1, 'abc', '1998-01-05'); +insert into t1 values (1, 'abc', '1998-01-06'); +insert into t1 values (1, 'abc', '1998-01-07'); +insert into t1 values (1, 'abc', '1998-01-08'); +insert into t1 values (1, 'abc', '1998-01-09'); +insert into t1 values (1, 'abc', '1998-01-10'); +insert into t1 values (1, 'abc', '1998-01-11'); +insert into t1 values (1, 'abc', '1998-01-12'); +insert into t1 values (1, 'abc', '1998-01-13'); +insert into t1 values (1, 'abc', '1998-01-14'); +insert into t1 values (1, 'abc', '1998-01-15'); +insert into t1 values (1, 'abc', '1999-01-01'); +insert into t1 values (1, 'abc', '1999-01-02'); +insert into t1 values (1, 'abc', '1999-01-03'); +insert into t1 values (1, 'abc', '1999-01-04'); +insert into t1 values (1, 'abc', '1999-01-05'); +insert into t1 values (1, 'abc', '1999-01-06'); +insert into t1 values (1, 'abc', '1999-01-07'); +insert into t1 values (1, 'abc', '1999-01-08'); +insert into t1 values (1, 'abc', '1999-01-09'); +insert into t1 values (1, 'abc', '1999-01-10'); +insert into t1 values (1, 'abc', '1999-01-11'); +insert into t1 values (1, 'abc', '1999-01-12'); +insert into t1 values (1, 'abc', '1999-01-13'); +insert into t1 values (1, 'abc', '1999-01-14'); +insert into t1 values (1, 'abc', '1999-01-15'); +insert into t1 values (1, 'abc', '2000-01-01'); +insert into t1 values (1, 'abc', '2000-01-02'); +insert into t1 values (1, 'abc', '2000-01-03'); +insert into t1 values (1, 'abc', '2000-01-04'); +insert into t1 values (1, 'abc', '2000-01-05'); +insert into t1 values (1, 'abc', '2000-01-06'); +insert into t1 values (1, 'abc', '2000-01-07'); +insert into t1 values (1, 'abc', '2000-01-08'); +insert into t1 values (1, 'abc', '2000-01-09'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2000-01-11'); +insert into t1 values (1, 'abc', '2000-01-12'); +insert into t1 values (1, 'abc', '2000-01-13'); +insert into t1 values (1, 'abc', '2000-01-14'); +insert into t1 values (1, 'abc', '2000-01-15'); +insert into t1 values (1, 'abc', '2001-01-01'); +insert into t1 values (1, 'abc', '2001-01-02'); +insert into t1 values (1, 'abc', '2001-01-03'); +insert into t1 values (1, 'abc', '2001-01-04'); +insert into t1 values (1, 'abc', '2001-01-05'); +insert into t1 values (1, 'abc', '2001-01-06'); +insert into t1 values (1, 'abc', '2001-01-07'); +insert into t1 values (1, 'abc', '2001-01-08'); +insert into t1 values (1, 'abc', '2001-01-09'); +insert into t1 values (1, 'abc', '2001-01-15'); +insert into t1 values (1, 'abc', '2001-01-11'); +insert into t1 values (1, 'abc', '2001-01-12'); +insert into t1 values (1, 'abc', '2001-01-13'); +insert into t1 values (1, 'abc', '2001-01-14'); +insert into t1 values (1, 'abc', '2001-01-15'); + +alter table t1 +partition by range (year(c)) +(partition p5 values less than (2000), partition p10 values less than (2010)); + +alter table t1 +reorganize partition p5 into +(partition p1 values less than (1996), + partition p2 values less than (1997), + partition p3 values less than (1998), + partition p4 values less than (1999), + partition p5 values less than (2000)); + +drop table t1; + diff --git a/mysys/mf_fn_ext.c b/mysys/mf_fn_ext.c index 9c86a8072ef..d7b1f8c1d61 100644 --- a/mysys/mf_fn_ext.c +++ b/mysys/mf_fn_ext.c @@ -40,14 +40,14 @@ my_string fn_ext(const char *name) DBUG_ENTER("fn_ext"); DBUG_PRINT("mfunkt",("name: '%s'",name)); -#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR) +#if defined(FN_DEVCHAR) || defined(FN_C_AFTER_DIR) || defined(BASKSLASH_MBTAIL) { char buff[FN_REFLEN]; gpos=(my_string) name+dirname_part(buff,(char*) name); } #else - if (!(gpos=strrchr(name,FNLIBCHAR))) - gpos=name; + if (!(gpos= strrchr(name, FN_LIBCHAR))) + gpos= (my_string) name; #endif pos=strchr(gpos,FN_EXTCHAR); DBUG_RETURN (pos ? pos : strend(gpos)); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 77a150994ad..f151d89bb1a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -611,6 +611,8 @@ int ha_partition::drop_partitions(const char *path) DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff)); if ((ret_error= file->delete_table((const char *) part_name_buff))) error= ret_error; + if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos)) + error= 1; } while (++j < no_subparts); } else @@ -622,6 +624,8 @@ int ha_partition::drop_partitions(const char *path) DBUG_PRINT("info", ("Drop partition %s", part_name_buff)); if ((ret_error= file->delete_table((const char *) part_name_buff))) error= ret_error; + if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos)) + error= 1; } if (part_elem->part_state == PART_IS_CHANGED) part_elem->part_state= PART_NORMAL; @@ -629,6 +633,7 @@ int ha_partition::drop_partitions(const char *path) part_elem->part_state= PART_IS_DROPPED; } } while (++i < no_parts); + VOID(sync_ddl_log()); DBUG_RETURN(error); } @@ -745,6 +750,7 @@ int ha_partition::rename_partitions(const char *path) */ part_elem= part_it++; if (part_elem->part_state == PART_IS_CHANGED || + part_elem->part_state == PART_TO_BE_DROPPED || (part_elem->part_state == PART_IS_ADDED && temp_partitions)) { if (m_is_sub_partitioned) diff --git a/sql/lock.cc b/sql/lock.cc index 80861e3beb5..e5003325df6 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -828,7 +828,7 @@ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list) if (wait_if_global_read_lock(thd, 0, 1)) DBUG_RETURN(1); VOID(pthread_mutex_lock(&LOCK_open)); - if ((lock_retcode = lock_table_name(thd, table_list)) < 0) + if ((lock_retcode = lock_table_name(thd, table_list, TRUE)) < 0) goto end; if (lock_retcode && wait_for_locked_table_names(thd, table_list)) { @@ -851,6 +851,7 @@ end: lock_table_name() thd Thread handler table_list Lock first table in this list + check_in_use Do we need to check if table already in use by us WARNING If you are going to update the table, you should use @@ -870,7 +871,7 @@ end: > 0 table locked, but someone is using it */ -int lock_table_name(THD *thd, TABLE_LIST *table_list) +int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use) { TABLE *table; char key[MAX_DBKEY_LENGTH]; @@ -882,17 +883,22 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) key_length= create_table_def_key(thd, key, table_list, 0); - /* Only insert the table if we haven't insert it already */ - for (table=(TABLE*) hash_first(&open_cache, (byte*)key, key_length, &state); - table ; - table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length, &state)) + if (check_in_use) { - if (table->in_use == thd) + /* Only insert the table if we haven't insert it already */ + for (table=(TABLE*) hash_first(&open_cache, (byte*)key, + key_length, &state); + table ; + table = (TABLE*) hash_next(&open_cache,(byte*) key, + key_length, &state)) { - DBUG_PRINT("info", ("Table is in use")); - table->s->version= 0; // Ensure no one can use this - table->locked_by_name= 1; - DBUG_RETURN(0); + if (table->in_use == thd) + { + DBUG_PRINT("info", ("Table is in use")); + table->s->version= 0; // Ensure no one can use this + table->locked_by_name= 1; + DBUG_RETURN(0); + } } } /* @@ -917,10 +923,10 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) my_free((gptr) table,MYF(0)); DBUG_RETURN(-1); } - + /* Return 1 if table is in use */ DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name, - RTFC_NO_FLAG))); + check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG))); } @@ -1003,7 +1009,7 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list) for (lock_table= table_list; lock_table; lock_table= lock_table->next_local) { int got_lock; - if ((got_lock=lock_table_name(thd,lock_table)) < 0) + if ((got_lock=lock_table_name(thd,lock_table, TRUE)) < 0) goto end; // Fatal error if (got_lock) got_all_locks=0; // Someone is using table diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 76d8aa18f59..3d499b67519 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1174,7 +1174,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, HA_CREATE_INFO *create_info, TABLE_LIST *table_list, List *create_list, - List *key_list, const char *db, + List *key_list, char *db, const char *table_name, uint fast_alter_partition); uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, @@ -1204,10 +1204,12 @@ void create_subpartition_name(char *out, const char *in1, typedef struct st_lock_param_type { + TABLE_LIST table_list; ulonglong copied; ulonglong deleted; THD *thd; HA_CREATE_INFO *create_info; + ALTER_INFO *alter_info; List *create_list; List new_create_list; List *key_list; @@ -1687,7 +1689,7 @@ void unset_protect_against_global_read_lock(void); /* Lock based on name */ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); -int lock_table_name(THD *thd, TABLE_LIST *table_list); +int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use); void unlock_table_name(THD *thd, TABLE_LIST *table_list); bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list); bool lock_table_names(THD *thd, TABLE_LIST *table_list); diff --git a/sql/partition_info.cc b/sql/partition_info.cc index edd8f56d8c4..59cedc884b6 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -442,9 +442,11 @@ bool partition_info::check_engine_mix(handlerton **engine_array, uint no_parts) DBUG_RETURN(TRUE); } } while (++i < no_parts); - if (engine_array[0] == &myisammrg_hton) + if (engine_array[0] == &myisammrg_hton || + engine_array[0] == &tina_hton) { - my_error(ER_PARTITION_MERGE_ERROR, MYF(0)); + my_error(ER_PARTITION_MERGE_ERROR, MYF(0), + engine_array[0] == &myisammrg_hton ? "MyISAM Merge" : "CSV"); DBUG_RETURN(TRUE); } DBUG_RETURN(FALSE); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index ae5ddd31475..1de2e893555 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5830,5 +5830,5 @@ ER_EVENT_MODIFY_QUEUE_ERROR ER_EVENT_SET_VAR_ERROR eng "Error during starting/stopping of the scheduler. Error code %u" ER_PARTITION_MERGE_ERROR - eng "MyISAM Merge handler cannot be used in partitioned tables" - swe "MyISAM Merge kan inte anändas i en partitionerad tabell" + eng "%s handler cannot be used in partitioned tables" + swe "%s kan inte användas i en partitionerad tabell" diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 2298de7eeb5..9b7d46119b7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2686,7 +2686,7 @@ retry: goto err; // Code below is for repairing a crashed file - if ((error= lock_table_name(thd, table_list))) + if ((error= lock_table_name(thd, table_list, TRUE))) { if (error < 0) goto err; diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a10a04ba9f9..db69fd3daef 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 MySQL AB +/* Copyright (C) 2005, 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -238,8 +238,8 @@ bool partition_default_handling(TABLE *table, partition_info *part_info, check_reorganise_list() new_part_info New partition info old_part_info Old partition info - list_part_names The list of partition names that will go away and can be reused in the - new table. + list_part_names The list of partition names that will go away and + can be reused in the new table. RETURN VALUES TRUE Inacceptable name conflict detected. @@ -1675,6 +1675,7 @@ static int add_partition_options(File fptr, partition_element *p_elem) { int err= 0; + err+= add_space(fptr); if (p_elem->tablespace_name) err+= add_keyword_string(fptr,"TABLESPACE", FALSE, p_elem->tablespace_name); @@ -1702,7 +1703,7 @@ static int add_partition_values(File fptr, partition_info *part_info, if (part_info->part_type == RANGE_PARTITION) { - err+= add_string(fptr, "VALUES LESS THAN "); + err+= add_string(fptr, " VALUES LESS THAN "); if (p_elem->range_value != LONGLONG_MAX) { err+= add_begin_parenthesis(fptr); @@ -1716,7 +1717,7 @@ static int add_partition_values(File fptr, partition_info *part_info, { uint i; List_iterator list_val_it(p_elem->list_val_list); - err+= add_string(fptr, "VALUES IN "); + err+= add_string(fptr, " VALUES IN "); uint no_items= p_elem->list_val_list.elements; err+= add_begin_parenthesis(fptr); if (p_elem->has_null_value) @@ -1740,7 +1741,7 @@ static int add_partition_values(File fptr, partition_info *part_info, err+= add_end_parenthesis(fptr); } end: - return err + add_space(fptr); + return err; } /* @@ -1754,6 +1755,7 @@ end: buf_length A pointer to the returned buffer length use_sql_alloc Allocate buffer from sql_alloc if true otherwise use my_malloc + show_partition_options Should we display partition options RETURN VALUES NULL error @@ -1781,7 +1783,8 @@ end: char *generate_partition_syntax(partition_info *part_info, uint *buf_length, - bool use_sql_alloc) + bool use_sql_alloc, + bool show_partition_options) { uint i,j, tot_no_parts, no_subparts, no_parts; partition_element *part_elem; @@ -1882,12 +1885,12 @@ char *generate_partition_syntax(partition_info *part_info, first= FALSE; err+= add_partition(fptr); err+= add_name_string(fptr, part_elem->partition_name); - err+= add_space(fptr); err+= add_partition_values(fptr, part_info, part_elem); if (!part_info->is_sub_partitioned() || part_info->use_default_subpartitions) { - err+= add_partition_options(fptr, part_elem); + if (show_partition_options) + err+= add_partition_options(fptr, part_elem); } else { @@ -1900,8 +1903,8 @@ char *generate_partition_syntax(partition_info *part_info, part_elem= sub_it++; err+= add_subpartition(fptr); err+= add_name_string(fptr, part_elem->partition_name); - err+= add_space(fptr); - err+= add_partition_options(fptr, part_elem); + if (show_partition_options) + err+= add_partition_options(fptr, part_elem); if (j != (no_subparts-1)) { err+= add_comma(fptr); @@ -4996,8 +4999,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; - if (temp_list) - sub_elem->log_entry= log_entry; + sub_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } while (++j < no_subparts); } @@ -5015,8 +5017,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt, DBUG_RETURN(TRUE); } *next_entry= log_entry->entry_pos; - if (temp_list) - part_elem->log_entry= log_entry; + part_elem->log_entry= log_entry; insert_part_info_log_entry_list(part_info, log_entry); } } @@ -5290,7 +5291,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) lpt->table_name, "#"); pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, - TRUE)) + lpt->alter_info->flags & ALTER_REORGANIZE_PARTITION)) goto error; if (write_log_changed_partitions(lpt, &next_entry, (const char*)path)) goto error; @@ -5377,6 +5378,79 @@ static void release_log_entries(partition_info *part_info) } +/* + Get a lock on table name to avoid that anyone can open the table in + a critical part of the ALTER TABLE. + SYNOPSIS + get_name_lock() + lpt Struct carrying parameters + RETURN VALUES + FALSE Success + TRUE Failure +*/ + +static int get_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + int error= 0; + DBUG_ENTER("get_name_lock"); + + bzero(&lpt->table_list, sizeof(lpt->table_list)); + lpt->table_list.db= (char*)lpt->db; + lpt->table_list.table= lpt->table; + lpt->table_list.table_name= (char*)lpt->table_name; + pthread_mutex_lock(&LOCK_open); + error= lock_table_name(lpt->thd, &lpt->table_list, FALSE); + pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(error); +} + + +/* + Unlock and close table before renaming and dropping partitions + SYNOPSIS + alter_close_tables() + lpt Struct carrying parameters + RETURN VALUES + 0 +*/ + +static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + THD *thd= lpt->thd; + TABLE *table= lpt->table; + DBUG_ENTER("alter_close_tables"); + /* + We need to also unlock tables and close all handlers. + We set lock to zero to ensure we don't do this twice + and we set db_stat to zero to ensure we don't close twice. + */ + mysql_unlock_tables(thd, thd->lock); + thd->lock= 0; + table->file->close(); + table->db_stat= 0; + DBUG_RETURN(0); +} + + +/* + Release a lock name + SYNOPSIS + release_name_lock() + lpt + RETURN VALUES + 0 +*/ + +static int release_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt) +{ + DBUG_ENTER("release_name_lock"); + pthread_mutex_lock(&LOCK_open); + unlock_table_name(lpt->thd, &lpt->table_list); + pthread_mutex_unlock(&LOCK_open); + DBUG_RETURN(0); +} + + /* Handle errors for ALTER TABLE for partitioning SYNOPSIS @@ -5527,7 +5601,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, HA_CREATE_INFO *create_info, TABLE_LIST *table_list, List *create_list, - List *key_list, const char *db, + List *key_list, char *db, const char *table_name, uint fast_alter_partition) { @@ -5544,6 +5618,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, lpt->thd= thd; lpt->part_info= part_info; + lpt->alter_info= alter_info; lpt->create_info= create_info; lpt->create_list= create_list; lpt->key_list= key_list; @@ -5667,8 +5742,17 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 2) Write the ddl log to ensure that the operation is completed even in the presence of a MySQL Server crash 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to - the table have completed - 4) Write the bin log + the table have completed. This ensures that other threads can not + execute on the table in parallel. + 4) Get a name lock on the table. This ensures that we can release all + locks on the table and since no one can open the table, there can + be no new threads accessing the table. They will be hanging on the + name lock. + 5) Close all tables that have already been opened but didn't stumble on + the abort locked previously. This is done as part of the + get_name_lock call. + 6) We are now ready to release all locks we got in this thread. + 7) Write the bin log Unfortunately the writing of the binlog is not synchronised with other logging activities. So no matter in which order the binlog is written compared to other activities there will always be cases @@ -5679,14 +5763,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, require writing the statement first in the ddl log and then when recovering from the crash read the binlog and insert it into the binlog if not written already. - 5) Install the previously written shadow frm file - 6) Ensure that any users that has opened the table but not yet - reached the abort lock do that before downgrading the lock. - 7) Prepare MyISAM handlers for drop of partitions - 8) Drop the partitions - 9) Remove entries from ddl log - 10) Wait until all accesses using the old frm file has completed - 11) Complete query + 8) Install the previously written shadow frm file + 9) Prepare handlers for drop of partitions + 10) Drop the partitions + 11) Remove entries from ddl log + 12) Release name lock so that all other threads can access the table + again. + 13) Complete query We insert Error injections at all places where it could be interesting to test if recovery is properly done. @@ -5699,22 +5782,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_3") || (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || /* Always returns 0 */ + ERROR_INJECT_CRASH("crash_drop_partition_4") || + get_name_lock(lpt) || + ERROR_INJECT_CRASH("crash_drop_partition_5") || + alter_close_tables(lpt) || + ERROR_INJECT_CRASH("crash_drop_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH("crash_drop_partition_4") || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || - ERROR_INJECT_CRASH("crash_drop_partition_5") || + ERROR_INJECT_CRASH("crash_drop_partition_7") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ((frm_install= FALSE), FALSE) || - (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH("crash_drop_partition_6") || - mysql_drop_partitions(lpt) || - ERROR_INJECT_CRASH("crash_drop_partition_7") || - (write_log_completed(lpt, FALSE), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_8") || - (mysql_wait_completed_table(lpt, table), FALSE)) + mysql_drop_partitions(lpt) || + ERROR_INJECT_CRASH("crash_drop_partition_9") || + (write_log_completed(lpt, FALSE), FALSE) || + ERROR_INJECT_CRASH("crash_drop_partition_10") || + (release_name_lock(lpt), FALSE)) { handle_alter_part_error(lpt, not_completed, TRUE, frm_install); DBUG_RETURN(TRUE); @@ -5740,15 +5825,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 4) Write binlog - 5) Now the change is completed except for the installation of the + 4) Get a name lock on the table. This ensures that we can release all + locks on the table and since no one can open the table, there can + be no new threads accessing the table. They will be hanging on the + name lock. + 5) Close all tables that have already been opened but didn't stumble on + the abort locked previously. This is done as part of the + get_name_lock call. + 6) Close all table handlers and unlock all handlers but retain name lock + 7) Write binlog + 8) Now the change is completed except for the installation of the new frm file. We thus write an action in the log to change to the shadow frm file - 6) Install the new frm file of the table where the partitions are + 9) Install the new frm file of the table where the partitions are added to the table. - 7) Wait until all accesses using the old frm file has completed - 8) Remove entries from ddl log - 9) Complete query + 10)Wait until all accesses using the old frm file has completed + 11)Remove entries from ddl log + 12)Release name lock + 13)Complete query */ if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_add_partition_1") || @@ -5757,19 +5851,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, mysql_change_partitions(lpt) || ERROR_INJECT_CRASH("crash_add_partition_3") || abort_and_upgrade_lock(lpt) || /* Always returns 0 */ + ERROR_INJECT_CRASH("crash_add_partition_3") || + get_name_lock(lpt) || + ERROR_INJECT_CRASH("crash_add_partition_4") || + alter_close_tables(lpt) || + ERROR_INJECT_CRASH("crash_add_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH("crash_add_partition_4") || + ERROR_INJECT_CRASH("crash_add_partition_6") || write_log_rename_frm(lpt) || (not_completed= FALSE) || - ERROR_INJECT_CRASH("crash_add_partition_5") || + ERROR_INJECT_CRASH("crash_add_partition_7") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH("crash_add_partition_6") || - (close_open_tables_and_downgrade(lpt), FALSE) || + ERROR_INJECT_CRASH("crash_add_partition_8") || (write_log_completed(lpt, FALSE), FALSE) || - ERROR_INJECT_CRASH("crash_add_partition_7")) + ERROR_INJECT_CRASH("crash_add_partition_9") || + (release_name_lock(lpt), FALSE)) { handle_alter_part_error(lpt, not_completed, FALSE, frm_install); DBUG_RETURN(TRUE); @@ -5819,16 +5918,20 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, 5) Lock all partitions in TL_WRITE_ONLY to ensure that no users are still using the old partitioning scheme. Wait until all ongoing users have completed before progressing. - 6) Prepare MyISAM handlers for rename and delete of partitions - 7) Rename the reorged partitions such that they are no longer - used and rename those added to their real new names. - 8) Write bin log - 9) Install the shadow frm file - 10) Wait until all accesses using the old frm file has completed - 11) Drop the reorganised partitions - 12) Remove log entry - 13)Wait until all accesses using the old frm file has completed - 14)Complete query + 6) Get a name lock of the table + 7) Close all tables opened but not yet locked, after this call we are + certain that no other thread is in the lock wait queue or has + opened the table. The name lock will ensure that they are blocked + on the open call. This is achieved also by get_name_lock call. + 8) Close all partitions opened by this thread, but retain name lock. + 9) Write bin log + 10) Prepare handlers for rename and delete of partitions + 11) Rename and drop the reorged partitions such that they are no + longer used and rename those added to their real new names. + 12) Install the shadow frm file + 13) Release the name lock to enable other threads to start using the + table again. + 14) Complete query */ if (write_log_add_change_partition(lpt) || ERROR_INJECT_CRASH("crash_change_partition_1") || @@ -5840,22 +5943,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_4") || (not_completed= FALSE) || abort_and_upgrade_lock(lpt) || /* Always returns 0 */ + ERROR_INJECT_CRASH("crash_change_partition_5") || + get_name_lock(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_6") || + alter_close_tables(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_7") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, thd->query, thd->query_length), FALSE)) || - ERROR_INJECT_CRASH("crash_change_partition_5") || - (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_6") || + ERROR_INJECT_CRASH("crash_change_partition_8") || + mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || + ERROR_INJECT_CRASH("crash_change_partition_9") || + mysql_drop_partitions(lpt) || + ERROR_INJECT_CRASH("crash_change_partition_10") || mysql_rename_partitions(lpt) || ((frm_install= TRUE), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_7") || - mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || - ERROR_INJECT_CRASH("crash_change_partition_8") || - (close_open_tables_and_downgrade(lpt), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_9") || + ERROR_INJECT_CRASH("crash_change_partition_11") || (write_log_completed(lpt, FALSE), FALSE) || - ERROR_INJECT_CRASH("crash_change_partition_10") || - (mysql_wait_completed_table(lpt, table), FALSE)) + ERROR_INJECT_CRASH("crash_change_partition_12") || + (release_name_lock(lpt), FALSE)) { handle_alter_part_error(lpt, not_completed, FALSE, frm_install); DBUG_RETURN(TRUE); diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 87f9a751ca3..7b07fd2eb53 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -69,7 +69,8 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type, bool fix_partition_func(THD *thd, const char *name, TABLE *table, bool create_table_ind); char *generate_partition_syntax(partition_info *part_info, - uint *buf_length, bool use_sql_alloc); + uint *buf_length, bool use_sql_alloc, + bool show_partition_options); bool partition_key_modified(TABLE *table, List &fields); void get_partition_set(const TABLE *table, byte *buf, const uint index, const key_range *key_spec, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 83f64e2c9c9..f500e3bf481 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -970,6 +970,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, handler *file= table->file; TABLE_SHARE *share= table->s; HA_CREATE_INFO create_info; + bool show_table_options= FALSE; bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL | MODE_ORACLE | MODE_MSSQL | @@ -1195,6 +1196,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN("\n)")); if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode) { + show_table_options= TRUE; /* Get possible table space definitions and append them to the CREATE TABLE statement @@ -1335,7 +1337,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet, (!table->part_info->is_auto_partitioned) && ((part_syntax= generate_partition_syntax(table->part_info, &part_syntax_len, - FALSE)))) + FALSE, + show_table_options)))) { packet->append(part_syntax, part_syntax_len); my_free(part_syntax, MYF(0)); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e9c89b4983d..a49b7a2cc42 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1233,7 +1233,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) { if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE))) + TRUE, TRUE))) { DBUG_RETURN(TRUE); } @@ -3155,7 +3155,7 @@ bool mysql_create_table_internal(THD *thd, */ if (!(part_syntax_buf= generate_partition_syntax(part_info, &syntax_len, - TRUE))) + TRUE, TRUE))) goto err; part_info->part_info_string= part_syntax_buf; part_info->part_info_len= syntax_len; diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp index 33492027ccf..3021799fd11 100644 --- a/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp +++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp @@ -1839,8 +1839,7 @@ int Dbtup::interpreterNextLab(Signal* signal, /* ------------------------------------------------------------- */ TregMemBuffer[theRegister]= 0x50; // arithmetic conversion if big-endian - * (Int64*)(TregMemBuffer+theRegister+2)= - TregMemBuffer[theRegister+1]; + * (Int64*)(TregMemBuffer+theRegister+2)= TregMemBuffer[theRegister+1]; } else if (TnoDataRW == 3) { /* ------------------------------------------------------------- */ // Three words read means that we get the instruction plus two diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp index a5fbd84e5b0..c8f05f3a96c 100644 --- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp +++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp @@ -1933,15 +1933,16 @@ static struct Ev_t { enum_DEL = NdbDictionary::Event::_TE_DELETE, enum_UPD = NdbDictionary::Event::_TE_UPDATE, enum_NUL = NdbDictionary::Event::_TE_NUL, - enum_ERR = 255 + enum_IDM = 254, // idempotent op possibly allowed on NF + enum_ERR = 255 // always impossible }; int t1, t2, t3; } ev_t[] = { - { Ev_t::enum_INS, Ev_t::enum_INS, Ev_t::enum_ERR }, + { Ev_t::enum_INS, Ev_t::enum_INS, Ev_t::enum_IDM }, { Ev_t::enum_INS, Ev_t::enum_DEL, Ev_t::enum_NUL }, //ok { Ev_t::enum_INS, Ev_t::enum_UPD, Ev_t::enum_INS }, //ok { Ev_t::enum_DEL, Ev_t::enum_INS, Ev_t::enum_UPD }, //ok - { Ev_t::enum_DEL, Ev_t::enum_DEL, Ev_t::enum_ERR }, + { Ev_t::enum_DEL, Ev_t::enum_DEL, Ev_t::enum_IDM }, { Ev_t::enum_DEL, Ev_t::enum_UPD, Ev_t::enum_ERR }, { Ev_t::enum_UPD, Ev_t::enum_INS, Ev_t::enum_ERR }, { Ev_t::enum_UPD, Ev_t::enum_DEL, Ev_t::enum_DEL }, //ok @@ -2010,6 +2011,34 @@ NdbEventBuffer::merge_data(const SubTableData * const sdata, } assert(tp != 0 && tp->t3 != Ev_t::enum_ERR); + if (tp->t3 == Ev_t::enum_IDM) { + LinearSectionPtr (&ptr1)[3] = data->ptr; + + /* + * TODO + * - can get data in INS ptr2[2] which is supposed to be empty + * - can get extra data in DEL ptr2[2] + * - why does DBUG_PRINT not work in this file ??? + * + * replication + bug#19872 can ignore this since merge is on + * only for tables with explicit PK and before data is not used + */ + const int maxsec = 1; // ignore section 2 + + int i; + for (i = 0; i <= maxsec; i++) { + if (ptr1[i].sz != ptr2[i].sz || + memcmp(ptr1[i].p, ptr2[i].p, ptr1[i].sz << 2) != 0) { + DBUG_PRINT("info", ("idempotent op %d*%d data differs in sec %d", + tp->t1, tp->t2, i)); + assert(false); + DBUG_RETURN_EVENT(-1); + } + } + DBUG_PRINT("info", ("idempotent op %d*%d data ok", tp->t1, tp->t2)); + DBUG_RETURN_EVENT(0); + } + // save old data EventBufData olddata = *data; data->memory = 0; diff --git a/storage/ndb/test/ndbapi/test_event.cpp b/storage/ndb/test/ndbapi/test_event.cpp index 2f2a28fbff2..d8939f06b14 100644 --- a/storage/ndb/test/ndbapi/test_event.cpp +++ b/storage/ndb/test/ndbapi/test_event.cpp @@ -25,7 +25,8 @@ #define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb() -static int createEvent(Ndb *pNdb, const NdbDictionary::Table &tab) +static int createEvent(Ndb *pNdb, const NdbDictionary::Table &tab, + bool merge_events = false) { char eventName[1024]; sprintf(eventName,"%s_EVENT",tab.getName()); @@ -45,6 +46,7 @@ static int createEvent(Ndb *pNdb, const NdbDictionary::Table &tab) for(int a = 0; a < tab.getNoOfColumns(); a++){ myEvent.addEventColumn(a); } + myEvent.mergeEvents(merge_events); int res = myDict->createEvent(myEvent); // Add event to database @@ -137,7 +139,8 @@ NdbEventOperation *createEventOperation(Ndb *ndb, static int runCreateEvent(NDBT_Context* ctx, NDBT_Step* step) { - if (createEvent(GETNDB(step),* ctx->getTab()) != 0){ + bool merge_events = ctx->getProperty("MergeEvents"); + if (createEvent(GETNDB(step),* ctx->getTab(), merge_events) != 0){ return NDBT_FAILED; } return NDBT_OK; @@ -584,6 +587,8 @@ int runEventApplier(NDBT_Context* ctx, NDBT_Step* step) g_err << "Event operation creation failed on %s" << buf << endl; DBUG_RETURN(NDBT_FAILED); } + bool merge_events = ctx->getProperty("MergeEvents"); + pOp->mergeEvents(merge_events); int i; int n_columns= table->getNoOfColumns(); @@ -616,6 +621,11 @@ int runEventApplier(NDBT_Context* ctx, NDBT_Step* step) while ((pOp= ndb->nextEvent()) != 0) { assert(pOp == pCreate); + + if (pOp->getEventType() >= + NdbDictionary::Event::TE_FIRST_NON_DATA_EVENT) + continue; + int noRetries= 0; do { @@ -640,7 +650,7 @@ int runEventApplier(NDBT_Context* ctx, NDBT_Step* step) goto end; } - + switch (pOp->getEventType()) { case NdbDictionary::Event::TE_INSERT: if (op->writeTuple()) @@ -1607,6 +1617,33 @@ TESTCASE("EventOperationApplier_NR", FINALIZER(runVerify); FINALIZER(runDropShadowTable); } +TESTCASE("MergeEventOperationApplier", + "Verify that if we apply the data we get from merged event " + "operation is the same as the original table" + "NOTE! No errors are allowed!" ){ + TC_PROPERTY("MergeEvents", 1); + INITIALIZER(runCreateEvent); + INITIALIZER(runCreateShadowTable); + STEP(runEventApplier); + STEP(runEventMixedLoad); + FINALIZER(runDropEvent); + FINALIZER(runVerify); + FINALIZER(runDropShadowTable); +} +TESTCASE("MergeEventOperationApplier_NR", + "Verify that if we apply the data we get from merged event " + "operation is the same as the original table" + "NOTE! No errors are allowed!" ){ + TC_PROPERTY("MergeEvents", 1); + INITIALIZER(runCreateEvent); + INITIALIZER(runCreateShadowTable); + STEP(runEventApplier); + STEP(runEventMixedLoad); + STEP(runRestarter); + FINALIZER(runDropEvent); + FINALIZER(runVerify); + FINALIZER(runDropShadowTable); +} TESTCASE("Multi", "Verify that we can work with all tables in parallell" "NOTE! HugoOperations::startTransaction, pTrans != NULL errors, " diff --git a/storage/ndb/test/run-test/daily-devel-tests.txt b/storage/ndb/test/run-test/daily-devel-tests.txt index 1a3a87fbc6e..75b85ebb1d2 100644 --- a/storage/ndb/test/run-test/daily-devel-tests.txt +++ b/storage/ndb/test/run-test/daily-devel-tests.txt @@ -213,6 +213,11 @@ max-time: 2500 cmd: test_event args: -n EventOperationApplier_NR -l 2 +# +max-time: 2500 +cmd: test_event +args: -n MergeEventOperationApplier_NR -l 2 + # max-time: 2500 cmd: test_event