From 0c8a78cca1ec1a8a93d80dd7355eba4123ccbe2c Mon Sep 17 00:00:00 2001 From: "wax@kishkin.ru" <> Date: Tue, 14 Dec 2004 19:24:19 +0500 Subject: [PATCH 01/54] BUG#6056 (continue) added event_conn_closed replaced WaitForSingleObject on WaitForMultipleObjects inserted a check in vio_close() added SetEvent() for event_conn_closed --- include/violite.h | 4 +++- sql-common/client.c | 12 +++++++++++- sql/mysqld.cc | 11 ++++++++++- vio/vio.c | 4 +++- vio/viosocket.c | 31 +++++++++++++++++++++++-------- 5 files changed, 50 insertions(+), 12 deletions(-) diff --git a/include/violite.h b/include/violite.h index ba7de3ee175..64e834d6653 100644 --- a/include/violite.h +++ b/include/violite.h @@ -45,7 +45,8 @@ Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE event_server_wrote, HANDLE event_server_read, HANDLE event_client_wrote, - HANDLE event_client_read); + HANDLE event_client_read, + HANDLE event_conn_closed); int vio_read_pipe(Vio *vio, gptr buf, int size); int vio_write_pipe(Vio *vio, const gptr buf, int size); int vio_close_pipe(Vio * vio); @@ -197,6 +198,7 @@ struct st_vio HANDLE event_server_read; HANDLE event_client_wrote; HANDLE event_client_read; + HANDLE event_conn_closed; long shared_memory_remain; char *shared_memory_pos; NET *net; diff --git a/sql-common/client.c b/sql-common/client.c index b847c467b85..0714ca4291f 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -396,6 +396,7 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) HANDLE event_server_read = NULL; HANDLE event_client_wrote = NULL; HANDLE event_client_read = NULL; + HANDLE event_conn_closed = NULL; HANDLE handle_file_map = NULL; ulong connect_number; char connect_number_char[22], *p; @@ -508,6 +509,13 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout) error_allow = CR_SHARED_MEMORY_EVENT_ERROR; goto err2; } + + strmov(suffix_pos, "CONNECTION_CLOSED"); + if ((event_conn_closed = OpenEvent(EVENT_ALL_ACCESS,FALSE,tmp)) == NULL) + { + error_allow = CR_SHARED_MEMORY_EVENT_ERROR; + goto err2; + } /* Set event that server should send data */ @@ -519,7 +527,7 @@ err2: net->vio= vio_new_win32shared_memory(net,handle_file_map,handle_map, event_server_wrote, event_server_read,event_client_wrote, - event_client_read); + event_client_read,event_conn_closed); } else { @@ -532,6 +540,8 @@ err2: CloseHandle(event_client_read); if (event_client_wrote) CloseHandle(event_client_wrote); + if (event_conn_closed) + CloseHandle(event_conn_closed); if (handle_map) UnmapViewOfFile(handle_map); if (handle_file_map) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index e39c902444e..4a6dc037557 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3813,6 +3813,7 @@ pthread_handler_decl(handle_connections_shared_memory,arg) HANDLE event_client_read= 0; // for transfer data server <-> client HANDLE event_server_wrote= 0; HANDLE event_server_read= 0; + HANDLE event_conn_closed= 0; THD *thd= 0; p= int10_to_str(connect_number, connect_number_char, 10); @@ -3866,6 +3867,12 @@ pthread_handler_decl(handle_connections_shared_memory,arg) errmsg= "Could not create server write event"; goto errorconn; } + strmov(suffix_pos, "CONNECTION_CLOSED"); + if ((event_conn_closed= CreateEvent(0,TRUE,FALSE,tmp)) == 0) + { + errmsg= "Could not create closed connection event"; + goto errorconn; + } if (abort_loop) goto errorconn; if (!(thd= new THD)) @@ -3889,7 +3896,8 @@ pthread_handler_decl(handle_connections_shared_memory,arg) event_client_wrote, event_client_read, event_server_wrote, - event_server_read)) || + event_server_read, + event_conn_closed)) || my_net_init(&thd->net, thd->net.vio)) { close_connection(thd, ER_OUT_OF_RESOURCES, 1); @@ -3916,6 +3924,7 @@ errorconn: if (event_server_read) CloseHandle(event_server_read); if (event_client_wrote) CloseHandle(event_client_wrote); if (event_client_read) CloseHandle(event_client_read); + if (event_conn_closed) CloseHandle(event_conn_closed); delete thd; } diff --git a/vio/vio.c b/vio/vio.c index a356d8edeff..92d69dc5148 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -171,7 +171,8 @@ Vio *vio_new_win32pipe(HANDLE hPipe) #ifdef HAVE_SMEM Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_map, HANDLE event_server_wrote, HANDLE event_server_read, - HANDLE event_client_wrote, HANDLE event_client_read) + HANDLE event_client_wrote, HANDLE event_client_read, + HANDLE event_conn_closed) { Vio *vio; DBUG_ENTER("vio_new_win32shared_memory"); @@ -184,6 +185,7 @@ Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_m vio->event_server_read = event_server_read; vio->event_client_wrote = event_client_wrote; vio->event_client_read = event_client_read; + vio->event_conn_closed = event_conn_closed; vio->shared_memory_remain = 0; vio->shared_memory_pos = handle_map; vio->net = net; diff --git a/vio/viosocket.c b/vio/viosocket.c index 48a9058480a..caf9451df7a 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -381,10 +381,21 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size) { if (vio->shared_memory_remain == 0) { - if (WaitForSingleObject(vio->event_server_wrote,vio->net->read_timeout*1000) != WAIT_OBJECT_0) + HANDLE events[2]; + events[0]= vio->event_server_wrote; + events[1]= vio->event_conn_closed; + /* + WaitForMultipleObjects can return next values: + WAIT_OBJECT_0+0 - event from vio->event_server_wrote + WAIT_OBJECT_0+1 - event from vio->event_conn_closed. We can't read anything + WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything + */ + if (WaitForMultipleObjects(2,(HANDLE*)&events,FALSE, + vio->net->read_timeout*1000) != WAIT_OBJECT_0) { DBUG_RETURN(-1); }; + vio->shared_memory_pos = vio->handle_map; vio->shared_memory_remain = uint4korr((ulong*)vio->shared_memory_pos); vio->shared_memory_pos+=4; @@ -454,17 +465,21 @@ int vio_close_shared_memory(Vio * vio) { int r; DBUG_ENTER("vio_close_shared_memory"); - r=UnmapViewOfFile(vio->handle_map) || CloseHandle(vio->event_server_wrote) || - CloseHandle(vio->event_server_read) || CloseHandle(vio->event_client_wrote) || - CloseHandle(vio->event_client_read) || CloseHandle(vio->handle_file_map); - if (r) + if (vio->type != VIO_CLOSED) { - DBUG_PRINT("vio_error", ("close() failed, error: %d",r)); - /* FIXME: error handling (not critical for MySQL) */ + SetEvent(vio->event_conn_closed); + r=UnmapViewOfFile(vio->handle_map) || CloseHandle(vio->event_server_wrote) || + CloseHandle(vio->event_server_read) || CloseHandle(vio->event_client_wrote) || + CloseHandle(vio->event_client_read) || CloseHandle(vio->handle_file_map); + if (!r) + { + DBUG_PRINT("vio_error", ("close() failed, error: %d",r)); + /* FIXME: error handling (not critical for MySQL) */ + } } vio->type= VIO_CLOSED; vio->sd= -1; - DBUG_RETURN(r); + DBUG_RETURN(!r); } #endif /* HAVE_SMEM */ #endif /* __WIN__ */ From da562b7e02aea6ed239d3c1a5a84ffe46fbf3e53 Mon Sep 17 00:00:00 2001 From: "ram@gw.mysql.r18.ru" <> Date: Mon, 20 Dec 2004 13:47:38 +0400 Subject: [PATCH 02/54] A fix (bug #7281: RAND(RAND) crashes server). --- mysql-test/r/func_math.result | 2 ++ mysql-test/t/func_math.test | 7 +++++++ sql/item_func.cc | 3 ++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 90aa04515d7..3a28cccfac5 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -124,3 +124,5 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1003 select degrees(pi()) AS `degrees(pi())`,radians(360) AS `radians(360)` +select rand(rand); +ERROR 42S22: Unknown column 'rand' in 'field list' diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index e58c097b5a6..668aefc2d8d 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -51,3 +51,10 @@ SELECT ASIN(1.2-0.2); #select floor(log(16)/log(2)); explain extended select degrees(pi()),radians(360); + +# +# Bug #7281: problem with rand() +# + +--error 1054 +select rand(rand); diff --git a/sql/item_func.cc b/sql/item_func.cc index 2d939f47716..3c565d0c466 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1091,7 +1091,8 @@ double Item_func_round::val() bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, Item **ref) { - Item_real_func::fix_fields(thd, tables, ref); + if (Item_real_func::fix_fields(thd, tables, ref)) + return TRUE; used_tables_cache|= RAND_TABLE_BIT; if (arg_count) { // Only use argument once in query From f3fc9a2dda9142c52ce28655b69e74b018fab7d5 Mon Sep 17 00:00:00 2001 From: "mwagner@here.mwagner.org" <> Date: Mon, 20 Dec 2004 15:12:13 -0600 Subject: [PATCH 03/54] configure.in: Increment from 4.0.23 to 4.0.24 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 06a0c1bd52f..65af867cbc0 100644 --- a/configure.in +++ b/configure.in @@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT(sql/mysqld.cc) AC_CANONICAL_SYSTEM # The Docs Makefile.am parses this line! -AM_INIT_AUTOMAKE(mysql, 4.0.23) +AM_INIT_AUTOMAKE(mysql, 4.0.24) AM_CONFIG_HEADER(config.h) PROTOCOL_VERSION=10 From 72dd42bee65e1378db071db873d49ada5dbb3c4d Mon Sep 17 00:00:00 2001 From: "hf@deer.(none)" <> Date: Tue, 21 Dec 2004 12:31:38 +0400 Subject: [PATCH 04/54] Tabs removed --- libmysqld/lib_sql.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index e866c801337..26d97fa03c8 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -604,7 +604,7 @@ static char *dup_str_aux(MEM_ROOT *root, const char *from, uint length, uint new_len= (tocs->mbmaxlen * length) / fromcs->mbminlen + 1; result= (char *)alloc_root(root, new_len); length= copy_and_convert(result, new_len, - tocs, from, length, fromcs, &dummy_err); + tocs, from, length, fromcs, &dummy_err); } else { @@ -645,15 +645,15 @@ bool Protocol::send_fields(List *list, uint flag) item->make_field(&server_field); client_field->db= dup_str_aux(field_alloc, server_field.db_name, - strlen(server_field.db_name), cs, thd_cs); + strlen(server_field.db_name), cs, thd_cs); client_field->table= dup_str_aux(field_alloc, server_field.table_name, - strlen(server_field.table_name), cs, thd_cs); + strlen(server_field.table_name), cs, thd_cs); client_field->name= dup_str_aux(field_alloc, server_field.col_name, - strlen(server_field.col_name), cs, thd_cs); + strlen(server_field.col_name), cs, thd_cs); client_field->org_table= dup_str_aux(field_alloc, server_field.org_table_name, - strlen(server_field.org_table_name), cs, thd_cs); + strlen(server_field.org_table_name), cs, thd_cs); client_field->org_name= dup_str_aux(field_alloc, server_field.org_col_name, - strlen(server_field.org_col_name), cs, thd_cs); + strlen(server_field.org_col_name), cs, thd_cs); if (item->collation.collation == &my_charset_bin || thd_cs == NULL) { /* No conversion */ From 490f2fbab1dc58f83bbab2f9f76c7826fa2e9f7f Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Tue, 21 Dec 2004 10:37:12 +0100 Subject: [PATCH 05/54] added ndb_init.h to distribution added missing copyright text moved ndb_init things to separate header file removed ndb_global include documented cluster connection class moved internal constants to NdbImpl.hpp class changed wait_until_ready behaviour somewhat --- ndb/config/type_ndbapitest.mk.am | 2 +- ndb/include/Makefile.am | 1 + ndb/include/ndb_global.h.in | 22 +++++-- ndb/include/ndb_init.h | 32 ++++++++++ ndb/include/ndbapi/NdbBlob.hpp | 15 ----- ndb/include/ndbapi/NdbReceiver.hpp | 3 +- ndb/include/ndbapi/ndb_cluster_connection.hpp | 60 +++++++++++++++--- ndb/src/ndbapi/Ndb.cpp | 2 +- ndb/src/ndbapi/NdbBlob.cpp | 63 ++++++++++--------- ndb/src/ndbapi/NdbBlobImpl.hpp | 39 ++++++++++++ ndb/src/ndbapi/NdbDictionaryImpl.cpp | 7 ++- ndb/src/ndbapi/NdbOperationInt.cpp | 18 ++---- ndb/src/ndbapi/ndb_cluster_connection.cpp | 14 +---- ndb/test/ndbapi/testBlobs.cpp | 3 +- 14 files changed, 190 insertions(+), 91 deletions(-) create mode 100644 ndb/include/ndb_init.h create mode 100644 ndb/src/ndbapi/NdbBlobImpl.hpp diff --git a/ndb/config/type_ndbapitest.mk.am b/ndb/config/type_ndbapitest.mk.am index f1fd8286337..392c4e9fc70 100644 --- a/ndb/config/type_ndbapitest.mk.am +++ b/ndb/config/type_ndbapitest.mk.am @@ -5,7 +5,7 @@ LDADD += $(top_builddir)/ndb/test/src/libNDBT.a \ $(top_builddir)/mysys/libmysys.a \ $(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@ -INCLUDES += -I$(srcdir) -I$(top_srcdir)/include \ +INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/include \ -I$(top_srcdir)/ndb/include \ -I$(top_srcdir)/ndb/include/ndbapi \ -I$(top_srcdir)/ndb/include/util \ diff --git a/ndb/include/Makefile.am b/ndb/include/Makefile.am index b29433a59b7..38b9d870fbc 100644 --- a/ndb/include/Makefile.am +++ b/ndb/include/Makefile.am @@ -2,6 +2,7 @@ include $(top_srcdir)/ndb/config/common.mk.am ndbinclude_HEADERS = \ +ndb_init.h \ ndb_types.h \ ndb_version.h diff --git a/ndb/include/ndb_global.h.in b/ndb/include/ndb_global.h.in index aefb319730c..aca67239719 100644 --- a/ndb/include/ndb_global.h.in +++ b/ndb/include/ndb_global.h.in @@ -1,3 +1,18 @@ +/* Copyright (C) 2003 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef NDBGLOBAL_H #define NDBGLOBAL_H @@ -96,15 +111,12 @@ extern "C" { #include -/* call in main() - does not return on error */ -extern int ndb_init(void); -extern void ndb_end(int); -#define NDB_INIT(prog_name) {my_progname=(prog_name); ndb_init();} - #ifdef __cplusplus } #endif +#include "ndb_init.h" + #ifdef SCO #ifndef PATH_MAX diff --git a/ndb/include/ndb_init.h b/ndb/include/ndb_init.h new file mode 100644 index 00000000000..0ff53e6a2af --- /dev/null +++ b/ndb/include/ndb_init.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef NDB_INIT_H +#define NDB_INIT_H + +#ifdef __cplusplus +extern "C" { +#endif +/* call in main() - does not return on error */ +extern int ndb_init(void); +extern void ndb_end(int); +#define NDB_INIT(prog_name) {my_progname=(prog_name); ndb_init();} +#ifdef __cplusplus +} +#endif + +#endif diff --git a/ndb/include/ndbapi/NdbBlob.hpp b/ndb/include/ndbapi/NdbBlob.hpp index 0fb63015da2..b145c69b04b 100644 --- a/ndb/include/ndbapi/NdbBlob.hpp +++ b/ndb/include/ndbapi/NdbBlob.hpp @@ -182,27 +182,12 @@ public: /** * Get blob parts table name. Useful only to test programs. */ - STATIC_CONST( BlobTableNameSize = 40 ); static int getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char* columnName); /** * Return error object. The error may be blob specific (below) or may * be copied from a failed implicit operation. */ const NdbError& getNdbError() const; - // "Invalid blob attributes or invalid blob parts table" - STATIC_CONST( ErrTable = 4263 ); - // "Invalid usage of blob attribute" - STATIC_CONST( ErrUsage = 4264 ); - // "Method is not valid in current blob state" - STATIC_CONST( ErrState = 4265 ); - // "Invalid blob seek position" - STATIC_CONST( ErrSeek = 4266 ); - // "Corrupted blob value" - STATIC_CONST( ErrCorrupt = 4267 ); - // "Error in blob head update forced rollback of transaction" - STATIC_CONST( ErrAbort = 4268 ); - // "Unknown blob error" - STATIC_CONST( ErrUnknown = 4269 ); /** * Return info about all blobs in this operation. */ diff --git a/ndb/include/ndbapi/NdbReceiver.hpp b/ndb/include/ndbapi/NdbReceiver.hpp index b95313db274..af624f69bd3 100644 --- a/ndb/include/ndbapi/NdbReceiver.hpp +++ b/ndb/include/ndbapi/NdbReceiver.hpp @@ -19,7 +19,6 @@ #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL // Not part of public interface #include -#include class Ndb; class NdbConnection; @@ -131,7 +130,9 @@ int NdbReceiver::execTCOPCONF(Uint32 len){ Uint32 tmp = m_received_result_length; m_expected_result_length = len; +#ifdef assert assert(!(tmp && !len)); +#endif return ((bool)len ^ (bool)tmp ? 0 : 1); } diff --git a/ndb/include/ndbapi/ndb_cluster_connection.hpp b/ndb/include/ndbapi/ndb_cluster_connection.hpp index 1b1c8575656..a98dcaaf5a4 100644 --- a/ndb/include/ndbapi/ndb_cluster_connection.hpp +++ b/ndb/include/ndbapi/ndb_cluster_connection.hpp @@ -18,28 +18,72 @@ #ifndef CLUSTER_CONNECTION_HPP #define CLUSTER_CONNECTION_HPP -struct Ndb_cluster_connection_node_iter; - +/** + * @class Ndb_cluster_connection + * @brief Represents a connection to a cluster of storage nodes + * + * Always start your application program by creating a + * Ndb_cluster_connection object. Your application should contain + * only one Ndb_cluster_connection. Your application connects to + * a cluster management server when method connect() is called. + * With the method wait_until_ready() it is possible to wait + * for the connection to one or several storage nodes. + */ class Ndb_cluster_connection { public: + /** + * Create a connection to a cluster of storage nodes + * + * @param specify the connectstring for where to find the + * management server + */ Ndb_cluster_connection(const char * connect_string = 0); ~Ndb_cluster_connection(); - int connect(int no_retries, int retry_delay_in_seconds, int verbose); - int start_connect_thread(int (*connect_callback)(void)= 0); - // add check coupled to init state of cluster connection - // timeout_after_first_alive negative - ok only if all alive - // timeout_after_first_alive positive - ok if some alive + /** + * Connect to a cluster management server + * + * @param no_retries specifies the number of retries to perform + * if the connect fails, negative number results in infinite + * number of retries + * @param retry_delay_in_seconds specifies how often retries should + * be performed + * @param verbose specifies if the method should print progess + * + * @return 0 if success, + * 1 if retriable error, + * -1 if non-retriable error + */ + int connect(int no_retries=0, int retry_delay_in_seconds=1, int verbose=0); + +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL + int start_connect_thread(int (*connect_callback)(void)= 0); +#endif + + /** + * Wait until one or several storage nodes are connected + * + * @param time_out_for_first_alive number of seconds to wait until + * first alive node is detected + * @param timeout_after_first_alive number of seconds to wait after + * first alive node is detected + * + * @return 0 all nodes alive, + * > 0 at least one node alive, + * < 0 error + */ int wait_until_ready(int timeout_for_first_alive, int timeout_after_first_alive); +#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL const char *get_connectstring(char *buf, int buf_sz) const; int get_connected_port() const; const char *get_connected_host() const; void set_optimized_node_selection(int val); - Uint32 no_db_nodes(); + int no_db_nodes(); +#endif private: friend class Ndb; diff --git a/ndb/src/ndbapi/Ndb.cpp b/ndb/src/ndbapi/Ndb.cpp index e9a125922c6..b5493622b70 100644 --- a/ndb/src/ndbapi/Ndb.cpp +++ b/ndb/src/ndbapi/Ndb.cpp @@ -282,7 +282,7 @@ Ndb::waitUntilReady(int timeout) } if (theImpl->m_ndb_cluster_connection.wait_until_ready - (timeout-secondsCounter,30)) + (timeout-secondsCounter,30) < 0) { theError.code = 4009; DBUG_RETURN(-1); diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp index da0a4f73c3e..f72361b86ac 100644 --- a/ndb/src/ndbapi/NdbBlob.cpp +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -21,6 +21,7 @@ #include #include #include +#include "NdbBlobImpl.hpp" #include #ifdef NDB_BLOB_DEBUG @@ -85,14 +86,14 @@ void NdbBlob::getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c) { assert(t != 0 && c != 0 && c->getBlobType()); - memset(btname, 0, BlobTableNameSize); + memset(btname, 0, NdbBlobImpl::BlobTableNameSize); sprintf(btname, "NDB$BLOB_%d_%d", (int)t->m_tableId, (int)c->m_attrId); } void NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl* c) { - char btname[BlobTableNameSize]; + char btname[NdbBlobImpl::BlobTableNameSize]; getBlobTableName(btname, t, c); bt.setName(btname); bt.setLogging(t->getLogging()); @@ -450,15 +451,15 @@ NdbBlob::getValue(void* data, Uint32 bytes) { DBG("getValue data=" << hex << data << " bytes=" << dec << bytes); if (theGetFlag || theState != Prepared) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } if (! isReadOp() && ! isScanOp()) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } if (data == NULL && bytes != 0) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } theGetFlag = true; @@ -472,15 +473,15 @@ NdbBlob::setValue(const void* data, Uint32 bytes) { DBG("setValue data=" << hex << data << " bytes=" << dec << bytes); if (theSetFlag || theState != Prepared) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } if (! isInsertOp() && ! isUpdateOp() && ! isWriteOp()) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } if (data == NULL && bytes != 0) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } theSetFlag = true; @@ -512,7 +513,7 @@ NdbBlob::setActiveHook(ActiveHook activeHook, void* arg) { DBG("setActiveHook hook=" << hex << (void*)activeHook << " arg=" << hex << arg); if (theState != Prepared) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } theActiveHook = activeHook; @@ -531,7 +532,7 @@ NdbBlob::getNull(bool& isNull) return 0; } if (theNullFlag == -1) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } isNull = theNullFlag; @@ -546,7 +547,7 @@ NdbBlob::setNull() if (theState == Prepared) { return setValue(0, 0); } - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } if (theNullFlag) @@ -568,7 +569,7 @@ NdbBlob::getLength(Uint64& len) return 0; } if (theNullFlag == -1) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } len = theLength; @@ -580,7 +581,7 @@ NdbBlob::truncate(Uint64 length) { DBG("truncate [in] length=" << length); if (theNullFlag == -1) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } if (theLength > length) { @@ -608,7 +609,7 @@ NdbBlob::getPos(Uint64& pos) { DBG("getPos"); if (theNullFlag == -1) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } pos = thePos; @@ -620,11 +621,11 @@ NdbBlob::setPos(Uint64 pos) { DBG("setPos pos=" << pos); if (theNullFlag == -1) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } if (pos > theLength) { - setErrorCode(ErrSeek); + setErrorCode(NdbBlobImpl::ErrSeek); return -1; } thePos = pos; @@ -637,7 +638,7 @@ int NdbBlob::readData(void* data, Uint32& bytes) { if (theState != Active) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } char* buf = static_cast(data); @@ -666,7 +667,7 @@ NdbBlob::readDataPrivate(char* buf, Uint32& bytes) } } if (len > 0 && thePartSize == 0) { - setErrorCode(ErrSeek); + setErrorCode(NdbBlobImpl::ErrSeek); return -1; } if (len > 0) { @@ -731,7 +732,7 @@ int NdbBlob::writeData(const void* data, Uint32 bytes) { if (theState != Active) { - setErrorCode(ErrState); + setErrorCode(NdbBlobImpl::ErrState); return -1; } const char* buf = static_cast(data); @@ -764,7 +765,7 @@ NdbBlob::writeDataPrivate(const char* buf, Uint32 bytes) } } if (len > 0 && thePartSize == 0) { - setErrorCode(ErrSeek); + setErrorCode(NdbBlobImpl::ErrSeek); return -1; } if (len > 0) { @@ -1081,7 +1082,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* theFillChar = 0x20; break; default: - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } // sizes @@ -1099,7 +1100,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* (bc = bt->getColumn("DATA")) == NULL || bc->getType() != partType || bc->getLength() != (int)thePartSize) { - setErrorCode(ErrTable); + setErrorCode(NdbBlobImpl::ErrTable); return -1; } theBlobTable = &NdbTableImpl::getImpl(*bt); @@ -1120,7 +1121,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* Uint32* data = (Uint32*)theKeyBuf.data; unsigned size = theTable->m_sizeOfKeysInWords; if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } } @@ -1129,7 +1130,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* Uint32* data = (Uint32*)theAccessKeyBuf.data; unsigned size = theAccessTable->m_sizeOfKeysInWords; if (theNdbOp->getKeyFromTCREQ(data, size) == -1) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } } @@ -1158,7 +1159,7 @@ NdbBlob::atPrepare(NdbConnection* aCon, NdbOperation* anOp, const NdbColumnImpl* supportedOp = true; } if (! supportedOp) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } setState(Prepared); @@ -1204,7 +1205,7 @@ NdbBlob::preExecute(ExecType anExecType, bool& batch) tOp->updateTuple() == -1 || setTableKeyValue(tOp) == -1 || setHeadInlineValue(tOp) == -1) { - setErrorCode(ErrAbort); + setErrorCode(NdbBlobImpl::ErrAbort); return -1; } DBG("add op to update head+inline"); @@ -1434,7 +1435,7 @@ NdbBlob::postExecute(ExecType anExecType) tOp->updateTuple() == -1 || setTableKeyValue(tOp) == -1 || setHeadInlineValue(tOp) == -1) { - setErrorCode(ErrAbort); + setErrorCode(NdbBlobImpl::ErrAbort); return -1; } tOp->m_abortOption = AbortOnError; @@ -1464,7 +1465,7 @@ NdbBlob::preCommit() tOp->updateTuple() == -1 || setTableKeyValue(tOp) == -1 || setHeadInlineValue(tOp) == -1) { - setErrorCode(ErrAbort); + setErrorCode(NdbBlobImpl::ErrAbort); return -1; } tOp->m_abortOption = AbortOnError; @@ -1489,7 +1490,7 @@ NdbBlob::atNextResult() { Uint32* data = (Uint32*)theKeyBuf.data; unsigned size = theTable->m_sizeOfKeysInWords; if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) { - setErrorCode(ErrUsage); + setErrorCode(NdbBlobImpl::ErrUsage); return -1; } } @@ -1545,7 +1546,7 @@ NdbBlob::setErrorCode(NdbOperation* anOp, bool invalidFlag) else if ((code = theNdb->theError.code) != 0) ; else - code = ErrUnknown; + code = NdbBlobImpl::ErrUnknown; setErrorCode(code, invalidFlag); } @@ -1558,7 +1559,7 @@ NdbBlob::setErrorCode(NdbConnection* aCon, bool invalidFlag) else if ((code = theNdb->theError.code) != 0) ; else - code = ErrUnknown; + code = NdbBlobImpl::ErrUnknown; setErrorCode(code, invalidFlag); } diff --git a/ndb/src/ndbapi/NdbBlobImpl.hpp b/ndb/src/ndbapi/NdbBlobImpl.hpp new file mode 100644 index 00000000000..0030e910c52 --- /dev/null +++ b/ndb/src/ndbapi/NdbBlobImpl.hpp @@ -0,0 +1,39 @@ +/* Copyright (C) 2003 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef NdbBlobImpl_H +#define NdbBlobImpl_H + +class NdbBlobImpl { +public: + STATIC_CONST( BlobTableNameSize = 40 ); + // "Invalid blob attributes or invalid blob parts table" + STATIC_CONST( ErrTable = 4263 ); + // "Invalid usage of blob attribute" + STATIC_CONST( ErrUsage = 4264 ); + // "Method is not valid in current blob state" + STATIC_CONST( ErrState = 4265 ); + // "Invalid blob seek position" + STATIC_CONST( ErrSeek = 4266 ); + // "Corrupted blob value" + STATIC_CONST( ErrCorrupt = 4267 ); + // "Error in blob head update forced rollback of transaction" + STATIC_CONST( ErrAbort = 4268 ); + // "Unknown blob error" + STATIC_CONST( ErrUnknown = 4269 ); +}; + +#endif diff --git a/ndb/src/ndbapi/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp index 5319e678441..7a293463c94 100644 --- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp +++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp @@ -34,7 +34,8 @@ #include #include #include "NdbEventOperationImpl.hpp" -#include "NdbBlob.hpp" +#include +#include "NdbBlobImpl.hpp" #include #include @@ -1385,7 +1386,7 @@ NdbDictionaryImpl::addBlobTables(NdbTableImpl &t) if (! c.getBlobType() || c.getPartSize() == 0) continue; n--; - char btname[NdbBlob::BlobTableNameSize]; + char btname[NdbBlobImpl::BlobTableNameSize]; NdbBlob::getBlobTableName(btname, &t, &c); // Save BLOB table handle NdbTableImpl * cachedBlobTable = getTable(btname); @@ -1793,7 +1794,7 @@ NdbDictionaryImpl::dropBlobTables(NdbTableImpl & t) NdbColumnImpl & c = *t.m_columns[i]; if (! c.getBlobType() || c.getPartSize() == 0) continue; - char btname[NdbBlob::BlobTableNameSize]; + char btname[NdbBlobImpl::BlobTableNameSize]; NdbBlob::getBlobTableName(btname, &t, &c); if (dropTable(btname) != 0) { if (m_error.code != 709){ diff --git a/ndb/src/ndbapi/NdbOperationInt.cpp b/ndb/src/ndbapi/NdbOperationInt.cpp index ee7b8132cd1..ace90e35ca4 100644 --- a/ndb/src/ndbapi/NdbOperationInt.cpp +++ b/ndb/src/ndbapi/NdbOperationInt.cpp @@ -15,21 +15,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/************************************************************************************************ -Name: NdbOperationInt.C -Include: -Link: -Author: UABRONM Mikael Ronström UAB/M/MT -Date: 991029 -Version: 0.1 -Description: Interpreted operations in NDB API -Documentation: -Adjust: 991029 UABRONM First version. -************************************************************************************************/ -#include "NdbOperation.hpp" +#include +#include #include "NdbApiSignal.hpp" -#include "NdbConnection.hpp" -#include "Ndb.hpp" +#include +#include #include "NdbRecAttr.hpp" #include "NdbUtil.hpp" #include "Interpreter.hpp" diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index 98a52786aab..f754ec8b40a 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -174,7 +174,7 @@ Ndb_cluster_connection_impl::get_next_node(Ndb_cluster_connection_node_iter &ite return node.id; } -Uint32 +int Ndb_cluster_connection::no_db_nodes() { return m_impl.m_all_nodes.size(); @@ -219,16 +219,8 @@ Ndb_cluster_connection::wait_until_ready(int timeout, else if (foundAliveNode > 0) { noChecksSinceFirstAliveFound++; - if (timeout_after_first_alive >= 0) - { - if (noChecksSinceFirstAliveFound > timeout_after_first_alive) - DBUG_RETURN(0); - } - else // timeout_after_first_alive < 0 - { - if (noChecksSinceFirstAliveFound > -timeout_after_first_alive) - DBUG_RETURN(-1); - } + if (noChecksSinceFirstAliveFound > timeout_after_first_alive) + DBUG_RETURN(1); } else if (secondsCounter >= timeout) { // no alive nodes and timed out diff --git a/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp index 4b532856709..b2cc5636e45 100644 --- a/ndb/test/ndbapi/testBlobs.cpp +++ b/ndb/test/ndbapi/testBlobs.cpp @@ -23,13 +23,14 @@ #include #include #include +#include struct Bcol { bool m_nullable; unsigned m_inline; unsigned m_partsize; unsigned m_stripe; - char m_btname[NdbBlob::BlobTableNameSize]; + char m_btname[NdbBlobImpl::BlobTableNameSize]; Bcol(bool a, unsigned b, unsigned c, unsigned d) : m_nullable(a), m_inline(b), From ecd85b1836ebfbb9a548526a658956ea8ba4cfd5 Mon Sep 17 00:00:00 2001 From: "acurtis@pcgem.rdg.cyberkinetica.com" <> Date: Tue, 21 Dec 2004 11:09:48 +0000 Subject: [PATCH 06/54] Bug#6481 - storage_engine system variable allows nonsensical value Check that the requested storage engine is enabled. --- sql/set_var.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sql/set_var.cc b/sql/set_var.cc index d10ea3e11c1..e39d9934278 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2945,9 +2945,11 @@ bool sys_var_thd_storage_engine::check(THD *thd, set_var *var) if (var->value->result_type() == STRING_RESULT) { + enum db_type db_type; if (!(res=var->value->val_str(&str)) || !(var->save_result.ulong_value= - (ulong) ha_resolve_by_name(res->ptr(), res->length()))) + (ulong) db_type= ha_resolve_by_name(res->ptr(), res->length())) || + ha_checktype(db_type) != db_type) { value= res ? res->c_ptr() : "NULL"; goto err; From 57ec14d939438086faeffce6d316ad463bd164b9 Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Tue, 21 Dec 2004 17:12:27 +0400 Subject: [PATCH 07/54] Bug#7302: UCS2 data in ENUM field get truncated when new column is added --- mysql-test/r/ctype_ucs.result | 11 +++++++++++ mysql-test/t/ctype_ucs.test | 10 ++++++++++ sql/mysql_priv.h | 1 + sql/strfunc.cc | 37 +++++++++++++++++++++++++++++++++++ sql/table.cc | 20 +------------------ sql/unireg.cc | 11 +++++++++++ 6 files changed, 71 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/ctype_ucs.result b/mysql-test/r/ctype_ucs.result index ef3682c1cfc..b1b83eb8b6c 100644 --- a/mysql-test/r/ctype_ucs.result +++ b/mysql-test/r/ctype_ucs.result @@ -581,3 +581,14 @@ x,y 0078002C0079 z 007A x,y,z,ä,ö,ü 0078002C0079002C007A002C00E4002C00F6002C00FC drop table t1; +create table t1(a enum('a','b','c')) default character set ucs2; +insert into t1 values('a'),('b'),('c'); +alter table t1 add b char(1); +show warnings; +Level Code Message +select * from t1 order by a; +a b +a NULL +b NULL +c NULL +drop table t1; diff --git a/mysql-test/t/ctype_ucs.test b/mysql-test/t/ctype_ucs.test index b8f58ab028b..b9f77505446 100644 --- a/mysql-test/t/ctype_ucs.test +++ b/mysql-test/t/ctype_ucs.test @@ -374,3 +374,13 @@ insert into t1 values ('x,y'); insert into t1 values ('x,y,z,Ä,Ö,Ü'); select a, hex(a) from t1 order by a; drop table t1; + +# +# Bug#7302 UCS2 data in ENUM fields get truncated when new column is added +# +create table t1(a enum('a','b','c')) default character set ucs2; +insert into t1 values('a'),('b'),('c'); +alter table t1 add b char(1); +show warnings; +select * from t1 order by a; +drop table t1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index c90935f4cf9..c300ea2885e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -815,6 +815,7 @@ ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs, char **err_pos, uint *err_len, bool *set_warning); uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match); uint find_type2(TYPELIB *lib, const char *find, uint length, CHARSET_INFO *cs); +void unhex_type2(TYPELIB *lib); uint check_word(TYPELIB *lib, const char *val, const char *end, const char **end_of_word); diff --git a/sql/strfunc.cc b/sql/strfunc.cc index 8ab6992a63a..3ad6b1155d1 100644 --- a/sql/strfunc.cc +++ b/sql/strfunc.cc @@ -169,6 +169,43 @@ uint find_type2(TYPELIB *typelib, const char *x, uint length, CHARSET_INFO *cs) } /* find_type */ +/* + Un-hex all elements in a typelib + + SYNOPSIS + unhex_type2() + interval TYPELIB (struct of pointer to values + lengths + count) + + NOTES + + RETURN + N/A +*/ + +void unhex_type2(TYPELIB *interval) +{ + for (uint pos= 0; pos < interval->count; pos++) + { + char *from, *to; + for (from= to= (char*) interval->type_names[pos]; *from; ) + { + /* + Note, hexchar_to_int(*from++) doesn't work + one some compilers, e.g. IRIX. Looks like a compiler + bug in inline functions in combination with arguments + that have a side effect. So, let's use from[0] and from[1] + and increment 'from' by two later. + */ + + *to++= (char) (hexchar_to_int(from[0]) << 4) + + hexchar_to_int(from[1]); + from+= 2; + } + interval->type_lengths[pos] /= 2; + } +} + + /* Check if the first word in a string is one of the ones in TYPELIB diff --git a/sql/table.cc b/sql/table.cc index 992f6df0401..7adca2a5ab0 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -490,25 +490,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, { /* Unescape UCS2 intervals from HEX notation */ TYPELIB *interval= outparam->intervals + interval_nr - 1; - for (uint pos= 0; pos < interval->count; pos++) - { - char *from, *to; - for (from= to= (char*) interval->type_names[pos]; *from; ) - { - /* - Note, hexchar_to_int(*from++) doesn't work - one some compilers, e.g. IRIX. Looks like a compiler - bug in inline functions in combination with arguments - that have a side effect. So, let's use from[0] and from[1] - and increment 'from' by two later. - */ - - *to++= (char) (hexchar_to_int(from[0]) << 4) + - hexchar_to_int(from[1]); - from+= 2; - } - interval->type_lengths[pos] /= 2; - } + unhex_type2(interval); } *field_ptr=reg_field= diff --git a/sql/unireg.cc b/sql/unireg.cc index 6d72c6af135..a550b06a466 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -174,6 +174,17 @@ bool mysql_create_frm(THD *thd, my_string file_name, goto err2; if (my_close(file,MYF(MY_WME))) goto err3; + + { + /* Unescape all UCS2 intervals: were escaped in pack_headers */ + List_iterator it(create_fields); + create_field *field; + while ((field=it++)) + { + if (field->interval && field->charset->mbminlen > 1) + unhex_type2(field->interval); + } + } DBUG_RETURN(0); err: From 6c9dcae99278972939def848d2f0eb163cc14ac5 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Tue, 21 Dec 2004 15:57:36 +0100 Subject: [PATCH 08/54] NdbApi.hpp: NdbApi.hpp to include ndb_inti.h and ndb_cluster_connecion.hpp --- ndb/include/ndbapi/NdbApi.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ndb/include/ndbapi/NdbApi.hpp b/ndb/include/ndbapi/NdbApi.hpp index add733cccd7..ae7025f560a 100644 --- a/ndb/include/ndbapi/NdbApi.hpp +++ b/ndb/include/ndbapi/NdbApi.hpp @@ -17,6 +17,8 @@ #ifndef NdbApi_H #define NdbApi_H +#include "ndb_init.h" +#include "ndb_cluster_connection.hpp" #include "ndbapi_limits.h" #include "Ndb.hpp" #include "NdbConnection.hpp" From e25b633367ea0ca9c9d9ffee8b7abed70ba436af Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Tue, 21 Dec 2004 18:21:17 +0200 Subject: [PATCH 09/54] os0file.c: Fix InnoDB bug: on HP-UX, with a 32-bit binary, InnoDB was only able to read or write <= 2 GB files; the reason was that InnoDB treated the return value of lseek() as a 32-bit integer; lseek was used on HP-UX-11 as a replacement for pread() and pwrite() because HAVE_BROKEN_PREAD was defined on that platform --- innobase/os/os0file.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index 6ed3720cc84..bab043fc746 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -6,6 +6,8 @@ The interface to the operating system file i/o primitives Created 10/21/1995 Heikki Tuuri *******************************************************/ +#define HAVE_BROKEN_PREAD + #include "os0file.h" #include "os0sync.h" #include "os0thread.h" @@ -14,8 +16,6 @@ Created 10/21/1995 Heikki Tuuri #include "fil0fil.h" #include "buf0buf.h" -#undef HAVE_FDATASYNC - #ifdef POSIX_ASYNC_IO /* We assume in this case that the OS has standard Posix aio (at least SunOS 2.6, HP-UX 11i and AIX 4.3 have) */ @@ -1195,6 +1195,7 @@ os_file_pread( return(n_bytes); #else { + off_t ret_offset; ssize_t ret; ulint i; @@ -1203,12 +1204,12 @@ os_file_pread( os_mutex_enter(os_file_seek_mutexes[i]); - ret = lseek(file, offs, 0); + ret_offset = lseek(file, offs, SEEK_SET); - if (ret < 0) { + if (ret_offset < 0) { os_mutex_exit(os_file_seek_mutexes[i]); - return(ret); + return(-1); } ret = read(file, buf, (ssize_t)n); @@ -1281,6 +1282,7 @@ os_file_pwrite( return(ret); #else { + off_t ret_offset; ulint i; /* Protect the seek / write operation with a mutex */ @@ -1288,12 +1290,12 @@ os_file_pwrite( os_mutex_enter(os_file_seek_mutexes[i]); - ret = lseek(file, offs, 0); + ret_offset = lseek(file, offs, SEEK_SET); - if (ret < 0) { + if (ret_offset < 0) { os_mutex_exit(os_file_seek_mutexes[i]); - return(ret); + return(-1); } ret = write(file, buf, (ssize_t)n); From b56085a87ecea5d4f524e4a1308cefccbd66e2f1 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Tue, 21 Dec 2004 18:33:53 +0200 Subject: [PATCH 10/54] os0file.c: Put back accidentally removed undef and remove a debug def --- innobase/os/os0file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index bab043fc746..b8339134fb1 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -6,8 +6,6 @@ The interface to the operating system file i/o primitives Created 10/21/1995 Heikki Tuuri *******************************************************/ -#define HAVE_BROKEN_PREAD - #include "os0file.h" #include "os0sync.h" #include "os0thread.h" @@ -16,6 +14,8 @@ Created 10/21/1995 Heikki Tuuri #include "fil0fil.h" #include "buf0buf.h" +#undef HAVE_FDATASYNC + #ifdef POSIX_ASYNC_IO /* We assume in this case that the OS has standard Posix aio (at least SunOS 2.6, HP-UX 11i and AIX 4.3 have) */ From 8f2579c6db5e3a79634c0394aada81b68e5f3ea4 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Tue, 21 Dec 2004 18:33:41 +0100 Subject: [PATCH 11/54] main.cpp: ifdef on version prior to 5.0 --- ndb/src/mgmsrv/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index 04c95117214..015e2de022d 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -161,9 +161,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'V': print_version(); exit(0); +#if NDB_VERSION_MAJOR <= 4 case 'c': printf("Warning: -c will be removed in 5.0, use -f instead\n"); break; +#endif case OPT_NDB_SHM: #ifndef NDB_SHM_TRANSPORTER printf("Warning: binary not compiled with shared memory support,\n" From 78ce178559becb8845bfc24dd5c0e7f70a7817b5 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 22 Dec 2004 07:20:01 +0100 Subject: [PATCH 12/54] added configuration hostnames to SHM config struct use configured hostnames for SHM transporter setup --- ndb/include/transporter/TransporterDefinitions.hpp | 2 ++ ndb/src/common/mgmcommon/IPCConfig.cpp | 2 ++ ndb/src/common/transporter/TransporterRegistry.cpp | 4 ++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ndb/include/transporter/TransporterDefinitions.hpp b/ndb/include/transporter/TransporterDefinitions.hpp index a8da8068552..4ff6b2073eb 100644 --- a/ndb/include/transporter/TransporterDefinitions.hpp +++ b/ndb/include/transporter/TransporterDefinitions.hpp @@ -68,6 +68,8 @@ struct TCP_TransporterConfiguration { */ struct SHM_TransporterConfiguration { Uint32 port; + const char *remoteHostName; + const char *localHostName; NodeId remoteNodeId; NodeId localNodeId; bool checksum; diff --git a/ndb/src/common/mgmcommon/IPCConfig.cpp b/ndb/src/common/mgmcommon/IPCConfig.cpp index 780504d2c62..1da03e3eaf2 100644 --- a/ndb/src/common/mgmcommon/IPCConfig.cpp +++ b/ndb/src/common/mgmcommon/IPCConfig.cpp @@ -383,6 +383,8 @@ IPCConfig::configureTransporters(Uint32 nodeId, if(iter.get(CFG_SHM_BUFFER_MEM, &conf.shmSize)) break; conf.port= server_port; + conf.localHostName = localHostName; + conf.remoteHostName = remoteHostName; if(!tr.createTransporter(&conf)){ DBUG_PRINT("error", ("Failed to create SHM Transporter from %d to %d", diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp index be51e9223ba..394c7cd490d 100644 --- a/ndb/src/common/transporter/TransporterRegistry.cpp +++ b/ndb/src/common/transporter/TransporterRegistry.cpp @@ -358,8 +358,8 @@ TransporterRegistry::createTransporter(SHM_TransporterConfiguration *config) { return false; SHM_Transporter * t = new SHM_Transporter(*this, - "localhost", - "localhost", + config->localHostName, + config->remoteHostName, config->port, localNodeId, config->remoteNodeId, From e28ad144296451a3f6b8b9343335f25f18e0f762 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 22 Dec 2004 07:50:44 +0100 Subject: [PATCH 13/54] added some debug printouts --- ndb/src/common/transporter/Transporter.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp index ee25d97feef..3fe10cb2fe8 100644 --- a/ndb/src/common/transporter/Transporter.cpp +++ b/ndb/src/common/transporter/Transporter.cpp @@ -37,6 +37,7 @@ Transporter::Transporter(TransporterRegistry &t_reg, m_packer(_signalId, _checksum), m_transporter_registry(t_reg) { + DBUG_ENTER("Transporter::Transporter"); if (rHostName && strlen(rHostName) > 0){ strncpy(remoteHostName, rHostName, sizeof(remoteHostName)); Ndb_getInAddr(&remoteHostAddress, rHostName); @@ -55,6 +56,11 @@ Transporter::Transporter(TransporterRegistry &t_reg, if (strlen(lHostName) > 0) Ndb_getInAddr(&localHostAddress, lHostName); + DBUG_PRINT("info",("rId=%d lId=%d isServer=%d rHost=%s lHost=%s r_port=%d", + remoteNodeId, localNodeId, isServer, + remoteHostName, localHostName, + r_port)); + byteOrder = _byteorder; compressionUsed = _compression; checksumUsed = _checksum; @@ -68,6 +74,7 @@ Transporter::Transporter(TransporterRegistry &t_reg, else m_socket_client= new SocketClient(remoteHostName, r_port, new SocketAuthSimple("ndbd", "ndbd passwd")); + DBUG_VOID_RETURN; } Transporter::~Transporter(){ @@ -77,8 +84,11 @@ Transporter::~Transporter(){ bool Transporter::connect_server(NDB_SOCKET_TYPE sockfd) { + DBUG_ENTER("Transporter::connect_server"); if(m_connected) - return true; // TODO assert(0); + { + DBUG_RETURN(true); // TODO assert(0); + } bool res = connect_server_impl(sockfd); if(res){ @@ -86,7 +96,7 @@ Transporter::connect_server(NDB_SOCKET_TYPE sockfd) { m_errorCount = 0; } - return res; + DBUG_RETURN(res); } bool From 917e8b4da32b612b29e76938362eef70b6420cd0 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 22 Dec 2004 11:01:25 +0200 Subject: [PATCH 14/54] ha_innodb.cc: If AUTOCOMMIT=1, do not acquire an InnoDB table lock in LOCK TABLES; this makes porting of old MyISAM applications to InnoDB easier, since in that mode InnoDB table locks caused deadlocks very easily --- sql/ha_innodb.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index c36075207ed..69d9d885b8e 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4702,7 +4702,8 @@ ha_innobase::external_lock( if (prebuilt->select_lock_type != LOCK_NONE) { if (thd->in_lock_tables && - thd->variables.innodb_table_locks) { + thd->variables.innodb_table_locks && + (thd->options & OPTION_NOT_AUTOCOMMIT)) { ulint error; error = row_lock_table_for_mysql(prebuilt); From 13916aa8ddb147eddf999c7cc61f47a107f95b56 Mon Sep 17 00:00:00 2001 From: "joreland@mysql.com" <> Date: Wed, 22 Dec 2004 10:01:31 +0100 Subject: [PATCH 15/54] wl1292 - ndb autotest - adapt to changes in Logger --- ndb/test/run-test/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ndb/test/run-test/main.cpp b/ndb/test/run-test/main.cpp index ac7710d9546..fb6754dae7a 100644 --- a/ndb/test/run-test/main.cpp +++ b/ndb/test/run-test/main.cpp @@ -275,6 +275,7 @@ parse_args(int argc, const char** argv){ int tmp = Logger::LL_WARNING - g_verbosity; tmp = (tmp < Logger::LL_DEBUG ? Logger::LL_DEBUG : tmp); g_logger.disable(Logger::LL_ALL); + g_logger.enable(Logger::LL_ON); g_logger.enable((Logger::LoggerLevel)tmp, Logger::LL_ALERT); } From 64f36c94d10f11dbbd3777b9d8fac17e463ce2e4 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 22 Dec 2004 11:11:16 +0200 Subject: [PATCH 16/54] ha_innodb.cc: Add a comment that no InnoDB table lock is now acquired in LOCK TABLES if AUTOCOMMIT=1. This helps to avoid deadlocks when porting old MyISAM applications to InnoDB. --- sql/ha_innodb.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 20837e2172d..552f2676bdd 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -5049,10 +5049,18 @@ ha_innobase::external_lock( prebuilt->select_lock_type = LOCK_S; } + /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK + TABLES if AUTOCOMMIT=1. It does not make much sense to acquire + an InnoDB table lock if it is released immediately at the end + of LOCK TABLES, and InnoDB's table locks in that case cause + VERY easily deadlocks. */ + if (prebuilt->select_lock_type != LOCK_NONE) { + if (thd->in_lock_tables && thd->variables.innodb_table_locks && (thd->options & OPTION_NOT_AUTOCOMMIT)) { + ulint error; error = row_lock_table_for_mysql(prebuilt, NULL, LOCK_TABLE_EXP); From e53b446a735d04b5f94e754f833d1480eb17874a Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Wed, 22 Dec 2004 16:02:27 +0400 Subject: [PATCH 17/54] Bug#7020: mysqldump --compatible=mysql40 still dumps in UTF8 See mysqldump.test comments for more details --- client/mysqldump.c | 6 ++ mysql-test/r/mysqldump.result | 106 ++++++++++++++++++++++++++++++++++ mysql-test/t/mysqldump.test | 16 +++++ 3 files changed, 128 insertions(+) diff --git a/client/mysqldump.c b/client/mysqldump.c index c36f9d3e23e..be2abd19822 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -613,6 +613,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } if (end!=compatible_mode_normal_str) end[-1]= 0; + /* + Set charset to the default compiled value if it hasn't + been reset yet by --default-character-set=xxx. + */ + if (default_charset == (char*) MYSQL_UNIVERSAL_CLIENT_CHARSET) + default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; break; } case (int) OPT_MYSQL_PROTOCOL: diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 239418733ba..57e04d38fc1 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -374,3 +374,109 @@ USE `mysqldump_test_db`; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; drop database mysqldump_test_db; +CREATE TABLE t1 (a CHAR(10)); +INSERT INTO t1 VALUES (_latin1 'ÄÖÜß'); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` char(10) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('ÄÖÜß'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` char(10) default NULL +) TYPE=MyISAM; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('ÄÖÜß'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` char(10) default NULL +) TYPE=MyISAM; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('Ž™šá'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` char(10) default NULL +) TYPE=MyISAM; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('Ž™šá'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; + +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO,MYSQL323" */; +DROP TABLE IF EXISTS `t1`; +CREATE TABLE `t1` ( + `a` char(10) default NULL +) TYPE=MyISAM; + + +/*!40000 ALTER TABLE `t1` DISABLE KEYS */; +LOCK TABLES `t1` WRITE; +INSERT INTO `t1` VALUES ('ÄÖÜß'); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t1` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; + +DROP TABLE t1; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 295658f21a8..7a6c1564e94 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -137,3 +137,19 @@ drop table t1; create database mysqldump_test_db character set latin2 collate latin2_bin; --exec $MYSQL_DUMP --skip-comments --databases mysqldump_test_db; drop database mysqldump_test_db; + +# +# Bug #7020 +# Check that we don't dump in UTF8 in compatible mode by default, +# but use the default compiled values, or the values given in +# --default-character-set=xxx. However, we should dump in UTF8 +# if it is explicitely set. + +CREATE TABLE t1 (a CHAR(10)); +INSERT INTO t1 VALUES (_latin1 'ÄÖÜß'); +--exec $MYSQL_DUMP --skip-comments test t1 +--exec $MYSQL_DUMP --skip-comments --compatible=mysql323 test t1 +--exec $MYSQL_DUMP --skip-comments --compatible=mysql323 --default-character-set=cp850 test t1 +--exec $MYSQL_DUMP --skip-comments --default-character-set=cp850 --compatible=mysql323 test t1 +--exec $MYSQL_DUMP --skip-comments --default-character-set=utf8 --compatible=mysql323 test t1 +DROP TABLE t1; From f57153fe8176df061c142c84e7eec2990d66e85e Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Wed, 22 Dec 2004 13:38:15 +0100 Subject: [PATCH 18/54] ndb: bug#7340 fix --- mysql-test/r/ndb_blob.result | 18 ++++++++++++++++++ mysql-test/t/ndb_blob.test | 14 ++++++++++++++ ndb/src/ndbapi/NdbConnection.cpp | 7 +++---- ndb/src/ndbapi/NdbOperationDefine.cpp | 4 +++- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/ndb_blob.result b/mysql-test/r/ndb_blob.result index 156c2d570a4..6f25ec95c80 100644 --- a/mysql-test/r/ndb_blob.result +++ b/mysql-test/r/ndb_blob.result @@ -467,3 +467,21 @@ a b 1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 2 BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB drop table t1; +create table t1 ( +id int(11) unsigned primary key NOT NULL auto_increment, +msg text NOT NULL +) engine=ndbcluster default charset=utf8; +insert into t1 (msg) values( +'Tries to validate (8 byte length + inline bytes) as UTF8 :( +Fast fix: removed validation for Text. It is not yet indexable +so bad data will not crash kernel. +Proper fix: Set inline bytes to multiple of mbmaxlen and +validate it (after the 8 byte length).'); +select * from t1; +id msg +1 Tries to validate (8 byte length + inline bytes) as UTF8 :( +Fast fix: removed validation for Text. It is not yet indexable +so bad data will not crash kernel. +Proper fix: Set inline bytes to multiple of mbmaxlen and +validate it (after the 8 byte length). +drop table t1; diff --git a/mysql-test/t/ndb_blob.test b/mysql-test/t/ndb_blob.test index 06ecbc66d97..96e38bfb58e 100644 --- a/mysql-test/t/ndb_blob.test +++ b/mysql-test/t/ndb_blob.test @@ -389,3 +389,17 @@ set autocommit=1; alter table t1 engine=myisam; select * from t1 order by a; drop table t1; + +# -- bug #7340 -- +create table t1 ( + id int(11) unsigned primary key NOT NULL auto_increment, + msg text NOT NULL +) engine=ndbcluster default charset=utf8; +insert into t1 (msg) values( +'Tries to validate (8 byte length + inline bytes) as UTF8 :( +Fast fix: removed validation for Text. It is not yet indexable +so bad data will not crash kernel. +Proper fix: Set inline bytes to multiple of mbmaxlen and +validate it (after the 8 byte length).'); +select * from t1; +drop table t1; diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index f4bb000300a..83715dbfca0 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -361,11 +361,10 @@ NdbConnection::execute(ExecType aTypeOfExec, if (executeNoBlobs(tExecType, abortOption, forceSend) == -1) ret = -1; -#ifndef VM_TRACE - // can happen in complex abort cases - theFirstOpInList = theLastOpInList = NULL; -#else +#ifdef ndb_api_crash_on_complex_blob_abort assert(theFirstOpInList == NULL && theLastOpInList == NULL); +#else + theFirstOpInList = theLastOpInList = NULL; #endif { diff --git a/ndb/src/ndbapi/NdbOperationDefine.cpp b/ndb/src/ndbapi/NdbOperationDefine.cpp index 35abb15b00d..c4aaffb3119 100644 --- a/ndb/src/ndbapi/NdbOperationDefine.cpp +++ b/ndb/src/ndbapi/NdbOperationDefine.cpp @@ -528,7 +528,9 @@ NdbOperation::setValue( const NdbColumnImpl* tAttrInfo, CHARSET_INFO* cs = tAttrInfo->m_cs; // invalid data can crash kernel if (cs != NULL && - (*cs->cset->well_formed_len)(cs, + // fast fix bug#7340 + tAttrInfo->m_type != NdbDictionary::Column::Text && + (*cs->cset->well_formed_len)(cs, aValue, aValue + sizeInBytes, sizeInBytes) != sizeInBytes) { From 8aa60fdd011fdae528991f318e26b2d5ecc30b3e Mon Sep 17 00:00:00 2001 From: "joreland@mysql.com" <> Date: Wed, 22 Dec 2004 14:58:57 +0100 Subject: [PATCH 19/54] ndb - Fix bug in backward compatility code (for our test programs) --- ndb/src/ndbapi/Ndbinit.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index e1af7bd4cc5..a11dd842495 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -204,14 +204,6 @@ Ndb::~Ndb() TransporterFacade::instance()->close(theNdbBlockNumber, theFirstTransId); } - if (global_ndb_cluster_connection != 0) { - theNoOfNdbObjects--; - if(theNoOfNdbObjects == 0){ - delete global_ndb_cluster_connection; - global_ndb_cluster_connection= 0; - } - }//if - // if (theSchemaConToNdbList != NULL) // closeSchemaTransaction(theSchemaConToNdbList); while ( theConIdleList != NULL ) @@ -249,6 +241,19 @@ Ndb::~Ndb() delete theImpl; + /** + * This needs to be put after delete theImpl + * as TransporterFacade::instance is delete by global_ndb_cluster_connection + * and used by theImpl + */ + if (global_ndb_cluster_connection != 0) { + theNoOfNdbObjects--; + if(theNoOfNdbObjects == 0){ + delete global_ndb_cluster_connection; + global_ndb_cluster_connection= 0; + } + }//if + /** * This sleep is to make sure that the transporter * send thread will come in and send any From 542820d3f8c15b1526dce4272a5b4d4598af6c77 Mon Sep 17 00:00:00 2001 From: "pekka@mysql.com" <> Date: Wed, 22 Dec 2004 15:08:22 +0100 Subject: [PATCH 20/54] ndb: use Ndb_cluster_connection in test* --- ndb/test/ndbapi/testBlobs.cpp | 10 +++++++--- ndb/test/ndbapi/testOIBasic.cpp | 11 ++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp index b2cc5636e45..7b30777456f 100644 --- a/ndb/test/ndbapi/testBlobs.cpp +++ b/ndb/test/ndbapi/testBlobs.cpp @@ -154,6 +154,7 @@ testcase(char x) (g_opt.m_skip == 0 || strchr(g_opt.m_skip, x) == 0); } +static Ndb_cluster_connection* g_ncc = 0; static Ndb* g_ndb = 0; static NdbDictionary::Dictionary* g_dic = 0; static NdbConnection* g_con = 0; @@ -1259,7 +1260,7 @@ deleteScan(bool idx) static int testmain() { - g_ndb = new Ndb("TEST_DB"); + g_ndb = new Ndb(g_ncc, "TEST_DB"); CHK(g_ndb->init() == 0); CHK(g_ndb->waitUntilReady() == 0); g_dic = g_ndb->getDictionary(); @@ -1448,7 +1449,7 @@ testperf() if (! testcase('p')) return 0; DBG("=== perf test ==="); - g_ndb = new Ndb("TEST_DB"); + g_ndb = new Ndb(g_ncc, "TEST_DB"); CHK(g_ndb->init() == 0); CHK(g_ndb->waitUntilReady() == 0); g_dic = g_ndb->getDictionary(); @@ -1860,10 +1861,13 @@ NDB_COMMAND(testOdbcDriver, "testBlobs", "testBlobs", "testBlobs", 65535) strcat(b, "r"); g_opt.m_skip = strdup(b); } - if (testmain() == -1 || testperf() == -1) { + g_ncc = new Ndb_cluster_connection(); + if (g_ncc->connect(30) != 0 || testmain() == -1 || testperf() == -1) { ndbout << "line " << __LINE__ << " FAIL loop=" << g_loop << endl; return NDBT_ProgramExit(NDBT_FAILED); } + delete g_ncc; + g_ncc = 0; return NDBT_ProgramExit(NDBT_OK); } diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp index 41f0686e63b..e6d3844d18e 100644 --- a/ndb/test/ndbapi/testOIBasic.cpp +++ b/ndb/test/ndbapi/testOIBasic.cpp @@ -59,7 +59,7 @@ struct Opt { unsigned m_subloop; const char* m_table; unsigned m_threads; - unsigned m_v; + int m_v; Opt() : m_batch(32), m_bound("01234"), @@ -672,6 +672,8 @@ tabcount = sizeof(tablist) / sizeof(tablist[0]); // connections +static Ndb_cluster_connection* g_ncc = 0; + struct Con { Ndb* m_ndb; NdbDictionary::Dictionary* m_dic; @@ -720,7 +722,7 @@ int Con::connect() { assert(m_ndb == 0); - m_ndb = new Ndb("TEST_DB"); + m_ndb = new Ndb(g_ncc, "TEST_DB"); CHKCON(m_ndb->init() == 0, *this); CHKCON(m_ndb->waitUntilReady(30) == 0, *this); m_tx = 0, m_op = 0; @@ -3514,8 +3516,11 @@ NDB_COMMAND(testOIBasic, "testOIBasic", "testOIBasic", "testOIBasic", 65535) } { Par par(g_opt); - if (runtest(par) < 0) + g_ncc = new Ndb_cluster_connection(); + if (g_ncc->connect(30) != 0 || runtest(par) < 0) goto failed; + delete g_ncc; + g_ncc = 0; } // always exit with NDBT code ok: From 78260fc1c81b19cbb8ae0b2cf15e19e51a5dd7eb Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Wed, 22 Dec 2004 18:56:57 +0400 Subject: [PATCH 21/54] Bugs#7278: Don't open a table if it contains columns with non-supported charsets --- sql/table.cc | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index 7adca2a5ab0..5ede9c1e43d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -24,7 +24,8 @@ /* Functions defined in this file */ -static void frm_error(int error,TABLE *form,const char *name,int errortype); +static void frm_error(int error,TABLE *form,const char *name, + int errortype, int errarg); static void fix_type_pointers(const char ***array, TYPELIB *point_to_type, uint types, char **names); static uint find_field(TABLE *form,uint start,uint length); @@ -57,6 +58,7 @@ static byte* get_field_name(Field **buff,uint *length, 2 Error (see frm_error) 3 Wrong data in .frm file 4 Error (see frm_error) + 5 Error (see frm_error: charset unavailable) */ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, @@ -64,7 +66,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, { reg1 uint i; reg2 uchar *strpos; - int j,error; + int j,error, errarg= 0; uint rec_buff_length,n_length,int_length,records,key_parts,keys, interval_count,interval_parts,read_length,db_create_options; uint key_info_length, com_length; @@ -436,10 +438,14 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, } else { - if (!strpos[14]) - charset= &my_charset_bin; - else if (!(charset=get_charset((uint) strpos[14], MYF(0)))) - charset= outparam->table_charset; + if (!strpos[14]) + charset= &my_charset_bin; + else if (!(charset=get_charset((uint) strpos[14], MYF(0)))) + { + error= 5; // Unknown or unavailable charset + errarg= (int) strpos[14]; + goto err_not_open; + } } if (!comment_length) { @@ -781,7 +787,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, err_end: /* Here when no file */ delete crypted; *root_ptr= old_root; - frm_error(error,outparam,name,ME_ERROR+ME_WAITTANG); + frm_error(error, outparam, name, ME_ERROR + ME_WAITTANG, errarg); delete outparam->file; outparam->file=0; // For easyer errorchecking outparam->db_stat=0; @@ -966,7 +972,8 @@ ulong make_new_entry(File file, uchar *fileinfo, TYPELIB *formnames, /* error message when opening a form file */ -static void frm_error(int error, TABLE *form, const char *name, myf errortype) +static void frm_error(int error, TABLE *form, const char *name, + myf errortype, int errarg) { int err_no; char buff[FN_REFLEN]; @@ -997,6 +1004,20 @@ static void frm_error(int error, TABLE *form, const char *name, myf errortype) fn_format(buff,form->real_name,form_dev,datext,2),my_errno); break; } + case 5: + { + const char *csname= get_charset_name((uint) errarg); + char tmp[10]; + if (!csname || csname[0] =='?') + { + my_snprintf(tmp, sizeof(tmp), "#%d", errarg); + csname= tmp; + } + my_printf_error(ER_UNKNOWN_COLLATION, + "Unknown collation '%s' in table '%-.64s' definition", + MYF(0), csname, form->real_name); + break; + } default: /* Better wrong error than none */ case 4: my_error(ER_NOT_FORM_FILE,errortype, From 09dccee098cefdd58016c265c7492961c17814b3 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 22 Dec 2004 16:29:01 +0100 Subject: [PATCH 22/54] changed name of g_eventLogger so it can be used in TransporterRegistry and is the same as in the kernel --- ndb/include/ndbapi/ndb_cluster_connection.hpp | 2 +- .../transporter/TransporterRegistry.hpp | 7 +- ndb/include/util/ndb_opts.h | 2 +- ndb/src/common/transporter/Makefile.am | 2 +- .../common/transporter/SCI_Transporter.cpp | 3 +- .../common/transporter/SHM_Transporter.cpp | 6 +- .../common/transporter/TCP_Transporter.cpp | 3 +- ndb/src/common/transporter/Transporter.cpp | 57 ++++++-- ndb/src/common/transporter/Transporter.hpp | 2 + .../transporter/TransporterRegistry.cpp | 133 ++++++++++++------ ndb/src/kernel/main.cpp | 2 +- ndb/src/mgmsrv/MgmtSrvr.cpp | 37 +++-- ndb/src/mgmsrv/main.cpp | 10 +- ndb/src/ndbapi/ndb_cluster_connection.cpp | 10 +- sql/mysqld.cc | 2 +- 15 files changed, 194 insertions(+), 84 deletions(-) diff --git a/ndb/include/ndbapi/ndb_cluster_connection.hpp b/ndb/include/ndbapi/ndb_cluster_connection.hpp index a98dcaaf5a4..0e559700716 100644 --- a/ndb/include/ndbapi/ndb_cluster_connection.hpp +++ b/ndb/include/ndbapi/ndb_cluster_connection.hpp @@ -82,7 +82,7 @@ public: void set_optimized_node_selection(int val); - int no_db_nodes(); + unsigned no_db_nodes(); #endif private: diff --git a/ndb/include/transporter/TransporterRegistry.hpp b/ndb/include/transporter/TransporterRegistry.hpp index 96da7eef2cb..7487d6b1e80 100644 --- a/ndb/include/transporter/TransporterRegistry.hpp +++ b/ndb/include/transporter/TransporterRegistry.hpp @@ -99,7 +99,12 @@ public: unsigned sizeOfLongSignalMemory = 100); bool init(NodeId localNodeId); - + + /** + * after a connect from client, perform connection using correct transporter + */ + bool connect_server(NDB_SOCKET_TYPE sockfd); + /** * Remove all transporters */ diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index 4bac36f5e5e..dc95149f706 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -34,7 +34,7 @@ OPT_NDB_OPTIMIZED_NODE_SELECTION #define OPT_NDB_CONNECTSTRING 'c' -#ifdef NDB_SHM_TRANSPORTER +#if defined(NDB_SHM_TRANSPORTER) && MYSQL_VERSION_ID >= 50000 #define OPT_NDB_SHM_DEFAULT 1 #else #define OPT_NDB_SHM_DEFAULT 0 diff --git a/ndb/src/common/transporter/Makefile.am b/ndb/src/common/transporter/Makefile.am index d76b1b6048b..b902012e56d 100644 --- a/ndb/src/common/transporter/Makefile.am +++ b/ndb/src/common/transporter/Makefile.am @@ -13,7 +13,7 @@ EXTRA_libtransporter_la_SOURCES = SHM_Transporter.cpp SHM_Transporter.unix.cpp S libtransporter_la_LIBADD = @ndb_transporter_opt_objs@ libtransporter_la_DEPENDENCIES = @ndb_transporter_opt_objs@ -INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel -I$(top_srcdir)/ndb/include/transporter @NDB_SCI_INCLUDES@ +INCLUDES_LOC = -I$(top_srcdir)/ndb/include/mgmapi -I$(top_srcdir)/ndb/include/debugger -I$(top_srcdir)/ndb/include/kernel -I$(top_srcdir)/ndb/include/transporter @NDB_SCI_INCLUDES@ include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_util.mk.am diff --git a/ndb/src/common/transporter/SCI_Transporter.cpp b/ndb/src/common/transporter/SCI_Transporter.cpp index 73fbb064599..e7807c972b1 100644 --- a/ndb/src/common/transporter/SCI_Transporter.cpp +++ b/ndb/src/common/transporter/SCI_Transporter.cpp @@ -44,7 +44,8 @@ SCI_Transporter::SCI_Transporter(TransporterRegistry &t_reg, bool chksm, bool signalId, Uint32 reportFreq) : - Transporter(t_reg, lHostName, rHostName, r_port, _localNodeId, + Transporter(t_reg, tt_SCI_TRANSPORTER, + lHostName, rHostName, r_port, _localNodeId, _remoteNodeId, 0, false, chksm, signalId) { DBUG_ENTER("SCI_Transporter::SCI_Transporter"); diff --git a/ndb/src/common/transporter/SHM_Transporter.cpp b/ndb/src/common/transporter/SHM_Transporter.cpp index e4051519b86..ffb51bf1326 100644 --- a/ndb/src/common/transporter/SHM_Transporter.cpp +++ b/ndb/src/common/transporter/SHM_Transporter.cpp @@ -38,7 +38,8 @@ SHM_Transporter::SHM_Transporter(TransporterRegistry &t_reg, bool signalId, key_t _shmKey, Uint32 _shmSize) : - Transporter(t_reg, lHostName, rHostName, r_port, lNodeId, rNodeId, + Transporter(t_reg, tt_SHM_TRANSPORTER, + lHostName, rHostName, r_port, lNodeId, rNodeId, 0, false, checksum, signalId), shmKey(_shmKey), shmSize(_shmSize) @@ -256,6 +257,9 @@ SHM_Transporter::connect_client_impl(NDB_SOCKET_TYPE sockfd) SocketOutputStream s_output(sockfd); char buf[256]; +#if 1 +#endif + // Wait for server to create and attach if (s_input.gets(buf, 256) == 0) { NDB_CLOSE_SOCKET(sockfd); diff --git a/ndb/src/common/transporter/TCP_Transporter.cpp b/ndb/src/common/transporter/TCP_Transporter.cpp index 524ecd653e0..a629b620157 100644 --- a/ndb/src/common/transporter/TCP_Transporter.cpp +++ b/ndb/src/common/transporter/TCP_Transporter.cpp @@ -72,7 +72,8 @@ TCP_Transporter::TCP_Transporter(TransporterRegistry &t_reg, NodeId rNodeId, bool chksm, bool signalId, Uint32 _reportFreq) : - Transporter(t_reg, lHostName, rHostName, r_port, lNodeId, rNodeId, + Transporter(t_reg, tt_TCP_TRANSPORTER, + lHostName, rHostName, r_port, lNodeId, rNodeId, 0, false, chksm, signalId), m_sendBuffer(sendBufSize) { diff --git a/ndb/src/common/transporter/Transporter.cpp b/ndb/src/common/transporter/Transporter.cpp index 3fe10cb2fe8..b84f8f6fb5e 100644 --- a/ndb/src/common/transporter/Transporter.cpp +++ b/ndb/src/common/transporter/Transporter.cpp @@ -24,7 +24,11 @@ #include #include +#include +extern EventLogger g_eventLogger; + Transporter::Transporter(TransporterRegistry &t_reg, + TransporterType _type, const char *lHostName, const char *rHostName, int r_port, @@ -35,6 +39,7 @@ Transporter::Transporter(TransporterRegistry &t_reg, : m_r_port(r_port), remoteNodeId(rNodeId), localNodeId(lNodeId), isServer(lNodeId < rNodeId), m_packer(_signalId, _checksum), + m_type(_type), m_transporter_registry(t_reg) { DBUG_ENTER("Transporter::Transporter"); @@ -73,7 +78,8 @@ Transporter::Transporter(TransporterRegistry &t_reg, m_socket_client= 0; else m_socket_client= new SocketClient(remoteHostName, r_port, - new SocketAuthSimple("ndbd", "ndbd passwd")); + new SocketAuthSimple("ndbd", + "ndbd passwd")); DBUG_VOID_RETURN; } @@ -84,7 +90,9 @@ Transporter::~Transporter(){ bool Transporter::connect_server(NDB_SOCKET_TYPE sockfd) { + // all initial negotiation is done in TransporterRegistry::connect_server DBUG_ENTER("Transporter::connect_server"); + if(m_connected) { DBUG_RETURN(true); // TODO assert(0); @@ -108,27 +116,60 @@ Transporter::connect_client() { if (sockfd == NDB_INVALID_SOCKET) return false; - // send info about own id + DBUG_ENTER("Transporter::connect_client"); + + // send info about own id + // send info about own transporter type SocketOutputStream s_output(sockfd); - s_output.println("%d", localNodeId); + s_output.println("%d %d", localNodeId, m_type); // get remote id - int nodeId; + int nodeId, remote_transporter_type= -1; SocketInputStream s_input(sockfd); char buf[256]; if (s_input.gets(buf, 256) == 0) { NDB_CLOSE_SOCKET(sockfd); - return false; + DBUG_RETURN(false); } - if (sscanf(buf, "%d", &nodeId) != 1) { + + int r= sscanf(buf, "%d %d", &nodeId, &remote_transporter_type); + switch (r) { + case 2: + break; + case 1: + // we're running version prior to 4.1.9 + // ok, but with no checks on transporter configuration compatability + break; + default: NDB_CLOSE_SOCKET(sockfd); - return false; + DBUG_RETURN(false); } + + DBUG_PRINT("info", ("nodeId=%d remote_transporter_type=%d", + nodeId, remote_transporter_type)); + + if (remote_transporter_type != -1) + { + if (remote_transporter_type != m_type) + { + DBUG_PRINT("error", ("Transporter types mismatch this=%d remote=%d", + m_type, remote_transporter_type)); + NDB_CLOSE_SOCKET(sockfd); + g_eventLogger.error("Incompatible configuration: transporter type " + "mismatch with node %d", nodeId); + DBUG_RETURN(false); + } + } + else if (m_type == tt_SHM_TRANSPORTER) + { + g_eventLogger.warning("Unable to verify transporter compatability with node %d", nodeId); + } + bool res = connect_client_impl(sockfd); if(res){ m_connected = true; m_errorCount = 0; } - return res; + DBUG_RETURN(res); } void diff --git a/ndb/src/common/transporter/Transporter.hpp b/ndb/src/common/transporter/Transporter.hpp index 9a39f8788bc..10303ec71ea 100644 --- a/ndb/src/common/transporter/Transporter.hpp +++ b/ndb/src/common/transporter/Transporter.hpp @@ -71,6 +71,7 @@ public: protected: Transporter(TransporterRegistry &, + TransporterType, const char *lHostName, const char *rHostName, int r_port, @@ -127,6 +128,7 @@ protected: protected: bool m_connected; // Are we connected + TransporterType m_type; TransporterRegistry &m_transporter_registry; void *get_callback_obj() { return m_transporter_registry.callbackObj; }; diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp index 394c7cd490d..2eb81b2b35d 100644 --- a/ndb/src/common/transporter/TransporterRegistry.cpp +++ b/ndb/src/common/transporter/TransporterRegistry.cpp @@ -47,6 +47,9 @@ #include #include +#include +extern EventLogger g_eventLogger; + int g_shm_pid = 0; SocketServer::Session * TransporterService::newSession(NDB_SOCKET_TYPE sockfd) @@ -57,49 +60,10 @@ SocketServer::Session * TransporterService::newSession(NDB_SOCKET_TYPE sockfd) DBUG_RETURN(0); } + if (!m_transporter_registry->connect_server(sockfd)) { - // read node id from client - int nodeId; - SocketInputStream s_input(sockfd); - char buf[256]; - if (s_input.gets(buf, 256) == 0) { - NDB_CLOSE_SOCKET(sockfd); - DBUG_PRINT("error", ("Could not get node id from client")); - DBUG_RETURN(0); - } - if (sscanf(buf, "%d", &nodeId) != 1) { - NDB_CLOSE_SOCKET(sockfd); - DBUG_PRINT("error", ("Error in node id from client")); - DBUG_RETURN(0); - } - - //check that nodeid is valid and that there is an allocated transporter - if ( nodeId < 0 || nodeId >= (int)m_transporter_registry->maxTransporters) { - NDB_CLOSE_SOCKET(sockfd); - DBUG_PRINT("error", ("Node id out of range from client")); - DBUG_RETURN(0); - } - if (m_transporter_registry->theTransporters[nodeId] == 0) { - NDB_CLOSE_SOCKET(sockfd); - DBUG_PRINT("error", ("No transporter for this node id from client")); - DBUG_RETURN(0); - } - - //check that the transporter should be connected - if (m_transporter_registry->performStates[nodeId] != TransporterRegistry::CONNECTING) { - NDB_CLOSE_SOCKET(sockfd); - DBUG_PRINT("error", ("Transporter in wrong state for this node id from client")); - DBUG_RETURN(0); - } - - Transporter *t= m_transporter_registry->theTransporters[nodeId]; - - // send info about own id (just as response to acknowledge connection) - SocketOutputStream s_output(sockfd); - s_output.println("%d", t->getLocalNodeId()); - - // setup transporter (transporter responsible for closing sockfd) - t->connect_server(sockfd); + NDB_CLOSE_SOCKET(sockfd); + DBUG_RETURN(0); } DBUG_RETURN(0); @@ -195,6 +159,91 @@ TransporterRegistry::init(NodeId nodeId) { return true; } +bool +TransporterRegistry::connect_server(NDB_SOCKET_TYPE sockfd) +{ + DBUG_ENTER("TransporterRegistry::connect_server"); + + // read node id from client + // read transporter type + int nodeId, remote_transporter_type= -1; + SocketInputStream s_input(sockfd); + char buf[256]; + if (s_input.gets(buf, 256) == 0) { + DBUG_PRINT("error", ("Could not get node id from client")); + DBUG_RETURN(false); + } + int r= sscanf(buf, "%d %d", &nodeId, &remote_transporter_type); + switch (r) { + case 2: + break; + case 1: + // we're running version prior to 4.1.9 + // ok, but with no checks on transporter configuration compatability + break; + default: + DBUG_PRINT("error", ("Error in node id from client")); + DBUG_RETURN(false); + } + + DBUG_PRINT("info", ("nodeId=%d remote_transporter_type=%d", + nodeId,remote_transporter_type)); + + //check that nodeid is valid and that there is an allocated transporter + if ( nodeId < 0 || nodeId >= (int)maxTransporters) { + DBUG_PRINT("error", ("Node id out of range from client")); + DBUG_RETURN(false); + } + if (theTransporters[nodeId] == 0) { + DBUG_PRINT("error", ("No transporter for this node id from client")); + DBUG_RETURN(false); + } + + //check that the transporter should be connected + if (performStates[nodeId] != TransporterRegistry::CONNECTING) { + DBUG_PRINT("error", ("Transporter in wrong state for this node id from client")); + DBUG_RETURN(false); + } + + Transporter *t= theTransporters[nodeId]; + + // send info about own id (just as response to acknowledge connection) + // send info on own transporter type + SocketOutputStream s_output(sockfd); + s_output.println("%d %d", t->getLocalNodeId(), t->m_type); + + if (remote_transporter_type != -1) + { + if (remote_transporter_type != t->m_type) + { + DBUG_PRINT("error", ("Transporter types mismatch this=%d remote=%d", + t->m_type, remote_transporter_type)); + g_eventLogger.error("Incompatible configuration: Transporter type " + "mismatch with node %d", nodeId); + + // wait for socket close for 1 second to let message arrive at client + { + fd_set a_set; + FD_ZERO(&a_set); + FD_SET(sockfd, &a_set); + struct timeval timeout; + timeout.tv_sec = 1; timeout.tv_usec = 0; + select(sockfd+1, &a_set, 0, 0, &timeout); + } + DBUG_RETURN(false); + } + } + else if (t->m_type == tt_SHM_TRANSPORTER) + { + g_eventLogger.warning("Unable to verify transporter compatability with node %d", nodeId); + } + + // setup transporter (transporter responsible for closing sockfd) + t->connect_server(sockfd); + + DBUG_RETURN(true); +} + bool TransporterRegistry::createTransporter(TCP_TransporterConfiguration *config) { #ifdef NDB_TCP_TRANSPORTER diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 44fe1725c9e..448bdd9a1fa 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -58,7 +58,7 @@ int main(int argc, char** argv) // Print to stdout/console g_eventLogger.createConsoleHandler(); g_eventLogger.setCategory("NDB"); - g_eventLogger.enable(Logger::LL_INFO, Logger::LL_ALERT); // Log INFO to ALERT + g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR); globalEmulatorData.create(); diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 3fcde997cb0..f698099141a 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -133,8 +133,7 @@ MgmtSrvr::signalRecvThreadRun() } } - -EventLogger g_EventLogger; +extern EventLogger g_eventLogger; static NdbOut& operator<<(NdbOut& out, const LogLevel & ll) @@ -200,7 +199,7 @@ MgmtSrvr::logLevelThreadRun() void MgmtSrvr::startEventLog() { - g_EventLogger.setCategory("MgmSrvr"); + g_eventLogger.setCategory("MgmSrvr"); ndb_mgm_configuration_iterator * iter = ndb_mgm_create_configuration_iterator ((ndb_mgm_configuration*)_config->m_configValues, CFG_SECTION_NODE); @@ -226,7 +225,7 @@ MgmtSrvr::startEventLog() logdest.assfmt("FILE:filename=%s,maxsize=1000000,maxfiles=6", clusterLog); } - if(!g_EventLogger.addHandler(logdest)) { + if(!g_eventLogger.addHandler(logdest)) { ndbout << "Warning: could not add log destination \"" << logdest.c_str() << "\"" << endl; } @@ -250,21 +249,21 @@ MgmtSrvr::setEventLogFilter(int severity, int enable) { Logger::LoggerLevel level = (Logger::LoggerLevel)severity; if (enable > 0) { - g_EventLogger.enable(level); + g_eventLogger.enable(level); } else if (enable == 0) { - g_EventLogger.disable(level); - } else if (g_EventLogger.isEnable(level)) { - g_EventLogger.disable(level); + g_eventLogger.disable(level); + } else if (g_eventLogger.isEnable(level)) { + g_eventLogger.disable(level); } else { - g_EventLogger.enable(level); + g_eventLogger.enable(level); } - return g_EventLogger.isEnable(level); + return g_eventLogger.isEnable(level); } bool MgmtSrvr::isEventLogFilterEnabled(int severity) { - return g_EventLogger.isEnable((Logger::LoggerLevel)severity); + return g_eventLogger.isEnable((Logger::LoggerLevel)severity); } static ErrorItem errorTable[] = @@ -1990,7 +1989,7 @@ MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal) } default: - g_EventLogger.error("Unknown signal received. SignalNumber: " + g_eventLogger.error("Unknown signal received. SignalNumber: " "%i from (%d, %x)", gsn, refToNode(signal->theSendersBlockRef), @@ -2066,7 +2065,7 @@ MgmtSrvr::handleStopReply(NodeId nodeId, Uint32 errCode) error: if(errCode != 0){ - g_EventLogger.error("Unexpected signal received. SignalNumber: %i from %d", + g_eventLogger.error("Unexpected signal received. SignalNumber: %i from %d", GSN_STOP_REF, nodeId); } } @@ -2286,7 +2285,7 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, m_reserved_nodes.set(id_found); char tmp_str[128]; m_reserved_nodes.getText(tmp_str); - g_EventLogger.info("Mgmt server state: nodeid %d reserved for ip %s, m_reserved_nodes %s.", + g_eventLogger.info("Mgmt server state: nodeid %d reserved for ip %s, m_reserved_nodes %s.", id_found, get_connect_address(id_found), tmp_str); DBUG_RETURN(true); } @@ -2346,7 +2345,7 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, *nodeId); } - g_EventLogger.warning("Allocate nodeid (%d) failed. Connection from ip %s. " + g_eventLogger.warning("Allocate nodeid (%d) failed. Connection from ip %s. " "Returned error string \"%s\"", *nodeId, client_addr != 0 ? inet_ntoa(((struct sockaddr_in *)(client_addr))->sin_addr) : "", @@ -2369,10 +2368,10 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, } } if (tmp_connected.length() > 0) - g_EventLogger.info("Mgmt server state: node id's %s connected but not reserved", + g_eventLogger.info("Mgmt server state: node id's %s connected but not reserved", tmp_connected.c_str()); if (tmp_not_connected.length() > 0) - g_EventLogger.info("Mgmt server state: node id's %s not connected but reserved", + g_eventLogger.info("Mgmt server state: node id's %s not connected but reserved", tmp_not_connected.c_str()); } DBUG_RETURN(false); @@ -2404,7 +2403,7 @@ MgmtSrvr::eventReport(NodeId nodeId, const Uint32 * theData) EventReport::EventType type = eventReport->getEventType(); // Log event - g_EventLogger.log(type, theData, nodeId, + g_eventLogger.log(type, theData, nodeId, &m_event_listner[0].m_logLevel); m_event_listner.log(type, theData, nodeId); } @@ -2647,7 +2646,7 @@ MgmtSrvr::Allocated_resources::~Allocated_resources() char tmp_str[128]; m_mgmsrv.m_reserved_nodes.getText(tmp_str); - g_EventLogger.info("Mgmt server state: nodeid %d freed, m_reserved_nodes %s.", + g_eventLogger.info("Mgmt server state: nodeid %d freed, m_reserved_nodes %s.", get_nodeid(), tmp_str); } } diff --git a/ndb/src/mgmsrv/main.cpp b/ndb/src/mgmsrv/main.cpp index 015e2de022d..ce79ccb732b 100644 --- a/ndb/src/mgmsrv/main.cpp +++ b/ndb/src/mgmsrv/main.cpp @@ -86,7 +86,7 @@ static MgmGlobals glob; * Global variables */ bool g_StopServer; -extern EventLogger g_EventLogger; +extern EventLogger g_eventLogger; extern int global_mgmt_server_check; @@ -303,12 +303,12 @@ int main(int argc, char** argv) BaseString::snprintf(msg, sizeof(msg), "NDB Cluster Management Server. %s", NDB_VERSION_STRING); ndbout_c(msg); - g_EventLogger.info(msg); + g_eventLogger.info(msg); BaseString::snprintf(msg, 256, "Id: %d, Command port: %d", glob.localNodeId, glob.port); ndbout_c(msg); - g_EventLogger.info(msg); + g_eventLogger.info(msg); g_StopServer = false; glob.socketServer->startServer(); @@ -324,10 +324,10 @@ int main(int argc, char** argv) NdbSleep_MilliSleep(500); } - g_EventLogger.info("Shutting down server..."); + g_eventLogger.info("Shutting down server..."); glob.socketServer->stopServer(); glob.socketServer->stopSessions(); - g_EventLogger.info("Shutdown complete"); + g_eventLogger.info("Shutdown complete"); return 0; error_end: return 1; diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp index f754ec8b40a..5df707e211d 100644 --- a/ndb/src/ndbapi/ndb_cluster_connection.cpp +++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp @@ -31,6 +31,9 @@ #include #include +#include +EventLogger g_eventLogger; + static int g_run_connect_thread= 0; #include @@ -174,7 +177,7 @@ Ndb_cluster_connection_impl::get_next_node(Ndb_cluster_connection_node_iter &ite return node.id; } -int +unsigned Ndb_cluster_connection::no_db_nodes() { return m_impl.m_all_nodes.size(); @@ -248,6 +251,11 @@ Ndb_cluster_connection_impl::Ndb_cluster_connection_impl(const char * { DBUG_ENTER("Ndb_cluster_connection"); DBUG_PRINT("enter",("Ndb_cluster_connection this=0x%x", this)); + + g_eventLogger.createConsoleHandler(); + g_eventLogger.setCategory("NdbApi"); + g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR); + m_transporter_facade= TransporterFacade::theFacadeInstance= new TransporterFacade(); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5cd85113641..e6e079d3deb 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -53,7 +53,7 @@ #endif #ifdef HAVE_NDBCLUSTER_DB #define OPT_NDBCLUSTER_DEFAULT 0 -#ifdef NDB_SHM_TRANSPORTER +#if defined(NDB_SHM_TRANSPORTER) && MYSQL_VERSION_ID >= 50000 #define OPT_NDB_SHM_DEFAULT 1 #else #define OPT_NDB_SHM_DEFAULT 0 From 7b9fd879f6810bb114b1aa97f3d1a5d442d1c622 Mon Sep 17 00:00:00 2001 From: "dlenev@brandersnatch.localdomain" <> Date: Wed, 22 Dec 2004 18:58:25 +0300 Subject: [PATCH 23/54] Fix for bug #7458 "Microseconds are gobbled from the string result of STR_TO_DATE() function if there is another format specifier after %f in format string". Also small cleanup of STR_TO_DATE() implementation. (After review version.) --- mysql-test/r/date_formats.result | 3 ++ mysql-test/t/date_formats.test | 2 ++ sql/item_timefunc.cc | 56 +++++++++++++++++++++----------- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result index 758a83defed..2db014c4a52 100644 --- a/mysql-test/r/date_formats.result +++ b/mysql-test/r/date_formats.result @@ -296,6 +296,9 @@ Tuesday 52 2001 %W %V %X 00:00:00 15-01-2001 %d-%m-%Y %H:%i:%S 00:00:00 15-01-20 %d-%m-%y 00:00:00 15-2001-1 %d-%Y-%c 00:00:00 +select concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d')); +concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d')) +2003-01-02 08:11:02.123456 truncate table t1; insert into t1 values ('2003-01-02 10:11:12 PM', '%Y-%m-%d %H:%i:%S %p'), diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test index c369a9c85d5..800e5880b09 100644 --- a/mysql-test/t/date_formats.test +++ b/mysql-test/t/date_formats.test @@ -166,6 +166,8 @@ select date,format,cast(str_to_date(date, format) as datetime) as datetime from select date,format,DATE(str_to_date(date, format)) as date2 from t1; select date,format,TIME(str_to_date(date, format)) as time from t1; select date,format,concat(TIME(str_to_date(date, format))) as time2 from t1; +# Test small bug in %f handling +select concat('',str_to_date('8:11:2.123456 03-01-02','%H:%i:%S.%f %y-%m-%d')); # Test wrong dates or converion specifiers diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 354c8b5c50c..84a9e01ed2a 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -149,6 +149,9 @@ static DATE_TIME_FORMAT time_24hrs_format= {{0}, '\0', 0, conversion specifiers that can be used in such sub-patterns is limited. Also most of checks are skipped in this case. + If one adds new format specifiers to this function he should also + consider adding them to get_date_time_result_type() function. + RETURN 0 ok 1 error @@ -2595,25 +2598,31 @@ void Item_func_get_format::print(String *str) /* - check_result_type(s, l) returns DATE/TIME type - according to format string + Get type of datetime value (DATE/TIME/...) which will be produced + according to format string. - s: DATE/TIME format string - l: length of s - Result: date_time_format_types value: - DATE_TIME_MICROSECOND, DATE_TIME, - TIME_MICROSECOND, TIME_ONLY + SYNOPSIS + get_date_time_result_type() + format - format string + length - length of format string - We don't process day format's characters('D', 'd', 'e') - because day may be a member of all date/time types. - If only day format's character and no time part present - the result type is MYSQL_TYPE_DATE + NOTE + We don't process day format's characters('D', 'd', 'e') because day + may be a member of all date/time types. + + Format specifiers supported by this function should be in sync with + specifiers supported by extract_date_time() function. + + RETURN VALUE + One of date_time_format_types values: + DATE_TIME_MICROSECOND, DATE_TIME, DATE_ONLY, TIME_MICROSECOND, TIME_ONLY */ -date_time_format_types check_result_type(const char *format, uint length) +static date_time_format_types +get_date_time_result_type(const char *format, uint length) { const char *time_part_frms= "HISThiklrs"; - const char *date_part_frms= "MUYWabcjmuyw"; + const char *date_part_frms= "MVUXYWabcjmvuxyw"; bool date_part_used= 0, time_part_used= 0, frac_second_used= 0; const char *val= format; @@ -2624,22 +2633,30 @@ date_time_format_types check_result_type(const char *format, uint length) if (*val == '%' && val+1 != end) { val++; - if ((frac_second_used= (*val == 'f')) || - (!time_part_used && strchr(time_part_frms, *val))) + if (*val == 'f') + frac_second_used= time_part_used= 1; + else if (!time_part_used && strchr(time_part_frms, *val)) time_part_used= 1; else if (!date_part_used && strchr(date_part_frms, *val)) date_part_used= 1; - if (time_part_used && date_part_used && frac_second_used) + if (date_part_used && frac_second_used) + { + /* + frac_second_used implies time_part_used, and thus we already + have all types of date-time components and can end our search. + */ return DATE_TIME_MICROSECOND; + } } } + /* We don't have all three types of date-time components */ + if (frac_second_used) + return TIME_MICROSECOND; if (time_part_used) { if (date_part_used) return DATE_TIME; - if (frac_second_used) - return TIME_MICROSECOND; return TIME_ONLY; } return DATE_ONLY; @@ -2670,7 +2687,8 @@ void Item_func_str_to_date::fix_length_and_dec() if ((const_item= args[1]->const_item())) { format= args[1]->val_str(&format_str); - cached_format_type= check_result_type(format->ptr(), format->length()); + cached_format_type= get_date_time_result_type(format->ptr(), + format->length()); switch (cached_format_type) { case DATE_ONLY: cached_timestamp_type= MYSQL_TIMESTAMP_DATE; From e9c0a17cf27dc451e8a154cb64fe8734ad56dc7d Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 22 Dec 2004 18:27:07 +0100 Subject: [PATCH 24/54] added handling of repeated messages --- ndb/include/logger/LogHandler.hpp | 10 ++++ ndb/src/common/logger/LogHandler.cpp | 59 ++++++++++++++++++++-- ndb/src/common/transporter/Transporter.hpp | 2 +- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/ndb/include/logger/LogHandler.hpp b/ndb/include/logger/LogHandler.hpp index ca4bd4c0668..57169e7ae6a 100644 --- a/ndb/include/logger/LogHandler.hpp +++ b/ndb/include/logger/LogHandler.hpp @@ -192,6 +192,16 @@ private: const char* m_pDateTimeFormat; int m_errorCode; + + // for handling repeated messages + unsigned m_count_repeated_messages; + unsigned m_max_repeat_frequency; + time_t m_last_log_time; + char m_last_category_buf[16]; + char m_last_message_buf[256]; + char *m_last_category; + Logger::LoggerLevel m_last_level; + char *m_last_message; }; #endif diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp index a76cb622878..5cc8de21f67 100644 --- a/ndb/src/common/logger/LogHandler.cpp +++ b/ndb/src/common/logger/LogHandler.cpp @@ -23,22 +23,71 @@ // LogHandler::LogHandler() : m_pDateTimeFormat("%d-%.2d-%.2d %.2d:%.2d:%.2d"), - m_errorCode(0) -{ + m_errorCode(0), + m_last_category(m_last_category_buf), + m_last_message(m_last_message_buf) +{ + m_max_repeat_frequency= 3; // repeat messages maximum every 3 seconds + m_last_category_buf[0]= 0; + m_last_message_buf[0]= 0; } LogHandler::~LogHandler() { + if (m_last_message != m_last_message_buf) + free(m_last_message); + if (m_last_category != m_last_category_buf) + free(m_last_category); } void LogHandler::append(const char* pCategory, Logger::LoggerLevel level, const char* pMsg) -{ +{ + time_t now; + now= ::time((time_t*)NULL); + + if (level != m_last_level || + strcmp(pCategory, m_last_category) || + strcmp(pMsg, m_last_message)) + { + if (m_last_message != m_last_message_buf) + free(m_last_message); + if (m_last_category != m_last_category_buf) + free(m_last_category); + + m_count_repeated_messages= 0; + + m_last_level= level; + BaseString::snprintf(m_last_category_buf, sizeof(m_last_category_buf), "%s", pCategory); + BaseString::snprintf(m_last_message_buf, sizeof(m_last_message_buf), "%s", pMsg); + // ToDo: handle too long messages correctly + // right now all that will happen is that too long messages + // will be repeated unneccesarily + } + else // repeated message + { + if (now < m_last_log_time+m_max_repeat_frequency) + { + m_count_repeated_messages++; + return; + } + } + writeHeader(pCategory, level); - writeMessage(pMsg); + if (m_count_repeated_messages == 0) + writeMessage(pMsg); + else + { + BaseString str(pMsg); + str.appfmt(" - repeated %d times", m_count_repeated_messages); + writeMessage(str.c_str()); + m_count_repeated_messages= 0; + } writeFooter(); -} + + m_last_log_time= now; +} const char* LogHandler::getDefaultHeader(char* pStr, const char* pCategory, diff --git a/ndb/src/common/transporter/Transporter.hpp b/ndb/src/common/transporter/Transporter.hpp index 10303ec71ea..baff6d53dd8 100644 --- a/ndb/src/common/transporter/Transporter.hpp +++ b/ndb/src/common/transporter/Transporter.hpp @@ -151,7 +151,7 @@ Transporter::getRemoteNodeId() const { inline NodeId Transporter::getLocalNodeId() const { - return remoteNodeId; + return localNodeId; } inline From e409ebf143c754b0a846e776854def244186943c Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Wed, 22 Dec 2004 21:31:17 +0200 Subject: [PATCH 25/54] A fix for the bug #7495 --- mysql-test/r/func_str.result | 12 ++++++++++++ mysql-test/t/func_str.test | 12 ++++++++++++ sql/item_strfunc.cc | 4 ++-- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index d38a2edfa1a..2ca90653fec 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -291,3 +291,15 @@ trim(trailing 'foo' from 'foo') select trim(leading 'foo' from 'foo'); trim(leading 'foo' from 'foo') +create table t1 (a varchar(80), b varchar(80)); +insert into t1 values(NULL,"12345"); +insert into t1 values(NULL,"chm"); +select quote(ltrim(concat(' ',t1.b))) from t1; +quote(ltrim(concat(' ',t1.b))) +'12345' +'chm' +select quote(trim(concat(' ',t1.b))) from t1; +quote(trim(concat(' ',t1.b))) +'12345' +'chm' +drop table t1; diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 1ae4db3a42a..421512c4dc4 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -185,3 +185,15 @@ drop table t1; select trim(trailing 'foo' from 'foo'); select trim(leading 'foo' from 'foo'); + +# +# crashing bug with QUOTE() and LTRIM() or TRIM() fixed +# Bug #7495 +# + +create table t1 (a varchar(80), b varchar(80)); +insert into t1 values(NULL,"12345"); +insert into t1 values(NULL,"chm"); +select quote(ltrim(concat(' ',t1.b))) from t1; +select quote(trim(concat(' ',t1.b))) from t1; +drop table t1; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 53a9d3fe219..61477753594 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1141,7 +1141,7 @@ String *Item_func_ltrim::val_str(String *str) } if (ptr == res->ptr()) return res; - tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr)); + tmp_value.copy(res->ptr() + (ptr - res->ptr()), (uint32) (end - ptr)); return &tmp_value; } @@ -1266,7 +1266,7 @@ String *Item_func_trim::val_str(String *str) } if (ptr == res->ptr() && end == ptr+res->length()) return res; - tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr)); + tmp_value.copy(res->ptr() + (ptr - res->ptr()), (uint32) (end - ptr)); return &tmp_value; } From 263832da6547abda093e49fbf2c773b31722adb1 Mon Sep 17 00:00:00 2001 From: "tomas@poseidon.ndb.mysql.com" <> Date: Wed, 22 Dec 2004 22:47:56 +0100 Subject: [PATCH 26/54] fixed so that last repeats are printed first with correct time if another message comes decided for fixed size buffers in LogHandler repeated messages --- mysql-test/ndb/basic.result | 8 ++--- ndb/include/logger/LogHandler.hpp | 29 ++++++++-------- ndb/include/logger/Logger.hpp | 2 ++ ndb/src/common/logger/LogHandler.cpp | 51 +++++++++++++--------------- ndb/src/common/logger/Logger.cpp | 4 +-- 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/mysql-test/ndb/basic.result b/mysql-test/ndb/basic.result index 7049c02f304..5ebd20a7f83 100644 --- a/mysql-test/ndb/basic.result +++ b/mysql-test/ndb/basic.result @@ -31,12 +31,12 @@ QUIT Quit management client = ALL | Any database node id Connected to Management Server at: localhost:1186 -Node 1: started (Version 4.1.8) -Node 2: started (Version 4.1.8) +Node 1: started (Version 4.1.9) +Node 2: started (Version 4.1.9) -Node 1: started (Version 4.1.8) +Node 1: started (Version 4.1.9) -Node 2: started (Version 4.1.8) +Node 2: started (Version 4.1.9) Executing CLUSTERLOG on node 1 OK! Executing CLUSTERLOG on node 2 OK! diff --git a/ndb/include/logger/LogHandler.hpp b/ndb/include/logger/LogHandler.hpp index 57169e7ae6a..7df6ad864e5 100644 --- a/ndb/include/logger/LogHandler.hpp +++ b/ndb/include/logger/LogHandler.hpp @@ -19,7 +19,6 @@ #include "Logger.hpp" - /** * This class is the base class for all log handlers. A log handler is * responsible for formatting and writing log messages to a specific output. @@ -68,7 +67,8 @@ public: /** * Append a log message to the output stream/file whatever. * append() will call writeHeader(), writeMessage() and writeFooter() for - * a child class and in that order. + * a child class and in that order. Append checks for repeated messages. + * append_impl() does not check for repeats. * * @param pCategory the category/name to tag the log entry with. * @param level the log level. @@ -76,6 +76,8 @@ public: */ void append(const char* pCategory, Logger::LoggerLevel level, const char* pMsg); + void append_impl(const char* pCategory, Logger::LoggerLevel level, + const char* pMsg); /** * Returns a default formatted header. It currently has the @@ -111,14 +113,6 @@ public: */ void setDateTimeFormat(const char* pFormat); - /** - * Returns a string date and time string. - * - * @param pStr a string. - * @return a string with date and time. - */ - char* getTimeAsString(char* pStr) const; - /** * Returns the error code. */ @@ -185,6 +179,15 @@ protected: virtual void writeFooter() = 0; private: + /** + * Returns a string date and time string. + * @note does not update time, uses m_now as time + * @param pStr a string. + * @return a string with date and time. + */ + char* getTimeAsString(char* pStr) const; + time_t m_now; + /** Prohibit */ LogHandler(const LogHandler&); LogHandler* operator = (const LogHandler&); @@ -197,11 +200,9 @@ private: unsigned m_count_repeated_messages; unsigned m_max_repeat_frequency; time_t m_last_log_time; - char m_last_category_buf[16]; - char m_last_message_buf[256]; - char *m_last_category; + char m_last_category[MAX_HEADER_LENGTH]; + char m_last_message[MAX_LOG_MESSAGE_SIZE]; Logger::LoggerLevel m_last_level; - char *m_last_message; }; #endif diff --git a/ndb/include/logger/Logger.hpp b/ndb/include/logger/Logger.hpp index f12297023b7..ee762098fb6 100644 --- a/ndb/include/logger/Logger.hpp +++ b/ndb/include/logger/Logger.hpp @@ -20,6 +20,8 @@ #include #include +#define MAX_LOG_MESSAGE_SIZE 1024 + class LogHandler; class LogHandlerList; diff --git a/ndb/src/common/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp index 5cc8de21f67..e038b05401e 100644 --- a/ndb/src/common/logger/LogHandler.cpp +++ b/ndb/src/common/logger/LogHandler.cpp @@ -23,21 +23,18 @@ // LogHandler::LogHandler() : m_pDateTimeFormat("%d-%.2d-%.2d %.2d:%.2d:%.2d"), - m_errorCode(0), - m_last_category(m_last_category_buf), - m_last_message(m_last_message_buf) + m_errorCode(0) { m_max_repeat_frequency= 3; // repeat messages maximum every 3 seconds - m_last_category_buf[0]= 0; - m_last_message_buf[0]= 0; + m_count_repeated_messages= 0; + m_last_category[0]= 0; + m_last_message[0]= 0; + m_last_log_time= 0; + m_now= 0; } LogHandler::~LogHandler() { - if (m_last_message != m_last_message_buf) - free(m_last_message); - if (m_last_category != m_last_category_buf) - free(m_last_category); } void @@ -51,42 +48,44 @@ LogHandler::append(const char* pCategory, Logger::LoggerLevel level, strcmp(pCategory, m_last_category) || strcmp(pMsg, m_last_message)) { - if (m_last_message != m_last_message_buf) - free(m_last_message); - if (m_last_category != m_last_category_buf) - free(m_last_category); - - m_count_repeated_messages= 0; + if (m_count_repeated_messages > 0) // print that message + append_impl(m_last_category, m_last_level, m_last_message); m_last_level= level; - BaseString::snprintf(m_last_category_buf, sizeof(m_last_category_buf), "%s", pCategory); - BaseString::snprintf(m_last_message_buf, sizeof(m_last_message_buf), "%s", pMsg); - // ToDo: handle too long messages correctly - // right now all that will happen is that too long messages - // will be repeated unneccesarily + strncpy(m_last_category, pCategory, sizeof(m_last_category)); + strncpy(m_last_message, pMsg, sizeof(m_last_message)); } else // repeated message { if (now < m_last_log_time+m_max_repeat_frequency) { m_count_repeated_messages++; + m_now= now; return; } } + m_now= now; + + append_impl(pCategory, level, pMsg); + m_last_log_time= now; +} + +void +LogHandler::append_impl(const char* pCategory, Logger::LoggerLevel level, + const char* pMsg) +{ writeHeader(pCategory, level); if (m_count_repeated_messages == 0) writeMessage(pMsg); else { BaseString str(pMsg); - str.appfmt(" - repeated %d times", m_count_repeated_messages); + str.appfmt(" - Repeated %d times", m_count_repeated_messages); writeMessage(str.c_str()); m_count_repeated_messages= 0; } writeFooter(); - - m_last_log_time= now; } const char* @@ -125,12 +124,10 @@ char* LogHandler::getTimeAsString(char* pStr) const { struct tm* tm_now; - time_t now; - now = ::time((time_t*)NULL); #ifdef NDB_WIN32 - tm_now = localtime(&now); + tm_now = localtime(&m_now); #else - tm_now = ::localtime(&now); //uses the "current" timezone + tm_now = ::localtime(&m_now); //uses the "current" timezone #endif BaseString::snprintf(pStr, MAX_DATE_TIME_HEADER_LENGTH, diff --git a/ndb/src/common/logger/Logger.cpp b/ndb/src/common/logger/Logger.cpp index 4fa7b462563..7f18f5bd3ec 100644 --- a/ndb/src/common/logger/Logger.cpp +++ b/ndb/src/common/logger/Logger.cpp @@ -355,11 +355,11 @@ Logger::log(LoggerLevel logLevel, const char* pMsg, va_list ap) const LogHandler* pHandler = NULL; while ( (pHandler = m_pHandlerList->next()) != NULL) { - char buf[1024]; + char buf[MAX_LOG_MESSAGE_SIZE]; BaseString::vsnprintf(buf, sizeof(buf), pMsg, ap); pHandler->append(m_pCategory, logLevel, buf); } - } + } } // From 9f94a42fccc6b0e3cf44e6ac83c18537f166618b Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Wed, 22 Dec 2004 22:59:19 +0100 Subject: [PATCH 27/54] BitKeeper/triggers/pre-delta don't checkin for Administrator or mysqldev sql/log.cc@1.157 restored a bugfix that was lost in a merge --- BitKeeper/triggers/pre-delta | 11 +++++++++++ sql/log.cc | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/BitKeeper/triggers/pre-delta b/BitKeeper/triggers/pre-delta index e22ae9ce940..cd861703bb5 100755 --- a/BitKeeper/triggers/pre-delta +++ b/BitKeeper/triggers/pre-delta @@ -1,5 +1,16 @@ #!/bin/sh +if [ "$BK_USER" = "Administrator" -o "$BK_USER" = "mysqldev" ] +then + echo "Error: you cannot checkin as 'Administrator' or 'mysqldev' user." + echo "as a workaround set BK_USER to your nickname" + echo "e.g.: export BK_USER='bar'" + echo "" + echo "Checkin FAILED!" + echo "Set BK_USER and retry." + exit 1 +fi + if [ `tail -c1 $BK_FILE` ] then echo "File $BK_FILE does not end with a new-line character!" diff --git a/sql/log.cc b/sql/log.cc index 3a420866025..ab0cb823f15 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -2036,6 +2036,7 @@ bool flush_error_log() char err_renamed[FN_REFLEN], *end; end= strmake(err_renamed,log_error_file,FN_REFLEN-4); strmov(end, "-old"); + VOID(pthread_mutex_lock(&LOCK_error_log)); #ifdef __WIN__ char err_temp[FN_REFLEN+4]; /* @@ -2056,7 +2057,7 @@ bool flush_error_log() if ((fd = my_open(err_temp, O_RDONLY, MYF(0))) >= 0) { while ((bytes = (int) my_read(fd, (byte*) buf, IO_SIZE, MYF(0))) > 0) - my_fwrite(stderr, (byte*) buf, (uint) strlen(buf),MYF(0)); + my_fwrite(stderr, (byte*) buf, bytes, MYF(0)); my_close(fd, MYF(0)); } (void) my_delete(err_temp, MYF(0)); @@ -2070,6 +2071,7 @@ bool flush_error_log() else result= 1; #endif + VOID(pthread_mutex_unlock(&LOCK_error_log)); } return result; } From b2368418900736c61984352908b23f49cd69f23f Mon Sep 17 00:00:00 2001 From: "bar@mysql.com" <> Date: Thu, 23 Dec 2004 13:52:25 +0400 Subject: [PATCH 28/54] Take charsets from the source directory rather than from the install directory. --- mysql-test/mysql-test-run.sh | 3 ++- mysql-test/t/mysqldump.test | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 93b1360846a..4c141e75baa 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -596,7 +596,8 @@ MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password= MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR $EXTRA_MYSQLBINLOG_OPT" MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD --basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose" MYSQL="$MYSQL --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD" -export MYSQL MYSQL_DUMP MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES CLIENT_BINDIR TESTS_BINDIR +export MYSQL MYSQL_DUMP MYSQL_BINLOG MYSQL_FIX_SYSTEM_TABLES +export CLIENT_BINDIR TESTS_BINDIR CHARSETSDIR export NDB_TOOLS_DIR MYSQL_TEST_ARGS="--no-defaults --socket=$MASTER_MYSOCK --database=$DB \ diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 7a6c1564e94..07b33689196 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -147,9 +147,9 @@ drop database mysqldump_test_db; CREATE TABLE t1 (a CHAR(10)); INSERT INTO t1 VALUES (_latin1 'ÄÖÜß'); ---exec $MYSQL_DUMP --skip-comments test t1 ---exec $MYSQL_DUMP --skip-comments --compatible=mysql323 test t1 ---exec $MYSQL_DUMP --skip-comments --compatible=mysql323 --default-character-set=cp850 test t1 ---exec $MYSQL_DUMP --skip-comments --default-character-set=cp850 --compatible=mysql323 test t1 ---exec $MYSQL_DUMP --skip-comments --default-character-set=utf8 --compatible=mysql323 test t1 +--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments test t1 +--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --compatible=mysql323 test t1 +--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --compatible=mysql323 --default-character-set=cp850 test t1 +--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=cp850 --compatible=mysql323 test t1 +--exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=utf8 --compatible=mysql323 test t1 DROP TABLE t1; From 4788b152012c3b41f72e08291efc4235913c9b33 Mon Sep 17 00:00:00 2001 From: "wax@kishkin.ru" <> Date: Thu, 23 Dec 2004 16:04:40 +0500 Subject: [PATCH 29/54] fix indentation add space after comma add space after equal add comments in vio_close_shared_memory() --- include/violite.h | 22 +++++++++++----------- sql-common/client.c | 4 ++-- sql/mysqld.cc | 45 ++++++++++++++++++++++++++------------------- vio/vio.c | 22 +++++++++++----------- vio/viosocket.c | 19 ++++++++++++++----- 5 files changed, 64 insertions(+), 48 deletions(-) diff --git a/include/violite.h b/include/violite.h index 64e834d6653..855d8a3d490 100644 --- a/include/violite.h +++ b/include/violite.h @@ -39,17 +39,17 @@ enum enum_vio_type Vio* vio_new(my_socket sd, enum enum_vio_type type, my_bool localhost); #ifdef __WIN__ -Vio* vio_new_win32pipe(HANDLE hPipe); -Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, - HANDLE handle_map, - HANDLE event_server_wrote, - HANDLE event_server_read, - HANDLE event_client_wrote, - HANDLE event_client_read, - HANDLE event_conn_closed); -int vio_read_pipe(Vio *vio, gptr buf, int size); -int vio_write_pipe(Vio *vio, const gptr buf, int size); -int vio_close_pipe(Vio * vio); +Vio* vio_new_win32pipe(HANDLE hPipe); +Vio* vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, + HANDLE handle_map, + HANDLE event_server_wrote, + HANDLE event_server_read, + HANDLE event_client_wrote, + HANDLE event_client_read, + HANDLE event_conn_closed); +int vio_read_pipe(Vio *vio, gptr buf, int size); +int vio_write_pipe(Vio *vio, const gptr buf, int size); +int vio_close_pipe(Vio * vio); #else #define HANDLE void * #endif /* __WIN__ */ diff --git a/sql-common/client.c b/sql-common/client.c index 0714ca4291f..87a781e0a0d 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -525,9 +525,9 @@ err2: if (error_allow == 0) { net->vio= vio_new_win32shared_memory(net,handle_file_map,handle_map, - event_server_wrote, + event_server_wrote, event_server_read,event_client_wrote, - event_client_read,event_conn_closed); + event_client_read,event_conn_closed); } else { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 2bf9e898920..bebecb394e9 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3853,31 +3853,31 @@ pthread_handler_decl(handle_connections_shared_memory,arg) goto errorconn; } strmov(suffix_pos, "CLIENT_WROTE"); - if ((event_client_wrote= CreateEvent(0,FALSE,FALSE,tmp)) == 0) + if ((event_client_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0) { errmsg= "Could not create client write event"; goto errorconn; } strmov(suffix_pos, "CLIENT_READ"); - if ((event_client_read= CreateEvent(0,FALSE,FALSE,tmp)) == 0) + if ((event_client_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0) { errmsg= "Could not create client read event"; goto errorconn; } strmov(suffix_pos, "SERVER_READ"); - if ((event_server_read= CreateEvent(0,FALSE,FALSE,tmp)) == 0) + if ((event_server_read= CreateEvent(0, FALSE, FALSE, tmp)) == 0) { errmsg= "Could not create server read event"; goto errorconn; } strmov(suffix_pos, "SERVER_WROTE"); - if ((event_server_wrote= CreateEvent(0,FALSE,FALSE,tmp)) == 0) + if ((event_server_wrote= CreateEvent(0, FALSE, FALSE, tmp)) == 0) { errmsg= "Could not create server write event"; goto errorconn; } strmov(suffix_pos, "CONNECTION_CLOSED"); - if ((event_conn_closed= CreateEvent(0,TRUE,FALSE,tmp)) == 0) + if ((event_conn_closed= CreateEvent(0, TRUE , FALSE, tmp)) == 0) { errmsg= "Could not create closed connection event"; goto errorconn; @@ -3900,14 +3900,14 @@ pthread_handler_decl(handle_connections_shared_memory,arg) goto errorconn; } if (!(thd->net.vio= vio_new_win32shared_memory(&thd->net, - handle_client_file_map, - handle_client_map, - event_client_wrote, - event_client_read, - event_server_wrote, - event_server_read, + handle_client_file_map, + handle_client_map, + event_client_wrote, + event_client_read, + event_server_wrote, + event_server_read, event_conn_closed)) || - my_net_init(&thd->net, thd->net.vio)) + my_net_init(&thd->net, thd->net.vio)) { close_connection(thd, ER_OUT_OF_RESOURCES, 1); errmsg= 0; @@ -3927,13 +3927,20 @@ errorconn: NullS); sql_perror(buff); } - if (handle_client_file_map) CloseHandle(handle_client_file_map); - if (handle_client_map) UnmapViewOfFile(handle_client_map); - if (event_server_wrote) CloseHandle(event_server_wrote); - if (event_server_read) CloseHandle(event_server_read); - if (event_client_wrote) CloseHandle(event_client_wrote); - if (event_client_read) CloseHandle(event_client_read); - if (event_conn_closed) CloseHandle(event_conn_closed); + if (handle_client_file_map) + CloseHandle(handle_client_file_map); + if (handle_client_map) + UnmapViewOfFile(handle_client_map); + if (event_server_wrote) + CloseHandle(event_server_wrote); + if (event_server_read) + CloseHandle(event_server_read); + if (event_client_wrote) + CloseHandle(event_client_wrote); + if (event_client_read) + CloseHandle(event_client_read); + if (event_conn_closed) + CloseHandle(event_conn_closed); delete thd; } diff --git a/vio/vio.c b/vio/vio.c index 92d69dc5148..978780d2632 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -172,23 +172,23 @@ Vio *vio_new_win32pipe(HANDLE hPipe) Vio *vio_new_win32shared_memory(NET *net,HANDLE handle_file_map, HANDLE handle_map, HANDLE event_server_wrote, HANDLE event_server_read, HANDLE event_client_wrote, HANDLE event_client_read, - HANDLE event_conn_closed) + HANDLE event_conn_closed) { Vio *vio; DBUG_ENTER("vio_new_win32shared_memory"); if ((vio = (Vio*) my_malloc(sizeof(Vio),MYF(MY_WME)))) { vio_reset(vio, VIO_TYPE_SHARED_MEMORY, 0, 0, TRUE); - vio->handle_file_map = handle_file_map; - vio->handle_map = handle_map; - vio->event_server_wrote = event_server_wrote; - vio->event_server_read = event_server_read; - vio->event_client_wrote = event_client_wrote; - vio->event_client_read = event_client_read; - vio->event_conn_closed = event_conn_closed; - vio->shared_memory_remain = 0; - vio->shared_memory_pos = handle_map; - vio->net = net; + vio->handle_file_map= handle_file_map; + vio->handle_map= handle_map; + vio->event_server_wrote= event_server_wrote; + vio->event_server_read= event_server_read; + vio->event_client_wrote= event_client_wrote; + vio->event_client_read= event_client_read; + vio->event_conn_closed= event_conn_closed; + vio->shared_memory_remain= 0; + vio->shared_memory_pos= handle_map; + vio->net= net; strmov(vio->desc, "shared memory"); } DBUG_RETURN(vio); diff --git a/vio/viosocket.c b/vio/viosocket.c index caf9451df7a..bcba05beef1 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -390,7 +390,7 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size) WAIT_OBJECT_0+1 - event from vio->event_conn_closed. We can't read anything WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail. We can't read anything */ - if (WaitForMultipleObjects(2,(HANDLE*)&events,FALSE, + if (WaitForMultipleObjects(2, (HANDLE*)&events,FALSE, vio->net->read_timeout*1000) != WAIT_OBJECT_0) { DBUG_RETURN(-1); @@ -440,7 +440,8 @@ int vio_write_shared_memory(Vio * vio, const gptr buf, int size) current_postion = buf; while (remain != 0) { - if (WaitForSingleObject(vio->event_server_read,vio->net->write_timeout*1000) != WAIT_OBJECT_0) + if (WaitForSingleObject(vio->event_server_read, vio->net->write_timeout*1000) + != WAIT_OBJECT_0) { DBUG_RETURN(-1); }; @@ -467,10 +468,18 @@ int vio_close_shared_memory(Vio * vio) DBUG_ENTER("vio_close_shared_memory"); if (vio->type != VIO_CLOSED) { + /* + Set event_conn_closed for notification of both client and server that + connection is closed + */ SetEvent(vio->event_conn_closed); - r=UnmapViewOfFile(vio->handle_map) || CloseHandle(vio->event_server_wrote) || - CloseHandle(vio->event_server_read) || CloseHandle(vio->event_client_wrote) || - CloseHandle(vio->event_client_read) || CloseHandle(vio->handle_file_map); + /* + Close all handlers. UnmapViewOfFile and CloseHandle return non-zero + result if they are success. + */ + r= UnmapViewOfFile(vio->handle_map) || CloseHandle(vio->event_server_wrote) || + CloseHandle(vio->event_server_read) || CloseHandle(vio->event_client_wrote) || + CloseHandle(vio->event_client_read) || CloseHandle(vio->handle_file_map); if (!r) { DBUG_PRINT("vio_error", ("close() failed, error: %d",r)); From 7960b09bca3a5732455feb5cbc344bf15b327e30 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 23 Dec 2004 17:32:29 +0100 Subject: [PATCH 30/54] incorrect result fixed --- mysql-test/r/func_concat.result | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/func_concat.result b/mysql-test/r/func_concat.result index 419413e4156..0bd53b32dd7 100644 --- a/mysql-test/r/func_concat.result +++ b/mysql-test/r/func_concat.result @@ -63,8 +63,8 @@ a0 select 'a' union select concat('a', -0.0); a a -a-0.0 +a0.0 select 'a' union select concat('a', -0.0000); a a -a-0.0000 +a0.0000 From caade862ae642ee6be00ac6413c04402972fda8e Mon Sep 17 00:00:00 2001 From: "dlenev@mysql.com" <> Date: Thu, 23 Dec 2004 21:59:36 +0300 Subject: [PATCH 31/54] Make GRANTs, which change SSL attributes and/or user limits, to behave well on 5.0 tables (well now you can't use tables from 4.1 and 5.0 with 4.0 because former use utf8, but still it is nice to have similar code in acl_init() and replace_user_table()). This also will make such GRANTs working in 5.0 (they are broken now). --- mysql-test/r/grant.result | 22 +++++++++++++++ mysql-test/t/grant.test | 17 ++++++++++++ sql/sql_acl.cc | 56 +++++++++++++++++++++------------------ 3 files changed, 69 insertions(+), 26 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 2a433e3d5db..19d83a95c5e 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -36,6 +36,28 @@ Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' REQUIRE ISSUER 'MySQL AB' SUBJECT 'testsubject' CIPHER 'EDH-RSA-DES-CBC3-SHA' delete from mysql.user where user='mysqltest_1'; flush privileges; +delete from mysql.user where user='mysqltest_1'; +flush privileges; +grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10; +select * from mysql.user where user="mysqltest_1"; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N 10 0 0 +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 +grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30; +select * from mysql.user where user="mysqltest_1"; +Host User Password Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Reload_priv Shutdown_priv Process_priv File_priv Grant_priv References_priv Index_priv Alter_priv Show_db_priv Super_priv Create_tmp_table_priv Lock_tables_priv Execute_priv Repl_slave_priv Repl_client_priv ssl_type ssl_cipher x509_issuer x509_subject max_questions max_updates max_connections +localhost mysqltest_1 N N N N N N N N N N N N N N N N N N N N N 10 20 30 +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 +flush privileges; +show grants for mysqltest_1@localhost; +Grants for mysqltest_1@localhost +GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' WITH MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 20 MAX_CONNECTIONS_PER_HOUR 30 +delete from mysql.user where user='mysqltest_1'; +flush privileges; grant CREATE TEMPORARY TABLES, LOCK TABLES on mysqltest.* to mysqltest_1@localhost; show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index d9b4be04de3..960c55065fe 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -27,6 +27,23 @@ show grants for mysqltest_1@localhost; delete from mysql.user where user='mysqltest_1'; flush privileges; +# +# Test of GRANTS specifying user limits +# +delete from mysql.user where user='mysqltest_1'; +flush privileges; +grant usage on *.* to mysqltest_1@localhost with max_queries_per_hour 10; +select * from mysql.user where user="mysqltest_1"; +show grants for mysqltest_1@localhost; +grant usage on *.* to mysqltest_1@localhost with max_updates_per_hour 20 max_connections_per_hour 30; +select * from mysql.user where user="mysqltest_1"; +show grants for mysqltest_1@localhost; +# This is just to double check that one won't ignore results of selects +flush privileges; +show grants for mysqltest_1@localhost; +delete from mysql.user where user='mysqltest_1'; +flush privileges; + # # Test that the new db privileges are stored/retrieved correctly # diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 67ca62357ec..1b55168695b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1403,6 +1403,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, Field **tmp_field; ulong priv; + uint next_field; for (tmp_field= table->field+3, priv = SELECT_ACL; *tmp_field && (*tmp_field)->real_type() == FIELD_TYPE_ENUM && ((Field_enum*) (*tmp_field))->typelib->count == 2 ; @@ -1411,56 +1412,59 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, if (priv & rights) // set requested privileges (*tmp_field)->store(&what,1); } - rights=get_access(table,3,0); + rights= get_access(table, 3, &next_field); DBUG_PRINT("info",("table->fields: %d",table->fields)); if (table->fields >= 31) /* From 4.0.0 we have more fields */ { /* We write down SSL related ACL stuff */ switch (thd->lex.ssl_type) { case SSL_TYPE_ANY: - table->field[24]->store("ANY",3); - table->field[25]->store("",0); - table->field[26]->store("",0); - table->field[27]->store("",0); + table->field[next_field]->store("ANY", 3); + table->field[next_field+1]->store("", 0); + table->field[next_field+2]->store("", 0); + table->field[next_field+3]->store("", 0); break; case SSL_TYPE_X509: - table->field[24]->store("X509",4); - table->field[25]->store("",0); - table->field[26]->store("",0); - table->field[27]->store("",0); + table->field[next_field]->store("X509", 4); + table->field[next_field+1]->store("", 0); + table->field[next_field+2]->store("", 0); + table->field[next_field+3]->store("", 0); break; case SSL_TYPE_SPECIFIED: - table->field[24]->store("SPECIFIED",9); - table->field[25]->store("",0); - table->field[26]->store("",0); - table->field[27]->store("",0); + table->field[next_field]->store("SPECIFIED", 9); + table->field[next_field+1]->store("", 0); + table->field[next_field+2]->store("", 0); + table->field[next_field+3]->store("", 0); if (thd->lex.ssl_cipher) - table->field[25]->store(thd->lex.ssl_cipher, - strlen(thd->lex.ssl_cipher)); + table->field[next_field+1]->store(thd->lex.ssl_cipher, + strlen(thd->lex.ssl_cipher)); if (thd->lex.x509_issuer) - table->field[26]->store(thd->lex.x509_issuer, - strlen(thd->lex.x509_issuer)); + table->field[next_field+2]->store(thd->lex.x509_issuer, + strlen(thd->lex.x509_issuer)); if (thd->lex.x509_subject) - table->field[27]->store(thd->lex.x509_subject, - strlen(thd->lex.x509_subject)); + table->field[next_field+3]->store(thd->lex.x509_subject, + strlen(thd->lex.x509_subject)); break; case SSL_TYPE_NOT_SPECIFIED: break; case SSL_TYPE_NONE: - table->field[24]->store("",0); - table->field[25]->store("",0); - table->field[26]->store("",0); - table->field[27]->store("",0); + table->field[next_field]->store("", 0); + table->field[next_field+1]->store("", 0); + table->field[next_field+2]->store("", 0); + table->field[next_field+3]->store("", 0); break; } + /* Skip over SSL related fields to first user limits related field */ + next_field+= 4; + USER_RESOURCES mqh = thd->lex.mqh; if (mqh.bits & 1) - table->field[28]->store((longlong) mqh.questions); + table->field[next_field]->store((longlong) mqh.questions); if (mqh.bits & 2) - table->field[29]->store((longlong) mqh.updates); + table->field[next_field+1]->store((longlong) mqh.updates); if (mqh.bits & 4) - table->field[30]->store((longlong) mqh.connections); + table->field[next_field+2]->store((longlong) mqh.connections); mqh_used = mqh_used || mqh.questions || mqh.updates || mqh.connections; } if (old_row_exists) From 3c5a3258972fa2487f0997db14ee6f31be862dbb Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Thu, 23 Dec 2004 21:08:54 +0200 Subject: [PATCH 32/54] Fix for a bug #7495 --- mysql-test/r/func_str.result | 18 ++++++------------ mysql-test/t/func_str.test | 8 ++------ sql/item_strfunc.cc | 14 +++++++------- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 2ca90653fec..278cd4dd935 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -291,15 +291,9 @@ trim(trailing 'foo' from 'foo') select trim(leading 'foo' from 'foo'); trim(leading 'foo' from 'foo') -create table t1 (a varchar(80), b varchar(80)); -insert into t1 values(NULL,"12345"); -insert into t1 values(NULL,"chm"); -select quote(ltrim(concat(' ',t1.b))) from t1; -quote(ltrim(concat(' ',t1.b))) -'12345' -'chm' -select quote(trim(concat(' ',t1.b))) from t1; -quote(trim(concat(' ',t1.b))) -'12345' -'chm' -drop table t1; +select quote(ltrim(concat(' ', 'a'))); +quote(ltrim(concat(' ', 'a'))) +'a' +select quote(trim(concat(' ', 'a'))); +quote(trim(concat(' ', 'a'))) +'a' diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 421512c4dc4..79a996e7e78 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -191,9 +191,5 @@ select trim(leading 'foo' from 'foo'); # Bug #7495 # -create table t1 (a varchar(80), b varchar(80)); -insert into t1 values(NULL,"12345"); -insert into t1 values(NULL,"chm"); -select quote(ltrim(concat(' ',t1.b))) from t1; -select quote(trim(concat(' ',t1.b))) from t1; -drop table t1; +select quote(ltrim(concat(' ', 'a'))); +select quote(trim(concat(' ', 'a'))); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 61477753594..a852906ee2c 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1141,7 +1141,7 @@ String *Item_func_ltrim::val_str(String *str) } if (ptr == res->ptr()) return res; - tmp_value.copy(res->ptr() + (ptr - res->ptr()), (uint32) (end - ptr)); + tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr)); return &tmp_value; } @@ -1266,7 +1266,7 @@ String *Item_func_trim::val_str(String *str) } if (ptr == res->ptr() && end == ptr+res->length()) return res; - tmp_value.copy(res->ptr() + (ptr - res->ptr()), (uint32) (end - ptr)); + tmp_value.set(*res,(uint) (ptr - res->ptr()),(uint) (end-ptr)); return &tmp_value; } @@ -2185,16 +2185,16 @@ String *Item_func_quote::val_str(String *str) /* We have to use realloc() instead of alloc() as we want to keep the - old result in str + old result in arg */ - if (str->realloc(new_length)) + if (arg->realloc(new_length)) goto null; /* As 'arg' and 'str' may be the same string, we must replace characters from the end to the beginning */ - to= (char*) str->ptr() + new_length - 1; + to= (char*) arg->ptr() + new_length - 1; *to--= '\''; for (start= (char*) arg->ptr(),end= start + arg_length; end-- != start; to--) { @@ -2222,9 +2222,9 @@ String *Item_func_quote::val_str(String *str) } } *to= '\''; - str->length(new_length); + arg->length(new_length); null_value= 0; - return str; + return arg; null: null_value= 1; From 45bd5ee6f411ca4587840467fd0b35b17e31dd17 Mon Sep 17 00:00:00 2001 From: "ram@gw.mysql.r18.ru" <> Date: Fri, 24 Dec 2004 18:52:24 +0400 Subject: [PATCH 33/54] A fix (bug #5652: [patch] tcpwrapper support is broken on systems using an unmodified tcpwrapper). --- sql/mysqld.cc | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 768acd77c27..eae63c5deb3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -107,15 +107,6 @@ extern "C" { // Because of SCO 3.2V4.2 int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; -#ifdef __STDC__ -#define my_fromhost(A) fromhost(A) -#define my_hosts_access(A) hosts_access(A) -#define my_eval_client(A) eval_client(A) -#else -#define my_fromhost(A) fromhost() -#define my_hosts_access(A) hosts_access() -#define my_eval_client(A) eval_client() -#endif #endif /* HAVE_LIBWRAP */ #ifdef HAVE_SYS_MMAN_H @@ -3240,8 +3231,8 @@ extern "C" pthread_handler_decl(handle_connections_sockets, struct request_info req; signal(SIGCHLD, SIG_DFL); request_init(&req, RQ_DAEMON, libwrapName, RQ_FILE, new_sock, NULL); - my_fromhost(&req); - if (!my_hosts_access(&req)) + fromhost(&req); + if (!hosts_access(&req)) { /* This may be stupid but refuse() includes an exit(0) @@ -3249,7 +3240,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets, clean_exit() - same stupid thing ... */ syslog(deny_severity, "refused connect from %s", - my_eval_client(&req)); + eval_client(&req)); /* C++ sucks (the gibberish in front just translates the supplied From ca74ce3398442acaaf9ef7554ae94616d787cb49 Mon Sep 17 00:00:00 2001 From: "Sinisa@sinisa.nasamreza.org" <> Date: Sat, 25 Dec 2004 00:07:22 +0200 Subject: [PATCH 34/54] additional 4.0 -> 4.1 merge !! --- mysql-test/r/func_str.result | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index f4185ad93de..1c560dfa8b4 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -691,7 +691,6 @@ select count(*) as total, left(c,10) as reg from t1 group by reg order by reg de total reg 10 2004-12-10 drop table t1; - select quote(ltrim(concat(' ', 'a'))); quote(ltrim(concat(' ', 'a'))) 'a' From 735d25ed731fc9056394a9a1b191c4f064a3d5a2 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 24 Dec 2004 23:30:40 +0100 Subject: [PATCH 35/54] better fix for bug#7242 (crash in prepared INSERT ... UPDATE) --- sql/sql_insert.cc | 9 ++++----- sql/sql_prepare.cc | 30 ++++-------------------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index ce64890523a..622176e22cc 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -427,6 +427,7 @@ abort: thd - thread handler table_list - global table list insert_table_list - local table list of INSERT SELECT_LEX + values - values to insert. NULL for INSERT ... SELECT RETURN VALUE 0 - OK @@ -442,7 +443,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (duplic == DUP_UPDATE && !table->insert_values) { /* it should be allocated before Item::fix_fields() */ - table->insert_values= + table->insert_values= (byte *)alloc_root(thd->mem_root, table->rec_buff_length); if (!table->insert_values) DBUG_RETURN(-1); @@ -454,10 +455,8 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, (setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0) || setup_fields(thd, 0, insert_table_list, update_values, 1, 0, 0)))) DBUG_RETURN(-1); - if ((thd->lex->sql_command==SQLCOM_INSERT || - thd->lex->sql_command==SQLCOM_REPLACE) && - find_real_table_in_list(table_list->next, - table_list->db, table_list->real_name)) + if (values && find_real_table_in_list(table_list->next, table_list->db, + table_list->real_name)) { my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name); DBUG_RETURN(-1); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 6d2ddf03b50..20ebc23e240 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -908,14 +908,15 @@ static int mysql_test_insert(Prepared_statement *stmt, uint value_count; ulong counter= 0; + table_list->table->insert_values=(byte *)1; // don't allocate insert_values if ((res= mysql_prepare_insert(thd, table_list, insert_table_list, table_list->table, fields, values, update_fields, update_values, duplic))) goto error; - + value_count= values->elements; its.rewind(); - + while ((values= its++)) { counter++; @@ -934,6 +935,7 @@ static int mysql_test_insert(Prepared_statement *stmt, res= 0; error: lex->unit.cleanup(); + table_list->table->insert_values=0; DBUG_RETURN(res); } @@ -1513,28 +1515,6 @@ static bool init_param_array(Prepared_statement *stmt) return 0; } - -/* Init statement before execution */ - -static void cleanup_stmt_for_execute(Prepared_statement *stmt) -{ - THD *thd= stmt->thd; - LEX *lex= stmt->lex; - SELECT_LEX *sl= lex->all_selects_list; - - for (; sl; sl= sl->next_select_in_list()) - { - for (TABLE_LIST *tables= (TABLE_LIST*) sl->table_list.first; - tables; - tables= tables->next) - { - if (tables->table) - tables->table->insert_values= 0; - } - } -} - - /* Given a query string with parameter markers, create a Prepared Statement from it and send PS info back to the client. @@ -1635,7 +1615,6 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, if (!error) error= send_prepare_results(stmt, test(name)); - cleanup_stmt_for_execute(stmt); /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */ if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -1926,7 +1905,6 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt, reset_stmt_params(stmt); close_thread_tables(thd); // to close derived tables thd->set_statement(&thd->stmt_backup); - cleanup_stmt_for_execute(stmt); DBUG_VOID_RETURN; } From d3fa24536394c8419bce81977c1b55e66ee05436 Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sat, 25 Dec 2004 19:17:57 -0800 Subject: [PATCH 36/54] subselect.result, subselect.test: Added test cases for bug #7351. item_cmpfunc.cc: Fixed bug #7351: incorrect result for a query with a subquery returning empty set. If in the predicate v IN (SELECT a FROM t WHERE cond) v is null, then the result of the predicate is either INKNOWN or FALSE. It is FALSE if the subquery returns an empty set. item_subselect.cc: Fixed bug #7351: incorrect result for a query with a subquery returning empty set. The problem was due to not a quite legal transformation for 'IN' subqueries. A subquery containing a predicate of the form v IN (SELECT a FROM t WHERE cond) was transformed into EXISTS(SELECT a FROM t WHERE cond AND (a=v OR a IS NULL)). Yet, this transformation is valid only if v is not null. If v is null, then, in the case when (SELECT a FROM t WHERE cond) returns an empty set the value of the predicate is FALSE, otherwise the result of the predicate is INKNOWN. The fix resolves this problem by changing the result of the transformation to EXISTS(SELECT a FROM t WHERE cond AND (v IS NULL OR (a=v OR a IS NULL))) in the case when v is nullable. The new transformation prevents applying the lookup optimization for IN subqueries. To make it still applicable we have to introduce guarded access methods. --- mysql-test/r/subselect.result | 25 ++++++++++++++++++++----- mysql-test/t/subselect.test | 21 ++++++++++++++++++++- sql/item_cmpfunc.cc | 5 +++-- sql/item_subselect.cc | 13 +++++++++---- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 0735f133e6f..b264018866c 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -1425,7 +1425,7 @@ Note 1003 (select test.t1.s1 AS `s1` from test.t1) s1 tttt drop table t1; -create table t1 (s1 char(5), index s1(s1)); +create table t1 (s1 char(5) not null, index s1(s1)); create table t2 (s1 char(5), index s1(s1)); insert into t1 values ('a1'),('a2'),('a3'); insert into t2 values ('a1'),('a2'); @@ -1451,25 +1451,25 @@ a2 1 a3 1 explain extended select s1, s1 NOT IN (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 index NULL s1 6 NULL 3 Using index +1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: Note 1003 select test.t1.s1 AS `s1`,not((test.t1.s1,(((test.t1.s1) in t2 on s1 chicking NULL)))) AS `s1 NOT IN (SELECT s1 FROM t2)` from test.t1 explain extended select s1, s1 = ANY (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 index NULL s1 6 NULL 3 Using index +1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: Note 1003 select test.t1.s1 AS `s1`,(test.t1.s1,(((test.t1.s1) in t2 on s1 chicking NULL))) AS `s1 = ANY (SELECT s1 FROM t2)` from test.t1 explain extended select s1, s1 <> ALL (SELECT s1 FROM t2) from t1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 index NULL s1 6 NULL 3 Using index +1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 2 Using index Warnings: Note 1003 select test.t1.s1 AS `s1`,not((test.t1.s1,(((test.t1.s1) in t2 on s1 chicking NULL)))) AS `s1 <> ALL (SELECT s1 FROM t2)` from test.t1 explain extended select s1, s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2') from t1; id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY t1 index NULL s1 6 NULL 3 Using index +1 PRIMARY t1 index NULL s1 5 NULL 3 Using index 2 DEPENDENT SUBQUERY t2 index_subquery s1 s1 6 func 1 Using index; Using where Warnings: Note 1003 select test.t1.s1 AS `s1`,not((test.t1.s1,(((test.t1.s1) in t2 on s1 chicking NULL where (test.t2.s1 < _latin1'a2'))))) AS `s1 NOT IN (SELECT s1 FROM t2 WHERE s1 < 'a2')` from test.t1 @@ -2125,3 +2125,18 @@ SELECT DISTINCT Continent AS c FROM t1 WHERE Code <> SOME ( SELECT Code FROM t1 c Oceania drop table t1; +CREATE TABLE t1 ( f1 BIGINT ); +INSERT INTO t1 SET f1= NULL; +INSERT INTO t1 SET f1= 1; +CREATE TABLE t2 ( f1 BIGINT ); +SELECT f1 FROM t1 +WHERE f1 <> ALL ( SELECT f1 FROM t2 ); +f1 +NULL +1 +INSERT INTO t2 VALUES (1), (2); +SELECT f1 FROM t1 +WHERE f1 <> ALL ( SELECT f1 FROM t2 WHERE f1 > 2 ); +f1 +NULL +1 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index f59851fa722..6f7daa66897 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -889,7 +889,7 @@ drop table t1; # # IN optimisation test results # -create table t1 (s1 char(5), index s1(s1)); +create table t1 (s1 char(5) not null, index s1(s1)); create table t2 (s1 char(5), index s1(s1)); insert into t1 values ('a1'),('a2'),('a3'); insert into t2 values ('a1'),('a2'); @@ -1386,3 +1386,22 @@ INSERT INTO t1 VALUES ('UMI','United States Minor Outlying Islands','Oceania','M /*!40000 ALTER TABLE t1 ENABLE KEYS */; SELECT DISTINCT Continent AS c FROM t1 WHERE Code <> SOME ( SELECT Code FROM t1 WHERE Continent = c AND Population < 200); drop table t1; + +# +# Test cases for bug #7351: +# quantified predicate with subquery returning empty result set +# + +CREATE TABLE t1 ( f1 BIGINT ); +INSERT INTO t1 SET f1= NULL; +INSERT INTO t1 SET f1= 1; +CREATE TABLE t2 ( f1 BIGINT ); + +SELECT f1 FROM t1 + WHERE f1 <> ALL ( SELECT f1 FROM t2 ); + +INSERT INTO t2 VALUES (1), (2); + +SELECT f1 FROM t1 + WHERE f1 <> ALL ( SELECT f1 FROM t2 WHERE f1 > 2 ); + diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a135f08ae45..3d79c16b5d0 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -636,12 +636,13 @@ longlong Item_in_optimizer::val_int() { DBUG_ASSERT(fixed == 1); cache->store(args[0]); + longlong tmp= args[1]->val_int_result(); if (cache->null_value) { - null_value= 1; + if (tmp) + null_value= 1; return 0; } - longlong tmp= args[1]->val_int_result(); null_value= args[1]->null_value; return tmp; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 1d0f46fd196..e1a80941a52 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -824,6 +824,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, select_lex->ref_pointer_array, (char *)"", this->full_name())); + if (!abort_on_null && left_expr->maybe_null) + item= new Item_cond_or(new Item_func_isnull(left_expr), item); /* AND and comparison functions can't be changed during fix_fields() we can assign select_lex->having here, and pass 0 as last @@ -869,6 +871,8 @@ Item_in_subselect::single_value_transformer(JOIN *join, select_lex->having_fix_field= 0; item= new Item_cond_or(item, new Item_func_isnull(orig_item)); + if (left_expr->maybe_null) + item= new Item_cond_or(new Item_func_isnull(left_expr), item); } item->name= (char *)in_additional_cond; /* @@ -889,12 +893,13 @@ Item_in_subselect::single_value_transformer(JOIN *join, we can assign select_lex->having here, and pass 0 as last argument (reference) to fix_fields() */ - select_lex->having= - join->having= - func->create(expr, - new Item_null_helper(this, item, + item= func->create(expr, + new Item_null_helper(this, item, (char *)"", (char *)"")); + if (!abort_on_null && left_expr->maybe_null) + item= new Item_cond_or(new Item_func_isnull(left_expr), item); + select_lex->having= join->having= item; select_lex->having_fix_field= 1; if (join->having->fix_fields(thd, join->tables_list, 0)) From 04974868a1170e6021761968d6ea2335bfed005b Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sun, 26 Dec 2004 02:04:40 -0800 Subject: [PATCH 37/54] subselect.result, subselect.test: Added a couple of new test cases for bug #7351. --- mysql-test/r/subselect.result | 12 ++++++++++++ mysql-test/t/subselect.test | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index b264018866c..9c442d8e3cb 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2140,3 +2140,15 @@ WHERE f1 <> ALL ( SELECT f1 FROM t2 WHERE f1 > 2 ); f1 NULL 1 +SELECT f1 FROM t1 +WHERE f1 <> ALL ( SELECT f1 FROM t2 WHERE f1 > 2 +UNION +SELECT f1 FROM t2 WHERE f1 > 3); +f1 +NULL +1 +SELECT f1 FROM t1 +WHERE f1 <> ALL ( SELECT SUM(f1) AS sf1 FROM t2 HAVING sf1 > 10000); +f1 +NULL +1 diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 6f7daa66897..6e4c3a5d604 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1405,3 +1405,10 @@ INSERT INTO t2 VALUES (1), (2); SELECT f1 FROM t1 WHERE f1 <> ALL ( SELECT f1 FROM t2 WHERE f1 > 2 ); +SELECT f1 FROM t1 + WHERE f1 <> ALL ( SELECT f1 FROM t2 WHERE f1 > 2 + UNION + SELECT f1 FROM t2 WHERE f1 > 3); + +SELECT f1 FROM t1 + WHERE f1 <> ALL ( SELECT SUM(f1) AS sf1 FROM t2 HAVING sf1 > 10000); From 7ad5e20461d04809a7e3bf1f966fe51c707f5332 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 04:10:25 +0200 Subject: [PATCH 38/54] Many files: Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1 --- innobase/buf/buf0rea.c | 2 +- innobase/dict/dict0load.c | 30 ++++++-- innobase/fil/fil0fil.c | 93 +++++++++++++++++++---- innobase/include/dict0load.h | 10 ++- innobase/include/fil0fil.h | 28 ++++--- innobase/include/row0mysql.h | 20 +---- innobase/include/trx0trx.h | 13 ++++ innobase/row/row0ins.c | 4 +- innobase/row/row0mysql.c | 141 +++++++++++++++++++++++++++++------ innobase/row/row0sel.c | 18 ++++- innobase/srv/srv0start.c | 43 ++++++++--- innobase/trx/trx0trx.c | 8 ++ sql/ha_innodb.cc | 15 +--- 13 files changed, 321 insertions(+), 104 deletions(-) diff --git a/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c index 11107d777c8..58287d37387 100644 --- a/innobase/buf/buf0rea.c +++ b/innobase/buf/buf0rea.c @@ -326,7 +326,7 @@ buf_read_page( if (err == DB_TABLESPACE_DELETED) { ut_print_timestamp(stderr); fprintf(stderr, -" InnoDB: error: trying to access tablespace %lu page no. %lu,\n" +" InnoDB: Error: trying to access tablespace %lu page no. %lu,\n" "InnoDB: but the tablespace does not exist or is just being dropped.\n", (ulong) space, (ulong) offset); } diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 7890ebd2b47..61facc8818d 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -205,12 +205,14 @@ loop: In a crash recovery we already have all the tablespace objects created. This function compares the space id information in the InnoDB data dictionary to what we already read with fil_load_single_table_tablespaces(). -In a normal startup we just scan the biggest space id, and store it to -fil_system. */ + +In a normal startup, we create the tablespace objects for every table in +InnoDB's data dictionary, if the corresponding .ibd file exists. +We also scan the biggest space id, and store it to fil_system. */ void -dict_check_tablespaces_or_store_max_id( -/*===================================*/ +dict_check_tablespaces_and_store_max_id( +/*====================================*/ ibool in_crash_recovery) /* in: are we doing a crash recovery */ { dict_table_t* sys_tables; @@ -280,6 +282,14 @@ loop: FALSE, TRUE, TRUE); } + if (space_id != 0 && !in_crash_recovery) { + /* It is a normal database startup: create the space + object and check that the .ibd file exists. */ + + fil_open_single_table_tablespace(FALSE, space_id, + name); + } + mem_free(name); if (space_id > max_space_id) { @@ -796,8 +806,18 @@ dict_load_table( /* Ok; (if we did a crash recovery then the tablespace can already be in the memory cache) */ } else { + /* In >= 4.1.9, InnoDB scans the data dictionary also + at a normal mysqld startup. It is an error if the + space object does not exist in memory. */ + + ut_print_timestamp(stderr); + fprintf(stderr, +" InnoDB: error: space object of table %s,\n" +"InnoDB: space id %lu did not exist in memory. Retrying an open.\n", + name, (ulong)space); /* Try to open the tablespace */ - if (!fil_open_single_table_tablespace(space, name)) { + if (!fil_open_single_table_tablespace(TRUE, + space, name)) { /* We failed to find a sensible tablespace file */ diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index de528355182..89648b3feca 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -466,6 +466,10 @@ fil_node_open_file( ulint size_low; ulint size_high; ibool ret; + byte* buf2; + byte* page; + ibool success; + ulint space_id; #ifdef UNIV_SYNC_DEBUG ut_ad(mutex_own(&(system->mutex))); @@ -494,6 +498,8 @@ fil_node_open_file( system->n_open++; if (node->size == 0) { + ut_a(space->purpose != FIL_LOG); + os_file_get_size(node->handle, &size_low, &size_high); size_bytes = (((ib_longlong)size_high) << 32) @@ -507,6 +513,46 @@ fil_node_open_file( ut_a(space->id != 0); + if (size_bytes < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) { + fprintf(stderr, +"InnoDB: Error: the size of single-table tablespace file %s\n" +"InnoDB: is only %lu %lu, should be at least %lu!", node->name, + (ulong) size_high, + (ulong) size_low, (ulong) (4 * UNIV_PAGE_SIZE)); + + ut_a(0); + } + + /* Read the first page of the tablespace */ + + buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); + /* Align the memory for file i/o if we might have O_DIRECT + set */ + page = ut_align(buf2, UNIV_PAGE_SIZE); + + success = os_file_read(node->handle, page, 0, 0, + UNIV_PAGE_SIZE); + space_id = fsp_header_get_space_id(page); + + ut_free(buf2); + + if (space_id == ULINT_UNDEFINED || space_id == 0) { + fprintf(stderr, +"InnoDB: Error: tablespace id %lu in file %s is not sensible\n", + (ulong) space_id, + node->name); + + ut_a(0); + } + + if (space_id != space->id) { + fprintf(stderr, +"InnoDB: Error: tablespace id is %lu in the data dictionary\n" +"InnoDB: but in file %s it is %lu!\n", space->id, node->name, space_id); + + ut_a(0); + } + if (size_bytes >= FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) { node->size = (ulint) ((size_bytes / (1024 * 1024)) * ((1024 * 1024) / UNIV_PAGE_SIZE)); @@ -2487,21 +2533,29 @@ func_exit: } /************************************************************************ -Tries to open a single-table tablespace and checks the space id is right in -it. If does not succeed, prints an error message to the .err log. This -function is used to open the tablespace when we load a table definition -to the dictionary cache. NOTE that we assume this operation is used under the -protection of the dictionary mutex, so that two users cannot race here. This -operation does not leave the file associated with the tablespace open, but -closes it after we have looked at the space id in it. */ +Tries to open a single-table tablespace and optionally checks the space id is +right in it. If does not succeed, prints an error message to the .err log. This +function is used to open a tablespace when we start up mysqld, and also in +IMPORT TABLESPACE. +NOTE that we assume this operation is used either at the database startup +or under the protection of the dictionary mutex, so that two users cannot +race here. This operation does not leave the file associated with the +tablespace open, but closes it after we have looked at the space id in it. */ ibool fil_open_single_table_tablespace( /*=============================*/ - /* out: TRUE if success */ - ulint id, /* in: space id */ - const char* name) /* in: table name in the - databasename/tablename format */ + /* out: TRUE if success */ + ibool check_space_id, /* in: should we check that the space + id in the file is right; we assume + that this function runs much faster + if no check is made, since accessing + the file inode probably is much + faster (the OS caches them) than + accessing the first page of the file */ + ulint id, /* in: space id */ + const char* name) /* in: table name in the + databasename/tablename format */ { os_file_t file; char* filepath; @@ -2540,6 +2594,12 @@ fil_open_single_table_tablespace( return(FALSE); } + if (!check_space_id) { + space_id = id; + + goto skip_check; + } + /* Read the first page of the tablespace */ buf2 = ut_malloc(2 * UNIV_PAGE_SIZE); @@ -2552,6 +2612,8 @@ fil_open_single_table_tablespace( space_id = fsp_header_get_space_id(page); + ut_free(buf2); + if (space_id != id) { ut_print_timestamp(stderr); @@ -2572,6 +2634,7 @@ fil_open_single_table_tablespace( goto func_exit; } +skip_check: success = fil_space_create(filepath, space_id, FIL_TABLESPACE); if (!success) { @@ -2584,7 +2647,6 @@ fil_open_single_table_tablespace( fil_node_create(filepath, 0, space_id, FALSE); func_exit: os_file_close(file); - ut_free(buf2); mem_free(filepath); return(ret); @@ -2651,7 +2713,7 @@ fil_load_single_table_tablespace( fprintf(stderr, "InnoDB: Error: could not open single-table tablespace file\n" "InnoDB: %s!\n" -"InnoDB: We do not continue crash recovery, because the table will become\n" +"InnoDB: We do not continue the crash recovery, because the table may become\n" "InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it.\n" "InnoDB: To fix the problem and start mysqld:\n" "InnoDB: 1) If there is a permission problem in the file and mysqld cannot\n" @@ -2822,8 +2884,9 @@ fil_load_single_table_tablespace( goto func_exit; } - /* We do not measure the size of the file, that is why we pass the 0 - below */ + /* We do not use the size information we have about the file, because + the rounding formulat for extents and pages is somewhat complex; we + let fil_node_open() do that task. */ fil_node_create(filepath, 0, space_id, FALSE); func_exit: diff --git a/innobase/include/dict0load.h b/innobase/include/dict0load.h index d4dccb33373..1f0a5407140 100644 --- a/innobase/include/dict0load.h +++ b/innobase/include/dict0load.h @@ -18,12 +18,14 @@ Created 4/24/1996 Heikki Tuuri In a crash recovery we already have all the tablespace objects created. This function compares the space id information in the InnoDB data dictionary to what we already read with fil_load_single_table_tablespaces(). -In a normal startup we just scan the biggest space id, and store it to -fil_system. */ + +In a normal startup, we create the tablespace objects for every table in +InnoDB's data dictionary, if the corresponding .ibd file exists. +We also scan the biggest space id, and store it to fil_system. */ void -dict_check_tablespaces_or_store_max_id( -/*===================================*/ +dict_check_tablespaces_and_store_max_id( +/*====================================*/ ibool in_crash_recovery); /* in: are we doing a crash recovery */ /************************************************************************ Finds the first table name in the given database. */ diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h index 43327aab9d2..c1a127aadca 100644 --- a/innobase/include/fil0fil.h +++ b/innobase/include/fil0fil.h @@ -364,19 +364,29 @@ fil_create_new_single_table_tablespace( tablespace file in pages, must be >= FIL_IBD_FILE_INITIAL_SIZE */ /************************************************************************ -Tries to open a single-table tablespace and checks the space id is right in -it. If does not succeed, prints an error message to the .err log. This -function is used to open the tablespace when we load a table definition -to the dictionary cache. NOTE that we assume this operation is used under the -protection of the dictionary mutex, so that two users cannot race here. */ +Tries to open a single-table tablespace and optionally checks the space id is +right in it. If does not succeed, prints an error message to the .err log. This +function is used to open a tablespace when we start up mysqld, and also in +IMPORT TABLESPACE. +NOTE that we assume this operation is used either at the database startup +or under the protection of the dictionary mutex, so that two users cannot +race here. This operation does not leave the file associated with the +tablespace open, but closes it after we have looked at the space id in it. */ ibool fil_open_single_table_tablespace( /*=============================*/ - /* out: TRUE if success */ - ulint id, /* in: space id */ - const char* name); /* in: table name in the - databasename/tablename format */ + /* out: TRUE if success */ + ibool check_space_id, /* in: should we check that the space + id in the file is right; we assume + that this function runs much faster + if no check is made, since accessing + the file inode probably is much + faster (the OS caches them) than + accessing the first page of the file */ + ulint id, /* in: space id */ + const char* name); /* in: table name in the + databasename/tablename format */ /************************************************************************ It is possible, though very improbable, that the lsn's in the tablespace to be imported have risen above the current system lsn, if a lengthy purge, ibuf diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h index f47ce74ce37..19007069e28 100644 --- a/innobase/include/row0mysql.h +++ b/innobase/include/row0mysql.h @@ -367,25 +367,7 @@ row_drop_table_for_mysql( /************************************************************************* Discards the tablespace of a table which stored in an .ibd file. Discarding means that this function deletes the .ibd file and assigns a new table id for -the table. Also the flag table->ibd_file_missing is set TRUE. - -How do we prevent crashes caused by ongoing operations on the table? Old -operations could try to access non-existent pages. - -1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock -on the table before we can do DISCARD TABLESPACE. Then there are no running -queries on the table. -2) Purge and rollback: we assign a new table id for the table. Since purge and -rollback look for the table based on the table id, they see the table as -'dropped' and discard their operations. -3) Insert buffer: we remove all entries for the tablespace in the insert -buffer tree; as long as the tablespace mem object does not exist, ongoing -insert buffer page merges are discarded in buf0rea.c. If we recreate the -tablespace mem object with IMPORT TABLESPACE later, then the tablespace will -have the same id, but the tablespace_version field in the mem object is -different, and ongoing old insert buffer page merges get discarded. -4) Linear readahead and random readahead: we use the same method as in 3) to -discard ongoing operations. */ +the table. Also the flag table->ibd_file_missing is set TRUE. */ int row_discard_tablespace_for_mysql( diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h index 7eb91048684..8336e05bdb0 100644 --- a/innobase/include/trx0trx.h +++ b/innobase/include/trx0trx.h @@ -378,6 +378,19 @@ struct trx_struct{ replication slave, this is the position in the log file up to which replication has processed */ + /* A MySQL variable mysql_thd->synchronous_repl tells if we have + to use synchronous replication. See ha_innodb.cc. */ + char* repl_wait_binlog_name;/* NULL, or if synchronous MySQL + replication is used, the binlog name + up to which we must communicate the + binlog to the slave, before returning + from a commit; this is the same as + mysql_log_file_name, but we allocate + and copy the name to a separate buffer + here */ + ib_longlong repl_wait_binlog_pos;/* see above at + repl_wait_binlog_name */ + os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated with this transaction object */ ulint mysql_process_no;/* since in Linux, 'top' reports diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 6d1482b6720..f596bd3d473 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1173,7 +1173,7 @@ run_again: check_index = foreign->foreign_index; } - if (check_table == NULL) { + if (check_table == NULL || check_table->ibd_file_missing) { if (check_ref) { FILE* ef = dict_foreign_err_file; mutex_enter(&dict_foreign_err_mutex); @@ -1192,7 +1192,7 @@ run_again: dtuple_print(ef, entry); fputs("\nBut the parent table ", ef); ut_print_name(ef, trx, foreign->referenced_table_name); - fputs(" does not currently exist!\n", ef); + fputs("\nor its .ind file does not currently exist!\n", ef); mutex_exit(&dict_foreign_err_mutex); return(DB_NO_REFERENCED_ROW); diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index dec2b19559c..3be3d3e6396 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -869,7 +869,21 @@ row_insert_for_mysql( ut_ad(trx); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); - + + if (prebuilt->table->ibd_file_missing) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error:\n" +"InnoDB: MySQL is trying to use a table handle but the .ibd file for\n" +"InnoDB: table %s does not exist.\n" +"InnoDB: Have you deleted the .ibd file from the database directory under\n" +"InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?\n" +"InnoDB: Look from\n" +"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" +"InnoDB: how you can resolve the problem.\n", + prebuilt->table->name); + return(DB_ERROR); + } + if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" @@ -1087,6 +1101,20 @@ row_update_for_mysql( ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); UT_NOT_USED(mysql_rec); + if (prebuilt->table->ibd_file_missing) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error:\n" +"InnoDB: MySQL is trying to use a table handle but the .ibd file for\n" +"InnoDB: table %s does not exist.\n" +"InnoDB: Have you deleted the .ibd file from the database directory under\n" +"InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?\n" +"InnoDB: Look from\n" +"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" +"InnoDB: how you can resolve the problem.\n", + prebuilt->table->name); + return(DB_ERROR); + } + if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" @@ -1966,9 +1994,25 @@ row_add_table_to_background_drop_list( /************************************************************************* Discards the tablespace of a table which stored in an .ibd file. Discarding means that this function deletes the .ibd file and assigns a new table id for -the table. Also the flag table->ibd_file_missing is set TRUE. +the table. Also the flag table->ibd_file_missing is set TRUE. */ -How do we prevent crashes caused by ongoing operations on the table? Old +int +row_discard_tablespace_for_mysql( +/*=============================*/ + /* out: error code or DB_SUCCESS */ + const char* name, /* in: table name */ + trx_t* trx) /* in: transaction handle */ +{ + dict_foreign_t* foreign; + dulint new_id; + dict_table_t* table; + que_thr_t* thr; + que_t* graph = NULL; + ibool success; + ulint err; + char* buf; + +/* How do we prevent crashes caused by ongoing operations on the table? Old operations could try to access non-existent pages. 1) SQL queries, INSERT, SELECT, ...: we must get an exclusive MySQL table lock @@ -1984,22 +2028,9 @@ tablespace mem object with IMPORT TABLESPACE later, then the tablespace will have the same id, but the tablespace_version field in the mem object is different, and ongoing old insert buffer page merges get discarded. 4) Linear readahead and random readahead: we use the same method as in 3) to -discard ongoing operations. */ - -int -row_discard_tablespace_for_mysql( -/*=============================*/ - /* out: error code or DB_SUCCESS */ - const char* name, /* in: table name */ - trx_t* trx) /* in: transaction handle */ -{ - dulint new_id; - dict_table_t* table; - que_thr_t* thr; - que_t* graph = NULL; - ibool success; - ulint err; - char* buf; +discard ongoing operations. +5) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0, we +do not allow the discard. We also reserve the data dictionary latch. */ static const char discard_tablespace_proc1[] = "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n" @@ -2060,6 +2091,54 @@ row_discard_tablespace_for_mysql( goto funct_exit; } + if (table->n_foreign_key_checks_running > 0) { + + ut_print_timestamp(stderr); + fputs(" InnoDB: You are trying to DISCARD table ", stderr); + ut_print_name(stderr, trx, table->name); + fputs("\n" + "InnoDB: though there is a foreign key check running on it.\n" + "InnoDB: Cannot discard the table.\n", + stderr); + + err = DB_ERROR; + + goto funct_exit; + } + + /* Check if the table is referenced by foreign key constraints from + some other table (not the table itself) */ + + foreign = UT_LIST_GET_FIRST(table->referenced_list); + + while (foreign && foreign->foreign_table == table) { + foreign = UT_LIST_GET_NEXT(referenced_list, foreign); + } + + if (foreign && trx->check_foreigns) { + + FILE* ef = dict_foreign_err_file; + + /* We only allow discarding a referenced table if + FOREIGN_KEY_CHECKS is set to 0 */ + + err = DB_CANNOT_DROP_CONSTRAINT; + + mutex_enter(&dict_foreign_err_mutex); + rewind(ef); + ut_print_timestamp(ef); + + fputs(" Cannot drop table ", ef); + ut_print_name(ef, trx, name); + fputs("\n" + "because it is referenced by ", ef); + ut_print_name(ef, trx, foreign->foreign_table_name); + putc('\n', ef); + mutex_exit(&dict_foreign_err_mutex); + + goto funct_exit; + } + new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); buf = mem_alloc((sizeof discard_tablespace_proc1) + @@ -2077,6 +2156,10 @@ row_discard_tablespace_for_mysql( ut_a(graph); + /* Remove any locks there are on the table or its records */ + + lock_reset_all_on_table(table); + graph->trx = trx; trx->graph = NULL; @@ -2227,8 +2310,8 @@ row_import_tablespace_for_mysql( ibuf_delete_for_discarded_space(table->space); - success = fil_open_single_table_tablespace(table->space, table->name); - + success = fil_open_single_table_tablespace(TRUE, table->space, + table->name); if (success) { table->ibd_file_missing = FALSE; table->tablespace_discarded = FALSE; @@ -2236,7 +2319,7 @@ row_import_tablespace_for_mysql( if (table->ibd_file_missing) { ut_print_timestamp(stderr); fputs( -" InnoDB: cannot find of open in the database directory the .ibd file of\n" +" InnoDB: cannot find or open in the database directory the .ibd file of\n" "InnoDB: table ", stderr); ut_print_name(stderr, trx, name); fputs("\n" @@ -3284,6 +3367,20 @@ row_check_table_for_mysql( ulint ret = DB_SUCCESS; ulint old_isolation_level; + if (prebuilt->table->ibd_file_missing) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error:\n" +"InnoDB: MySQL is trying to use a table handle but the .ibd file for\n" +"InnoDB: table %s does not exist.\n" +"InnoDB: Have you deleted the .ibd file from the database directory under\n" +"InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?\n" +"InnoDB: Look from\n" +"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" +"InnoDB: how you can resolve the problem.\n", + prebuilt->table->name); + return(DB_ERROR); + } + prebuilt->trx->op_info = "checking table"; old_isolation_level = prebuilt->trx->isolation_level; diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index ce76f48e7a7..8cdcdd569ac 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -2776,7 +2776,7 @@ row_search_for_mysql( /* out: DB_SUCCESS, DB_RECORD_NOT_FOUND, DB_END_OF_INDEX, DB_DEADLOCK, - DB_LOCK_TABLE_FULL, + DB_LOCK_TABLE_FULL, DB_CORRUPTION, or DB_TOO_BIG_RECORD */ byte* buf, /* in/out: buffer for the fetched row in the MySQL format */ @@ -2828,7 +2828,21 @@ row_search_for_mysql( ut_ad(index && pcur && search_tuple); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); - + + if (prebuilt->table->ibd_file_missing) { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Error:\n" +"InnoDB: MySQL is trying to use a table handle but the .ibd file for\n" +"InnoDB: table %s does not exist.\n" +"InnoDB: Have you deleted the .ibd file from the database directory under\n" +"InnoDB: the MySQL datadir, or have you used DISCARD TABLESPACE?\n" +"InnoDB: Look from\n" +"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n" +"InnoDB: how you can resolve the problem.\n", + prebuilt->table->name); + return(DB_ERROR); + } + if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) { fprintf(stderr, "InnoDB: Error: trying to free a corrupt\n" diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 69341a1d7d1..c91db1f0dcc 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1378,14 +1378,39 @@ NetWare. */ return(DB_ERROR); } - /* Since ibuf init is in dict_boot, and ibuf is needed - in any disk i/o, first call dict_boot */ + /* Since the insert buffer init is in dict_boot, and the + insert buffer is needed in any disk i/o, first we call + dict_boot(). Note that trx_sys_init_at_db_start() only needs + to access space 0, and the insert buffer at this stage already + works for space 0. */ dict_boot(); trx_sys_init_at_db_start(); - /* The following needs trx lists which are initialized in - trx_sys_init_at_db_start */ + if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) { + /* The following call is necessary for the insert + buffer to work with multiple tablespaces. We must + know the mapping between space id's and .ibd file + names. + + In a crash recovery, we check that the info in data + dictionary is consistent with what we already know + about space id's from the call of + fil_load_single_table_tablespaces(). + + In a normal startup, we create the space objects for + every table in the InnoDB data dictionary that has + an .ibd file. + + We also determine the maximum tablespace id used. + + TODO: We may have incomplete transactions in the + data dictionary tables. Does that harm the scanning of + the data dictionary below? */ + + dict_check_tablespaces_and_store_max_id( + recv_needed_recovery); + } srv_startup_is_before_trx_rollback_phase = FALSE; @@ -1393,6 +1418,9 @@ NetWare. */ system */ fsp_header_get_free_limit(0); + /* recv_recovery_from_checkpoint_finish needs trx lists which + are initialized in trx_sys_init_at_db_start(). */ + recv_recovery_from_checkpoint_finish(); } @@ -1433,13 +1461,6 @@ NetWare. */ } } #endif /* UNIV_LOG_ARCHIVE */ - if (!create_new_db && srv_force_recovery == 0) { - /* After a crash recovery we only check that the info in data - dictionary is consistent with what we already know about space - id's from the call of fil_load_single_table_tablespaces(). */ - - dict_check_tablespaces_or_store_max_id(recv_needed_recovery); - } if (srv_measure_contention) { /* os_thread_create(&test_measure_cont, NULL, thread_ids + diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c index f7497ac4090..af4f1979858 100644 --- a/innobase/trx/trx0trx.c +++ b/innobase/trx/trx0trx.c @@ -109,6 +109,9 @@ trx_create( trx->mysql_log_offset = 0; trx->mysql_master_log_file_name = ""; trx->mysql_master_log_pos = 0; + + trx->repl_wait_binlog_name = NULL; + trx->repl_wait_binlog_pos = 0; mutex_create(&(trx->undo_mutex)); mutex_set_level(&(trx->undo_mutex), SYNC_TRX_UNDO); @@ -271,6 +274,11 @@ trx_free( trx_undo_arr_free(trx->undo_no_arr); } + if (trx->repl_wait_binlog_name != NULL) { + + mem_free(trx->repl_wait_binlog_name); + } + ut_a(UT_LIST_GET_LEN(trx->signals) == 0); ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 552f2676bdd..b8ac40cee92 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4977,7 +4977,7 @@ the SQL statement in case of an error. */ int ha_innobase::external_lock( /*=======================*/ - /* out: 0 */ + /* out: 0 or HA_ERR_CRASHED */ THD* thd, /* in: handle to the user thread */ int lock_type) /* in: lock type */ { @@ -4989,19 +4989,6 @@ ha_innobase::external_lock( update_thd(thd); - if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB error:\n" -"MySQL is trying to use a table handle but the .ibd file for\n" -"table %s does not exist.\n" -"Have you deleted the .ibd file from the database directory under\n" -"the MySQL datadir, or have you used DISCARD TABLESPACE?\n" -"Look from section 15.1 of http://www.innodb.com/ibman.html\n" -"how you can resolve the problem.\n", - prebuilt->table->name); - DBUG_RETURN(HA_ERR_CRASHED); - } - trx = prebuilt->trx; prebuilt->sql_stat_start = TRUE; From 10a246e4537a5cb4485d9882cd7db3d652851e4d Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 04:27:09 +0200 Subject: [PATCH 39/54] ha_innodb.cc, row0ins.c, fil0fil.c: Correct typo --- innobase/fil/fil0fil.c | 2 +- innobase/row/row0ins.c | 2 +- sql/ha_innodb.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c index 89648b3feca..d1a083fcd66 100644 --- a/innobase/fil/fil0fil.c +++ b/innobase/fil/fil0fil.c @@ -2885,7 +2885,7 @@ fil_load_single_table_tablespace( } /* We do not use the size information we have about the file, because - the rounding formulat for extents and pages is somewhat complex; we + the rounding formula for extents and pages is somewhat complex; we let fil_node_open() do that task. */ fil_node_create(filepath, 0, space_id, FALSE); diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index f596bd3d473..c82231ef5f6 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1192,7 +1192,7 @@ run_again: dtuple_print(ef, entry); fputs("\nBut the parent table ", ef); ut_print_name(ef, trx, foreign->referenced_table_name); - fputs("\nor its .ind file does not currently exist!\n", ef); + fputs("\nor its .ibd file does not currently exist!\n", ef); mutex_exit(&dict_foreign_err_mutex); return(DB_NO_REFERENCED_ROW); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index b8ac40cee92..7b6fb31acc6 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4977,7 +4977,7 @@ the SQL statement in case of an error. */ int ha_innobase::external_lock( /*=======================*/ - /* out: 0 or HA_ERR_CRASHED */ + /* out: 0 */ THD* thd, /* in: handle to the user thread */ int lock_type) /* in: lock type */ { From 0aa1815bd132f57a47f9f2de7cb332365cdfb48a Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 04:32:37 +0200 Subject: [PATCH 40/54] row0mysql.c: Fix typo --- innobase/row/row0mysql.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 3be3d3e6396..e887079e025 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2128,7 +2128,7 @@ do not allow the discard. We also reserve the data dictionary latch. */ rewind(ef); ut_print_timestamp(ef); - fputs(" Cannot drop table ", ef); + fputs(" Cannot DISCARD table ", ef); ut_print_name(ef, trx, name); fputs("\n" "because it is referenced by ", ef); From cf4a0552855634051d39071c47d03cf5767a34fd Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 04:40:10 +0200 Subject: [PATCH 41/54] ha_innodb.cc: Return a sensible error code from DISCARD TABLESPACE, if it fails because the table is referenced by a FOREIGN KEY --- sql/ha_innodb.cc | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 7b6fb31acc6..14b143ca04b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -278,15 +278,15 @@ convert_error_code_to_mysql( } else if (error == (int) DB_LOCK_WAIT_TIMEOUT) { - /* Since we rolled back the whole transaction, we must - tell it also to MySQL so that MySQL knows to empty the - cached binlog for this transaction */ + /* Since we rolled back the whole transaction, we must + tell it also to MySQL so that MySQL knows to empty the + cached binlog for this transaction */ - if (thd) { - ha_rollback(thd); - } + if (thd) { + ha_rollback(thd); + } - return(HA_ERR_LOCK_WAIT_TIMEOUT); + return(HA_ERR_LOCK_WAIT_TIMEOUT); } else if (error == (int) DB_NO_REFERENCED_ROW) { @@ -3954,11 +3954,9 @@ ha_innobase::discard_or_import_tablespace( err = row_import_tablespace_for_mysql(dict_table->name, trx); } - if (err == DB_SUCCESS) { - DBUG_RETURN(0); - } + err = convert_error_code_to_mysql(err, NULL); - DBUG_RETURN(-1); + DBUG_RETURN(err); } /********************************************************************* From fdffb4b8490a247e55c41a79da7a88e0602ed107 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 05:03:11 +0200 Subject: [PATCH 42/54] sql_table.cc: Return a sensible error code from DISCARD TABLESPACE, if it fails because the table is referenced by a FOREIGN KEY --- sql/sql_table.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c798760cfa8..43f466282b1 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2465,7 +2465,11 @@ err: send_ok(thd); DBUG_RETURN(0); } - DBUG_RETURN(error); + + if (error == HA_ERR_ROW_IS_REFERENCED) + my_error(ER_ROW_IS_REFERENCED, MYF(0)); + + DBUG_RETURN(-1); } From 5eab756a6381da78e30b824f93894b2b86b05f92 Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Mon, 27 Dec 2004 14:05:35 +0200 Subject: [PATCH 43/54] Fix for BUG#7377. This fix adds the same implementation for ha_myisammgr::index_type as in version 5.0. --- mysql-test/r/merge.result | 5 +++++ mysql-test/t/merge.test | 3 +++ sql/ha_myisammrg.cc | 11 +++++++++++ sql/ha_myisammrg.h | 1 + 4 files changed, 20 insertions(+) diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index f71626221cb..79d8f019ce3 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -675,4 +675,9 @@ a b c 1 2 0 1 1 1 1 1 0 +show index from t3; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t3 1 a 1 a A NULL NULL NULL YES BTREE +t3 1 a 2 b A NULL NULL NULL YES BTREE +t3 1 a 3 c A NULL NULL NULL YES BTREE drop table t1, t2, t3; diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index b628cb07f7b..508f9da225e 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -301,5 +301,8 @@ select a,b,c from t3 force index (a) where a=1 order by a,b,c; explain select a,b,c from t3 force index (a) where a=1 order by a desc, b desc, c desc; select a,b,c from t3 force index (a) where a=1 order by a desc, b desc, c desc; +# BUG#7377 SHOW index on MERGE table crashes debug server +show index from t3; + drop table t1, t2, t3; diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index bf4c2a36ffd..bf47b4625e0 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -35,6 +35,17 @@ const char **ha_myisammrg::bas_ext() const { static const char *ext[]= { ".MRG", NullS }; return ext; } +const char *ha_myisammrg::index_type(uint key_number) +{ + return ((table->key_info[key_number].flags & HA_FULLTEXT) ? + "FULLTEXT" : + (table->key_info[key_number].flags & HA_SPATIAL) ? + "SPATIAL" : + (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ? + "RTREE" : + "BTREE"); +} + int ha_myisammrg::open(const char *name, int mode, uint test_if_locked) { diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h index 264c580220c..6058c32c805 100644 --- a/sql/ha_myisammrg.h +++ b/sql/ha_myisammrg.h @@ -32,6 +32,7 @@ class ha_myisammrg: public handler ~ha_myisammrg() {} const char *table_type() const { return "MRG_MyISAM"; } const char **bas_ext() const; + const char *index_type(uint key_number); ulong table_flags() const { return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_READ_RND_SAME | From b8d576d087abbaf8075adb8936d505d0afd872f2 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 17:15:38 +0200 Subject: [PATCH 44/54] row0ins.c: Fix bug: if we dropped a table where an INSERT was waiting for a lock to check a FOREIGN KEY constraint, then an assertion would fail in lock_reset_all_on_table(), since that operation assumes no waiting locks on the table or its records row0mysql.c: Fix bug: InnoDB failed to drop a table in the background drop queue if the table was referenced by a foreign key constraint --- innobase/row/row0ins.c | 26 ++++++++++++++++++++++++++ innobase/row/row0mysql.c | 16 +++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index b9f860903cb..60dbf059673 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -1373,8 +1373,34 @@ row_ins_check_foreign_constraints( row_mysql_freeze_data_dictionary(trx); } + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + (foreign->referenced_table + ->n_foreign_key_checks_running)++; + + mutex_exit(&(dict_sys->mutex)); + } + + /* NOTE that if the thread ends up waiting for a lock + we will release dict_operation_lock temporarily! + But the counter on the table protects the referenced + table from being dropped while the check is running. */ + err = row_ins_check_foreign_constraint(TRUE, foreign, table, entry, thr); + + if (foreign->referenced_table) { + mutex_enter(&(dict_sys->mutex)); + + ut_a(foreign->referenced_table + ->n_foreign_key_checks_running > 0); + (foreign->referenced_table + ->n_foreign_key_checks_running)--; + + mutex_exit(&(dict_sys->mutex)); + } + if (got_s_lock) { row_mysql_unfreeze_data_dictionary(trx); } diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 2e8f7121d2c..ad5efc160c8 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1761,6 +1761,12 @@ row_drop_table_for_mysql_in_background( trx = trx_allocate_for_background(); + /* If the original transaction was dropping a table referenced by + foreign keys, we must set the following to be able to drop the + table: */ + + trx->check_foreigns = FALSE; + /* fputs("InnoDB: Error: Dropping table ", stderr); ut_print_name(stderr, name); fputs(" in background drop list\n", stderr); */ @@ -1834,16 +1840,16 @@ loop: goto already_dropped; } - - if (table->n_mysql_handles_opened > 0 - || table->n_foreign_key_checks_running > 0) { + + if (DB_SUCCESS != row_drop_table_for_mysql_in_background( + drop->table_name)) { + /* If the DROP fails for some table, we return, and let the + main thread retry later */ return(n_tables + n_tables_dropped); } n_tables_dropped++; - - row_drop_table_for_mysql_in_background(drop->table_name); already_dropped: mutex_enter(&kernel_mutex); From 2ca0c44fe31b5b1bf0154699023dfb89d7c1928a Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 17:28:17 +0200 Subject: [PATCH 45/54] row0mysql.c: Merge the two FOREIGN KEY bug fixes from 4.0, and add a TODO comment --- innobase/row/row0mysql.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 47f1f4c444c..e2b89cba866 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -2598,6 +2598,12 @@ row_drop_table_for_mysql( goto funct_exit; } + /* TODO: could we replace the counter n_foreign_key_checks_running + with lock checks on the table? Acquire here an exclusive lock on the + table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that + they can cope with the table having been dropped here? Foreign key + checks take an IS or IX lock on the table. */ + if (table->n_foreign_key_checks_running > 0) { ut_print_timestamp(stderr); From 9682485c1eabd93ee9106831a7c673cbc3699d71 Mon Sep 17 00:00:00 2001 From: "lenz@mysql.com" <> Date: Mon, 27 Dec 2004 18:15:32 +0100 Subject: [PATCH 46/54] - make sure that MYSQL_VERSION_ID created by "configure" does not contain any non-numerical characters (if $VERSION was e.g. "4.1.8a", $MYSQL_VERSION_ID resulted in "40108a", which broke the build as MYSQL_VERSION_ID must be numerical) --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index bc78c9c8764..f8b40872d3d 100644 --- a/configure.in +++ b/configure.in @@ -23,7 +23,7 @@ NDB_VERSION_STATUS="" # Remember that regexps needs to quote [ and ] since this is run through m4 MYSQL_NO_DASH_VERSION=`echo $VERSION | sed -e "s|[[a-z]]*-.*$||"` MYSQL_BASE_VERSION=`echo $MYSQL_NO_DASH_VERSION | sed -e "s|\.[[^.]]*$||"` -MYSQL_VERSION_ID=`echo $MYSQL_NO_DASH_VERSION. | sed -e 's/\./ /g; s/ \([[0-9]]\) / 0\\1 /g; s/ //g'` +MYSQL_VERSION_ID=`echo $MYSQL_NO_DASH_VERSION. | sed -e 's/[[^0-9.]]//g; s/\./ /g; s/ \([[0-9]]\) / 0\\1 /g; s/ //g'` # The port should be constant for a LONG time MYSQL_TCP_PORT_DEFAULT=3306 From 72d446ace5fba03f407b8092d3ab0dcf40099c8a Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 20:06:40 +0200 Subject: [PATCH 47/54] row0mysql.c: Fix the previous bug fix: dropping a table with FOREIGN KEY checks running on it caused a cascade of failed drops while the foreign key check was waiting for a lock --- innobase/row/row0mysql.c | 100 ++++++++++++++++++++++++++------------- 1 file changed, 66 insertions(+), 34 deletions(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index ad5efc160c8..1ab7bb1deb0 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1771,16 +1771,9 @@ row_drop_table_for_mysql_in_background( ut_print_name(stderr, name); fputs(" in background drop list\n", stderr); */ - /* Drop the table in InnoDB */ + /* Try to drop the table in InnoDB */ error = row_drop_table_for_mysql(name, trx, FALSE); - - if (error != DB_SUCCESS) { - ut_print_timestamp(stderr); - fputs(" InnoDB: Error: Dropping table ", stderr); - ut_print_name(stderr, name); - fputs(" in background drop list failed\n", stderr); - } /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -1792,7 +1785,7 @@ row_drop_table_for_mysql_in_background( trx_free_for_background(trx); - return(DB_SUCCESS); + return(error); } /************************************************************************* @@ -1826,6 +1819,7 @@ loop: mutex_exit(&kernel_mutex); if (drop == NULL) { + /* All tables dropped */ return(n_tables + n_tables_dropped); } @@ -1893,21 +1887,21 @@ row_get_background_drop_list_len_low(void) } /************************************************************************* -Adds a table to the list of tables which the master thread drops in -background. We need this on Unix because in ALTER TABLE MySQL may call -drop table even if the table has running queries on it. */ +If a table is not yet in the drop list, adds the table to the list of tables +which the master thread drops in background. We need this on Unix because in +ALTER TABLE MySQL may call drop table even if the table has running queries on +it. Also, if there are running foreign key checks on the table, we drop the +table lazily. */ static -void +ibool row_add_table_to_background_drop_list( /*==================================*/ + /* out: TRUE if the table was not yet in the + drop list, and was added there */ dict_table_t* table) /* in: table */ { row_mysql_drop_t* drop; - drop = mem_alloc(sizeof(row_mysql_drop_t)); - - drop->table_name = mem_strdup(table->name); - mutex_enter(&kernel_mutex); if (!row_mysql_drop_list_inited) { @@ -1915,6 +1909,25 @@ row_add_table_to_background_drop_list( UT_LIST_INIT(row_mysql_drop_list); row_mysql_drop_list_inited = TRUE; } + + /* Look if the table already is in the drop list */ + drop = UT_LIST_GET_FIRST(row_mysql_drop_list); + + while (drop != NULL) { + if (strcmp(drop->table_name, table->name) == 0) { + /* Already in the list */ + + mutex_exit(&kernel_mutex); + + return(FALSE); + } + + drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop); + } + + drop = mem_alloc(sizeof(row_mysql_drop_t)); + + drop->table_name = mem_strdup(table->name); UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop); @@ -1923,6 +1936,8 @@ row_add_table_to_background_drop_list( fputs(" to background drop list\n", stderr); */ mutex_exit(&kernel_mutex); + + return(TRUE); } /************************************************************************* @@ -2157,36 +2172,53 @@ row_drop_table_for_mysql( } if (table->n_mysql_handles_opened > 0) { + ibool added; - ut_print_timestamp(stderr); - fputs(" InnoDB: Warning: MySQL is trying to drop table ", - stderr); - ut_print_name(stderr, table->name); - fputs("\n" - "InnoDB: though there are still open handles to it.\n" - "InnoDB: Adding the table to the background drop queue.\n", + added = row_add_table_to_background_drop_list(table); + + if (added) { + ut_print_timestamp(stderr); +fputs(" InnoDB: Warning: MySQL is trying to drop table ", stderr); + ut_print_name(stderr, table->name); + fputs("\n" +"InnoDB: though there are still open handles to it.\n" +"InnoDB: Adding the table to the background drop queue.\n", stderr); + + /* We return DB_SUCCESS to MySQL though the drop will + happen lazily later */ - row_add_table_to_background_drop_list(table); - - err = DB_SUCCESS; + err = DB_SUCCESS; + } else { + /* The table is already in the background drop list */ + err = DB_ERROR; + } goto funct_exit; } if (table->n_foreign_key_checks_running > 0) { + ibool added; - ut_print_timestamp(stderr); - fputs(" InnoDB: You are trying to drop table ", stderr); + added = row_add_table_to_background_drop_list(table); + + if (added) { + ut_print_timestamp(stderr); +fputs(" InnoDB: You are trying to drop table ", stderr); ut_print_name(stderr, table->name); - fputs("\n" - "InnoDB: though there is a foreign key check running on it.\n" - "InnoDB: Adding the table to the background drop queue.\n", + fputs("\n" +"InnoDB: though there is a foreign key check running on it.\n" +"InnoDB: Adding the table to the background drop queue.\n", stderr); - row_add_table_to_background_drop_list(table); + /* We return DB_SUCCESS to MySQL though the drop will + happen lazily later */ - err = DB_SUCCESS; + err = DB_SUCCESS; + } else { + /* The table is already in the background drop list */ + err = DB_ERROR; + } goto funct_exit; } From 967fac4ef6270d4cd458c8f40024b58c167c1c04 Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Mon, 27 Dec 2004 19:10:30 +0100 Subject: [PATCH 48/54] WL#2319 V2: Exclude tables from dump - Added a hash to keep track of database-table pairs. - Specified database-table tables do not get dumped --- client/client_priv.h | 1 + client/mysqldump.c | 106 +++++++++++++++++++++++++++++++--- mysql-test/r/mysqldump.result | 33 +++++++++++ mysql-test/t/mysqldump.test | 12 ++++ 4 files changed, 145 insertions(+), 7 deletions(-) diff --git a/client/client_priv.h b/client/client_priv.h index e86a56f58c1..95f4d105156 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -49,4 +49,5 @@ enum options_client #ifdef HAVE_NDBCLUSTER_DB ,OPT_NDBCLUSTER,OPT_NDB_CONNECTSTRING #endif + ,OPT_IGNORE_TABLE }; diff --git a/client/mysqldump.c b/client/mysqldump.c index be2abd19822..ffdb84397e9 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "client_priv.h" #include "mysql.h" @@ -128,6 +129,16 @@ const char *compatible_mode_names[]= TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, "", compatible_mode_names, NULL}; +#define TABLE_RULE_HASH_SIZE 16 + +typedef struct st_table_rule_ent +{ + char* key; /* dbname.tablename */ + uint key_len; +} TABLE_RULE_ENT; + +my_bool ignore_table_inited; +HASH ignore_table; static struct my_option my_long_options[] = { @@ -233,6 +244,11 @@ static struct my_option my_long_options[] = (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", (gptr*) ¤t_host, (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"ignore-table", OPT_IGNORE_TABLE, + "Do not dump the specified table. To specify more than one table to ignore, " + "use the directive multiple times, once for each table. Each table must " + "be specified with both database and table names, e.g. --ignore-table=database.table", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -502,6 +518,32 @@ static void write_footer(FILE *sql_file) } /* write_footer */ +static void free_table_ent(TABLE_RULE_ENT* e) +{ + my_free((gptr) e, MYF(0)); +} + + +static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, + my_bool not_used __attribute__((unused))) +{ + *len= e->key_len; + return (byte*)e->key; +} + + +void init_table_rule_hash(HASH* h, bool* h_inited) +{ + if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0, + (hash_get_key) get_table_key, + (hash_free_key) free_table_ent, 0)) + { + fprintf(stderr, "Internal hash initialization error\n"); + exit(1); + } + *h_inited= 1; +} + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), @@ -573,6 +615,37 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case (int) OPT_TABLES: opt_databases=0; break; + case (int) OPT_IGNORE_TABLE: + { + const char* dot = strchr(argument, '.'); + if (!dot) + { + fprintf(stderr, "Illegal use of option --ignore-table=.\n"); + exit(1); + } + // len is always > 0 because we know the there exists a '.' + uint len= (uint)strlen(argument); + TABLE_RULE_ENT* e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + + len, MYF(MY_WME)); + if (!e) + { + fprintf(stderr, "Internal memory allocation error\n"); + exit(1); + } + e->key= (char*)e + sizeof(TABLE_RULE_ENT); + e->key_len= len; + memcpy(e->key, argument, len); + + if (!ignore_table_inited) + init_table_rule_hash(&ignore_table, &ignore_table_inited); + + if(my_hash_insert(&ignore_table, (byte*)e)) + { + fprintf(stderr, "Internal hash insert error\n"); + exit(1); + } + break; + } case (int) OPT_COMPATIBLE: { char buff[255]; @@ -1946,6 +2019,15 @@ static int init_dumping(char *database) } /* init_dumping */ +my_bool include_table(byte* hash_key, uint len) +{ + if (ignore_table_inited && + hash_search(&ignore_table, (byte*) hash_key, len)) + return FALSE; + + return TRUE; +} + static int dump_all_tables_in_db(char *database) { @@ -1953,6 +2035,12 @@ static int dump_all_tables_in_db(char *database) uint numrows; char table_buff[NAME_LEN*2+3]; + char hash_key[2*NAME_LEN+2]; /* "db.tablename" */ + char *afterdot; + + afterdot= strmov(hash_key, database); + *afterdot++= '.'; + if (init_dumping(database)) return 1; if (opt_xml) @@ -1961,7 +2049,7 @@ static int dump_all_tables_in_db(char *database) { DYNAMIC_STRING query; init_dynamic_string(&query, "LOCK TABLES ", 256, 1024); - for (numrows=0 ; (table = getTableName(1)) ; numrows++) + for (numrows= 0 ; (table= getTableName(1)) ; numrows++) { dynstr_append(&query, quote_name(table, table_buff, 1)); dynstr_append(&query, " READ /*!32311 LOCAL */,"); @@ -1977,13 +2065,17 @@ static int dump_all_tables_in_db(char *database) DBerror(sock, "when doing refresh"); /* We shall continue here, if --force was given */ } - while ((table = getTableName(0))) + while ((table= getTableName(0))) { - numrows = getTableStructure(table, database); - if (!dFlag && numrows > 0) - dumpTable(numrows,table); - my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); - order_by= 0; + char *end= strmov(afterdot, table); + if (include_table(hash_key, end - hash_key)) + { + numrows = getTableStructure(table, database); + if (!dFlag && numrows > 0) + dumpTable(numrows,table); + my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); + order_by= 0; + } } if (opt_xml) { diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 57e04d38fc1..623bd2a0f3c 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -480,3 +480,36 @@ UNLOCK TABLES; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; DROP TABLE t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (4),(5),(6); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +LOCK TABLES `t2` WRITE; +INSERT INTO `t2` VALUES (4),(5),(6); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; + +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 07b33689196..255ae50a8ca 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -153,3 +153,15 @@ INSERT INTO t1 VALUES (_latin1 ' --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=cp850 --compatible=mysql323 test t1 --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=utf8 --compatible=mysql323 test t1 DROP TABLE t1; + +# +# WL #2319: Exclude Tables from dump +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (4),(5),(6); +--exec $MYSQL_DUMP --skip-comments --ignore-table=test.t1 test +DROP TABLE t1; +DROP TABLE t2; From 2f9c038ecfd09c37a2ce45a2307c2c627df5799a Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Mon, 27 Dec 2004 21:22:06 +0200 Subject: [PATCH 49/54] row0mysql.c: Manually merge the latest FOREIGN KEY lock wait + DROP TABLE fix from 4.0 --- innobase/row/row0mysql.c | 105 +++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 36 deletions(-) diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index e2b89cba866..b7cd730828a 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1843,16 +1843,9 @@ row_drop_table_for_mysql_in_background( ut_print_name(stderr, name); fputs(" in background drop list\n", stderr); */ - /* Drop the table in InnoDB */ + /* Try to drop the table in InnoDB */ error = row_drop_table_for_mysql(name, trx, FALSE); - - if (error != DB_SUCCESS) { - ut_print_timestamp(stderr); - fputs(" InnoDB: Error: Dropping table ", stderr); - ut_print_name(stderr, trx, name); - fputs(" in background drop list failed\n", stderr); - } /* Flush the log to reduce probability that the .frm files and the InnoDB data dictionary get out-of-sync if the user runs @@ -1864,7 +1857,7 @@ row_drop_table_for_mysql_in_background( trx_free_for_background(trx); - return(DB_SUCCESS); + return(error); } /************************************************************************* @@ -1898,6 +1891,7 @@ loop: mutex_exit(&kernel_mutex); if (drop == NULL) { + /* All tables dropped */ return(n_tables + n_tables_dropped); } @@ -1965,21 +1959,21 @@ row_get_background_drop_list_len_low(void) } /************************************************************************* -Adds a table to the list of tables which the master thread drops in -background. We need this on Unix because in ALTER TABLE MySQL may call -drop table even if the table has running queries on it. */ +If a table is not yet in the drop list, adds the table to the list of tables +which the master thread drops in background. We need this on Unix because in +ALTER TABLE MySQL may call drop table even if the table has running queries on +it. Also, if there are running foreign key checks on the table, we drop the +table lazily. */ static -void +ibool row_add_table_to_background_drop_list( /*==================================*/ + /* out: TRUE if the table was not yet in the + drop list, and was added there */ dict_table_t* table) /* in: table */ { row_mysql_drop_t* drop; - drop = mem_alloc(sizeof(row_mysql_drop_t)); - - drop->table_name = mem_strdup(table->name); - mutex_enter(&kernel_mutex); if (!row_mysql_drop_list_inited) { @@ -1987,7 +1981,26 @@ row_add_table_to_background_drop_list( UT_LIST_INIT(row_mysql_drop_list); row_mysql_drop_list_inited = TRUE; } + + /* Look if the table already is in the drop list */ + drop = UT_LIST_GET_FIRST(row_mysql_drop_list); + while (drop != NULL) { + if (strcmp(drop->table_name, table->name) == 0) { + /* Already in the list */ + + mutex_exit(&kernel_mutex); + + return(FALSE); + } + + drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop); + } + + drop = mem_alloc(sizeof(row_mysql_drop_t)); + + drop->table_name = mem_strdup(table->name); + UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop); /* fputs("InnoDB: Adding table ", stderr); @@ -1995,6 +2008,8 @@ row_add_table_to_background_drop_list( fputs(" to background drop list\n", stderr); */ mutex_exit(&kernel_mutex); + + return(TRUE); } /************************************************************************* @@ -2347,7 +2362,7 @@ funct_exit: } /************************************************************************* -Drops a table for MySQL. If the name of the table to be dropped is equal +Drops a table for MySQL. If the name of the table to be dropped is equal with one of the predefined magic table names, then this also stops printing the corresponding monitor output by the master thread. */ @@ -2581,19 +2596,27 @@ row_drop_table_for_mysql( } if (table->n_mysql_handles_opened > 0) { + ibool added; - ut_print_timestamp(stderr); - fputs(" InnoDB: Warning: MySQL is trying to drop table ", - stderr); - ut_print_name(stderr, trx, table->name); - fputs("\n" - "InnoDB: though there are still open handles to it.\n" - "InnoDB: Adding the table to the background drop queue.\n", + added = row_add_table_to_background_drop_list(table); + + if (added) { + ut_print_timestamp(stderr); +fputs(" InnoDB: Warning: MySQL is trying to drop table ", stderr); + ut_print_name(stderr, trx, table->name); + fputs("\n" +"InnoDB: though there are still open handles to it.\n" +"InnoDB: Adding the table to the background drop queue.\n", stderr); + + /* We return DB_SUCCESS to MySQL though the drop will + happen lazily later */ - row_add_table_to_background_drop_list(table); - - err = DB_SUCCESS; + err = DB_SUCCESS; + } else { + /* The table is already in the background drop list */ + err = DB_ERROR; + } goto funct_exit; } @@ -2606,17 +2629,27 @@ row_drop_table_for_mysql( if (table->n_foreign_key_checks_running > 0) { - ut_print_timestamp(stderr); - fputs(" InnoDB: You are trying to drop table ", stderr); - ut_print_name(stderr, trx, table->name); - fputs("\n" - "InnoDB: though there is a foreign key check running on it.\n" - "InnoDB: Adding the table to the background drop queue.\n", + ibool added; + + added = row_add_table_to_background_drop_list(table); + + if (added) { + ut_print_timestamp(stderr); +fputs(" InnoDB: You are trying to drop table ", stderr); + ut_print_name(stderr, trx, table->name); + fputs("\n" +"InnoDB: though there is a foreign key check running on it.\n" +"InnoDB: Adding the table to the background drop queue.\n", stderr); - row_add_table_to_background_drop_list(table); + /* We return DB_SUCCESS to MySQL though the drop will + happen lazily later */ - err = DB_SUCCESS; + err = DB_SUCCESS; + } else { + /* The table is already in the background drop list */ + err = DB_ERROR; + } goto funct_exit; } From 064c73490b7266bc00cb2a6668332414673b4cec Mon Sep 17 00:00:00 2001 From: "timour@mysql.com" <> Date: Tue, 28 Dec 2004 11:57:56 +0200 Subject: [PATCH 50/54] Fix for BUG#7455. The fix checks if the trim string argument is NULL. If so, the standard mandates that the function result must be also NULL. --- mysql-test/r/func_str.result | 6 ++++++ mysql-test/t/func_str.test | 8 ++++++++ sql/item_strfunc.cc | 11 ++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result index 1c560dfa8b4..8348ef12b0d 100644 --- a/mysql-test/r/func_str.result +++ b/mysql-test/r/func_str.result @@ -697,3 +697,9 @@ quote(ltrim(concat(' ', 'a'))) select quote(trim(concat(' ', 'a'))); quote(trim(concat(' ', 'a'))) 'a' +select trim(null from 'kate') as "must_be_null"; +must_be_null +NULL +select trim('xyz' from null) as "must_be_null"; +must_be_null +NULL diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test index 5477a0ccb30..a5d95332caa 100644 --- a/mysql-test/t/func_str.test +++ b/mysql-test/t/func_str.test @@ -435,3 +435,11 @@ drop table t1; select quote(ltrim(concat(' ', 'a'))); select quote(trim(concat(' ', 'a'))); + +# +# Bug#7455 unexpected result: TRIM( FROM ) gives NOT NULL +# According to ANSI if one of the TRIM arguments is NULL, then the result +# must be NULL too. +# +select trim(null from 'kate') as "must_be_null"; +select trim('xyz' from null) as "must_be_null"; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 068878652e4..2a63c5355a4 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1302,9 +1302,18 @@ String *Item_func_trim::val_str(String *str) return 0; /* purecov: inspected */ char buff[MAX_FIELD_WIDTH]; String tmp(buff,sizeof(buff),res->charset()); - String *remove_str= (arg_count==2) ? args[1]->val_str(&tmp) : &remove; uint remove_length; LINT_INIT(remove_length); + String *remove_str; /* The string to remove from res. */ + + if (arg_count == 2) + { + remove_str= args[1]->val_str(&tmp); + if ((null_value= args[1]->null_value)) + return 0; + } + else + remove_str= &remove; /* Default value. */ if (!remove_str || (remove_length=remove_str->length()) == 0 || remove_length > res->length()) From cf6e2214d8b4660c4fa2dfd16ed10f0a30409a43 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 28 Dec 2004 17:33:49 +0100 Subject: [PATCH 51/54] client/mysqldump.c compilation failure fixed cleanup --- client/mysqldump.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index ffdb84397e9..98de9e0b069 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -137,7 +137,6 @@ typedef struct st_table_rule_ent uint key_len; } TABLE_RULE_ENT; -my_bool ignore_table_inited; HASH ignore_table; static struct my_option my_long_options[] = @@ -532,16 +531,12 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, } -void init_table_rule_hash(HASH* h, bool* h_inited) +void init_table_rule_hash(HASH* h) { if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0, (hash_get_key) get_table_key, (hash_free_key) free_table_ent, 0)) - { - fprintf(stderr, "Internal hash initialization error\n"); - exit(1); - } - *h_inited= 1; + exit(EX_EOM); } @@ -617,37 +612,30 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case (int) OPT_IGNORE_TABLE: { - const char* dot = strchr(argument, '.'); - if (!dot) + uint len= (uint)strlen(argument); + TABLE_RULE_ENT* e; + if (!strchr(argument, '.')) { fprintf(stderr, "Illegal use of option --ignore-table=.
\n"); exit(1); } - // len is always > 0 because we know the there exists a '.' - uint len= (uint)strlen(argument); - TABLE_RULE_ENT* e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) - + len, MYF(MY_WME)); - if (!e) - { - fprintf(stderr, "Internal memory allocation error\n"); - exit(1); - } + /* len is always > 0 because we know the there exists a '.' */ + e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME)); + if (!e) + exit(EX_EOM); e->key= (char*)e + sizeof(TABLE_RULE_ENT); e->key_len= len; memcpy(e->key, argument, len); - if (!ignore_table_inited) - init_table_rule_hash(&ignore_table, &ignore_table_inited); - + if (!hash_inited(&ignore_table)) + init_table_rule_hash(&ignore_table); + if(my_hash_insert(&ignore_table, (byte*)e)) - { - fprintf(stderr, "Internal hash insert error\n"); - exit(1); - } + exit(EX_EOM); break; } case (int) OPT_COMPATIBLE: - { + { char buff[255]; char *end= compatible_mode_normal_str; int i; @@ -2021,8 +2009,7 @@ static int init_dumping(char *database) my_bool include_table(byte* hash_key, uint len) { - if (ignore_table_inited && - hash_search(&ignore_table, (byte*) hash_key, len)) + if (hash_search(&ignore_table, (byte*) hash_key, len)) return FALSE; return TRUE; From 2aa98f89aaaad9b386c1712a03efa2ec9e9e93b4 Mon Sep 17 00:00:00 2001 From: "heikki@hundin.mysql.fi" <> Date: Wed, 29 Dec 2004 17:06:26 +0200 Subject: [PATCH 52/54] srv0start.c: Print a more descriptive error and refuse to start InnoDB if the size of ibdata files is smaller than what is stored in the tablespace header; innodb_force_recovery will override this --- innobase/srv/srv0start.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index c91db1f0dcc..7a61a885ef9 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1528,6 +1528,21 @@ NetWare. */ "InnoDB: the sum of data file sizes is %lu pages\n", (ulong) tablespace_size_in_header, (ulong) sum_of_data_file_sizes); + + if (srv_force_recovery == 0 + && sum_of_data_file_sizes < tablespace_size_in_header) { + /* This is a fatal error, the tail of a tablespace is + missing */ + + fprintf(stderr, +"InnoDB: Cannot start InnoDB. The tail of the system tablespace is\n" +"InnoDB: missing. Have you edited innodb_data_file_path in my.cnf in an\n" +"InnoDB: inappropriate way, removing ibdata files from there?\n" +"InnoDB: You can set innodb_force_recovery=1 in my.cnf to force\n" +"InnoDB: a startup if you are trying to recover a badly corrupt database.\n"); + + return(DB_ERROR); + } } if (srv_auto_extend_last_data_file @@ -1538,6 +1553,18 @@ NetWare. */ "InnoDB: the sum of data file sizes is only %lu pages\n", (ulong) tablespace_size_in_header, (ulong) sum_of_data_file_sizes); + + if (srv_force_recovery == 0) { + + fprintf(stderr, +"InnoDB: Cannot start InnoDB. The tail of the system tablespace is\n" +"InnoDB: missing. Have you edited innodb_data_file_path in my.cnf in an\n" +"InnoDB: inappropriate way, removing ibdata files from there?\n" +"InnoDB: You can set innodb_force_recovery=1 in my.cnf to force\n" +"InnoDB: a startup if you are trying to recover a badly corrupt database.\n"); + + return(DB_ERROR); + } } /* Check that os_fast_mutexes work as expected */ From 12bf7dcd048bd93c7a905b343afb86bed83fd01d Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Thu, 30 Dec 2004 21:01:11 +0100 Subject: [PATCH 53/54] unsufficient privilege checks in GRANT, when a grantor has column-level privileges --- mysql-test/r/alter_table.result | 2 +- mysql-test/r/grant.result | 2 +- mysql-test/r/grant_cache.result | 6 +- sql/sql_acl.cc | 100 ++++++++++++++++---------------- 4 files changed, 55 insertions(+), 55 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index e7a8d2c7cdf..78925a64e93 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -121,7 +121,7 @@ create database mysqltest; create table mysqltest.t1 (a int,b int,c int); grant all on mysqltest.t1 to mysqltest_1@localhost; alter table t1 rename t2; -insert command denied to user: 'mysqltest_1@localhost' for table 't2' +INSERT,CREATE command denied to user: 'mysqltest_1@localhost' for table 't2' revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; delete from mysql.user where user='mysqltest_1'; drop database mysqltest; diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index 19d83a95c5e..9df50a242d7 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -198,7 +198,7 @@ GRANT UPDATE (d) ON `mysqltest_2`.`t2` TO 'mysqltest_3'@'localhost' update mysqltest_1.t1, mysqltest_1.t2 set q=10 where b=1; UPDATE command denied to user: 'mysqltest_3@localhost' for column 'q' in table 't1' update mysqltest_1.t1, mysqltest_2.t2 set d=20 where d=1; -select command denied to user: 'mysqltest_3@localhost' for table 't1' +SELECT command denied to user: 'mysqltest_3@localhost' for table 't1' update mysqltest_2.t1, mysqltest_1.t2 set c=20 where b=1; UPDATE command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1' update mysqltest_2.t1, mysqltest_2.t2 set d=10 where s=2; diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result index 96eb9d2bc62..e31294154bb 100644 --- a/mysql-test/r/grant_cache.result +++ b/mysql-test/r/grant_cache.result @@ -121,7 +121,7 @@ a b c a 1 1 1 test.t1 2 2 2 test.t1 select * from t2; -select command denied to user: 'mysqltest_2@localhost' for table 't2' +SELECT command denied to user: 'mysqltest_2@localhost' for table 't2' show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 6 @@ -135,7 +135,7 @@ select "user3"; user3 user3 select * from t1; -select command denied to user: 'mysqltest_3@localhost' for column 'b' in table 't1' +SELECT command denied to user: 'mysqltest_3@localhost' for column 'b' in table 't1' select a from t1; a 1 @@ -143,7 +143,7 @@ a select c from t1; SELECT command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1' select * from t2; -select command denied to user: 'mysqltest_3@localhost' for table 't2' +SELECT command denied to user: 'mysqltest_3@localhost' for table 't2' select mysqltest.t1.c from test.t1,mysqltest.t1; SELECT command denied to user: 'mysqltest_3@localhost' for column 'c' in table 't1' show status like "Qcache_queries_in_cache"; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1b55168695b..c883407970a 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2134,37 +2134,57 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(-1); } - if (columns.elements && !revoke_grant) + if (!revoke_grant) { - TABLE *table; - class LEX_COLUMN *column; - List_iterator column_iter(columns); + if (columns.elements && !revoke_grant) + { + TABLE *table; + class LEX_COLUMN *column; + List_iterator column_iter(columns); - if (!(table=open_ltable(thd,table_list,TL_READ))) - DBUG_RETURN(-1); - while ((column = column_iter++)) - { - if (!find_field_in_table(thd,table,column->column.ptr(), - column->column.length(),0,0)) + if (!(table=open_ltable(thd,table_list,TL_READ))) + DBUG_RETURN(-1); + while ((column = column_iter++)) { - my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), - column->column.c_ptr(), table_list->alias); - DBUG_RETURN(-1); + Field *f= find_field_in_table(thd,table,column->column.ptr(), + column->column.length(),1,0); + if (!f) + { + my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), + column->column.c_ptr(), table_list->alias); + DBUG_RETURN(-1); + } + if (f == (Field*)-1) + { + DBUG_RETURN(-1); + } + column_priv|= column->rights; } - column_priv|= column->rights; + close_thread_tables(thd); } - close_thread_tables(thd); - } - else if (!(rights & CREATE_ACL) && !revoke_grant) - { - char buf[FN_REFLEN]; - sprintf(buf,"%s/%s/%s.frm",mysql_data_home, table_list->db, - table_list->real_name); - fn_format(buf,buf,"","",4+16+32); - if (access(buf,F_OK)) + else { - my_error(ER_NO_SUCH_TABLE,MYF(0),table_list->db, table_list->alias); - DBUG_RETURN(-1); + if (!(rights & CREATE_ACL)) + { + char buf[FN_REFLEN]; + sprintf(buf,"%s/%s/%s.frm",mysql_data_home, table_list->db, + table_list->real_name); + fn_format(buf,buf,"","",4+16+32); + if (access(buf,F_OK)) + { + my_error(ER_NO_SUCH_TABLE,MYF(0),table_list->db, table_list->alias); + DBUG_RETURN(-1); + } + } + if (table_list->grant.want_privilege) + { + char command[128]; + get_privilege_desc(command, sizeof(command), + table_list->grant.want_privilege); + my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), + command, thd->priv_user, thd->host_or_ip, table_list->alias); + DBUG_RETURN(-1); + } } } @@ -2189,7 +2209,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, */ if (thd->slave_thread && table_rules_on) { - /* + /* The tables must be marked "updating" so that tables_ok() takes them into account in tests. */ @@ -2636,25 +2656,8 @@ err: pthread_mutex_unlock(&LOCK_grant); if (!no_errors) // Not a silent skip of table { - const char *command=""; - if (want_access & SELECT_ACL) - command ="select"; - else if (want_access & INSERT_ACL) - command = "insert"; - else if (want_access & UPDATE_ACL) - command = "update"; - else if (want_access & DELETE_ACL) - command = "delete"; - else if (want_access & DROP_ACL) - command = "drop"; - else if (want_access & CREATE_ACL) - command = "create"; - else if (want_access & ALTER_ACL) - command = "alter"; - else if (want_access & INDEX_ACL) - command = "index"; - else if (want_access & GRANT_ACL) - command = "grant"; + char command[128]; + get_privilege_desc(command, sizeof(command), want_access); net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR, command, thd->priv_user, @@ -2767,11 +2770,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) err: pthread_mutex_unlock(&LOCK_grant); - const char *command=""; - if (want_access & SELECT_ACL) - command ="select"; - else if (want_access & INSERT_ACL) - command = "insert"; + char command[128]; + get_privilege_desc(command, sizeof(command), want_access); my_printf_error(ER_COLUMNACCESS_DENIED_ERROR, ER(ER_COLUMNACCESS_DENIED_ERROR), MYF(0), From 45ce994e5dc31c6eb802c3b8eb8955c320a4c111 Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Fri, 31 Dec 2004 11:52:14 +0100 Subject: [PATCH 54/54] post-merge --- mysql-test/r/alter_table.result | 2 +- mysql-test/r/grant2.result | 17 ++++++++++++++--- mysql-test/r/grant_cache.result | 6 +++--- mysql-test/r/ps_1general.result | 4 ++-- mysql-test/r/timezone2.result | 4 ++-- mysql-test/r/variables.result | 6 +++--- mysql-test/t/grant2.test | 28 ++++++++++++++++++++++++---- mysql-test/t/multi_update.test | 2 ++ mysql-test/t/variables.test | 4 ++-- sql/sql_acl.cc | 3 +-- 10 files changed, 54 insertions(+), 22 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 5a47110dda3..a7ae8bc310c 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -121,7 +121,7 @@ create database mysqltest; create table mysqltest.t1 (a int,b int,c int); grant all on mysqltest.t1 to mysqltest_1@localhost; alter table t1 rename t2; -ERROR 42000: INSERT,CREATE command denied to user: 'mysqltest_1@localhost' for table 't2' +ERROR 42000: INSERT,CREATE command denied to user 'mysqltest_1'@'localhost' for table 't2' revoke all privileges on mysqltest.t1 from mysqltest_1@localhost; delete from mysql.user where user=_binary'mysqltest_1'; drop database mysqltest; diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index a31fa2ac3dc..6d8bdbaf8f9 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -37,7 +37,6 @@ show grants for current_user(); Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' GRANT SELECT, INSERT ON `mysqltest`.* TO 'mysqltest_1'@'localhost' -use mysqltest; insert into t1 values (1, 'I can''t change it!'); update t1 set data='I can change it!' where id = 1; ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest' @@ -47,8 +46,20 @@ select * from t1; id data 1 I can't change it! drop table t1; -drop database mysqltest; -use test; delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.db where user like 'mysqltest\_%'; flush privileges; +create table t1 (a int, b int); +grant select (a) on t1 to mysqltest_1@localhost with grant option; +grant select (a,b) on t1 to mysqltest_2@localhost; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't1' +grant select on t1 to mysqltest_3@localhost; +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 't1' +drop table t1; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; +drop database mysqltest; +use test; diff --git a/mysql-test/r/grant_cache.result b/mysql-test/r/grant_cache.result index b3e16f1fcf0..d905e9319fd 100644 --- a/mysql-test/r/grant_cache.result +++ b/mysql-test/r/grant_cache.result @@ -134,7 +134,7 @@ a b c a 1 1 1 test.t1 2 2 2 test.t1 select * from t2; -ERROR 42000: SELECT command denied to user: 'mysqltest_2@localhost' for table 't2' +ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2' show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 6 @@ -148,7 +148,7 @@ select "user3"; user3 user3 select * from t1; -ERROR 42000: SELECT command denied to user: 'mysqltest_3@localhost' for column 'b' in table 't1' +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'b' in table 't1' select a from t1; a 1 @@ -156,7 +156,7 @@ a select c from t1; ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'c' in table 't1' select * from t2; -ERROR 42000: SELECT command denied to user: 'mysqltest_3@localhost' for table 't2' +ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for table 't2' select mysqltest.t1.c from test.t1,mysqltest.t1; ERROR 42000: SELECT command denied to user 'mysqltest_3'@'localhost' for column 'c' in table 't1' show status like "Qcache_queries_in_cache"; diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index 5f8cb2597c6..25b9e2dcda4 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -834,7 +834,7 @@ execute s_t9 ; my_col 1 select a as my_col from t1; -ERROR 42000: select command denied to user 'second_user'@'localhost' for table 't1' +ERROR 42000: SELECT command denied to user 'second_user'@'localhost' for table 't1' grant select on mysqltest.t1 to second_user@localhost identified by 'looser' ; show grants for second_user@localhost ; @@ -873,7 +873,7 @@ Grants for second_user@localhost GRANT USAGE ON *.* TO 'second_user'@'localhost' IDENTIFIED BY PASSWORD '*13843FE600B19A81E32AF50D4A6FED25875FF1F3' GRANT SELECT ON `mysqltest`.`t9` TO 'second_user'@'localhost' execute s_t1 ; -ERROR 42000: select command denied to user 'second_user'@'localhost' for table 't1' +ERROR 42000: SELECT command denied to user 'second_user'@'localhost' for table 't1' revoke all privileges, grant option from second_user@localhost ; show grants for second_user@localhost ; Grants for second_user@localhost diff --git a/mysql-test/r/timezone2.result b/mysql-test/r/timezone2.result index 1c98fd18a08..a1a2fec739f 100644 --- a/mysql-test/r/timezone2.result +++ b/mysql-test/r/timezone2.result @@ -295,9 +295,9 @@ convert_tz(b, 'Europe/Moscow', 'UTC') update t1, t2 set t1.b = convert_tz('2004-11-30 12:00:00', 'Europe/Moscow', 'UTC') where t1.a = t2.c and t2.d = (select max(d) from t2); select * from mysql.time_zone_name; -ERROR 42000: select command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name' +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name' select Name, convert_tz('2004-11-30 12:00:00', Name, 'UTC') from mysql.time_zone_name; -ERROR 42000: select command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name' +ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for table 'time_zone_name' delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.db where user like 'mysqltest\_%'; delete from mysql.tables_priv where user like 'mysqltest\_%'; diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index 01db98648bd..6b700f7f6a2 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -115,13 +115,13 @@ set global concurrent_insert=DEFAULT; show variables like 'concurrent_insert'; Variable_name Value concurrent_insert ON -set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="INNODB"; +set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="MERGE"; show local variables like 'storage_engine'; Variable_name Value storage_engine HEAP show global variables like 'storage_engine'; Variable_name Value -storage_engine InnoDB +storage_engine MERGE set GLOBAL query_cache_size=100000; set GLOBAL myisam_max_sort_file_size=2000000; show global variables like 'myisam_max_sort_file_size'; @@ -220,7 +220,7 @@ set max_join_size="hello"; ERROR 42000: Incorrect argument type to variable 'max_join_size' set storage_engine=UNKNOWN_TABLE_TYPE; ERROR 42000: Unknown table engine 'UNKNOWN_TABLE_TYPE' -set storage_engine=INNODB, big_tables=2; +set storage_engine=MERGE, big_tables=2; ERROR 42000: Variable 'big_tables' can't be set to the value of '2' show local variables like 'storage_engine'; Variable_name Value diff --git a/mysql-test/t/grant2.test b/mysql-test/t/grant2.test index f86be0c95b9..7060d35e9a4 100644 --- a/mysql-test/t/grant2.test +++ b/mysql-test/t/grant2.test @@ -50,10 +50,9 @@ flush privileges; use mysqltest; create table t1 (id int primary key, data varchar(255)); -connect (mrbad, localhost, mysqltest_1,,); +connect (mrbad, localhost, mysqltest_1,,mysqltest); connection mrbad; show grants for current_user(); -use mysqltest; insert into t1 values (1, 'I can''t change it!'); --error 1044 update t1 set data='I can change it!' where id = 1; @@ -61,11 +60,32 @@ update t1 set data='I can change it!' where id = 1; --error 1044 insert into t1 values (1, 'XXX') on duplicate key update data= 'I can change it!'; select * from t1; +disconnect mrbad; connection default; drop table t1; -drop database mysqltest; -use test; delete from mysql.user where user like 'mysqltest\_%'; delete from mysql.db where user like 'mysqltest\_%'; flush privileges; + +create table t1 (a int, b int); +grant select (a) on t1 to mysqltest_1@localhost with grant option; +connect (mrugly, localhost, mysqltest_1,,mysqltest); +connection mrugly; +--error 1143 +grant select (a,b) on t1 to mysqltest_2@localhost; +--error 1142 +grant select on t1 to mysqltest_3@localhost; +disconnect mrugly; + +connection default; +drop table t1; +delete from mysql.user where user like 'mysqltest\_%'; +delete from mysql.db where user like 'mysqltest\_%'; +delete from mysql.tables_priv where user like 'mysqltest\_%'; +delete from mysql.columns_priv where user like 'mysqltest\_%'; +flush privileges; + +drop database mysqltest; +use test; + diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test index e90de399500..4035099ec7e 100644 --- a/mysql-test/t/multi_update.test +++ b/mysql-test/t/multi_update.test @@ -433,6 +433,7 @@ delete t1 from t1,t2 where t1.col1 < (select max(col1) from t1) and t1.col1 = t2 drop table t1,t2; # Test for BUG#5837 - delete with outer join and const tables +--disable_warnings create table t1 ( aclid bigint not null primary key, status tinyint(1) not null @@ -442,6 +443,7 @@ create table t2 ( refid bigint not null primary key, aclid bigint, index idx_acl(aclid) ) engine = innodb; +--enable_warnings insert into t2 values(1,null); delete t2, t1 from t2 left join t1 on (t2.aclid=t1.aclid) where t2.refid='1'; drop table t1, t2; diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index 7dc07f9313e..3a76ae5136e 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -71,7 +71,7 @@ show variables like 'concurrent_insert'; set global concurrent_insert=DEFAULT; show variables like 'concurrent_insert'; -set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="INNODB"; +set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="MERGE"; show local variables like 'storage_engine'; show global variables like 'storage_engine'; set GLOBAL query_cache_size=100000; @@ -128,7 +128,7 @@ set max_join_size="hello"; --error 1286 set storage_engine=UNKNOWN_TABLE_TYPE; --error 1231 -set storage_engine=INNODB, big_tables=2; +set storage_engine=MERGE, big_tables=2; show local variables like 'storage_engine'; --error 1229 set SESSION query_cache_size=10000; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5579aa9b3f5..2c11d1c87ad 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -964,9 +964,8 @@ static void acl_insert_db(const char *user, const char *host, const char *db, ulong acl_get(const char *host, const char *ip, const char *user, const char *db, my_bool db_is_pattern) { - ulong host_access,db_access; + ulong host_access= ~0,db_access= 0; uint i,key_length; - db_access=0; host_access= ~0; char key[ACL_KEY_LENGTH],*tmp_db,*end; acl_entry *entry; DBUG_ENTER("acl_get");