From 92b901d297e666b20343e00c4e0b39b5843299ce Mon Sep 17 00:00:00 2001 From: Tatjana Azundris Nuernberg Date: Thu, 19 May 2011 10:47:43 +0100 Subject: [PATCH 01/11] Bug#11745920/Bug#21287: "SSL connection error" is not helpful! (ssl-verify-server-cert=true vs localhos) SSL errors on client and now more specific to aid end-user with debugging. Also restructures error handling for compliance with SSL docs. --- include/violite.h | 6 +++--- libmysql/errmsg.c | 2 +- mysql-test/r/openssl_1.result | 14 +++++++------- sql-common/client.c | 35 ++++++++++++++++++++++++----------- sql/sql_acl.cc | 4 ++-- vio/test-ssl.c | 9 ++++++--- vio/test-sslclient.c | 8 ++++++-- vio/test-sslserver.c | 3 ++- vio/viossl.c | 17 +++++++++-------- vio/viosslfactories.c | 7 +++---- vio/viotest-ssl.c | 9 ++++++--- 11 files changed, 69 insertions(+), 45 deletions(-) diff --git a/include/violite.h b/include/violite.h index 140f021ebb4..ba057028ed2 100644 --- a/include/violite.h +++ b/include/violite.h @@ -134,13 +134,13 @@ struct st_VioSSLFd SSL_CTX *ssl_context; }; -int sslaccept(struct st_VioSSLFd*, Vio *, long timeout); -int sslconnect(struct st_VioSSLFd*, Vio *, long timeout); +int sslaccept(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr); +int sslconnect(struct st_VioSSLFd*, Vio *, long timeout, unsigned long *errptr); struct st_VioSSLFd *new_VioSSLConnectorFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, - const char *cipher); + const char *cipher, enum enum_ssl_init_error* error); struct st_VioSSLFd *new_VioSSLAcceptorFd(const char *key_file, const char *cert_file, const char *ca_file,const char *ca_path, diff --git a/libmysql/errmsg.c b/libmysql/errmsg.c index b99b3f2de30..a2d066b1eba 100644 --- a/libmysql/errmsg.c +++ b/libmysql/errmsg.c @@ -51,7 +51,7 @@ const char *client_errors[]= "Error on SHOW SLAVE HOSTS:", "Error connecting to slave:", "Error connecting to master:", - "SSL connection error", + "SSL connection error: %-.100s", "Malformed packet", "This client library is licensed only for use with MySQL servers having '%s' license", "Invalid use of null pointer", diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result index 6389438c993..72bbaa71da5 100644 --- a/mysql-test/r/openssl_1.result +++ b/mysql-test/r/openssl_1.result @@ -44,13 +44,13 @@ ERROR 42000: DELETE command denied to user 'ssl_user4'@'localhost' for table 't1 drop user ssl_user1@localhost, ssl_user2@localhost, ssl_user3@localhost, ssl_user4@localhost, ssl_user5@localhost; drop table t1; -mysqltest: Could not open connection 'default': 2026 SSL connection error -mysqltest: Could not open connection 'default': 2026 SSL connection error -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: ASN: bad other signature confirmation +mysqltest: Could not open connection 'default': 2026 SSL connection error: ASN: bad other signature confirmation +mysqltest: Could not open connection 'default': 2026 SSL connection error: ASN: bad other signature confirmation SSL error: Unable to get private key from '' -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: Unable to get private key SSL error: Unable to get certificate from '' -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: Unable to get certificate SHOW STATUS LIKE 'Ssl_cipher'; Variable_name Value Ssl_cipher DHE-RSA-AES256-SHA @@ -83,7 +83,7 @@ Ssl_cipher AES128-SHA SHOW STATUS LIKE 'Ssl_cipher'; Variable_name Value Ssl_cipher AES128-SHA -mysqltest: Could not open connection 'default': 2026 SSL connection error +mysqltest: Could not open connection 'default': 2026 SSL connection error: SSL_CTX_new failed CREATE TABLE t1(a int); INSERT INTO t1 VALUES (1), (2); @@ -189,7 +189,7 @@ UNLOCK TABLES; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; SSL error: Unable to get private key from 'MYSQL_TEST_DIR/std_data/client-cert.pem' -mysqldump: Got error: 2026: SSL connection error when trying to connect +mysqldump: Got error: 2026: SSL connection error: Unable to get private key when trying to connect DROP TABLE t1; Variable_name Value Ssl_cipher DHE-RSA-AES256-SHA diff --git a/sql-common/client.c b/sql-common/client.c index abaea310aae..f38467ff731 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1840,6 +1840,8 @@ mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused))) ssl_verify_server_cert() vio pointer to a SSL connected vio server_hostname name of the server that we connected to + errptr if we fail, we'll return (a pointer to a string + describing) the reason here RETURN VALUES 0 Success @@ -1849,7 +1851,7 @@ mysql_get_ssl_cipher(MYSQL *mysql __attribute__((unused))) #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY) -static int ssl_verify_server_cert(Vio *vio, const char* server_hostname) +static int ssl_verify_server_cert(Vio *vio, const char* server_hostname, const char **errptr) { SSL *ssl; X509 *server_cert; @@ -1860,19 +1862,19 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname) if (!(ssl= (SSL*)vio->ssl_arg)) { - DBUG_PRINT("error", ("No SSL pointer found")); + *errptr= "No SSL pointer found"; DBUG_RETURN(1); } if (!server_hostname) { - DBUG_PRINT("error", ("No server hostname supplied")); + *errptr= "No server hostname supplied"; DBUG_RETURN(1); } if (!(server_cert= SSL_get_peer_certificate(ssl))) { - DBUG_PRINT("error", ("Could not get server certificate")); + *errptr= "Could not get server certificate"; DBUG_RETURN(1); } @@ -1901,7 +1903,7 @@ static int ssl_verify_server_cert(Vio *vio, const char* server_hostname) DBUG_RETURN(0); } } - DBUG_PRINT("error", ("SSL certificate validation failure")); + *errptr= "SSL certificate validation failure"; DBUG_RETURN(1); } @@ -2507,6 +2509,9 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, /* Do the SSL layering. */ struct st_mysql_options *options= &mysql->options; struct st_VioSSLFd *ssl_fd; + enum enum_ssl_init_error ssl_init_error; + const char *cert_error; + unsigned long ssl_error; /* Send mysql->client_flag, max_packet_size - unencrypted otherwise @@ -2526,9 +2531,11 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, options->ssl_cert, options->ssl_ca, options->ssl_capath, - options->ssl_cipher))) + options->ssl_cipher, + &ssl_init_error))) { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), sslGetErrString(ssl_init_error)); goto error; } mysql->connector_fd= (unsigned char *) ssl_fd; @@ -2536,18 +2543,24 @@ static int send_client_reply_packet(MCPVIO_EXT *mpvio, /* Connect to the server */ DBUG_PRINT("info", ("IO layer change in progress...")); if (sslconnect(ssl_fd, net->vio, - (long) (mysql->options.connect_timeout))) + (long) (mysql->options.connect_timeout), &ssl_error)) { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + char buf[512]; + ERR_error_string_n(ssl_error, buf, 512); + buf[511]= 0; + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), + buf); goto error; } DBUG_PRINT("info", ("IO layer change done!")); /* Verify server cert */ if ((mysql->client_flag & CLIENT_SSL_VERIFY_SERVER_CERT) && - ssl_verify_server_cert(net->vio, mysql->host)) + ssl_verify_server_cert(net->vio, mysql->host, &cert_error)) { - set_mysql_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate); + set_mysql_extended_error(mysql, CR_SSL_CONNECTION_ERROR, unknown_sqlstate, + ER(CR_SSL_CONNECTION_ERROR), cert_error); goto error; } } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0eb05489015..5056fb32bc7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8528,14 +8528,14 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, DBUG_PRINT("info", ("client capabilities: %lu", mpvio->client_capabilities)); if (mpvio->client_capabilities & CLIENT_SSL) { - char error_string[1024] __attribute__((unused)); + unsigned long errptr; /* Do the SSL layering. */ if (!ssl_acceptor_fd) return packet_error; DBUG_PRINT("info", ("IO layer change in progress...")); - if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout)) + if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout, &errptr)) { DBUG_PRINT("error", ("Failed to accept new SSL connection")); return packet_error; diff --git a/vio/test-ssl.c b/vio/test-ssl.c index 1e846727d00..4d158ae83f7 100644 --- a/vio/test-ssl.c +++ b/vio/test-ssl.c @@ -59,6 +59,9 @@ main(int argc, char** argv) struct st_VioSSLFd* ssl_acceptor= 0; struct st_VioSSLFd* ssl_connector= 0; Vio* client_vio=0, *server_vio=0; + enum enum_ssl_init_error ssl_init_error; + unsigned long ssl_error; + MY_INIT(argv[0]); DBUG_PROCESS(argv[0]); DBUG_PUSH(default_dbug_option); @@ -91,16 +94,16 @@ main(int argc, char** argv) ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path, cipher); ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, - ca_path, cipher); + ca_path, cipher, &ssl_init_error); client_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0)); client_vio->sd = sv[0]; client_vio->vioblocking(client_vio, 0, &unused); - sslconnect(ssl_connector,client_vio,60L); + sslconnect(ssl_connector,client_vio,60L,&ssl_error); server_vio = (struct st_vio*)my_malloc(sizeof(struct st_vio),MYF(0)); server_vio->sd = sv[1]; server_vio->vioblocking(client_vio, 0, &unused); - sslaccept(ssl_acceptor,server_vio,60L); + sslaccept(ssl_acceptor,server_vio,60L, &ssl_error); printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd); diff --git a/vio/test-sslclient.c b/vio/test-sslclient.c index 643dcbf2c8e..9d8a741e313 100644 --- a/vio/test-sslclient.c +++ b/vio/test-sslclient.c @@ -50,6 +50,9 @@ main( int argc __attribute__((unused)), Vio* client_vio=0; int err; char xbuf[100]="Ohohhhhoh1234"; + enum enum_ssl_init_error ssl_init_error; + unsigned long ssl_error; + MY_INIT(argv[0]); DBUG_PROCESS(argv[0]); DBUG_PUSH(default_dbug_option); @@ -60,7 +63,8 @@ main( int argc __attribute__((unused)), if (ca_path!=0) printf("CApath : %s\n", ca_path); - ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path, cipher); + ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, ca_path, cipher, + &ssl_init_error); if(!ssl_connector) { fatal_error("client:new_VioSSLConnectorFd failed"); } @@ -81,7 +85,7 @@ main( int argc __attribute__((unused)), /* ----------------------------------------------- */ /* Now we have TCP conncetion. Start SSL negotiation. */ read(client_vio->sd,xbuf, sizeof(xbuf)); - sslconnect(ssl_connector,client_vio,60L); + sslconnect(ssl_connector,client_vio,60L,&ssl_error); err = vio_read(client_vio,xbuf, sizeof(xbuf)); if (err<=0) { my_free(ssl_connector); diff --git a/vio/test-sslserver.c b/vio/test-sslserver.c index 3123a4def2c..35cfa26bd00 100644 --- a/vio/test-sslserver.c +++ b/vio/test-sslserver.c @@ -52,6 +52,7 @@ do_ssl_stuff( TH_ARGS* args) const char* s = "Huhuhuhuuu"; Vio* server_vio; int err; + unsigned long ssl_error; DBUG_ENTER("do_ssl_stuff"); server_vio = vio_new(args->sd, VIO_TYPE_TCPIP, TRUE); @@ -60,7 +61,7 @@ do_ssl_stuff( TH_ARGS* args) /* TCP connection is ready. Do server side SSL. */ err = write(server_vio->sd,(uchar*)s, strlen(s)); - sslaccept(args->ssl_acceptor,server_vio,60L); + sslaccept(args->ssl_acceptor,server_vio,60L,&ssl_error); err = server_vio->write(server_vio,(uchar*)s, strlen(s)); DBUG_VOID_RETURN; } diff --git a/vio/viossl.c b/vio/viossl.c index 5cb5f36f20d..290abf788c2 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -144,8 +144,9 @@ void vio_ssl_delete(Vio *vio) static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout, - int (*connect_accept_func)(SSL*)) + int (*connect_accept_func)(SSL*), unsigned long *errptr) { + int r; SSL *ssl; my_bool unused; my_bool was_blocking; @@ -160,7 +161,7 @@ static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout, if (!(ssl= SSL_new(ptr->ssl_context))) { DBUG_PRINT("error", ("SSL_new failure")); - report_errors(ssl); + *errptr= ERR_get_error(); vio_blocking(vio, was_blocking, &unused); DBUG_RETURN(1); } @@ -169,10 +170,10 @@ static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout, SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout); SSL_set_fd(ssl, vio->sd); - if (connect_accept_func(ssl) < 1) + if ((r= connect_accept_func(ssl)) < 1) { DBUG_PRINT("error", ("SSL_connect/accept failure")); - report_errors(ssl); + *errptr= SSL_get_error(ssl, r); SSL_free(ssl); vio_blocking(vio, was_blocking, &unused); DBUG_RETURN(1); @@ -220,17 +221,17 @@ static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout, } -int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout) +int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout, unsigned long *errptr) { DBUG_ENTER("sslaccept"); - DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_accept)); + DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_accept, errptr)); } -int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout) +int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout, unsigned long *errptr) { DBUG_ENTER("sslconnect"); - DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect)); + DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect, errptr)); } diff --git a/vio/viosslfactories.c b/vio/viosslfactories.c index 4971dec37fb..4f4dd5758ba 100644 --- a/vio/viosslfactories.c +++ b/vio/viosslfactories.c @@ -165,7 +165,7 @@ static struct st_VioSSLFd * new_VioSSLFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, const char *cipher, SSL_METHOD *method, - enum enum_ssl_init_error* error) + enum enum_ssl_init_error *error) { DH *dh; struct st_VioSSLFd *ssl_fd; @@ -249,11 +249,10 @@ new_VioSSLFd(const char *key_file, const char *cert_file, struct st_VioSSLFd * new_VioSSLConnectorFd(const char *key_file, const char *cert_file, const char *ca_file, const char *ca_path, - const char *cipher) + const char *cipher, enum enum_ssl_init_error* error) { struct st_VioSSLFd *ssl_fd; int verify= SSL_VERIFY_PEER; - enum enum_ssl_init_error dummy; /* Turn off verification of servers certificate if both @@ -263,7 +262,7 @@ new_VioSSLConnectorFd(const char *key_file, const char *cert_file, verify= SSL_VERIFY_NONE; if (!(ssl_fd= new_VioSSLFd(key_file, cert_file, ca_file, - ca_path, cipher, TLSv1_client_method(), &dummy))) + ca_path, cipher, TLSv1_client_method(), error))) { return 0; } diff --git a/vio/viotest-ssl.c b/vio/viotest-ssl.c index 5c68e861d2a..90489b46605 100644 --- a/vio/viotest-ssl.c +++ b/vio/viotest-ssl.c @@ -60,6 +60,9 @@ int main(int argc, char **argv) struct st_VioSSLConnectorFd* ssl_connector=0; Vio* client_vio=0; Vio* server_vio=0; + enum enum_ssl_init_error ssl_init_error; + unsigned long ssl_error; + MY_INIT(argv[0]); DBUG_PROCESS(argv[0]); DBUG_PUSH(default_dbug_option); @@ -92,14 +95,14 @@ int main(int argc, char **argv) ssl_acceptor = new_VioSSLAcceptorFd(server_key, server_cert, ca_file, ca_path); ssl_connector = new_VioSSLConnectorFd(client_key, client_cert, ca_file, - ca_path); + ca_path, &ssl_init_error); client_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0)); client_vio->sd = sv[0]; - sslconnect(ssl_connector,client_vio); + sslconnect(ssl_connector,client_vio,&ssl_error); server_vio = (Vio*)my_malloc(sizeof(struct st_vio),MYF(0)); server_vio->sd = sv[1]; - sslaccept(ssl_acceptor,server_vio); + sslaccept(ssl_acceptor,server_vio,&ssl_error); printf("Socketpair: %d , %d\n", client_vio->sd, server_vio->sd); From b0a74097f1c6bddb5229f19bc0214b86684b1f6d Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Tue, 24 May 2011 10:54:34 +0200 Subject: [PATCH 02/11] Bug#11831031: MTR SHOULD FIND TEST SUITES FROM FEATURE TREES OUTSIDE MYSQL-TEST Backported from trunk-mtr --- mysql-test/lib/mtr_cases.pm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm index c3dd43c12ca..d677645d9da 100644 --- a/mysql-test/lib/mtr_cases.pm +++ b/mysql-test/lib/mtr_cases.pm @@ -287,9 +287,11 @@ sub collect_one_suite($) "mysql-test/suite", "mysql-test", # Look in storage engine specific suite dirs - "storage/*/mysql-test-suites" + "storage/*/mtr", + # Look in plugin specific suite dir + "plugin/$suite/tests", ], - [$suite]); + [$suite, "mtr"]); } mtr_verbose("suitedir: $suitedir"); } From d7334d8d859b787bfb4a3dd508618675dd2d85d9 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 25 May 2011 10:58:33 +0200 Subject: [PATCH 03/11] Bug #11750043 40340: USE GZIPPED CORE FILES TO SAVE SPACE Use [g]zip on core file if available, ignore if not Skip if running named test, and print a line saying what it compressed. --- mysql-test/lib/mtr_misc.pl | 35 +++++++++++++++++++++++++++++++++++ mysql-test/mysql-test-run.pl | 2 ++ 2 files changed, 37 insertions(+) diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl index a7b5afd9fd7..e50e8cc77df 100644 --- a/mysql-test/lib/mtr_misc.pl +++ b/mysql-test/lib/mtr_misc.pl @@ -31,6 +31,7 @@ sub mtr_script_exists(@); sub mtr_file_exists(@); sub mtr_exe_exists(@); sub mtr_exe_maybe_exists(@); +sub mtr_compress_file($); sub mtr_milli_sleep($); sub start_timer($); sub has_expired($); @@ -199,6 +200,40 @@ sub mtr_exe_exists (@) { } } +# +# Try to compress file using tools that might be available. +# If zip/gzip is not available, just silently ignore. +# + +sub mtr_compress_file ($) { + my ($filename)= @_; + + mtr_error ("File to compress not found: $filename") unless -f $filename; + + my $did_compress= 0; + + if (IS_WINDOWS) + { + # Capture stderr + my $ziperr= `zip $filename.zip $filename 2>&1`; + if ($?) { + print "$ziperr\n" if $ziperr !~ /recognized as an internal or external/; + } else { + unlink($filename); + $did_compress=1; + } + } + else + { + my $gzres= system("gzip $filename"); + $did_compress= ! $gzres; + if ($gzres && $gzres != -1) { + mtr_error ("Error: have gzip but it fails to compress core file"); + } + } + mtr_print("Compressed file $filename") if $did_compress; +} + sub mtr_milli_sleep ($) { die "usage: mtr_milli_sleep(milliseconds)" unless @_ == 1; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0e4b3cedbfd..067c83a6f51 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -657,6 +657,8 @@ sub run_test_server ($$$) { mtr_report(" - deleting it, already saved", "$opt_max_save_core"); unlink("$core_file"); + } else { + mtr_compress_file($core_file) unless @opt_cases; } ++$num_saved_cores; } From eb8586236662b6715a0fd852286ab0d1c56ad90b Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 25 May 2011 12:39:11 +0200 Subject: [PATCH 04/11] Bug #12586211 ENABLE GCOV BUILDS WITH CMAKE, INCLUDING PLUGINS Added --with-gcov option to configure.pl and use that from SETUP.sh --- BUILD/SETUP.sh | 4 ++-- cmake/configure.pl | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index c7f434d1bb3..00bd4965f87 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (C) 2000, 2007 MySQL AB +# Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public @@ -250,7 +250,7 @@ gcov_compile_flags="$gcov_compile_flags -DMYSQL_SERVER_SUFFIX=-gcov -DHAVE_gcov" gcov_link_flags="-fprofile-arcs -ftest-coverage" -gcov_configs="--disable-shared" +gcov_configs="--with-gcov" # gprof diff --git a/cmake/configure.pl b/cmake/configure.pl index b24afa034c7..bf872264953 100644 --- a/cmake/configure.pl +++ b/cmake/configure.pl @@ -190,6 +190,11 @@ foreach my $option (@ARGV) $cmakeargs = $cmakeargs." \"-DWITH_COMMENT=".substr($option,13)."\""; next; } + if ($option =~ /with-gcov/) + { + $cmakeargs = $cmakeargs." -DENABLE_GCOV=ON"; + next; + } $option = uc($option); $option =~ s/-/_/g; From 850b27ccdb0f0337ca06c39dc81f09a2da6da9e7 Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 25 May 2011 16:07:16 +0200 Subject: [PATCH 05/11] Bug #12590770 TEST SPECIFIC TIMEOUT SETTING DOES NOT APPLY TO "CHECK" OR "WARNINGS" Replace global check_timeout with one that calls testcase_timeout for the test --- mysql-test/mysql-test-run.pl | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 067c83a6f51..42360aeb28f 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -263,7 +263,6 @@ my $opt_shutdown_timeout= $ENV{MTR_SHUTDOWN_TIMEOUT} || 10; # seconds my $opt_start_timeout = $ENV{MTR_START_TIMEOUT} || 180; # seconds sub suite_timeout { return $opt_suite_timeout * 60; }; -sub check_timeout { return $opt_testcase_timeout * 6; }; my $opt_wait_all; my $opt_user_args; @@ -299,6 +298,8 @@ sub testcase_timeout ($) { return $opt_testcase_timeout * 60; } +sub check_timeout ($) { return testcase_timeout($_[0]) / 10; } + our $opt_warnings= 1; our $opt_include_ndbcluster= 0; @@ -3415,7 +3416,7 @@ sub check_testcase($$) # Return immediately if no check proceess was started return 0 unless ( keys %started ); - my $timeout= start_timer(check_timeout()); + my $timeout= start_timer(check_timeout($tinfo)); while (1){ my $result; @@ -3487,7 +3488,7 @@ test case was executed:\n"; } elsif ( $proc->{timeout} ) { $tinfo->{comment}.= "Timeout for 'check-testcase' expired after " - .check_timeout()." seconds"; + .check_timeout($tinfo)." seconds"; $result= 4; } else { @@ -3577,7 +3578,7 @@ sub run_on_all($$) # Return immediately if no check proceess was started return 0 unless ( keys %started ); - my $timeout= start_timer(check_timeout()); + my $timeout= start_timer(check_timeout($tinfo)); while (1){ my $result; @@ -3608,7 +3609,7 @@ sub run_on_all($$) } elsif ($proc->{timeout}) { $tinfo->{comment}.= "Timeout for '$run' expired after " - .check_timeout()." seconds"; + .check_timeout($tinfo)." seconds"; } else { # Unknown process returned, most likley a crash, abort everything @@ -4333,7 +4334,7 @@ sub check_warnings ($) { # Return immediately if no check proceess was started return 0 unless ( keys %started ); - my $timeout= start_timer(check_timeout()); + my $timeout= start_timer(check_timeout($tinfo)); while (1){ my $result= 0; @@ -4385,7 +4386,7 @@ sub check_warnings ($) { } elsif ( $proc->{timeout} ) { $tinfo->{comment}.= "Timeout for 'check warnings' expired after " - .check_timeout()." seconds"; + .check_timeout($tinfo)." seconds"; $result= 4; } else { From e75292dbeea23601d294bd166cca3e324dce4fff Mon Sep 17 00:00:00 2001 From: Bjorn Munch Date: Wed, 25 May 2011 16:39:39 +0200 Subject: [PATCH 06/11] Increase test timeout for rpl.rpl_typeconv Not for test itself but because it procuces large number of warnings, and this may take >90s to filter on slow boxes --- mysql-test/suite/rpl/t/rpl_typeconv-master.opt | 1 + 1 file changed, 1 insertion(+) create mode 100644 mysql-test/suite/rpl/t/rpl_typeconv-master.opt diff --git a/mysql-test/suite/rpl/t/rpl_typeconv-master.opt b/mysql-test/suite/rpl/t/rpl_typeconv-master.opt new file mode 100644 index 00000000000..de048691031 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_typeconv-master.opt @@ -0,0 +1 @@ +--testcase-timeout=40 From fa86ab02cfd0f8c2e5aba26b8ea448d24aa7b11b Mon Sep 17 00:00:00 2001 From: Tor Didriksen Date: Thu, 26 May 2011 09:54:19 +0200 Subject: [PATCH 07/11] Don't check for FIONREAD on windows. Execution of platforms tests are slow/flaky when building on windows. in PB:mysql-next-mr-opt-team on 2011-05-18 for win x86 debug_max, i see: -- Looking for FIONREAD -- Looking for FIONREAD - found and the build fails. --- cmake/os/WindowsCache.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/os/WindowsCache.cmake b/cmake/os/WindowsCache.cmake index 477fd1d2b88..68bbb337e15 100644 --- a/cmake/os/WindowsCache.cmake +++ b/cmake/os/WindowsCache.cmake @@ -341,6 +341,7 @@ SET(SIGNAL_RETURN_TYPE_IS_VOID 1 CACHE INTERNAL "") SET(C_HAS_inline CACHE INTERNAL "") SET(C_HAS___inline 1 CACHE INTERNAL "") SET(FIONREAD_IN_SYS_IOCTL CACHE INTERNAL "") +SET(FIONREAD_IN_SYS_FILIO CACHE INTERNAL "") SET(GWINSZ_IN_SYS_IOCTL CACHE INTERNAL "") SET(HAVE_CXXABI_H CACHE INTERNAL "") SET(HAVE_NDIR_H CACHE INTERNAL "") From aa0c8235a4fed513982cf3f576184404cf357826 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Thu, 26 May 2011 14:06:39 +0400 Subject: [PATCH 08/11] Bug#12392636 ASSERTION FAILED: SCALE >= 0 && PRECISION > 0 && SCALE <= PRECISION Assertion happens due to missing NULL value check in Item_func_round::fix_length_and_dec() function. The fix: added NULL value check for second parameter. --- mysql-test/r/func_math.result | 6 ++++++ mysql-test/t/func_math.test | 6 ++++++ sql/item_func.cc | 3 +++ 3 files changed, 15 insertions(+) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index b9118feab1a..4e3608240d4 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -540,4 +540,10 @@ ROUND(LEAST(15, -4939092, 0.2704), STDDEV('a')) -4939092.0000 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' +# +# Bug#12392636 ASSERTION FAILED: SCALE >= 0 && PRECISION > 0 && SCALE <= PRECISION +# +SELECT SUM(DISTINCT (TRUNCATE((.1), NULL))); +SUM(DISTINCT (TRUNCATE((.1), NULL))) +NULL End of 5.1 tests diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index 9d51a5c94f9..1906d2d347a 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -349,4 +349,10 @@ DROP TABLE t1; SELECT ROUND(LEAST(15, -4939092, 0.2704), STDDEV('a')); +--echo # +--echo # Bug#12392636 ASSERTION FAILED: SCALE >= 0 && PRECISION > 0 && SCALE <= PRECISION +--echo # + +SELECT SUM(DISTINCT (TRUNCATE((.1), NULL))); + --echo End of 5.1 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index b1398b78b84..feb87fe5fd7 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1972,6 +1972,9 @@ void Item_func_round::fix_length_and_dec() } val1= args[1]->val_int(); + if ((null_value= args[1]->is_null())) + return; + val1_unsigned= args[1]->unsigned_flag; if (val1 < 0) decimals_to_set= val1_unsigned ? INT_MAX : 0; From b76c277a8f46f7e1047099df4686cb06c26a08fa Mon Sep 17 00:00:00 2001 From: Sven Sandberg Date: Thu, 26 May 2011 12:50:43 +0200 Subject: [PATCH 09/11] BUG#12574820: binlog.binlog_tmp_table timing out in daily and weekly trunk run Problem: MYSQL_BIN_LOG::reset_logs acquires mutexes in wrong order. The correct order is first LOCK_thread_count and then LOCK_log. This function does it the other way around. This leads to deadlock when run in parallel with a thread that takes the two locks in correct order. For example, a thread that disconnects will take the locks in the correct order. Fix: change order of the locks in MYSQL_BIN_LOG::reset_logs: first LOCK_thread_count and then LOCK_log. --- .../suite/binlog/r/binlog_reset_master.result | 1 + .../suite/binlog/t/binlog_reset_master.test | 26 +++++++++++++++++++ sql/log.cc | 15 ++++++----- sql/mysqld.cc | 6 +++++ 4 files changed, 41 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/binlog/r/binlog_reset_master.result create mode 100644 mysql-test/suite/binlog/t/binlog_reset_master.test diff --git a/mysql-test/suite/binlog/r/binlog_reset_master.result b/mysql-test/suite/binlog/r/binlog_reset_master.result new file mode 100644 index 00000000000..b3d605560ff --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_reset_master.result @@ -0,0 +1 @@ +RESET MASTER; diff --git a/mysql-test/suite/binlog/t/binlog_reset_master.test b/mysql-test/suite/binlog/t/binlog_reset_master.test new file mode 100644 index 00000000000..b7ad69da3ea --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_reset_master.test @@ -0,0 +1,26 @@ +# ==== Purpose ==== +# +# Test bugs in RESET MASTER. + +--source include/have_debug.inc +--source include/have_log_bin.inc + +####################################################################### +# BUG#12574820: binlog.binlog_tmp_table timing out in daily and weekly trunk run +# Problem: MYSQL_BIN_LOG::reset_logs acquired LOCK_thread_count and +# LOCK_log in the wrong order. This could cause a deadlock when +# RESET MASTER was run concurrently with a disconnecting thread. +####################################################################### + +# We use sleep, not debug_sync, because the sync point needs to be in +# the thread shut down code after the debug sync facility has been +# shut down. +--let $write_var= SET DEBUG="+d,sleep_after_lock_thread_count_before_delete_thd"; CREATE TEMPORARY TABLE test.t1 (a INT); +--let $write_to_file= GENERATE +--disable_query_log +--source include/write_var_to_file.inc +--enable_query_log + +--exec $MYSQL < $write_to_file +RESET MASTER; +--remove_file $write_to_file diff --git a/sql/log.cc b/sql/log.cc index 17642696e7d..77d12641442 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2989,12 +2989,6 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) DBUG_ENTER("reset_logs"); ha_reset_logs(thd); - /* - We need to get both locks to be sure that no one is trying to - write to the index log file. - */ - pthread_mutex_lock(&LOCK_log); - pthread_mutex_lock(&LOCK_index); /* The following mutex is needed to ensure that no threads call @@ -3002,7 +2996,14 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) thread. If the transaction involved MyISAM tables, it should go into binlog even on rollback. */ - VOID(pthread_mutex_lock(&LOCK_thread_count)); + pthread_mutex_lock(&LOCK_thread_count); + + /* + We need to get both locks to be sure that no one is trying to + write to the index log file. + */ + pthread_mutex_lock(&LOCK_log); + pthread_mutex_lock(&LOCK_index); /* Save variables so that we can reopen the log */ save_name=name; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 54850f36d10..2d1290bf88a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1903,6 +1903,12 @@ void unlink_thd(THD *thd) pthread_mutex_unlock(&LOCK_connection_count); (void) pthread_mutex_lock(&LOCK_thread_count); + /* + Used by binlog_reset_master. It would be cleaner to use + DEBUG_SYNC here, but that's not possible because the THD's debug + sync feature has been shut down at this point. + */ + DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5);); thread_count--; delete thd; DBUG_VOID_RETURN; From d076be2a3234a7b0d7ad1e77cc82ca84cfa9dd11 Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Thu, 26 May 2011 17:14:47 +0400 Subject: [PATCH 10/11] Fix for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE::UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". Attempt to update an InnoDB temporary table under LOCK TABLES led to assertion failure in both debug and production builds if this temporary table was explicitly locked for READ. The same scenario works fine for MyISAM temporary tables. The assertion failure was caused by discrepancy between lock that was requested on the rows of temporary table at LOCK TABLES time and by update operation. Since SQL-layer requested a read-lock at LOCK TABLES time InnoDB engine assumed that upcoming statements which are going to be executed under LOCK TABLES will only read table and therefore should acquire only S-lock. An update operation broken this assumption by requesting X-lock. Possible approaches to fixing this problem are: 1) Skip locking of temporary tables as locking doesn't make any sense for connection-local objects. 2) Prohibit changing of temporary table locked by LOCK TABLES ... READ. Unfortunately both of these approaches have drawbacks which make them unviable for stable versions of server. So this patch takes another approach and changes code in such way that LOCK TABLES for a temporary table will always request write lock. In 5.1 version of this patch switch from read lock to write lock is done inside of InnoDBs handler methods as doing it on SQL-layer causes compatibility troubles with FLUSH TABLES WITH READ LOCK. --- mysql-test/suite/innodb/r/innodb_mysql.result | 18 ++++++++++++- mysql-test/suite/innodb/t/innodb_mysql.test | 25 ++++++++++++++++--- .../suite/innodb_plugin/r/innodb_mysql.result | 16 ++++++++++++ .../suite/innodb_plugin/t/innodb_mysql.test | 20 +++++++++++++++ storage/innobase/handler/ha_innodb.cc | 12 +++++++-- storage/innodb_plugin/handler/ha_innodb.cc | 12 +++++++-- 6 files changed, 95 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index fa26b8b1d01..a7feb692091 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -2639,7 +2639,6 @@ COUNT(*) 1537 SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; -End of 5.1 tests # # Test for bug #39932 "create table fails if column for FK is in different # case than in corr index". @@ -2668,3 +2667,20 @@ DROP TABLE IF EXISTS t1, t2; CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb; ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; DROP TABLE IF EXISTS t1, t2; +# +# Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +# UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +# +DROP TABLE IF EXISTS t1; +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +# Even though temporary table was locked for READ we +# still allow writes to it to be compatible with MyISAM. +# This is possible since due to fact that temporary tables +# are specific to connection and therefore locking for them +# is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; +End of 5.1 tests diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test index cb6082be0d0..12bd2801556 100644 --- a/mysql-test/suite/innodb/t/innodb_mysql.test +++ b/mysql-test/suite/innodb/t/innodb_mysql.test @@ -868,9 +868,6 @@ SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; ---echo End of 5.1 tests - - --echo # --echo # Test for bug #39932 "create table fails if column for FK is in different --echo # case than in corr index". @@ -900,3 +897,25 @@ CREATE TABLE t1 (a INT, INDEX(a)) engine=innodb; ALTER TABLE t1 RENAME TO t2, DISABLE KEYS; DROP TABLE IF EXISTS t1, t2; --enable_warnings + + +--echo # +--echo # Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +--echo # UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +--echo # Even though temporary table was locked for READ we +--echo # still allow writes to it to be compatible with MyISAM. +--echo # This is possible since due to fact that temporary tables +--echo # are specific to connection and therefore locking for them +--echo # is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; + +--echo End of 5.1 tests diff --git a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result index 448bf54ce51..ebaa52d3b4d 100644 --- a/mysql-test/suite/innodb_plugin/r/innodb_mysql.result +++ b/mysql-test/suite/innodb_plugin/r/innodb_mysql.result @@ -2438,4 +2438,20 @@ COUNT(*) 1537 SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; +# +# Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +# UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +# +DROP TABLE IF EXISTS t1; +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +# Even though temporary table was locked for READ we +# still allow writes to it to be compatible with MyISAM. +# This is possible since due to fact that temporary tables +# are specific to connection and therefore locking for them +# is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; End of 5.1 tests diff --git a/mysql-test/suite/innodb_plugin/t/innodb_mysql.test b/mysql-test/suite/innodb_plugin/t/innodb_mysql.test index 08d77ba448a..24beaef2fe7 100644 --- a/mysql-test/suite/innodb_plugin/t/innodb_mysql.test +++ b/mysql-test/suite/innodb_plugin/t/innodb_mysql.test @@ -689,4 +689,24 @@ SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; + +--echo # +--echo # Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +--echo # UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +--echo # Even though temporary table was locked for READ we +--echo # still allow writes to it to be compatible with MyISAM. +--echo # This is possible since due to fact that temporary tables +--echo # are specific to connection and therefore locking for them +--echo # is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; + --echo End of 5.1 tests diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2afacf6d2a8..dfe13ccbbfe 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7325,10 +7325,18 @@ ha_innobase::external_lock( reset_template(prebuilt); - if (lock_type == F_WRLCK) { + if (lock_type == F_WRLCK + || (table->s->tmp_table + && thd_sql_command(thd) == SQLCOM_LOCK_TABLES)) { /* If this is a SELECT, then it is in UPDATE TABLE ... - or SELECT ... FOR UPDATE */ + or SELECT ... FOR UPDATE + + For temporary tables which are locked for READ by LOCK TABLES + updates are still allowed by SQL-layer. In order to accomodate + for such a situation we always request X-lock for such table + at LOCK TABLES time. + */ prebuilt->select_lock_type = LOCK_X; prebuilt->stored_select_lock_type = LOCK_X; } diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 2b0dbf82b34..a9c9f379528 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -8642,10 +8642,18 @@ ha_innobase::external_lock( reset_template(prebuilt); - if (lock_type == F_WRLCK) { + if (lock_type == F_WRLCK + || (table->s->tmp_table + && thd_sql_command(thd) == SQLCOM_LOCK_TABLES)) { /* If this is a SELECT, then it is in UPDATE TABLE ... - or SELECT ... FOR UPDATE */ + or SELECT ... FOR UPDATE + + For temporary tables which are locked for READ by LOCK TABLES + updates are still allowed by SQL-layer. In order to accomodate + for such a situation we always request X-lock for such table + at LOCK TABLES time. + */ prebuilt->select_lock_type = LOCK_X; prebuilt->stored_select_lock_type = LOCK_X; } From c61e346f51e88a7c03c6372a41209b572e49510e Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Thu, 26 May 2011 19:50:06 +0400 Subject: [PATCH 11/11] Fix for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE::UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". Attempt to update an InnoDB temporary table under LOCK TABLES led to assertion failure in both debug and production builds if this temporary table was explicitly locked for READ. The same scenario works fine for MyISAM temporary tables. The assertion failure was caused by discrepancy between lock that was requested on the rows of temporary table at LOCK TABLES time and by update operation. Since SQL-layer requested a read-lock at LOCK TABLES time InnoDB engine assumed that upcoming statements which are going to be executed under LOCK TABLES will only read table and therefore should acquire only S-lock. An update operation broken this assumption by requesting X-lock. Possible approaches to fixing this problem are: 1) Skip locking of temporary tables as locking doesn't make any sense for connection-local objects. 2) Prohibit changing of temporary table locked by LOCK TABLES ... READ. Unfortunately both of these approaches have drawbacks which make them unviable for stable versions of server. So this patch takes another approach and changes code in such way that LOCK TABLES for a temporary table will always request write lock. In 5.5 version of this patch switch from read lock to write lock is done on SQL-layer. --- mysql-test/suite/innodb/r/innodb_mysql.result | 18 +++- mysql-test/suite/innodb/t/innodb_mysql.test | 24 +++++- sql/sql_parse.cc | 83 ++++++++++++++----- 3 files changed, 101 insertions(+), 24 deletions(-) diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 7d96a4acf3f..b6976e43bcb 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -2663,7 +2663,6 @@ COUNT(*) 1537 SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; -End of 5.1 tests # # Test for bug #39932 "create table fails if column for FK is in different # case than in corr index". @@ -2685,6 +2684,23 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 drop table t2, t1; # +# Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +# UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +# +DROP TABLE IF EXISTS t1; +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +# Even though temporary table was locked for READ we +# still allow writes to it to be compatible with MyISAM. +# This is possible since due to fact that temporary tables +# are specific to connection and therefore locking for them +# is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; +End of 5.1 tests +# # Bug#44613 SELECT statement inside FUNCTION takes a shared lock # DROP TABLE IF EXISTS t1; diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test index acc843341eb..910b93b443b 100644 --- a/mysql-test/suite/innodb/t/innodb_mysql.test +++ b/mysql-test/suite/innodb/t/innodb_mysql.test @@ -830,8 +830,6 @@ SET SESSION sort_buffer_size = DEFAULT; DROP TABLE t1; ---echo End of 5.1 tests - --echo # --echo # Test for bug #39932 "create table fails if column for FK is in different @@ -851,6 +849,28 @@ show create table t2; drop table t2, t1; +--echo # +--echo # Test for bug #11762012 - "54553: INNODB ASSERTS IN HA_INNOBASE:: +--echo # UPDATE_ROW, TEMPORARY TABLE, TABLE LOCK". +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TEMPORARY TABLE t1 (c int) ENGINE = InnoDB; +INSERT INTO t1 VALUES (1); +LOCK TABLES t1 READ; +--echo # Even though temporary table was locked for READ we +--echo # still allow writes to it to be compatible with MyISAM. +--echo # This is possible since due to fact that temporary tables +--echo # are specific to connection and therefore locking for them +--echo # is irrelevant. +UPDATE t1 SET c = 5; +UNLOCK TABLES; +DROP TEMPORARY TABLE t1; + +--echo End of 5.1 tests + + --echo # --echo # Bug#44613 SELECT statement inside FUNCTION takes a shared lock --echo # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4f5bce3e8af..44a9243d8f5 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1748,6 +1748,67 @@ bool sp_process_definer(THD *thd) } +/** + Auxiliary call that opens and locks tables for LOCK TABLES statement + and initializes the list of locked tables. + + @param thd Thread context. + @param tables List of tables to be locked. + + @return FALSE in case of success, TRUE in case of error. +*/ + +static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables) +{ + Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; + uint counter; + TABLE_LIST *table; + + thd->in_lock_tables= 1; + + if (open_tables(thd, &tables, &counter, 0, &lock_tables_prelocking_strategy)) + goto err; + + /* + We allow to change temporary tables even if they were locked for read + by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK + TABLES time and by the statement which is later executed under LOCK TABLES + we ensure that for temporary tables we always request a write lock (such + discrepancy can cause problems for the storage engine). + We don't set TABLE_LIST::lock_type in this case as this might result in + extra warnings from THD::decide_logging_format() even though binary logging + is totally irrelevant for LOCK TABLES. + */ + for (table= tables; table; table= table->next_global) + if (!table->placeholder() && table->table->s->tmp_table) + table->table->reginfo.lock_type= TL_WRITE; + + if (lock_tables(thd, tables, counter, 0) || + thd->locked_tables_list.init_locked_tables(thd)) + goto err; + + thd->in_lock_tables= 0; + + return FALSE; + +err: + thd->in_lock_tables= 0; + + trans_rollback_stmt(thd); + /* + Need to end the current transaction, so the storage engine (InnoDB) + can free its locks if LOCK TABLES locked some tables before finding + that it can't lock a table in its list + */ + trans_commit_implicit(thd); + /* Close tables and release metadata locks. */ + close_thread_tables(thd); + DBUG_ASSERT(!thd->locked_tables_mode); + thd->mdl_context.release_transactional_locks(); + return TRUE; +} + + /** Execute command saved in thd and lex->sql_command. @@ -3093,31 +3154,11 @@ end_with_restore_list: goto error; thd->variables.option_bits|= OPTION_TABLE_LOCK; - thd->in_lock_tables=1; - { - Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; - - res= (open_and_lock_tables(thd, all_tables, FALSE, 0, - &lock_tables_prelocking_strategy) || - thd->locked_tables_list.init_locked_tables(thd)); - } - - thd->in_lock_tables= 0; + res= lock_tables_open_and_lock_tables(thd, all_tables); if (res) { - trans_rollback_stmt(thd); - /* - Need to end the current transaction, so the storage engine (InnoDB) - can free its locks if LOCK TABLES locked some tables before finding - that it can't lock a table in its list - */ - trans_commit_implicit(thd); - /* Close tables and release metadata locks. */ - close_thread_tables(thd); - DBUG_ASSERT(!thd->locked_tables_mode); - thd->mdl_context.release_transactional_locks(); thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); } else