[packages/mysql] - rel 4; fix for SECURITY bug that allows any user to crash entire server (also fixes upstream #1873

arekm arekm at pld-linux.org
Fri Sep 26 19:35:48 CEST 2014


commit 97e12482fabfccbdf4c8952317b1219b6419f15e
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Fri Sep 26 19:35:42 2014 +0200

    - rel 4; fix for SECURITY bug that allows any user to crash entire server (also fixes upstream #18734396)

 bug-73834.patch | 607 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 mysql.spec      |   4 +-
 2 files changed, 610 insertions(+), 1 deletion(-)
---
diff --git a/mysql.spec b/mysql.spec
index 5e6ea3a..2118321 100644
--- a/mysql.spec
+++ b/mysql.spec
@@ -23,7 +23,7 @@
 %bcond_with	tests		# FIXME: don't run correctly
 %bcond_with	ndb		# NDB is now a separate product, this here is broken, so disable it
 
-%define		rel	3
+%define		rel	4
 %define		percona_rel	68.0
 %include	/usr/lib/rpm/macros.perl
 Summary:	MySQL: a very fast and reliable SQL database engine
@@ -65,6 +65,7 @@ Patch4:		%{name}-no-default-secure-auth.patch
 Patch5:		%{name}-system-libhsclient.patch
 # from fedora
 Patch6:		%{name}-system-users.patch
+Patch7:		bug-73834.patch
 
 Patch9:		%{name}-build.patch
 Patch11:	%{name}-upgrade.patch
@@ -512,6 +513,7 @@ mv sphinx-*/mysqlse storage/sphinx
 %patch4 -p1
 %patch5 -p1
 %patch6 -p1
+%patch7 -p1
 
 %patch9 -p1
 %patch11 -p1
diff --git a/bug-73834.patch b/bug-73834.patch
new file mode 100644
index 0000000..4f10824
--- /dev/null
+++ b/bug-73834.patch
@@ -0,0 +1,607 @@
+commit b54c850236f23c2aeb087bde53a9d975d0355486
+Author: Thirunarayanan B <thirunarayanan.balathandayuth at oracle.com>
+Date:   Wed Aug 6 15:34:47 2014 +0530
+
+    Bug #18734396	INNODB IN-PLACE ALTER FAILURES BLOCK FUTURE ALTERS
+    
+    Analysis:
+    	When an InnoDB in-place ALTER fails, it leaves behind both a
+    temporary filename like "#sql-ibtid" where tid represents the table ID of
+    the table being altered) in its data dictionary. This makes future in-place
+    ALTERs of the same table impossible because the temporary table is named
+    only with the table ID.
+    
+    Solution:
+    	This patch is adding more uniqueness to the temporary file name. It
+    creates a temporary tablename like
+    "#sql-ibtid-inc" where
+             tid = the table ID
+             inc = static global number that is initialized to a random
+    distributed 32-bit number using ut_time() and ut_crc32().It is then
+    incremented atomically for each temporary file name assigned.
+    
+    	rb5580 Approved by Kevin, Marko
+
+diff --git a/mysql-test/suite/innodb/r/innodb-alter-tempfile.result b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result
+new file mode 100644
+index 0000000..12ec408
+--- /dev/null
++++ b/mysql-test/suite/innodb/r/innodb-alter-tempfile.result
+@@ -0,0 +1,38 @@
++#
++# Bug #18734396	INNODB IN-PLACE ALTER FAILURES BLOCK FUTURE ALTERS
++#
++# Temporary tablename will be unique. This makes sure that future
++# in-place ALTERs of the same table will not be blocked due to
++# temporary tablename.
++# Crash the server in ha_innobase::commit_inplace_alter_table()
++CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL) ENGINE=innodb;
++SET debug='d,innodb_alter_commit_crash_before_commit';
++# Write file to make mysql-test-run.pl expect crash
++# Execute the statement that causes the crash
++ALTER TABLE t1 ADD PRIMARY KEY (f2, f1);
++ERROR HY000: Lost connection to MySQL server during query
++# Startup the server after the crash
++# Read and remember the temporary table name
++show create table t1;
++Table	Create Table
++t1	CREATE TABLE `t1` (
++  `f1` int(11) NOT NULL,
++  `f2` int(11) NOT NULL
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++# Consecutive Alter table does not create same temporary file name
++ALTER TABLE t1 ADD PRIMARY KEY (f2, f1);
++# Shutdown the server to allow manual recovery
++# Manual recovery begin. The dictionary was not updated
++# and the files were not renamed. The rebuilt table
++# was left behind on purpose, to faciliate data recovery.
++# Manual recovery end
++# Startup the server after manual recovery
++# Drop the orphaned rebuilt table.
++show create table t1;
++Table	Create Table
++t1	CREATE TABLE `t1` (
++  `f1` int(11) NOT NULL,
++  `f2` int(11) NOT NULL,
++  PRIMARY KEY (`f2`,`f1`)
++) ENGINE=InnoDB DEFAULT CHARSET=latin1
++drop table t1;
+diff --git a/mysql-test/suite/innodb/t/innodb-alter-tempfile.test b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test
+new file mode 100644
+index 0000000..aff179a
+--- /dev/null
++++ b/mysql-test/suite/innodb/t/innodb-alter-tempfile.test
+@@ -0,0 +1,72 @@
++# Not supported in embedded
++--source include/not_embedded.inc
++
++# This test case needs to crash the server. Needs a debug server.
++--source include/have_debug.inc
++
++# Don't test this under valgrind, memory leaks will occur.
++--source include/not_valgrind.inc
++
++# Avoid CrashReporter popup on Mac
++--source include/not_crashrep.inc
++
++--echo #
++--echo # Bug #18734396	INNODB IN-PLACE ALTER FAILURES BLOCK FUTURE ALTERS
++--echo #
++--echo # Temporary tablename will be unique. This makes sure that future
++--echo # in-place ALTERs of the same table will not be blocked due to
++--echo # temporary tablename.
++
++let datadir= `select @@datadir`;
++
++--let $_server_id= `SELECT @@server_id`
++--let $_expect_file_name=$MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
++
++--echo # Crash the server in ha_innobase::commit_inplace_alter_table()
++CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL) ENGINE=innodb;
++SET debug='d,innodb_alter_commit_crash_before_commit';
++
++let $orig_table_id = `SELECT table_id
++	FROM information_schema.innodb_sys_tables
++	WHERE name = 'test/t1'`;
++
++--echo # Write file to make mysql-test-run.pl expect crash
++--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
++
++--echo # Execute the statement that causes the crash
++--error 2013
++ALTER TABLE t1 ADD PRIMARY KEY (f2, f1);
++--echo # Startup the server after the crash
++--source include/start_mysqld.inc
++
++--echo # Read and remember the temporary table name
++let $temp_table_name = `SELECT SUBSTRING(name,6)
++	FROM information_schema.innodb_sys_tables
++	WHERE name LIKE "test/#sql-ib$orig_table_id%"`;
++# This second copy is an environment variable for the perl script below.
++let temp_table_name = $temp_table_name;
++show create table t1;
++--echo # Consecutive Alter table does not create same temporary file name
++ALTER TABLE t1 ADD PRIMARY KEY (f2, f1);
++--echo # Shutdown the server to allow manual recovery
++--source include/shutdown_mysqld.inc
++
++--echo # Manual recovery begin. The dictionary was not updated
++--echo # and the files were not renamed. The rebuilt table
++--echo # was left behind on purpose, to faciliate data recovery.
++
++perl;
++my @frm_file = glob "$ENV{'datadir'}/test/#sql-*.frm";
++my $target_frm = "$ENV{'datadir'}/test/$ENV{'temp_table_name'}.frm";
++rename($frm_file[0], $target_frm);
++EOF
++--echo # Manual recovery end
++--echo # Startup the server after manual recovery
++--source include/start_mysqld.inc
++
++--echo # Drop the orphaned rebuilt table.
++--disable_query_log
++eval DROP TABLE `#mysql50#$temp_table_name`;
++--enable_query_log
++show create table t1;
++drop table t1;
+diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
+index 885627a..cd9eed9 100644
+--- a/storage/innobase/dict/dict0mem.cc
++++ b/storage/innobase/dict/dict0mem.cc
+@@ -35,6 +35,7 @@ Created 1/8/1996 Heikki Tuuri
+ #include "mach0data.h"
+ #include "dict0dict.h"
+ #include "fts0priv.h"
++#include "ut0crc32.h"
+ #ifndef UNIV_HOTBACKUP
+ # include "ha_prototypes.h"	/* innobase_casedn_str(),
+ 				innobase_get_lower_case_table_names */
+@@ -53,6 +54,10 @@ Created 1/8/1996 Heikki Tuuri
+ UNIV_INTERN mysql_pfs_key_t	autoinc_mutex_key;
+ #endif /* UNIV_PFS_MUTEX */
+ 
++/** An interger randomly initialized at startup used to make a temporary
++table name as unique as possible. */
++static ib_uint32_t	dict_temp_file_num;
++
+ /**********************************************************************//**
+ Creates a table memory object.
+ @return	own: table object */
+@@ -614,26 +619,62 @@ dict_mem_index_free(
+ 	mem_heap_free(index->heap);
+ }
+ 
+-/*******************************************************************//**
+-Create a temporary tablename.
+- at return temporary tablename suitable for InnoDB use */
++/** Create a temporary tablename like "#sql-ibtid-inc where
++  tid = the Table ID
++  inc = a randomly initialized number that is incremented for each file
++The table ID is a 64 bit integer, can use up to 20 digits, and is
++initialized at bootstrap. The second number is 32 bits, can use up to 10
++digits, and is initialized at startup to a randomly distributed number.
++It is hoped that the combination of these two numbers will provide a
++reasonably unique temporary file name.
++ at param[in]	heap	A memory heap
++ at param[in]	dbtab	Table name in the form database/table name
++ at param[in]	id	Table id
++ at return A unique temporary tablename suitable for InnoDB use */
+ UNIV_INTERN
+ char*
+ dict_mem_create_temporary_tablename(
+-/*================================*/
+-	mem_heap_t*	heap,	/*!< in: memory heap */
+-	const char*	dbtab,	/*!< in: database/table name */
+-	table_id_t	id)	/*!< in: InnoDB table id */
++	mem_heap_t*	heap,
++	const char*	dbtab,
++	table_id_t	id)
+ {
+-	const char*	dbend   = strchr(dbtab, '/');
++	size_t		size;
++	char*		name;
++	const char*	dbend = strchr(dbtab, '/');
+ 	ut_ad(dbend);
+-	size_t		dblen   = dbend - dbtab + 1;
+-	size_t		size = tmp_file_prefix_length + 4 + 9 + 9 + dblen;
++	size_t		dblen = dbend - dbtab + 1;
++
++#ifdef HAVE_ATOMIC_BUILTINS
++	/* Increment a randomly initialized number for each temp file. */
++	os_atomic_increment_uint32(&dict_temp_file_num, 1);
++#else /* HAVE_ATOMIC_BUILTINS */
++	dict_temp_file_num++;
++#endif /* HAVE_ATOMIC_BUILTINS */
+ 
+-	char*	name = static_cast<char*>(mem_heap_alloc(heap, size));
++	size = tmp_file_prefix_length + 3 + 20 + 1 + 10 + dblen;
++	name = static_cast<char*>(mem_heap_alloc(heap, size));
+ 	memcpy(name, dbtab, dblen);
+ 	ut_snprintf(name + dblen, size - dblen,
+-		    tmp_file_prefix "-ib" UINT64PF, id);
++		    TEMP_FILE_PREFIX_INNODB UINT64PF "-" UINT32PF,
++		    id, dict_temp_file_num);
++
+ 	return(name);
+ }
+ 
++/** Initialize dict memory variables */
++
++void
++dict_mem_init(void)
++{
++	/* Initialize a randomly distributed temporary file number */
++	ib_uint32_t now = static_cast<ib_uint32_t>(ut_time());
++
++	const byte* buf = reinterpret_cast<const byte*>(&now);
++	ut_ad(ut_crc32 != NULL);
++
++	dict_temp_file_num = ut_crc32(buf, sizeof(now));
++
++	DBUG_PRINT("dict_mem_init",
++		   ("Starting Temporary file number is " UINT32PF,
++		   dict_temp_file_num));
++}
+diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
+index 63bc4ff..e2977ca 100644
+--- a/storage/innobase/include/dict0mem.h
++++ b/storage/innobase/include/dict0mem.h
+@@ -384,16 +384,29 @@ dict_mem_referenced_table_name_lookup_set(
+ 	dict_foreign_t*	foreign,	/*!< in/out: foreign struct */
+ 	ibool		do_alloc);	/*!< in: is an alloc needed */
+ 
+-/*******************************************************************//**
+-Create a temporary tablename.
+- at return temporary tablename suitable for InnoDB use */
+-UNIV_INTERN __attribute__((nonnull, warn_unused_result))
++/** Create a temporary tablename like "#sql-ibtid-inc where
++  tid = the Table ID
++  inc = a randomly initialized number that is incremented for each file
++The table ID is a 64 bit integer, can use up to 20 digits, and is
++initialized at bootstrap. The second number is 32 bits, can use up to 10
++digits, and is initialized at startup to a randomly distributed number.
++It is hoped that the combination of these two numbers will provide a
++reasonably unique temporary file name.
++ at param[in]	heap	A memory heap
++ at param[in]	dbtab	Table name in the form database/table name
++ at param[in]	id	Table id
++ at return A unique temporary tablename suitable for InnoDB use */
++UNIV_INTERN
+ char*
+ dict_mem_create_temporary_tablename(
+-/*================================*/
+-	mem_heap_t*	heap,	/*!< in: memory heap */
+-	const char*	dbtab,	/*!< in: database/table name */
+-	table_id_t	id);	/*!< in: InnoDB table id */
++	mem_heap_t*	heap,
++	const char*	dbtab,
++	table_id_t	id);
++
++/** Initialize dict memory variables */
++
++void
++dict_mem_init(void);
+ 
+ /** Data structure for a column in a table */
+ struct dict_col_t{
+diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h
+index 1299445..d34b6f7 100644
+--- a/storage/innobase/include/dict0types.h
++++ b/storage/innobase/include/dict0types.h
+@@ -78,6 +78,7 @@ enum ib_quiesce_t {
+ /** Prefix for tmp tables, adopted from sql/table.h */
+ #define tmp_file_prefix		"#sql"
+ #define tmp_file_prefix_length	4
++#define TEMP_FILE_PREFIX_INNODB	"#sql-ib"
+ 
+ #define TEMP_TABLE_PREFIX                "#sql"
+ #define TEMP_TABLE_PATH_PREFIX           "/" TEMP_TABLE_PREFIX
+diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
+index 499c0fc..cf8b288 100644
+--- a/storage/innobase/srv/srv0srv.cc
++++ b/storage/innobase/srv/srv0srv.cc
+@@ -979,6 +979,8 @@ srv_init(void)
+ 	trx_i_s_cache_init(trx_i_s_cache);
+ 
+ 	ut_crc32_init();
++
++	dict_mem_init();
+ }
+ 
+ /*********************************************************************//**
+From da00483beb3fe1375fc1ebeaac7943f73b56637e Mon Sep 17 00:00:00 2001
+From: MySQL Build Team <mysql-build at oss.oracle.com>
+Date: Mon, 8 Sep 2014 12:33:48 +0200
+Subject: [PATCH] bug19471516 for mysql-5.6
+
+---
+ mysql-test/suite/innodb/r/add_foreign_key.result | 31 +++++++++++++
+ mysql-test/suite/innodb/t/add_foreign_key.test   | 38 +++++++++++++++
+ storage/innobase/dict/dict0dict.cc               | 11 +++++
+ storage/innobase/dict/dict0load.cc               |  2 +
+ storage/innobase/dict/dict0mem.cc                | 59 ++++++++++++++++++++++++
+ storage/innobase/include/dict0mem.h              | 51 ++++++++++++++++++++
+ 6 files changed, 192 insertions(+)
+ create mode 100644 mysql-test/suite/innodb/r/add_foreign_key.result
+ create mode 100644 mysql-test/suite/innodb/t/add_foreign_key.test
+
+diff --git a/mysql-test/suite/innodb/r/add_foreign_key.result b/mysql-test/suite/innodb/r/add_foreign_key.result
+new file mode 100644
+index 0000000..7517747
+--- /dev/null
++++ b/mysql-test/suite/innodb/r/add_foreign_key.result
+@@ -0,0 +1,31 @@
++#
++# Bug #19471516 SERVER CRASHES WHEN EXECUTING ALTER TABLE ADD
++# FOREIGN KEY
++#
++CREATE TABLE `parent` (`parent_id` INT, PRIMARY KEY (`parent_id`));
++CREATE TABLE `child1` (`id` INT ,`child1_fk1` INT, `child1_fk2` INT,
++PRIMARY KEY (`id`));
++CREATE TABLE `child2` (`id` INT, `child2_fk1` INT, `child2_fk2` INT,
++PRIMARY KEY (`id`));
++CREATE TABLE `child3` (`id` INT , `child3_fk1` INT, PRIMARY KEY (`id`));
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk1`) REFERENCES `parent`
++(`parent_id`);
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk1`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk2`) REFERENCES `parent`
++(`parent_id`);
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk1`) REFERENCES `parent`
++(`parent_id`);
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk2`) REFERENCES `parent`
++(`parent_id`);
++ALTER TABLE `child3` ADD FOREIGN KEY (`child3_fk1`) REFERENCES `parent`
++(`parent_id`);
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk2`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk1`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk2`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child3` ADD FOREIGN KEY (`child3_fk1`) REFERENCES
++`parent` (`parent_id`);
++drop table child3, child2, child1, parent;
+diff --git a/mysql-test/suite/innodb/t/add_foreign_key.test b/mysql-test/suite/innodb/t/add_foreign_key.test
+new file mode 100644
+index 0000000..d0febfd
+--- /dev/null
++++ b/mysql-test/suite/innodb/t/add_foreign_key.test
+@@ -0,0 +1,38 @@
++--source include/have_innodb.inc
++
++--echo #
++--echo # Bug #19471516 SERVER CRASHES WHEN EXECUTING ALTER TABLE ADD
++--echo # FOREIGN KEY
++--echo #
++
++CREATE TABLE `parent` (`parent_id` INT, PRIMARY KEY (`parent_id`));
++CREATE TABLE `child1` (`id` INT ,`child1_fk1` INT, `child1_fk2` INT,
++PRIMARY KEY (`id`));
++CREATE TABLE `child2` (`id` INT, `child2_fk1` INT, `child2_fk2` INT,
++PRIMARY KEY (`id`));
++CREATE TABLE `child3` (`id` INT , `child3_fk1` INT, PRIMARY KEY (`id`));
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk1`) REFERENCES `parent`
++(`parent_id`);
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk1`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk2`) REFERENCES `parent`
++(`parent_id`);
++
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk1`) REFERENCES `parent`
++(`parent_id`);
++
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk2`) REFERENCES `parent`
++(`parent_id`);
++
++ALTER TABLE `child3` ADD FOREIGN KEY (`child3_fk1`) REFERENCES `parent`
++(`parent_id`);
++ALTER TABLE `child1` ADD FOREIGN KEY (`child1_fk2`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk1`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child2` ADD FOREIGN KEY (`child2_fk2`) REFERENCES
++`parent` (`parent_id`);
++ALTER TABLE `child3` ADD FOREIGN KEY (`child3_fk1`) REFERENCES
++`parent` (`parent_id`);
++
++drop table child3, child2, child1, parent;
+diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
+index 5b0d7da..6acd6b6 100644
+--- a/storage/innobase/dict/dict0dict.cc
++++ b/storage/innobase/dict/dict0dict.cc
+@@ -1694,6 +1694,10 @@ dict_table_rename_in_cache(
+ 
+ 		foreign = *it;
+ 
++		if (foreign->referenced_table) {
++			foreign->referenced_table->referenced_set.erase(foreign);
++		}
++
+ 		if (ut_strlen(foreign->foreign_table_name)
+ 		    < ut_strlen(table->name)) {
+ 			/* Allocate a longer name buffer;
+@@ -1845,6 +1849,10 @@ dict_table_rename_in_cache(
+ 
+ 		table->foreign_set.erase(it);
+ 		fk_set.insert(foreign);
++
++		if (foreign->referenced_table) {
++			foreign->referenced_table->referenced_set.insert(foreign);
++		}
+ 	}
+ 
+ 	ut_a(table->foreign_set.empty());
+@@ -3253,6 +3261,9 @@ dict_foreign_find(
+ {
+ 	ut_ad(mutex_own(&(dict_sys->mutex)));
+ 
++	ut_ad(dict_foreign_set_validate(table->foreign_set));
++	ut_ad(dict_foreign_set_validate(table->referenced_set));
++
+ 	dict_foreign_set::iterator it = table->foreign_set.find(foreign);
+ 
+ 	if (it != table->foreign_set.end()) {
+diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
+index 272467e..6921199 100644
+--- a/storage/innobase/dict/dict0load.cc
++++ b/storage/innobase/dict/dict0load.cc
+@@ -2537,6 +2537,8 @@ dict_load_table(
+ 		}
+ 	}
+ 
++	ut_ad(err != DB_SUCCESS || dict_foreign_set_validate(*table));
++
+ 	return(table);
+ }
+ 
+diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
+index cd9eed9..979c18e 100644
+--- a/storage/innobase/dict/dict0mem.cc
++++ b/storage/innobase/dict/dict0mem.cc
+@@ -45,6 +45,7 @@ Created 1/8/1996 Heikki Tuuri
+ #ifdef UNIV_BLOB_DEBUG
+ # include "ut0rbt.h"
+ #endif /* UNIV_BLOB_DEBUG */
++#include <iostream>
+ 
+ #define	DICT_HEAP_SIZE		100	/*!< initial memory heap size when
+ 					creating a table or index object */
+@@ -678,3 +679,61 @@ dict_mem_init(void)
+ 		   ("Starting Temporary file number is " UINT32PF,
+ 		   dict_temp_file_num));
+ }
++
++/** Validate the search order in the foreign key set.
++ at param[in]	fk_set	the foreign key set to be validated
++ at return true if search order is fine in the set, false otherwise. */
++bool
++dict_foreign_set_validate(
++	const dict_foreign_set&	fk_set)
++{
++	dict_foreign_not_exists	not_exists(fk_set);
++
++	dict_foreign_set::iterator it = std::find_if(
++		fk_set.begin(), fk_set.end(), not_exists);
++
++	if (it == fk_set.end()) {
++		return(true);
++	}
++
++	dict_foreign_t*	foreign = *it;
++	std::cerr << "Foreign key lookup failed: " << *foreign;
++	std::cerr << fk_set;
++	ut_ad(0);
++	return(false);
++}
++
++/** Validate the search order in the foreign key sets of the table
++(foreign_set and referenced_set).
++ at param[in]	table	table whose foreign key sets are to be validated
++ at return true if foreign key sets are fine, false otherwise. */
++bool
++dict_foreign_set_validate(
++	const dict_table_t&	table)
++{
++	return(dict_foreign_set_validate(table.foreign_set)
++	       && dict_foreign_set_validate(table.referenced_set));
++}
++
++std::ostream&
++operator<< (std::ostream& out, const dict_foreign_t& foreign)
++{
++	out << "[dict_foreign_t: id='" << foreign.id << "'";
++
++	if (foreign.foreign_table_name != NULL) {
++		out << ",for: '" << foreign.foreign_table_name << "'";
++	}
++
++	out << "]";
++	return(out);
++}
++
++std::ostream&
++operator<< (std::ostream& out, const dict_foreign_set& fk_set)
++{
++	out << "[dict_foreign_set:";
++	std::for_each(fk_set.begin(), fk_set.end(), dict_foreign_print(out));
++	out << "]" << std::endl;
++	return(out);
++}
++
+diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
+index e2977ca..460a7e1 100644
+--- a/storage/innobase/include/dict0mem.h
++++ b/storage/innobase/include/dict0mem.h
+@@ -49,6 +49,7 @@ Created 1/8/1996 Heikki Tuuri
+ #include "os0once.h"
+ #include <set>
+ #include <algorithm>
++#include <iterator>
+ 
+ /* Forward declaration. */
+ struct ib_rbt_t;
+@@ -720,6 +721,22 @@ struct dict_foreign_t{
+ 	dict_index_t*	referenced_index;/*!< referenced index */
+ };
+ 
++std::ostream&
++operator<< (std::ostream& out, const dict_foreign_t& foreign);
++
++struct dict_foreign_print {
++
++	dict_foreign_print(std::ostream& out)
++		: m_out(out)
++	{}
++
++	void operator()(const dict_foreign_t* foreign) {
++		m_out << *foreign;
++	}
++private:
++	std::ostream&	m_out;
++};
++
+ /** Compare two dict_foreign_t objects using their ids. Used in the ordering
+ of dict_table_t::foreign_set and dict_table_t::referenced_set.  It returns
+ true if the first argument is considered to go before the second in the
+@@ -789,6 +806,40 @@ struct dict_foreign_matches_id {
+ 
+ typedef std::set<dict_foreign_t*, dict_foreign_compare> dict_foreign_set;
+ 
++std::ostream&
++operator<< (std::ostream& out, const dict_foreign_set& fk_set);
++
++/** Function object to check if a foreign key object is there
++in the given foreign key set or not.  It returns true if the
++foreign key is not found, false otherwise */
++struct dict_foreign_not_exists {
++	dict_foreign_not_exists(const dict_foreign_set& obj_)
++		: m_foreigns(obj_)
++	{}
++
++	/* Return true if the given foreign key is not found */
++	bool operator()(dict_foreign_t* const & foreign) const {
++		return(m_foreigns.find(foreign) == m_foreigns.end());
++	}
++private:
++	const dict_foreign_set&	m_foreigns;
++};
++
++/** Validate the search order in the foreign key set.
++ at param[in]	fk_set	the foreign key set to be validated
++ at return true if search order is fine in the set, false otherwise. */
++bool
++dict_foreign_set_validate(
++	const dict_foreign_set&	fk_set);
++
++/** Validate the search order in the foreign key sets of the table
++(foreign_set and referenced_set).
++ at param[in]	table	table whose foreign key sets are to be validated
++ at return true if foreign key sets are fine, false otherwise. */
++bool
++dict_foreign_set_validate(
++	const dict_table_t&	table);
++
+ /*********************************************************************//**
+ Frees a foreign key struct. */
+ inline
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/mysql.git/commitdiff/97e12482fabfccbdf4c8952317b1219b6419f15e



More information about the pld-cvs-commit mailing list