Commit b83c2976 authored by unknown's avatar unknown
Browse files

Fix BUG#14747: "Race condition can cause btr_search_drop_page_hash_index()

 to crash".
 Changes from snapshot innodb-5.0-ss52.
 Note that buf_block_t::index should be protected by btr_search_latch
 or an s-latch or x-latch on the index page.
 btr_search_drop_page_hash_index(): Read block->index while holding
 btr_search_latch and use the cached value in the loop. Remove some
 redundant assertions.
 Also fix 13778. When FOREIGN_KEY_CHECKS=0 we still need to check that
 datatypes between foreign key references are compatible.
 Also added test cases to 9802.


innobase/btr/btr0sea.c:
  Changes from innodb-5.0-ss52
innobase/dict/dict0dict.c:
  Changes from innodb-5.0-ss52
innobase/dict/dict0load.c:
  Changes from innodb-5.0-ss52
innobase/include/buf0buf.h:
  Changes from innodb-5.0-ss52
innobase/include/dict0dict.h:
  Changes from innodb-5.0-ss52
innobase/include/dict0load.h:
  Changes from innodb-5.0-ss52
innobase/include/rem0cmp.h:
  Changes from innodb-5.0-ss52
innobase/rem/rem0cmp.c:
  Changes from innodb-5.0-ss52
innobase/row/row0mysql.c:
  Changes from innodb-5.0-ss52
mysql-test/r/innodb.result:
  Changes from innodb-5.0-ss52
mysql-test/t/innodb.test:
  Changes from innodb-5.0-ss52
sql/ha_innodb.cc:
  Changes from innodb-5.0-ss52
sql/ha_innodb.h:
  Changes from innodb-5.0-ss52
parent c9bf8e28
Loading
Loading
Loading
Loading
+10 −18
Original line number Diff line number Diff line
@@ -904,6 +904,7 @@ btr_search_drop_page_hash_index(
	ulint*		folds;
	ulint		i;
	mem_heap_t*	heap;
	dict_index_t*	index;
	ulint*		offsets;

#ifdef UNIV_SYNC_DEBUG
@@ -932,11 +933,16 @@ btr_search_drop_page_hash_index(

	n_fields = block->curr_n_fields;
	n_bytes = block->curr_n_bytes;
	index = block->index;

	ut_a(n_fields + n_bytes > 0);
	/* NOTE: The fields of block must not be accessed after
	releasing btr_search_latch, as the index page might only
	be s-latched! */

	rw_lock_s_unlock(&btr_search_latch);
	
	ut_a(n_fields + n_bytes > 0);

	n_recs = page_get_n_recs(page);

	/* Calculate and cache fold values into an array for fast deletion
@@ -949,14 +955,6 @@ btr_search_drop_page_hash_index(
	rec = page_get_infimum_rec(page);
	rec = page_rec_get_next(rec);

	if (!page_rec_is_supremum(rec)) {
		ut_a(n_fields <= rec_get_n_fields(rec, block->index));

		if (n_bytes > 0) {
			ut_a(n_fields < rec_get_n_fields(rec, block->index));
		}
	}

	tree_id = btr_page_get_index_id(page);
	
	prev_fold = 0;
@@ -964,18 +962,12 @@ btr_search_drop_page_hash_index(
	heap = NULL;
	offsets = NULL;

	if (block->index == NULL) {

		mem_analyze_corruption((byte*)block);

		ut_a(block->index != NULL);
	}

	while (!page_rec_is_supremum(rec)) {
		/* FIXME: in a mixed tree, not all records may have enough
		ordering fields: */
		offsets = rec_get_offsets(rec, block->index,
				offsets, n_fields + (n_bytes > 0), &heap);
		offsets = rec_get_offsets(rec, index, offsets,
					n_fields + (n_bytes > 0), &heap);
		ut_a(rec_offs_n_fields(offsets) == n_fields + (n_bytes > 0));
		fold = rec_fold(rec, offsets, n_fields, n_bytes, tree_id);

		if (fold == prev_fold && prev_fold != 0) {
+13 −21
Original line number Diff line number Diff line
@@ -2104,8 +2104,11 @@ dict_foreign_find_index(
	dict_table_t*	table,	/* in: table */
	const char**	columns,/* in: array of column names */
	ulint		n_cols,	/* in: number of columns */
	dict_index_t*	types_idx)/* in: NULL or an index to whose types the
	dict_index_t*	types_idx, /* in: NULL or an index to whose types the
				   column types must match */
	ibool		check_charsets)	/* in: whether to check charsets.
					only has an effect if types_idx !=
					NULL. */
{
#ifndef UNIV_HOTBACKUP
	dict_index_t*	index;
@@ -2135,7 +2138,8 @@ dict_foreign_find_index(

				if (types_idx && !cmp_types_are_equal(
				     dict_index_get_nth_type(index, i),
				     dict_index_get_nth_type(types_idx, i))) {
				     dict_index_get_nth_type(types_idx, i),
				     check_charsets)) {

				  	break;
				}		
@@ -2212,7 +2216,8 @@ dict_foreign_add_to_cache(
/*======================*/
					/* out: DB_SUCCESS or error code */
	dict_foreign_t*	foreign,	/* in, own: foreign key constraint */
	ibool		check_types)	/* in: TRUE=check type compatibility */
	ibool		check_charsets)	/* in: TRUE=check charset
					compatibility */
{
	dict_table_t*	for_table;
	dict_table_t*	ref_table;
@@ -2248,16 +2253,10 @@ dict_foreign_add_to_cache(
	}

	if (for_in_cache->referenced_table == NULL && ref_table) {
		dict_index_t*	types_idx;
		if (check_types) {
			types_idx = for_in_cache->foreign_index;
		} else {
			types_idx = NULL;
		}
		index = dict_foreign_find_index(ref_table,
			(const char**) for_in_cache->referenced_col_names,
			for_in_cache->n_fields,
			types_idx);
			for_in_cache->foreign_index, check_charsets);

		if (index == NULL) {
			dict_foreign_error_report(ef, for_in_cache,
@@ -2281,16 +2280,10 @@ dict_foreign_add_to_cache(
	}

	if (for_in_cache->foreign_table == NULL && for_table) {
		dict_index_t*	types_idx;
		if (check_types) {
			types_idx = for_in_cache->referenced_index;
		} else {
			types_idx = NULL;
		}
		index = dict_foreign_find_index(for_table,
			(const char**) for_in_cache->foreign_col_names,
			for_in_cache->n_fields,
			types_idx);
			for_in_cache->referenced_index, check_charsets);

		if (index == NULL) {
			dict_foreign_error_report(ef, for_in_cache,
@@ -3097,7 +3090,7 @@ dict_create_foreign_constraints_low(
	/* Try to find an index which contains the columns
	as the first fields and in the right order */

	index = dict_foreign_find_index(table, column_names, i, NULL);
	index = dict_foreign_find_index(table, column_names, i, NULL, TRUE);

	if (!index) {
		mutex_enter(&dict_foreign_err_mutex);
@@ -3362,8 +3355,7 @@ dict_create_foreign_constraints_low(

	if (referenced_table) {
		index = dict_foreign_find_index(referenced_table,
						column_names, i,
						foreign->foreign_index);
			column_names, i, foreign->foreign_index, TRUE);
		if (!index) {
			dict_foreign_free(foreign);
			mutex_enter(&dict_foreign_err_mutex);
+5 −4
Original line number Diff line number Diff line
@@ -1091,7 +1091,7 @@ dict_load_foreign(
				/* out: DB_SUCCESS or error code */
	const char*	id,	/* in: foreign constraint id as a
				null-terminated string */
	ibool		check_types)/* in: TRUE=check type compatibility */
	ibool		check_charsets)/* in: TRUE=check charset compatibility */
{	
	dict_foreign_t*	foreign;
	dict_table_t*	sys_foreign;
@@ -1204,7 +1204,7 @@ dict_load_foreign(
	a new foreign key constraint but loading one from the data
	dictionary. */

	return(dict_foreign_add_to_cache(foreign, check_types));
	return(dict_foreign_add_to_cache(foreign, check_charsets));
}

/***************************************************************************
@@ -1219,7 +1219,8 @@ dict_load_foreigns(
/*===============*/
					/* out: DB_SUCCESS or error code */
	const char*	table_name,	/* in: table name */
	ibool		check_types)	/* in: TRUE=check type compatibility */
	ibool		check_charsets)	/* in: TRUE=check charset
					compatibility */
{
	btr_pcur_t	pcur;
	mem_heap_t* 	heap;
@@ -1319,7 +1320,7 @@ dict_load_foreigns(

	/* Load the foreign constraint definition to the dictionary cache */
	
	err = dict_load_foreign(id, check_types);
	err = dict_load_foreign(id, check_charsets);

	if (err != DB_SUCCESS) {
		btr_pcur_close(&pcur);
+7 −3
Original line number Diff line number Diff line
@@ -745,8 +745,6 @@ struct buf_block_struct{
					buffer pool which are index pages,
					but this flag is not set because
					we do not keep track of all pages */
	dict_index_t*	index;		/* index for which the adaptive
					hash index has been created */
	/* 2. Page flushing fields */

	UT_LIST_NODE_T(buf_block_t) flush_list;
@@ -833,7 +831,7 @@ struct buf_block_struct{
					records with the same prefix should be
					indexed in the hash index */
					
	/* The following 4 fields are protected by btr_search_latch: */
	/* The following 6 fields are protected by btr_search_latch: */

	ibool		is_hashed;	/* TRUE if hash index has already been
					built on this page; note that it does
@@ -850,6 +848,12 @@ struct buf_block_struct{
	ulint		curr_side;	/* BTR_SEARCH_LEFT_SIDE or
					BTR_SEARCH_RIGHT_SIDE in hash
					indexing */
	dict_index_t*	index;		/* Index for which the adaptive
					hash index has been created.
					This field may only be modified
					while holding an s-latch or x-latch
					on block->lock and an x-latch on
					btr_search_latch. */
	/* 6. Debug fields */
#ifdef UNIV_SYNC_DEBUG
	rw_lock_t	debug_latch;	/* in the debug version, each thread
+2 −1
Original line number Diff line number Diff line
@@ -197,7 +197,8 @@ dict_foreign_add_to_cache(
/*======================*/
					/* out: DB_SUCCESS or error code */
	dict_foreign_t*	foreign,	/* in, own: foreign key constraint */
	ibool		check_types);	/* in: TRUE=check type compatibility */
	ibool		check_charsets);/* in: TRUE=check charset
					compatibility */
/*************************************************************************
Checks if a table is referenced by foreign keys. */

Loading