summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBitKeeper/triggers/pre-delta11
-rw-r--r--client/client_priv.h1
-rw-r--r--client/mysqldump.c101
-rw-r--r--configure.in2
-rw-r--r--include/violite.h22
-rw-r--r--innobase/buf/buf0rea.c2
-rw-r--r--innobase/dict/dict0load.c30
-rw-r--r--innobase/fil/fil0fil.c93
-rw-r--r--innobase/include/dict0load.h10
-rw-r--r--innobase/include/fil0fil.h28
-rw-r--r--innobase/include/row0mysql.h20
-rw-r--r--innobase/include/trx0trx.h13
-rw-r--r--innobase/os/os0file.c14
-rw-r--r--innobase/row/row0ins.c30
-rw-r--r--innobase/row/row0mysql.c268
-rw-r--r--innobase/row/row0sel.c18
-rw-r--r--innobase/srv/srv0start.c70
-rw-r--r--innobase/trx/trx0trx.c8
-rw-r--r--libmysqld/lib_sql.cc12
-rw-r--r--mysql-test/mysql-test-run.sh3
-rw-r--r--mysql-test/ndb/basic.result8
-rw-r--r--mysql-test/r/alter_table.result2
-rw-r--r--mysql-test/r/ctype_ucs.result11
-rw-r--r--mysql-test/r/date_formats.result3
-rw-r--r--mysql-test/r/func_concat.result4
-rw-r--r--mysql-test/r/func_math.result2
-rw-r--r--mysql-test/r/func_str.result12
-rw-r--r--mysql-test/r/grant.result22
-rw-r--r--mysql-test/r/grant2.result17
-rw-r--r--mysql-test/r/grant_cache.result6
-rw-r--r--mysql-test/r/merge.result5
-rw-r--r--mysql-test/r/mysqldump.result141
-rw-r--r--mysql-test/r/ndb_blob.result18
-rw-r--r--mysql-test/r/ps_1general.result4
-rw-r--r--mysql-test/r/subselect.result37
-rw-r--r--mysql-test/r/timezone2.result4
-rw-r--r--mysql-test/r/variables.result6
-rw-r--r--mysql-test/t/ctype_ucs.test10
-rw-r--r--mysql-test/t/date_formats.test2
-rw-r--r--mysql-test/t/func_math.test7
-rw-r--r--mysql-test/t/func_str.test14
-rw-r--r--mysql-test/t/grant.test17
-rw-r--r--mysql-test/t/grant2.test28
-rw-r--r--mysql-test/t/merge.test3
-rw-r--r--mysql-test/t/multi_update.test2
-rw-r--r--mysql-test/t/mysqldump.test28
-rw-r--r--mysql-test/t/ndb_blob.test14
-rw-r--r--mysql-test/t/subselect.test28
-rw-r--r--mysql-test/t/variables.test4
-rw-r--r--ndb/config/type_ndbapitest.mk.am2
-rw-r--r--ndb/include/Makefile.am1
-rw-r--r--ndb/include/logger/LogHandler.hpp31
-rw-r--r--ndb/include/logger/Logger.hpp2
-rw-r--r--ndb/include/ndb_global.h.in22
-rw-r--r--ndb/include/ndb_init.h32
-rw-r--r--ndb/include/ndbapi/NdbApi.hpp2
-rw-r--r--ndb/include/ndbapi/NdbBlob.hpp15
-rw-r--r--ndb/include/ndbapi/NdbReceiver.hpp3
-rw-r--r--ndb/include/ndbapi/ndb_cluster_connection.hpp58
-rw-r--r--ndb/include/transporter/TransporterDefinitions.hpp2
-rw-r--r--ndb/include/transporter/TransporterRegistry.hpp7
-rw-r--r--ndb/include/util/ndb_opts.h2
-rw-r--r--ndb/src/common/logger/LogHandler.cpp62
-rw-r--r--ndb/src/common/logger/Logger.cpp4
-rw-r--r--ndb/src/common/mgmcommon/IPCConfig.cpp2
-rw-r--r--ndb/src/common/transporter/Makefile.am2
-rw-r--r--ndb/src/common/transporter/SCI_Transporter.cpp3
-rw-r--r--ndb/src/common/transporter/SHM_Transporter.cpp6
-rw-r--r--ndb/src/common/transporter/TCP_Transporter.cpp3
-rw-r--r--ndb/src/common/transporter/Transporter.cpp71
-rw-r--r--ndb/src/common/transporter/Transporter.hpp4
-rw-r--r--ndb/src/common/transporter/TransporterRegistry.cpp137
-rw-r--r--ndb/src/kernel/main.cpp2
-rw-r--r--ndb/src/mgmsrv/MgmtSrvr.cpp37
-rw-r--r--ndb/src/mgmsrv/main.cpp10
-rw-r--r--ndb/src/ndbapi/Ndb.cpp2
-rw-r--r--ndb/src/ndbapi/NdbBlob.cpp63
-rw-r--r--ndb/src/ndbapi/NdbBlobImpl.hpp39
-rw-r--r--ndb/src/ndbapi/NdbConnection.cpp7
-rw-r--r--ndb/src/ndbapi/NdbDictionaryImpl.cpp7
-rw-r--r--ndb/src/ndbapi/NdbOperationDefine.cpp4
-rw-r--r--ndb/src/ndbapi/NdbOperationInt.cpp18
-rw-r--r--ndb/src/ndbapi/Ndbinit.cpp21
-rw-r--r--ndb/src/ndbapi/ndb_cluster_connection.cpp22
-rw-r--r--ndb/test/ndbapi/testBlobs.cpp13
-rw-r--r--ndb/test/ndbapi/testOIBasic.cpp11
-rw-r--r--ndb/test/run-test/main.cpp1
-rw-r--r--sql-common/client.c14
-rw-r--r--sql/ha_innodb.cc44
-rw-r--r--sql/item_cmpfunc.cc5
-rw-r--r--sql/item_func.cc3
-rw-r--r--sql/item_strfunc.cc21
-rw-r--r--sql/item_subselect.cc11
-rw-r--r--sql/item_timefunc.cc60
-rw-r--r--sql/log.cc4
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/mysqld.cc67
-rw-r--r--sql/set_var.cc4
-rw-r--r--sql/sql_acl.cc160
-rw-r--r--sql/sql_insert.cc4
-rw-r--r--sql/sql_prepare.cc28
-rw-r--r--sql/sql_table.cc6
-rw-r--r--sql/strfunc.cc37
-rw-r--r--sql/table.cc62
-rw-r--r--sql/unireg.cc11
-rw-r--r--vio/vio.c22
-rw-r--r--vio/viosocket.c42
107 files changed, 1892 insertions, 659 deletions
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/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 042ce7e28a5..76330a98b9c 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -43,6 +43,7 @@
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
+#include <hash.h>
#include "client_priv.h"
#include "mysql.h"
@@ -130,6 +131,15 @@ 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;
+
+HASH ignore_table;
static struct my_option my_long_options[] =
{
@@ -235,6 +245,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*) &current_host,
(gptr*) &current_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},
@@ -506,6 +521,28 @@ 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)
+{
+ 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))
+ exit(EX_EOM);
+}
+
static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
@@ -577,8 +614,32 @@ 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:
+ {
+ uint len= (uint)strlen(argument);
+ TABLE_RULE_ENT* e;
+ if (!strchr(argument, '.'))
+ {
+ fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\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 (!hash_inited(&ignore_table))
+ init_table_rule_hash(&ignore_table);
+
+ if(my_hash_insert(&ignore_table, (byte*)e))
+ exit(EX_EOM);
+ break;
+ }
case (int) OPT_COMPATIBLE:
- {
+ {
char buff[255];
char *end= compatible_mode_normal_str;
int i;
@@ -617,6 +678,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:
@@ -1991,6 +2058,14 @@ static int init_dumping(char *database)
} /* init_dumping */
+my_bool include_table(byte* hash_key, uint len)
+{
+ if (hash_search(&ignore_table, (byte*) hash_key, len))
+ return FALSE;
+
+ return TRUE;
+}
+
static int dump_all_tables_in_db(char *database)
{
@@ -1998,6 +2073,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)
@@ -2006,7 +2087,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 */,");
@@ -2022,13 +2103,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/configure.in b/configure.in
index 3a508ecba51..53fc4feb722 100644
--- a/configure.in
+++ b/configure.in
@@ -24,7 +24,7 @@ NDB_VERSION_STATUS="alpha"
# 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
diff --git a/include/violite.h b/include/violite.h
index ba7de3ee175..855d8a3d490 100644
--- a/include/violite.h
+++ b/include/violite.h
@@ -39,16 +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);
-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__ */
@@ -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/innobase/buf/buf0rea.c b/innobase/buf/buf0rea.c
index f34920549fe..1ce52c8ee31 100644
--- a/innobase/buf/buf0rea.c
+++ b/innobase/buf/buf0rea.c
@@ -332,7 +332,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 12ceba38815..f835d1b949a 100644
--- a/innobase/dict/dict0load.c
+++ b/innobase/dict/dict0load.c
@@ -207,12 +207,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;
@@ -283,6 +285,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) {
@@ -797,8 +807,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 f62f63da538..f2d0790892e 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -469,6 +469,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)));
@@ -497,6 +501,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)
@@ -510,6 +516,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));
@@ -2498,21 +2544,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;
@@ -2551,6 +2605,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);
@@ -2563,6 +2623,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);
@@ -2583,6 +2645,7 @@ fil_open_single_table_tablespace(
goto func_exit;
}
+skip_check:
success = fil_space_create(filepath, space_id, FIL_TABLESPACE);
if (!success) {
@@ -2595,7 +2658,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);
@@ -2662,7 +2724,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"
@@ -2833,8 +2895,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 formula 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 75b32937e0b..aa1ec5c25a5 100644
--- a/innobase/include/fil0fil.h
+++ b/innobase/include/fil0fil.h
@@ -366,19 +366,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 c23a0e025ad..bd5ad3adba5 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -378,25 +378,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 e305226f9e3..76b051105de 100644
--- a/innobase/include/trx0trx.h
+++ b/innobase/include/trx0trx.h
@@ -414,6 +414,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/os/os0file.c b/innobase/os/os0file.c
index 434f9460bb6..e0d822b016f 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -1854,6 +1854,7 @@ os_file_pread(
return(n_bytes);
#else
{
+ off_t ret_offset;
ssize_t ret;
ulint i;
@@ -1862,12 +1863,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);
@@ -1940,6 +1941,7 @@ os_file_pwrite(
return(ret);
#else
{
+ off_t ret_offset;
ulint i;
/* Protect the seek / write operation with a mutex */
@@ -1947,12 +1949,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);
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 8b19f9d9a11..3c190915732 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -1187,7 +1187,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);
@@ -1206,7 +1206,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 .ibd file does not currently exist!\n", ef);
mutex_exit(&dict_foreign_err_mutex);
err = DB_NO_REFERENCED_ROW;
@@ -1437,8 +1437,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 0a2e9e5eaad..380fcf236ed 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -875,7 +875,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"
@@ -1094,6 +1108,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"
@@ -1865,20 +1893,19 @@ 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); */
- /* 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
@@ -1890,7 +1917,7 @@ row_drop_table_for_mysql_in_background(
trx_free_for_background(trx);
- return(DB_SUCCESS);
+ return(error);
}
/*************************************************************************
@@ -1924,6 +1951,7 @@ loop:
mutex_exit(&kernel_mutex);
if (drop == NULL) {
+ /* All tables dropped */
return(n_tables + n_tables_dropped);
}
@@ -1938,16 +1966,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);
@@ -1991,21 +2019,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) {
@@ -2013,7 +2041,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);
@@ -2021,14 +2068,32 @@ row_add_table_to_background_drop_list(
fputs(" to background drop list\n", stderr); */
mutex_exit(&kernel_mutex);
+
+ return(TRUE);
}
/*************************************************************************
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
@@ -2044,22 +2109,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"
@@ -2120,6 +2172,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 DISCARD 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) +
@@ -2137,6 +2237,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;
@@ -2287,8 +2391,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;
@@ -2296,7 +2400,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"
@@ -2318,7 +2422,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. */
@@ -2552,36 +2656,60 @@ 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",
- stderr);
+ added = row_add_table_to_background_drop_list(table);
- 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 */
- err = DB_SUCCESS;
+ err = DB_SUCCESS;
+ } else {
+ /* The table is already in the background drop list */
+ err = DB_ERROR;
+ }
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);
- 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;
}
@@ -3349,6 +3477,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 9104d6e1f4f..6cd265f23e3 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -2897,7 +2897,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 */
@@ -2952,7 +2952,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 a0e763d7a44..061bdb82d3e 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();
}
@@ -1431,13 +1459,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 +
@@ -1505,6 +1526,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
@@ -1515,6 +1551,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 */
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index f676c21934b..6619286ee71 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -110,6 +110,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);
@@ -277,6 +280,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/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index 2554fadc216..ffbde84f673 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<Item> *list, uint flags)
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 */
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index c21deaf39b6..b3b961fe42d 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/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
<id> = 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/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 37f5d0aa26a..3da828ebf9c 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 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/ctype_ucs.result b/mysql-test/r/ctype_ucs.result
index 238191b8e03..891786961b1 100644
--- a/mysql-test/r/ctype_ucs.result
+++ b/mysql-test/r/ctype_ucs.result
@@ -591,3 +591,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/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/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
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/r/func_str.result b/mysql-test/r/func_str.result
index ff0529472da..530651e63f8 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -691,3 +691,15 @@ 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'
+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/r/grant.result b/mysql-test/r/grant.result
index 87a496e7a1b..ddaa0064f18 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -37,6 +37,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/r/grant2.result b/mysql-test/r/grant2.result
index 48cbac10d46..dd784c65953 100644
--- a/mysql-test/r/grant2.result
+++ b/mysql-test/r/grant2.result
@@ -45,7 +45,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: update command denied to user 'mysqltest_1'@'localhost' for table 't1'
@@ -55,8 +54,6 @@ 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;
@@ -222,3 +219,17 @@ drop user mysqltest_B@'%';
ERROR 42000: Access denied for user 'mysqltest_3'@'localhost' to database 'mysql'
drop user mysqltest_B@'%';
drop user mysqltest_3@localhost;
+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 0c59ed1584c..2a1170ee751 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/merge.result b/mysql-test/r/merge.result
index e014d2b80b7..54feabc6608 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -677,4 +677,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/r/mysqldump.result b/mysql-test/r/mysqldump.result
index 62b7bdb9fb1..346629044b4 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -387,6 +387,7 @@ USE `test`;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+drop database mysqldump_test_db;
create database mysqldump_test_db character set latin2 collate latin2_bin;
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
@@ -409,3 +410,143 @@ 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;
+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;
+drop database mysqldump_test_db;
diff --git a/mysql-test/r/ndb_blob.result b/mysql-test/r/ndb_blob.result
index 44109dabbc8..f806cf08ea9 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/r/ps_1general.result b/mysql-test/r/ps_1general.result
index 2507d545feb..29309564c45 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/subselect.result b/mysql-test/r/subselect.result
index a425f054d5e..1a1a9a256db 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -1433,7 +1433,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');
@@ -1459,25 +1459,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(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`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`,<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`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(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`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(<in_optimizer>(`test`.`t1`.`s1`,<exists>(<index_lookup>(<cache>(`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`
@@ -2133,3 +2133,30 @@ 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
+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/r/timezone2.result b/mysql-test/r/timezone2.result
index 040ec866080..94d660c90d0 100644
--- a/mysql-test/r/timezone2.result
+++ b/mysql-test/r/timezone2.result
@@ -297,9 +297,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 56704cf4f35..1659a9dddb5 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -145,13 +145,13 @@ set global timed_mutexes=0;
show variables like 'timed_mutexes';
Variable_name Value
timed_mutexes OFF
-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';
@@ -250,7 +250,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/ctype_ucs.test b/mysql-test/t/ctype_ucs.test
index 9d6cb6649ab..506c47ae55a 100644
--- a/mysql-test/t/ctype_ucs.test
+++ b/mysql-test/t/ctype_ucs.test
@@ -376,3 +376,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/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/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/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 4404429cf7e..a5d95332caa 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -429,3 +429,17 @@ create table t1 (a int not null primary key, b varchar(40), c datetime);
insert into t1 (a,b,c) values (1,'Tom','2004-12-10 12:13:14'),(2,'ball games','2004-12-10 12:13:14'), (3,'Basil','2004-12-10 12:13:14'), (4,'Dean','2004-12-10 12:13:14'),(5,'Ellis','2004-12-10 12:13:14'), (6,'Serg','2004-12-10 12:13:14'), (7,'Sergei','2004-12-10 12:13:14'),(8,'Georg','2004-12-10 12:13:14'),(9,'Salle','2004-12-10 12:13:14'),(10,'Sinisa','2004-12-10 12:13:14');
select count(*) as total, left(c,10) as reg from t1 group by reg order by reg desc limit 0,12;
drop table t1;
+# crashing bug with QUOTE() and LTRIM() or TRIM() fixed
+# Bug #7495
+#
+
+select quote(ltrim(concat(' ', 'a')));
+select quote(trim(concat(' ', 'a')));
+
+#
+# Bug#7455 unexpected result: TRIM(<NULL> FROM <whatever>) 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/mysql-test/t/grant.test b/mysql-test/t/grant.test
index c05bed4b701..0bb83891fe2 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -33,6 +33,23 @@ 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/mysql-test/t/grant2.test b/mysql-test/t/grant2.test
index ad3fc1c228e..7a09559ac56 100644
--- a/mysql-test/t/grant2.test
+++ b/mysql-test/t/grant2.test
@@ -59,10 +59,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 1142
update t1 set data='I can change it!' where id = 1;
@@ -70,11 +69,10 @@ update t1 set data='I can change it!' where id = 1;
--error 1142
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;
@@ -226,4 +224,26 @@ connection default;
drop user mysqltest_B@'%';
drop user mysqltest_3@localhost;
#
+#
+#
+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/merge.test b/mysql-test/t/merge.test
index 02c3aae71ef..4c8d7cc1b74 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -303,5 +303,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/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index b74b06fe191..de66218c4a6 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -434,6 +434,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
@@ -443,6 +444,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/mysqldump.test b/mysql-test/t/mysqldump.test
index 7a811e69147..7b1fdc7c05b 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -146,3 +146,31 @@ 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 --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;
+
+#
+# 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;
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/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index d0202bff48d..bedeecd5d12 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -894,7 +894,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');
@@ -1391,3 +1391,29 @@ 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 );
+
+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);
diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test
index 97c59224c63..6c1ae733647 100644
--- a/mysql-test/t/variables.test
+++ b/mysql-test/t/variables.test
@@ -89,7 +89,7 @@ set global timed_mutexes=0;
show variables like 'timed_mutexes';
-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;
@@ -146,7 +146,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/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/logger/LogHandler.hpp b/ndb/include/logger/LogHandler.hpp
index ca4bd4c0668..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
@@ -112,14 +114,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.
*/
int getErrorCode() const;
@@ -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&);
@@ -192,6 +195,14 @@ 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[MAX_HEADER_LENGTH];
+ char m_last_message[MAX_LOG_MESSAGE_SIZE];
+ Logger::LoggerLevel m_last_level;
};
#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 <ndb_global.h>
#include <BaseString.hpp>
+#define MAX_LOG_MESSAGE_SIZE 1024
+
class LogHandler;
class LogHandlerList;
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 <assert.h>
-/* 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/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"
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 <ndb_types.h>
-#include <ndb_global.h>
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..0e559700716 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);
+
+ /**
+ * 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
- // 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
+ /**
+ * 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();
+ unsigned no_db_nodes();
+#endif
private:
friend class Ndb;
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/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/logger/LogHandler.cpp b/ndb/src/common/logger/LogHandler.cpp
index a76cb622878..e038b05401e 100644
--- a/ndb/src/common/logger/LogHandler.cpp
+++ b/ndb/src/common/logger/LogHandler.cpp
@@ -24,7 +24,13 @@
LogHandler::LogHandler() :
m_pDateTimeFormat("%d-%.2d-%.2d %.2d:%.2d:%.2d"),
m_errorCode(0)
-{
+{
+ m_max_repeat_frequency= 3; // repeat messages maximum every 3 seconds
+ 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()
@@ -34,11 +40,53 @@ LogHandler::~LogHandler()
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_count_repeated_messages > 0) // print that message
+ append_impl(m_last_category, m_last_level, m_last_message);
+
+ m_last_level= level;
+ 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);
- 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();
-}
+}
const char*
LogHandler::getDefaultHeader(char* pStr, const char* pCategory,
@@ -76,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);
}
- }
+ }
}
//
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/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 ee25d97feef..b84f8f6fb5e 100644
--- a/ndb/src/common/transporter/Transporter.cpp
+++ b/ndb/src/common/transporter/Transporter.cpp
@@ -24,7 +24,11 @@
#include <InputStream.hpp>
#include <OutputStream.hpp>
+#include <EventLogger.hpp>
+extern EventLogger g_eventLogger;
+
Transporter::Transporter(TransporterRegistry &t_reg,
+ TransporterType _type,
const char *lHostName,
const char *rHostName,
int r_port,
@@ -35,8 +39,10 @@ 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");
if (rHostName && strlen(rHostName) > 0){
strncpy(remoteHostName, rHostName, sizeof(remoteHostName));
Ndb_getInAddr(&remoteHostAddress, rHostName);
@@ -55,6 +61,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;
@@ -67,7 +78,9 @@ 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;
}
Transporter::~Transporter(){
@@ -77,8 +90,13 @@ 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)
- return true; // TODO assert(0);
+ {
+ DBUG_RETURN(true); // TODO assert(0);
+ }
bool res = connect_server_impl(sockfd);
if(res){
@@ -86,7 +104,7 @@ Transporter::connect_server(NDB_SOCKET_TYPE sockfd) {
m_errorCount = 0;
}
- return res;
+ DBUG_RETURN(res);
}
bool
@@ -98,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..baff6d53dd8 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; };
@@ -149,7 +151,7 @@ Transporter::getRemoteNodeId() const {
inline
NodeId
Transporter::getLocalNodeId() const {
- return remoteNodeId;
+ return localNodeId;
}
inline
diff --git a/ndb/src/common/transporter/TransporterRegistry.cpp b/ndb/src/common/transporter/TransporterRegistry.cpp
index be51e9223ba..2eb81b2b35d 100644
--- a/ndb/src/common/transporter/TransporterRegistry.cpp
+++ b/ndb/src/common/transporter/TransporterRegistry.cpp
@@ -47,6 +47,9 @@
#include <InputStream.hpp>
#include <OutputStream.hpp>
+#include <EventLogger.hpp>
+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);
@@ -196,6 +160,91 @@ TransporterRegistry::init(NodeId nodeId) {
}
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
@@ -358,8 +407,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,
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) : "<none>",
@@ -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 aa2cefae38c..4a8b79d3ddc 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;
@@ -284,12 +284,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();
@@ -305,10 +305,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.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 0a1433c71f3..c72568f7201 100644
--- a/ndb/src/ndbapi/NdbBlob.cpp
+++ b/ndb/src/ndbapi/NdbBlob.cpp
@@ -21,6 +21,7 @@
#include <NdbIndexOperation.hpp>
#include <NdbRecAttr.hpp>
#include <NdbBlob.hpp>
+#include "NdbBlobImpl.hpp"
#include <NdbScanOperation.hpp>
#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<char*>(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<const char*>(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_keyLenInWords;
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_keyLenInWords;
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_keyLenInWords;
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/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp
index 29959a4ed7e..aa4f68a85b4 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/NdbDictionaryImpl.cpp b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
index d39b921072b..b3b8e48edd1 100644
--- a/ndb/src/ndbapi/NdbDictionaryImpl.cpp
+++ b/ndb/src/ndbapi/NdbDictionaryImpl.cpp
@@ -34,7 +34,8 @@
#include <AttributeList.hpp>
#include <NdbEventOperation.hpp>
#include "NdbEventOperationImpl.hpp"
-#include "NdbBlob.hpp"
+#include <NdbBlob.hpp>
+#include "NdbBlobImpl.hpp"
#include <AttributeHeader.hpp>
#include <my_sys.h>
@@ -1381,7 +1382,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);
@@ -1789,7 +1790,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/NdbOperationDefine.cpp b/ndb/src/ndbapi/NdbOperationDefine.cpp
index d9aa860f71f..bc960a72d2e 100644
--- a/ndb/src/ndbapi/NdbOperationDefine.cpp
+++ b/ndb/src/ndbapi/NdbOperationDefine.cpp
@@ -523,7 +523,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) {
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 <ndb_global.h>
+#include <NdbOperation.hpp>
#include "NdbApiSignal.hpp"
-#include "NdbConnection.hpp"
-#include "Ndb.hpp"
+#include <NdbConnection.hpp>
+#include <Ndb.hpp>
#include "NdbRecAttr.hpp"
#include "NdbUtil.hpp"
#include "Interpreter.hpp"
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
diff --git a/ndb/src/ndbapi/ndb_cluster_connection.cpp b/ndb/src/ndbapi/ndb_cluster_connection.cpp
index 98a52786aab..5df707e211d 100644
--- a/ndb/src/ndbapi/ndb_cluster_connection.cpp
+++ b/ndb/src/ndbapi/ndb_cluster_connection.cpp
@@ -31,6 +31,9 @@
#include <Vector.hpp>
#include <md5_hash.hpp>
+#include <EventLogger.hpp>
+EventLogger g_eventLogger;
+
static int g_run_connect_thread= 0;
#include <NdbMutex.h>
@@ -174,7 +177,7 @@ Ndb_cluster_connection_impl::get_next_node(Ndb_cluster_connection_node_iter &ite
return node.id;
}
-Uint32
+unsigned
Ndb_cluster_connection::no_db_nodes()
{
return m_impl.m_all_nodes.size();
@@ -219,16 +222,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
@@ -256,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/ndb/test/ndbapi/testBlobs.cpp b/ndb/test/ndbapi/testBlobs.cpp
index 4b532856709..7b30777456f 100644
--- a/ndb/test/ndbapi/testBlobs.cpp
+++ b/ndb/test/ndbapi/testBlobs.cpp
@@ -23,13 +23,14 @@
#include <NdbOut.hpp>
#include <NdbTest.hpp>
#include <NdbTick.h>
+#include <ndb/src/ndbapi/NdbBlobImpl.hpp>
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),
@@ -153,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;
@@ -1258,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();
@@ -1447,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();
@@ -1859,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:
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);
}
diff --git a/sql-common/client.c b/sql-common/client.c
index a014e398d8b..0ff98102da9 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -393,6 +393,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;
@@ -505,6 +506,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
*/
@@ -514,9 +522,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_client_read,event_conn_closed);
}
else
{
@@ -529,6 +537,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/ha_innodb.cc b/sql/ha_innodb.cc
index 6577590f14a..91517770d04 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -380,15 +380,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) {
@@ -4075,11 +4075,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);
}
/*********************************************************************
@@ -5215,19 +5213,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;
@@ -5276,9 +5261,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->variables.innodb_table_locks &&
+ (thd->options & OPTION_NOT_AUTOCOMMIT)) {
+
ulint error;
error = row_lock_table_for_mysql(prebuilt,
NULL, LOCK_TABLE_EXP);
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 40513c2c25a..aa98f1860b6 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -661,12 +661,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_func.cc b/sql/item_func.cc
index f2d78fdb9e8..69ddd21f913 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1187,7 +1187,8 @@ double Item_func_round::val_real()
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
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index c271ff43fa3..88f32067c6c 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())
@@ -2608,16 +2617,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--)
{
@@ -2645,10 +2654,10 @@ String *Item_func_quote::val_str(String *str)
}
}
*to= '\'';
- str->length(new_length);
+ arg->length(new_length);
str->set_charset(collation.collation);
null_value= 0;
- return str;
+ return arg;
null:
null_value= 1;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 064744158d1..dbf30d7d793 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -830,6 +830,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
ref_pointer_array,
(char *)"<ref>",
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
@@ -874,6 +876,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
goto err;
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;
/*
@@ -895,12 +899,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,
+ item= func->create(expr,
new Item_null_helper(this, item,
(char *)"<no matter>",
(char *)"<result>"));
+ 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;
tmp= join->having->fix_fields(thd, join->tables_list, 0);
select_lex->having_fix_field= 0;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 215218a8277..27c000138d8 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
@@ -2821,25 +2824,31 @@ void Item_func_get_format::print(String *str)
/*
- check_result_type(s, l) returns DATE/TIME type
- 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
-
- 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
+ Get type of datetime value (DATE/TIME/...) which will be produced
+ according to format string.
+
+ SYNOPSIS
+ get_date_time_result_type()
+ format - format string
+ length - length of format string
+
+ 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;
@@ -2850,22 +2859,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;
@@ -2896,7 +2913,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;
diff --git a/sql/log.cc b/sql/log.cc
index 5d56fefa26a..00c39acec09 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2046,6 +2046,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];
/*
@@ -2066,7 +2067,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));
@@ -2080,6 +2081,7 @@ bool flush_error_log()
else
result= 1;
#endif
+ VOID(pthread_mutex_unlock(&LOCK_error_log));
}
return result;
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 4cba19181d4..88260bb7b1b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -939,6 +939,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/mysqld.cc b/sql/mysqld.cc
index de1ac6d8727..e9d4a088d16 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -54,7 +54,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
@@ -141,15 +141,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 /* __STDC__ */
#endif /* HAVE_LIBWRAP */
#ifdef HAVE_SYS_MMAN_H
@@ -3689,8 +3680,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)
@@ -3698,7 +3689,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
@@ -3939,6 +3930,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);
@@ -3969,29 +3961,35 @@ 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)
+ {
+ errmsg= "Could not create closed connection event";
+ goto errorconn;
+ }
if (abort_loop)
goto errorconn;
if (!(thd= new THD))
@@ -4010,13 +4008,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)) ||
- my_net_init(&thd->net, thd->net.vio))
+ 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))
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
errmsg= 0;
@@ -4036,12 +4035,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 (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/sql/set_var.cc b/sql/set_var.cc
index 3fb39d0fc27..fbbe209eea4 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -3051,9 +3051,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;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 16503c58739..85f8d5d5e6f 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1644,6 +1644,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 ;
@@ -1652,59 +1653,60 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (priv & rights) // set requested privileges
(*tmp_field)->store(&what, 1, &my_charset_latin1);
}
- rights=get_access(table,3);
+ 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 (lex->ssl_type) {
case SSL_TYPE_ANY:
- table->field[24]->store("ANY",3, &my_charset_latin1);
- table->field[25]->store("", 0, &my_charset_latin1);
- table->field[26]->store("", 0, &my_charset_latin1);
- table->field[27]->store("", 0, &my_charset_latin1);
+ table->field[next_field]->store("ANY", 3, &my_charset_latin1);
+ table->field[next_field+1]->store("", 0, &my_charset_latin1);
+ table->field[next_field+2]->store("", 0, &my_charset_latin1);
+ table->field[next_field+3]->store("", 0, &my_charset_latin1);
break;
case SSL_TYPE_X509:
- table->field[24]->store("X509",4, &my_charset_latin1);
- table->field[25]->store("", 0, &my_charset_latin1);
- table->field[26]->store("", 0, &my_charset_latin1);
- table->field[27]->store("", 0, &my_charset_latin1);
+ table->field[next_field]->store("X509", 4, &my_charset_latin1);
+ table->field[next_field+1]->store("", 0, &my_charset_latin1);
+ table->field[next_field+2]->store("", 0, &my_charset_latin1);
+ table->field[next_field+3]->store("", 0, &my_charset_latin1);
break;
case SSL_TYPE_SPECIFIED:
- table->field[24]->store("SPECIFIED",9, &my_charset_latin1);
- table->field[25]->store("", 0, &my_charset_latin1);
- table->field[26]->store("", 0, &my_charset_latin1);
- table->field[27]->store("", 0, &my_charset_latin1);
+ table->field[next_field]->store("SPECIFIED", 9, &my_charset_latin1);
+ table->field[next_field+1]->store("", 0, &my_charset_latin1);
+ table->field[next_field+2]->store("", 0, &my_charset_latin1);
+ table->field[next_field+3]->store("", 0, &my_charset_latin1);
if (lex->ssl_cipher)
- table->field[25]->store(lex->ssl_cipher,
- strlen(lex->ssl_cipher), system_charset_info);
+ table->field[next_field+1]->store(lex->ssl_cipher,
+ strlen(lex->ssl_cipher), system_charset_info);
if (lex->x509_issuer)
- table->field[26]->store(lex->x509_issuer,
- strlen(lex->x509_issuer), system_charset_info);
+ table->field[next_field+2]->store(lex->x509_issuer,
+ strlen(lex->x509_issuer), system_charset_info);
if (lex->x509_subject)
- table->field[27]->store(lex->x509_subject,
- strlen(lex->x509_subject), system_charset_info);
+ table->field[next_field+3]->store(lex->x509_subject,
+ strlen(lex->x509_subject), system_charset_info);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
case SSL_TYPE_NONE:
- table->field[24]->store("", 0, &my_charset_latin1);
- table->field[25]->store("", 0, &my_charset_latin1);
- table->field[26]->store("", 0, &my_charset_latin1);
- table->field[27]->store("", 0, &my_charset_latin1);
+ table->field[next_field]->store("", 0, &my_charset_latin1);
+ table->field[next_field+1]->store("", 0, &my_charset_latin1);
+ table->field[next_field+2]->store("", 0, &my_charset_latin1);
+ table->field[next_field+3]->store("", 0, &my_charset_latin1);
break;
}
+ next_field+=4;
USER_RESOURCES mqh= lex->mqh;
if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
- table->field[28]->store((longlong) mqh.questions);
+ table->field[next_field]->store((longlong) mqh.questions);
if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
- table->field[29]->store((longlong) mqh.updates);
+ table->field[next_field+1]->store((longlong) mqh.updates);
if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
- table->field[30]->store((longlong) mqh.conn_per_hour);
+ table->field[next_field+2]->store((longlong) mqh.conn_per_hour);
if (table->fields >= 36 &&
(mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
- table->field[33]->store((longlong) mqh.user_conn);
+ table->field[next_field+3]->store((longlong) mqh.user_conn);
mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
}
if (old_row_exists)
@@ -2587,41 +2589,59 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(TRUE);
}
- if (columns.elements && !revoke_grant)
+ if (!revoke_grant)
{
- class LEX_COLUMN *column;
- List_iterator <LEX_COLUMN> column_iter(columns);
- int res;
-
- if (open_and_lock_tables(thd, table_list))
- DBUG_RETURN(TRUE);
-
- while ((column = column_iter++))
+ if (columns.elements)
{
- uint unused_field_idx= NO_CACHED_FIELD_INDEX;
- if (!find_field_in_table(thd, table_list, column->column.ptr(),
- column->column.ptr(),
- column->column.length(), 0, 0, 0, 0,
- &unused_field_idx, FALSE))
+ class LEX_COLUMN *column;
+ List_iterator <LEX_COLUMN> column_iter(columns);
+ int res;
+
+ if (open_and_lock_tables(thd, table_list))
+ DBUG_RETURN(TRUE);
+
+ while ((column = column_iter++))
{
- my_error(ER_BAD_FIELD_ERROR, MYF(0),
- column->column.c_ptr(), table_list->alias);
- DBUG_RETURN(TRUE);
+ uint unused_field_idx= NO_CACHED_FIELD_INDEX;
+ Field *f=find_field_in_table(thd, table_list, column->column.ptr(),
+ column->column.ptr(),
+ column->column.length(), 0, 0, 0, 0,
+ &unused_field_idx, FALSE);
+ if (f == (Field*)0)
+ {
+ my_error(ER_BAD_FIELD_ERROR, MYF(0),
+ column->column.c_ptr(), table_list->alias);
+ DBUG_RETURN(TRUE);
+ }
+ if (f == (Field *)-1)
+ DBUG_RETURN(TRUE);
+ 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(TRUE);
+ 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(TRUE);
+ }
+ }
+ 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);
+ }
}
}
@@ -3337,25 +3357,8 @@ err:
rw_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);
else if (want_access & CREATE_VIEW_ACL)
command= "create view";
else if (want_access & SHOW_VIEW_ACL)
@@ -3473,11 +3476,8 @@ bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
err:
rw_unlock(&LOCK_grant);
err2:
- 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_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
command,
thd->priv_user,
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c681fe25548..7a271daa862 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -702,9 +702,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
if (!table)
table= table_list->table;
- if ((thd->lex->sql_command == SQLCOM_INSERT ||
- thd->lex->sql_command == SQLCOM_REPLACE) &&
- unique_table(table_list, table_list->next_global))
+ if (!select_insert && unique_table(table_list, table_list->next_global))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(TRUE);
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index c860e3a79ac..180e2c67f8d 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -907,15 +907,16 @@ static bool mysql_test_insert(Prepared_statement *stmt,
ulong counter= 0;
Item *unused_conds= 0;
+ table_list->table->insert_values=(byte *)1; // don't allocate insert_values
if ((res= mysql_prepare_insert(thd, table_list, table_list->table,
fields, values, update_fields,
update_values, duplic,
&unused_conds, FALSE)))
goto error;
-
+
value_count= values->elements;
its.rewind();
-
+
while ((values= its++))
{
counter++;
@@ -932,6 +933,7 @@ static bool mysql_test_insert(Prepared_statement *stmt,
res= 0;
error:
lex->unit.cleanup();
+ table_list->table->insert_values=0;
DBUG_RETURN(res);
}
@@ -1587,28 +1589,6 @@ static bool init_param_array(Prepared_statement *stmt)
return FALSE;
}
-
-/* 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_global)
- {
- 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.
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 3cc421b1312..e8655a2a304 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -2585,7 +2585,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);
}
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index 777b3851294..824aa15097e 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -170,6 +170,43 @@ uint find_type2(TYPELIB *typelib, const char *x, uint length, CHARSET_INFO *cs)
/*
+ 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
SYNOPSIS
diff --git a/sql/table.cc b/sql/table.cc
index efc27a964c7..ee204347b88 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,7 +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 It is new format of .frm file
+ 5 Error (see frm_error: charset unavailable)
*/
int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
@@ -65,7 +66,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
{
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;
@@ -454,10 +455,14 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
}
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)
{
@@ -509,25 +514,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
{
/* 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=
@@ -847,7 +834,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
delete crypted;
*root_ptr= old_root;
if (! error_reported)
- 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 easier errorchecking
outparam->db_stat=0;
@@ -1032,7 +1019,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];
@@ -1059,8 +1047,22 @@ static void frm_error(int error, TABLE *form, const char *name, myf errortype)
datext= datext==NullS ? "" : datext;
err_no= (my_errno == ENOENT) ? ER_FILE_NOT_FOUND : (my_errno == EAGAIN) ?
ER_FILE_USED : ER_CANT_OPEN_FILE;
- my_error(err_no, errortype,
- fn_format(buff, form->real_name, form_dev, datext, 2), my_errno);
+ my_error(err_no,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 */
diff --git a/sql/unireg.cc b/sql/unireg.cc
index a16439530fc..ee036ed113d 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<create_field> it(create_fields);
+ create_field *field;
+ while ((field=it++))
+ {
+ if (field->interval && field->charset->mbminlen > 1)
+ unhex_type2(field->interval);
+ }
+ }
DBUG_RETURN(0);
err:
diff --git a/vio/vio.c b/vio/vio.c
index 39b5f843e5e..ea254e2ed5a 100644
--- a/vio/vio.c
+++ b/vio/vio.c
@@ -172,22 +172,24 @@ 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");
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->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 2921eb7495e..de50dabba5f 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;
@@ -429,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);
};
@@ -454,17 +466,29 @@ 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) */
+ /*
+ Set event_conn_closed for notification of both client and server that
+ connection is closed
+ */
+ SetEvent(vio->event_conn_closed);
+ /*
+ 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));
+ /* 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__ */