InnoDB 5.6.20

This commit is contained in:
Sergei Golubchik 2014-09-11 16:42:54 +02:00
commit 75796d9ecb
51 changed files with 1027 additions and 659 deletions

View file

@ -1,7 +1,7 @@
FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT;
UNLOCK TABLES;
CREATE TABLE t1 ( m MEDIUMTEXT ) ENGINE=InnoDB;
INSERT INTO t1 VALUES ( REPEAT('i',1048576) );
INSERT INTO t1 VALUES ( REPEAT('i',65535) );
DROP TABLE t1;
#

View file

@ -1,4 +1,3 @@
ERROR 42000: Row size too large (> ####). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
f4 f8
xxx zzz
f4 f8
xxx zzz

View file

@ -1,31 +1,32 @@
--source include/have_innodb.inc
#
# Bug#34300 Tinyblob & tinytext fields currupted after export/import and alter in 5.1
# http://bugs.mysql.com/34300
#
-- source include/have_innodb.inc
-- disable_query_log
-- disable_result_log
call mtr.add_suppression("InnoDB: Warning: a long semaphore wait:");
call mtr.add_suppression("the age of the last checkpoint is");
call mtr.add_suppression("InnoDB: The total blob data length");
# set packet size and reconnect
let $max_packet=`select @@global.max_allowed_packet`;
SET @@global.max_allowed_packet=16777216;
--connect (newconn, localhost, root,,)
DROP TABLE IF EXISTS bug34300;
--enable_result_log
CREATE TABLE bug34300 (
f4 TINYTEXT,
f6 MEDIUMTEXT,
f8 TINYBLOB
) ENGINE=InnoDB;
--replace_regex /\(> [0-9]*\)/(> ####)/
--error ER_TOO_BIG_ROWSIZE
INSERT INTO bug34300 VALUES ('xxx', repeat('a', 8459264), 'zzz');
-- enable_result_log
SELECT f4, f8 FROM bug34300;
ALTER TABLE bug34300 ADD COLUMN (f10 INT);

View file

@ -4,7 +4,7 @@
FLUSH TABLES WITH READ LOCK AND DISABLE CHECKPOINT;
UNLOCK TABLES;
CREATE TABLE t1 ( m MEDIUMTEXT ) ENGINE=InnoDB;
INSERT INTO t1 VALUES ( REPEAT('i',1048576) );
INSERT INTO t1 VALUES ( REPEAT('i',65535) );
DROP TABLE t1;

View file

@ -72,7 +72,6 @@ IF(NOT CMAKE_CROSSCOMPILING)
long x;
long y;
long res;
char c;
x = 10;
y = 123;
@ -93,6 +92,16 @@ IF(NOT CMAKE_CROSSCOMPILING)
if (res != 123 + 10 || x != 123 + 10) {
return(1);
}
return(0);
}"
HAVE_IB_GCC_ATOMIC_BUILTINS
)
CHECK_C_SOURCE_RUNS(
"
int main()
{
long res;
char c;
c = 10;
res = __sync_lock_test_and_set(&c, 123);
@ -101,7 +110,7 @@ IF(NOT CMAKE_CROSSCOMPILING)
}
return(0);
}"
HAVE_IB_GCC_ATOMIC_BUILTINS
HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE
)
CHECK_C_SOURCE_RUNS(
"#include<stdint.h>
@ -148,6 +157,10 @@ IF(HAVE_IB_GCC_ATOMIC_BUILTINS)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_BYTE=1)
ENDIF()
IF(HAVE_IB_GCC_ATOMIC_BUILTINS_64)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_64=1)
ENDIF()

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2008, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -2044,6 +2044,8 @@ ib_cursor_delete_row(
const rec_t* rec;
ib_bool_t page_format;
mtr_t mtr;
rec_t* copy = NULL;
byte ptr[UNIV_PAGE_SIZE_MAX];
page_format = static_cast<ib_bool_t>(
dict_table_is_comp(index->table));
@ -2052,16 +2054,27 @@ ib_cursor_delete_row(
if (btr_pcur_restore_position(
BTR_SEARCH_LEAF, pcur, &mtr)) {
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
rec_offs_init(offsets_);
rec = btr_pcur_get_rec(pcur);
} else {
rec = NULL;
/* Since mtr will be commited, the rec
will not be protected. Make a copy of
the rec. */
offsets = rec_get_offsets(
rec, index, offsets, ULINT_UNDEFINED, &heap);
ut_ad(rec_offs_size(offsets) < UNIV_PAGE_SIZE_MAX);
copy = rec_copy(ptr, rec, offsets);
}
mtr_commit(&mtr);
if (rec && !rec_get_deleted_flag(rec, page_format)) {
err = ib_delete_row(cursor, pcur, rec);
if (copy && !rec_get_deleted_flag(copy, page_format)) {
err = ib_delete_row(cursor, pcur, copy);
} else {
err = DB_RECORD_NOT_FOUND;
}

View file

@ -2557,6 +2557,31 @@ make_external:
ut_ad(flags & BTR_KEEP_POS_FLAG);
}
if (big_rec_vec) {
const ulint redo_10p = srv_log_file_size * UNIV_PAGE_SIZE / 10;
ulint total_blob_len = 0;
/* Calculate the total number of bytes for blob data */
for (ulint i = 0; i < big_rec_vec->n_fields; i++) {
total_blob_len += big_rec_vec->fields[i].len;
}
if (total_blob_len > redo_10p) {
ib_logf(IB_LOG_LEVEL_ERROR, "The total blob data"
" length (" ULINTPF ") is greater than"
" 10%% of the redo log file size (" UINT64PF
"). Please increase innodb_log_file_size.",
total_blob_len, srv_log_file_size);
if (n_reserved > 0) {
fil_space_release_free_extents(
index->space, n_reserved);
}
err = DB_TOO_BIG_RECORD;
goto err_exit;
}
}
/* Store state of explicit locks on rec on the page infimum record,
before deleting rec. The page infimum acts as a dummy carrier of the
locks, taking care also of lock releases, before we can move the locks
@ -4378,6 +4403,7 @@ btr_store_big_rec_extern_fields(
buf_block_t** freed_pages = NULL;
ulint n_freed_pages = 0;
dberr_t error = DB_SUCCESS;
ulint total_blob_len = 0;
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(rec_offs_any_extern(offsets));
@ -4397,6 +4423,23 @@ btr_store_big_rec_extern_fields(
rec_page_no = buf_block_get_page_no(rec_block);
ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX);
const ulint redo_10p = (srv_log_file_size * UNIV_PAGE_SIZE / 10);
/* Calculate the total number of bytes for blob data */
for (ulint i = 0; i < big_rec_vec->n_fields; i++) {
total_blob_len += big_rec_vec->fields[i].len;
}
if (total_blob_len > redo_10p) {
ut_ad(op == BTR_STORE_INSERT);
ib_logf(IB_LOG_LEVEL_ERROR, "The total blob data length"
" (" ULINTPF ") is greater than 10%% of the"
" redo log file size (" UINT64PF "). Please"
" increase innodb_log_file_size.",
total_blob_len, srv_log_file_size);
return(DB_TOO_BIG_RECORD);
}
if (page_zip) {
int err;

View file

@ -2882,12 +2882,6 @@ got_block:
ut_ad(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in buf_page_t. On
other systems, Valgrind could complain about uninitialized pad
bytes. */
UNIV_MEM_ASSERT_RW(&fix_block->page, sizeof(fix_block->page));
#endif
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
if ((mode == BUF_GET_IF_IN_POOL || mode == BUF_GET_IF_IN_POOL_OR_WATCH)
@ -5401,7 +5395,7 @@ buf_get_free_list_len(void)
#else /* !UNIV_HOTBACKUP */
/********************************************************************//**
Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
Inits a page to the buffer buf_pool, for use in mysqlbackup --restore. */
UNIV_INTERN
void
buf_page_init_for_backup_restore(

View file

@ -1818,13 +1818,6 @@ buf_LRU_free_page(
rw_lock_x_lock(hash_lock);
mutex_enter(block_mutex);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in buf_page_t. On
other systems, Valgrind could complain about uninitialized pad
bytes. */
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
#endif
if (!buf_page_can_relocate(bpage)) {
/* Do not free buffer fixed or I/O-fixed blocks. */
@ -1862,12 +1855,6 @@ func_exit:
ut_ad(buf_page_in_file(bpage));
ut_ad(bpage->in_LRU_list);
ut_ad(!bpage->in_flush_list == !bpage->oldest_modification);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in buf_page_t. On
other systems, Valgrind could complain about uninitialized pad
bytes. */
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
#endif
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
@ -1940,13 +1927,6 @@ func_exit:
ut_ad(prev_b->in_LRU_list);
ut_ad(buf_page_in_file(prev_b));
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no
padding in buf_page_t. On other
systems, Valgrind could complain about
uninitialized pad bytes. */
UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b);
#endif
UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU,
prev_b, b);
@ -2172,13 +2152,6 @@ buf_LRU_block_remove_hashed(
ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
ut_a(bpage->buf_fix_count == 0);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in
buf_page_t. On other systems, Valgrind could complain
about uninitialized pad bytes. */
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
#endif
buf_LRU_remove_block(bpage);
buf_pool->freed_page_clock += 1;

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1611,26 +1611,25 @@ dict_create_add_foreign_to_dictionary(
return(error);
}
/********************************************************************//**
Adds foreign key definitions to data dictionary tables in the database.
@return error code or DB_SUCCESS */
/** Adds the given set of foreign key objects to the dictionary tables
in the database. This function does not modify the dictionary cache. The
caller must ensure that all foreign key objects contain a valid constraint
name in foreign->id.
@param[in] local_fk_set set of foreign key objects, to be added to
the dictionary tables
@param[in] table table to which the foreign key objects in
local_fk_set belong to
@param[in,out] trx transaction
@return error code or DB_SUCCESS */
UNIV_INTERN
dberr_t
dict_create_add_foreigns_to_dictionary(
/*===================================*/
ulint start_id,/*!< in: if we are actually doing ALTER TABLE
ADD CONSTRAINT, we want to generate constraint
numbers which are bigger than in the table so
far; we number the constraints from
start_id + 1 up; start_id should be set to 0 if
we are creating a new table, or if the table
so far has no constraints for which the name
was generated here */
dict_table_t* table, /*!< in: table */
trx_t* trx) /*!< in: transaction */
const dict_foreign_set& local_fk_set,
const dict_table_t* table,
trx_t* trx)
{
dict_foreign_t* foreign;
ulint number = start_id + 1;
dberr_t error;
ut_ad(mutex_own(&(dict_sys->mutex)));
@ -1643,17 +1642,12 @@ dict_create_add_foreigns_to_dictionary(
return(DB_ERROR);
}
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
foreign;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
for (dict_foreign_set::const_iterator it = local_fk_set.begin();
it != local_fk_set.end();
++it) {
error = dict_create_add_foreign_id(&number, table->name,
foreign);
if (error != DB_SUCCESS) {
return(error);
}
foreign = *it;
ut_ad(foreign->id != NULL);
error = dict_create_add_foreign_to_dictionary(table->name,
foreign, trx);

View file

@ -27,6 +27,7 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0dict.h"
#include "fts0fts.h"
#include "fil0fil.h"
#include <algorithm>
#ifdef UNIV_NONINL
#include "dict0dict.ic"
@ -1251,8 +1252,8 @@ dict_table_can_be_evicted(
#endif /* UNIV_SYNC_DEBUG */
ut_a(table->can_be_evicted);
ut_a(UT_LIST_GET_LEN(table->foreign_list) == 0);
ut_a(UT_LIST_GET_LEN(table->referenced_list) == 0);
ut_a(table->foreign_set.empty());
ut_a(table->referenced_set.empty());
if (table->n_ref_count == 0) {
dict_index_t* index;
@ -1468,6 +1469,22 @@ dict_index_find_on_id_low(
return(NULL);
}
/** Function object to remove a foreign key constraint from the
referenced_set of the referenced table. The foreign key object is
also removed from the dictionary cache. The foreign key constraint
is not removed from the foreign_set of the table containing the
constraint. */
struct dict_foreign_remove_partial
{
void operator()(dict_foreign_t* foreign) {
dict_table_t* table = foreign->referenced_table;
if (table != NULL) {
table->referenced_set.erase(foreign);
}
dict_foreign_free(foreign);
}
};
/**********************************************************************//**
Renames a table object.
@return TRUE if success */
@ -1642,27 +1659,25 @@ dict_table_rename_in_cache(
system tables through a call of dict_load_foreigns. */
/* Remove the foreign constraints from the cache */
foreign = UT_LIST_GET_LAST(table->foreign_list);
while (foreign != NULL) {
dict_foreign_remove_from_cache(foreign);
foreign = UT_LIST_GET_LAST(table->foreign_list);
}
std::for_each(table->foreign_set.begin(),
table->foreign_set.end(),
dict_foreign_remove_partial());
table->foreign_set.clear();
/* Reset table field in referencing constraints */
for (dict_foreign_set::iterator it
= table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
foreign = UT_LIST_GET_FIRST(table->referenced_list);
while (foreign != NULL) {
foreign = *it;
foreign->referenced_table = NULL;
foreign->referenced_index = NULL;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
/* Make the list of referencing constraints empty */
UT_LIST_INIT(table->referenced_list);
/* Make the set of referencing constraints empty */
table->referenced_set.clear();
return(DB_SUCCESS);
}
@ -1671,9 +1686,19 @@ dict_table_rename_in_cache(
the constraint id of new format >= 4.0.18 constraints. Note that at
this point we have already changed table->name to the new name. */
foreign = UT_LIST_GET_FIRST(table->foreign_list);
dict_foreign_set fk_set;
for (;;) {
dict_foreign_set::iterator it
= table->foreign_set.begin();
if (it == table->foreign_set.end()) {
break;
}
foreign = *it;
while (foreign != NULL) {
if (ut_strlen(foreign->foreign_table_name)
< ut_strlen(table->name)) {
/* Allocate a longer name buffer;
@ -1823,12 +1848,18 @@ dict_table_rename_in_cache(
mem_free(old_id);
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
table->foreign_set.erase(it);
fk_set.insert(foreign);
}
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
ut_a(table->foreign_set.empty());
table->foreign_set.swap(fk_set);
for (dict_foreign_set::iterator it = table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
foreign = *it;
if (ut_strlen(foreign->referenced_table_name)
< ut_strlen(table->name)) {
@ -1898,27 +1929,17 @@ dict_table_remove_from_cache_low(
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
#if 0
fputs("Removing table ", stderr);
ut_print_name(stderr, table->name, ULINT_UNDEFINED);
fputs(" from dictionary cache\n", stderr);
#endif
/* Remove the foreign constraints from the cache */
for (foreign = UT_LIST_GET_LAST(table->foreign_list);
foreign != NULL;
foreign = UT_LIST_GET_LAST(table->foreign_list)) {
dict_foreign_remove_from_cache(foreign);
}
std::for_each(table->foreign_set.begin(), table->foreign_set.end(),
dict_foreign_remove_partial());
table->foreign_set.clear();
/* Reset table field in referencing constraints */
for (dict_foreign_set::iterator it = table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
foreign = *it;
foreign->referenced_table = NULL;
foreign->referenced_index = NULL;
}
@ -3134,7 +3155,7 @@ dict_table_is_referenced_by_foreign_key(
/*====================================*/
const dict_table_t* table) /*!< in: InnoDB table */
{
return(UT_LIST_GET_LEN(table->referenced_list) > 0);
return(!table->referenced_set.empty());
}
/*********************************************************************//**
@ -3154,9 +3175,11 @@ dict_table_get_referenced_constraint(
ut_ad(index != NULL);
ut_ad(table != NULL);
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
foreign;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
for (dict_foreign_set::iterator it = table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
foreign = *it;
if (foreign->referenced_index == index) {
@ -3185,9 +3208,11 @@ dict_table_get_foreign_constraint(
ut_ad(index != NULL);
ut_ad(table != NULL);
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
foreign;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
++it) {
foreign = *it;
if (foreign->foreign_index == index) {
@ -3198,17 +3223,6 @@ dict_table_get_foreign_constraint(
return(NULL);
}
/*********************************************************************//**
Frees a foreign key struct. */
UNIV_INTERN
void
dict_foreign_free(
/*==============*/
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
{
mem_heap_free(foreign->heap);
}
/**********************************************************************//**
Removes a foreign constraint struct from the dictionary cache. */
UNIV_INTERN
@ -3220,16 +3234,12 @@ dict_foreign_remove_from_cache(
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_a(foreign);
if (foreign->referenced_table) {
UT_LIST_REMOVE(referenced_list,
foreign->referenced_table->referenced_list,
foreign);
if (foreign->referenced_table != NULL) {
foreign->referenced_table->referenced_set.erase(foreign);
}
if (foreign->foreign_table) {
UT_LIST_REMOVE(foreign_list,
foreign->foreign_table->foreign_list,
foreign);
if (foreign->foreign_table != NULL) {
foreign->foreign_table->foreign_set.erase(foreign);
}
dict_foreign_free(foreign);
@ -3243,33 +3253,21 @@ static
dict_foreign_t*
dict_foreign_find(
/*==============*/
dict_table_t* table, /*!< in: table object */
const char* id) /*!< in: foreign constraint id */
dict_table_t* table, /*!< in: table object */
dict_foreign_t* foreign) /*!< in: foreign constraint */
{
dict_foreign_t* foreign;
ut_ad(mutex_own(&(dict_sys->mutex)));
foreign = UT_LIST_GET_FIRST(table->foreign_list);
dict_foreign_set::iterator it = table->foreign_set.find(foreign);
while (foreign) {
if (ut_strcmp(id, foreign->id) == 0) {
return(foreign);
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
if (it != table->foreign_set.end()) {
return(*it);
}
foreign = UT_LIST_GET_FIRST(table->referenced_list);
it = table->referenced_set.find(foreign);
while (foreign) {
if (ut_strcmp(id, foreign->id) == 0) {
return(foreign);
}
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
if (it != table->referenced_set.end()) {
return(*it);
}
return(NULL);
@ -3407,11 +3405,11 @@ dict_foreign_add_to_cache(
ut_a(for_table || ref_table);
if (for_table) {
for_in_cache = dict_foreign_find(for_table, foreign->id);
for_in_cache = dict_foreign_find(for_table, foreign);
}
if (!for_in_cache && ref_table) {
for_in_cache = dict_foreign_find(ref_table, foreign->id);
for_in_cache = dict_foreign_find(ref_table, foreign);
}
if (for_in_cache) {
@ -3448,9 +3446,12 @@ dict_foreign_add_to_cache(
for_in_cache->referenced_table = ref_table;
for_in_cache->referenced_index = index;
UT_LIST_ADD_LAST(referenced_list,
ref_table->referenced_list,
for_in_cache);
std::pair<dict_foreign_set::iterator, bool> ret
= ref_table->referenced_set.insert(for_in_cache);
ut_a(ret.second); /* second is true if the insertion
took place */
added_to_referenced_list = TRUE;
}
@ -3479,10 +3480,13 @@ dict_foreign_add_to_cache(
if (for_in_cache == foreign) {
if (added_to_referenced_list) {
UT_LIST_REMOVE(
referenced_list,
ref_table->referenced_list,
for_in_cache);
const dict_foreign_set::size_type n
= ref_table->referenced_set
.erase(for_in_cache);
ut_a(n == 1); /* the number of
elements removed must
be one */
}
mem_heap_free(foreign->heap);
@ -3493,9 +3497,11 @@ dict_foreign_add_to_cache(
for_in_cache->foreign_table = for_table;
for_in_cache->foreign_index = index;
UT_LIST_ADD_LAST(foreign_list,
for_table->foreign_list,
for_in_cache);
std::pair<dict_foreign_set::iterator, bool> ret
= for_table->foreign_set.insert(for_in_cache);
ut_a(ret.second); /* second is true if the insertion
took place */
}
/* We need to move the table to the non-LRU end of the table LRU
@ -4073,9 +4079,12 @@ dict_table_get_highest_foreign_id(
ut_a(table);
len = ut_strlen(table->name);
foreign = UT_LIST_GET_FIRST(table->foreign_list);
while (foreign) {
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
++it) {
foreign = *it;
if (ut_strlen(foreign->id) > ((sizeof dict_ibfk) - 1) + len
&& 0 == ut_memcmp(foreign->id, table->name, len)
&& 0 == ut_memcmp(foreign->id + len,
@ -4094,8 +4103,6 @@ dict_table_get_highest_foreign_id(
}
}
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
return(biggest_id);
@ -4156,6 +4163,7 @@ dict_create_foreign_constraints_low(
dict_table_t* referenced_table;
dict_table_t* table_to_alter;
ulint highest_id_so_far = 0;
ulint number = 1;
dict_index_t* index;
dict_foreign_t* foreign;
const char* ptr = sql_string;
@ -4174,6 +4182,8 @@ dict_create_foreign_constraints_low(
const dict_col_t*columns[500];
const char* column_names[500];
const char* referenced_table_name;
dict_foreign_set local_fk_set;
dict_foreign_set_free local_fk_set_free(local_fk_set);
ut_ad(!srv_read_only_mode);
ut_ad(mutex_own(&(dict_sys->mutex)));
@ -4238,6 +4248,7 @@ dict_create_foreign_constraints_low(
table_to_alter);
}
number = highest_id_so_far + 1;
/* Scan for foreign key declarations in a loop */
loop:
/* Scan either to "CONSTRAINT" or "FOREIGN", whichever is closer */
@ -4282,7 +4293,7 @@ loop:
command, determine if there are any foreign keys, and
if so, immediately reject the command if the table is a
temporary one. For now, this kludge will work. */
if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0)) {
if (reject_fks && !local_fk_set.empty()) {
return(DB_CANNOT_ADD_CONSTRAINT);
}
@ -4292,7 +4303,17 @@ loop:
to the data dictionary system tables on disk */
error = dict_create_add_foreigns_to_dictionary(
highest_id_so_far, table, trx);
local_fk_set, table, trx);
if (error == DB_SUCCESS) {
table->foreign_set.insert(local_fk_set.begin(),
local_fk_set.end());
std::for_each(local_fk_set.begin(),
local_fk_set.end(),
dict_foreign_add_to_referenced_table());
local_fk_set.clear();
}
return(error);
}
@ -4451,6 +4472,24 @@ col_loop1:
strcpy(foreign->id + db_len + 1, constraint_name);
}
if (foreign->id == NULL) {
error = dict_create_add_foreign_id(&number,
table->name, foreign);
if (error != DB_SUCCESS) {
dict_foreign_free(foreign);
return(error);
}
}
std::pair<dict_foreign_set::iterator, bool> ret
= local_fk_set.insert(foreign);
if (!ret.second) {
/* A duplicate foreign key name has been found */
dict_foreign_free(foreign);
return(DB_CANNOT_ADD_CONSTRAINT);
}
foreign->foreign_table = table;
foreign->foreign_table_name = mem_heap_strdup(
foreign->heap, table->name);
@ -4476,8 +4515,6 @@ col_loop1:
checking of foreign key constraints! */
if (!success || (!referenced_table && trx->check_foreigns)) {
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
fprintf(ef, "%s:\nCannot resolve table name close to:\n"
@ -4491,7 +4528,6 @@ col_loop1:
ptr = dict_accept(cs, ptr, "(", &success);
if (!success) {
dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT);
@ -4506,7 +4542,6 @@ col_loop2:
i++;
if (!success) {
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
@ -4527,7 +4562,6 @@ col_loop2:
ptr = dict_accept(cs, ptr, ")", &success);
if (!success || foreign->n_fields != i) {
dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
@ -4553,7 +4587,6 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "UPDATE", &success);
if (!success) {
dict_foreign_free(foreign);
dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr);
@ -4591,7 +4624,6 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "ACTION", &success);
if (!success) {
dict_foreign_free(foreign);
dict_foreign_report_syntax_err(
name, start_of_latest_foreign, ptr);
@ -4610,7 +4642,6 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "SET", &success);
if (!success) {
dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT);
@ -4619,7 +4650,6 @@ scan_on_conditions:
ptr = dict_accept(cs, ptr, "NULL", &success);
if (!success) {
dict_foreign_free(foreign);
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
ptr);
return(DB_CANNOT_ADD_CONSTRAINT);
@ -4632,8 +4662,6 @@ scan_on_conditions:
/* It is not sensible to define SET NULL
if the column is not allowed to be NULL! */
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
fprintf(ef, "%s:\n"
@ -4659,8 +4687,6 @@ try_find_index:
if (n_on_deletes > 1 || n_on_updates > 1) {
/* It is an error to define more than 1 action */
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
fprintf(ef, "%s:\n"
@ -4682,7 +4708,6 @@ try_find_index:
foreign->foreign_index,
TRUE, FALSE);
if (!index) {
dict_foreign_free(foreign);
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
fprintf(ef, "%s:\n"
@ -4726,16 +4751,6 @@ try_find_index:
= mem_heap_strdup(foreign->heap, column_names[i]);
}
/* We found an ok constraint definition: add to the lists */
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
if (referenced_table) {
UT_LIST_ADD_LAST(referenced_list,
referenced_table->referenced_list,
foreign);
}
goto loop;
}
/**************************************************************************
@ -4821,7 +4836,6 @@ dict_foreign_parse_drop_constraints(
const char*** constraints_to_drop) /*!< out: id's of the
constraints to drop */
{
dict_foreign_t* foreign;
ibool success;
char* str;
size_t len;
@ -4898,25 +4912,10 @@ loop:
(*constraints_to_drop)[*n] = id;
(*n)++;
/* Look for the given constraint id */
foreign = UT_LIST_GET_FIRST(table->foreign_list);
while (foreign != NULL) {
if (0 == innobase_strcasecmp(foreign->id, id)
|| (strchr(foreign->id, '/')
&& 0 == innobase_strcasecmp(
id,
dict_remove_db_name(foreign->id)))) {
/* Found */
break;
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
if (foreign == NULL) {
if (std::find_if(table->foreign_set.begin(),
table->foreign_set.end(),
dict_foreign_matches_id(id))
== table->foreign_set.end()) {
if (!srv_read_only_mode) {
FILE* ef = dict_foreign_err_file;
@ -5243,7 +5242,6 @@ dict_table_print(
dict_table_t* table) /*!< in: table */
{
dict_index_t* index;
dict_foreign_t* foreign;
ulint i;
ut_ad(mutex_own(&(dict_sys->mutex)));
@ -5282,19 +5280,13 @@ dict_table_print(
dict_table_stats_unlock(table, RW_X_LATCH);
foreign = UT_LIST_GET_FIRST(table->foreign_list);
std::for_each(table->foreign_set.begin(),
table->foreign_set.end(),
dict_foreign_print_low);
while (foreign != NULL) {
dict_foreign_print_low(foreign);
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
foreign = UT_LIST_GET_FIRST(table->referenced_list);
while (foreign != NULL) {
dict_foreign_print_low(foreign);
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
std::for_each(table->referenced_set.begin(),
table->referenced_set.end(),
dict_foreign_print_low);
}
/**********************************************************************//**
@ -5502,15 +5494,12 @@ dict_print_info_on_foreign_keys(
mutex_enter(&(dict_sys->mutex));
foreign = UT_LIST_GET_FIRST(table->foreign_list);
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
++it) {
if (foreign == NULL) {
mutex_exit(&(dict_sys->mutex));
foreign = *it;
return;
}
while (foreign != NULL) {
if (create_table_format) {
dict_print_info_on_foreign_key_in_create_format(
file, trx, foreign, TRUE);
@ -5567,8 +5556,6 @@ dict_print_info_on_foreign_keys(
fputs(" ON UPDATE NO ACTION", file);
}
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
mutex_exit(&(dict_sys->mutex));
@ -5900,10 +5887,11 @@ dict_foreign_replace_index(
ut_ad(index->to_be_dropped);
ut_ad(index->table == table);
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
foreign;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
++it) {
foreign = *it;
if (foreign->foreign_index == index) {
ut_ad(foreign->foreign_table == index->table);
@ -5923,10 +5911,11 @@ dict_foreign_replace_index(
}
}
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
foreign;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
for (dict_foreign_set::iterator it = table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
foreign = *it;
if (foreign->referenced_index == index) {
ut_ad(foreign->referenced_table == index->table);
@ -6246,24 +6235,24 @@ dict_table_schema_check(
}
}
if (req_schema->n_foreign != UT_LIST_GET_LEN(table->foreign_list)) {
if (req_schema->n_foreign != table->foreign_set.size()) {
ut_snprintf(
errstr, errstr_sz,
"Table %s has %lu foreign key(s) pointing to other "
"tables, but it must have %lu.",
"Table %s has " ULINTPF " foreign key(s) pointing"
" to other tables, but it must have %lu.",
ut_format_name(req_schema->table_name,
TRUE, buf, sizeof(buf)),
UT_LIST_GET_LEN(table->foreign_list),
static_cast<ulint>(table->foreign_set.size()),
req_schema->n_foreign);
return(DB_ERROR);
}
if (req_schema->n_referenced != UT_LIST_GET_LEN(table->referenced_list)) {
if (req_schema->n_referenced != table->referenced_set.size()) {
ut_snprintf(
errstr, errstr_sz,
"There are %lu foreign key(s) pointing to %s, "
"There are " ULINTPF " foreign key(s) pointing to %s, "
"but there must be %lu.",
UT_LIST_GET_LEN(table->referenced_list),
static_cast<ulint>(table->referenced_set.size()),
ut_format_name(req_schema->table_name,
TRUE, buf, sizeof(buf)),
req_schema->n_referenced);

View file

@ -124,6 +124,9 @@ dict_mem_table_create(
}
#endif /* !UNIV_HOTBACKUP */
new(&table->foreign_set) dict_foreign_set();
new(&table->referenced_set) dict_foreign_set();
return(table);
}
@ -156,6 +159,9 @@ dict_mem_table_free(
dict_table_stats_latch_destroy(table);
table->foreign_set.~dict_foreign_set();
table->referenced_set.~dict_foreign_set();
ut_free(table->name);
mem_heap_free(table->heap);
}
@ -326,10 +332,15 @@ dict_mem_table_col_rename_low(
table->col_names = col_names;
}
dict_foreign_t* foreign;
/* Replace the field names in every foreign key constraint. */
for (dict_foreign_t* foreign = UT_LIST_GET_FIRST(table->foreign_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
++it) {
foreign = *it;
for (unsigned f = 0; f < foreign->n_fields; f++) {
/* These can point straight to
table->col_names, because the foreign key
@ -341,10 +352,12 @@ dict_mem_table_col_rename_low(
}
}
for (dict_foreign_t* foreign = UT_LIST_GET_FIRST(
table->referenced_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
for (dict_foreign_set::iterator it = table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
foreign = *it;
for (unsigned f = 0; f < foreign->n_fields; f++) {
/* foreign->referenced_col_names[] need to be
copies, because the constraint may become

View file

@ -112,7 +112,7 @@ completes, we decrement the count and return the file node to the LRU-list if
the count drops to zero. */
/** When mysqld is run, the default directory "." is the mysqld datadir,
but in the MySQL Embedded Server Library and ibbackup it is not the default
but in the MySQL Embedded Server Library and mysqlbackup it is not the default
directory, and we must set the base file path explicitly */
UNIV_INTERN const char* fil_path_to_mysql_datadir = ".";
@ -2017,8 +2017,8 @@ fil_check_first_page(
}
/*******************************************************************//**
Reads the flushed lsn, arch no, and tablespace flag fields from a data
file at database startup.
Reads the flushed lsn, arch no, space_id and tablespace flag fields from
the first page of a data file at database startup.
@retval NULL on success, or if innodb_force_recovery is set
@return pointer to an error message string */
UNIV_INTERN
@ -2055,16 +2055,19 @@ fil_read_first_page(
os_file_read(data_file, page, 0, UNIV_PAGE_SIZE);
*flags = fsp_header_get_flags(page);
*space_id = fsp_header_get_space_id(page);
flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN);
/* The FSP_HEADER on page 0 is only valid for the first file
in a tablespace. So if this is not the first datafile, leave
*flags and *space_id as they were read from the first file and
do not validate the first page. */
if (!one_read_already) {
*flags = fsp_header_get_flags(page);
*space_id = fsp_header_get_space_id(page);
check_msg = fil_check_first_page(page);
}
flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN);
ut_free(buf);
if (check_msg) {
@ -2272,13 +2275,13 @@ exists and the space id in it matches. Replays the create operation if a file
at that path does not exist yet. If the database directory for the file to be
created does not exist, then we create the directory, too.
Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the
datadir that we should use in replaying the file operations.
Note that mysqlbackup --apply-log sets fil_path_to_mysql_datadir to point to
the datadir that we should use in replaying the file operations.
InnoDB recovery does not replay these fully since it always sets the space id
to zero. But ibbackup does replay them. TODO: If remote tablespaces are used,
ibbackup will only create tables in the default directory since MLOG_FILE_CREATE
and MLOG_FILE_CREATE2 only know the tablename, not the path.
to zero. But mysqlbackup does replay them. TODO: If remote tablespaces are
used, mysqlbackup will only create tables in the default directory since
MLOG_FILE_CREATE and MLOG_FILE_CREATE2 only know the tablename, not the path.
@return end of log record, or NULL if the record was not completely
contained between ptr and end_ptr */
@ -2365,11 +2368,11 @@ fil_op_log_parse_or_replay(
}
/* Let us try to perform the file operation, if sensible. Note that
ibbackup has at this stage already read in all space id info to the
mysqlbackup has at this stage already read in all space id info to the
fil0fil.cc data structures.
NOTE that our algorithm is not guaranteed to work correctly if there
were renames of tables during the backup. See ibbackup code for more
were renames of tables during the backup. See mysqlbackup code for more
on the problem. */
switch (type) {
@ -2784,12 +2787,12 @@ fil_delete_tablespace(
if (err == DB_SUCCESS) {
#ifndef UNIV_HOTBACKUP
/* Write a log record about the deletion of the .ibd
file, so that ibbackup can replay it in the
file, so that mysqlbackup can replay it in the
--apply-log phase. We use a dummy mtr and the familiar
log write mechanism. */
mtr_t mtr;
/* When replaying the operation in ibbackup, do not try
/* When replaying the operation in mysqlbackup, do not try
to write any log record */
mtr_start(&mtr);
@ -4463,7 +4466,7 @@ will_not_choose:
" (< 4 pages 16 kB each),\n"
"InnoDB: or the space id in the file header"
" is not sensible.\n"
"InnoDB: This can happen in an ibbackup run,"
"InnoDB: This can happen in an mysqlbackup run,"
" and is not dangerous.\n",
fsp->filepath, fsp->id, fsp->filepath, size);
os_file_close(fsp->file);
@ -4500,7 +4503,7 @@ will_not_choose:
"InnoDB: because space %s with the same id\n"
"InnoDB: was scanned earlier. This can happen"
" if you have renamed tables\n"
"InnoDB: during an ibbackup run.\n",
"InnoDB: during an mysqlbackup run.\n",
fsp->filepath, fsp->id, fsp->filepath,
space->name);
os_file_close(fsp->file);
@ -5213,9 +5216,9 @@ file_extended:
#ifdef UNIV_HOTBACKUP
/********************************************************************//**
Extends all tablespaces to the size stored in the space header. During the
ibbackup --apply-log phase we extended the spaces on-demand so that log records
could be applied, but that may have left spaces still too small compared to
the size stored in the space header. */
mysqlbackup --apply-log phase we extended the spaces on-demand so that log
records could be applied, but that may have left spaces still too small
compared to the size stored in the space header. */
UNIV_INTERN
void
fil_extend_tablespaces_to_stored_len(void)
@ -5712,7 +5715,7 @@ fil_io(
ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
#ifdef UNIV_HOTBACKUP
/* In ibbackup do normal i/o, not aio */
/* In mysqlbackup do normal i/o, not aio */
if (type == OS_FILE_READ) {
ret = os_file_read(node->handle, buf, offset, len);
} else {

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -83,11 +83,11 @@ UNIV_INTERN
fts_ast_node_t*
fts_ast_create_node_term(
/*=====================*/
void* arg, /*!< in: ast state instance */
const char* ptr) /*!< in: ast term string */
void* arg, /*!< in: ast state instance */
const fts_ast_string_t* ptr) /*!< in: ast term string */
{
fts_ast_state_t* state = static_cast<fts_ast_state_t*>(arg);
ulint len = strlen(ptr);
ulint len = ptr->len;
ulint cur_pos = 0;
fts_ast_node_t* node = NULL;
fts_ast_node_t* node_list = NULL;
@ -101,8 +101,9 @@ fts_ast_create_node_term(
cur_len = innobase_mysql_fts_get_token(
state->charset,
reinterpret_cast<const byte*>(ptr) + cur_pos,
reinterpret_cast<const byte*>(ptr) + len, &str, &offset);
reinterpret_cast<const byte*>(ptr->str) + cur_pos,
reinterpret_cast<const byte*>(ptr->str) + len,
&str, &offset);
if (cur_len == 0) {
break;
@ -124,10 +125,8 @@ fts_ast_create_node_term(
node->type = FTS_AST_TERM;
node->term.ptr = static_cast<byte*>(ut_malloc(
str.f_len + 1));
memcpy(node->term.ptr, str.f_str, str.f_len);
node->term.ptr[str.f_len] = '\0';
node->term.ptr = fts_ast_string_create(
str.f_str, str.f_len);
fts_ast_state_add_node(
static_cast<fts_ast_state_t*>(arg), node);
@ -160,25 +159,21 @@ UNIV_INTERN
fts_ast_node_t*
fts_ast_create_node_text(
/*=====================*/
void* arg, /*!< in: ast state instance */
const char* ptr) /*!< in: ast text string */
void* arg, /*!< in: ast state instance */
const fts_ast_string_t* ptr) /*!< in: ast text string */
{
ulint len = strlen(ptr);
ulint len = ptr->len;
fts_ast_node_t* node = NULL;
/* Once we come here, the string must have at least 2 quotes ""
around the query string, which could be empty. Also the query
string may contain 0x00 in it, we don't treat it as null-terminated. */
ut_ad(len >= 2);
ut_ad(ptr->str[0] == '\"' && ptr->str[len - 1] == '\"');
ut_ad(len >= 1);
if (len <= 2) {
/* There is a way to directly supply null terminator
in the query string (by using 0x220022) and get here,
and certainly it would not make a valid query text */
ut_ad(ptr[0] == '\"');
if (len == 2) {
ut_ad(ptr[1] == '\"');
}
if (len == 2) {
/* If the query string contains nothing except quotes,
it's obviously an invalid query. */
return(NULL);
}
@ -188,11 +183,9 @@ fts_ast_create_node_text(
len -= 2;
node->type = FTS_AST_TEXT;
node->text.ptr = static_cast<byte*>(ut_malloc(len + 1));
/*!< Skip copying the first quote */
memcpy(node->text.ptr, ptr + 1, len);
node->text.ptr[len] = 0;
node->text.ptr = fts_ast_string_create(
reinterpret_cast<const byte*>(ptr->str + 1), len);
node->text.distance = ULINT_UNDEFINED;
fts_ast_state_add_node((fts_ast_state_t*) arg, node);
@ -275,14 +268,14 @@ fts_ast_free_node(
switch (node->type) {
case FTS_AST_TEXT:
if (node->text.ptr) {
ut_free(node->text.ptr);
fts_ast_string_free(node->text.ptr);
node->text.ptr = NULL;
}
break;
case FTS_AST_TERM:
if (node->term.ptr) {
ut_free(node->term.ptr);
fts_ast_string_free(node->term.ptr);
node->term.ptr = NULL;
}
break;
@ -421,10 +414,10 @@ fts_ast_state_free(
fts_ast_node_t* next = node->next_alloc;
if (node->type == FTS_AST_TEXT && node->text.ptr) {
ut_free(node->text.ptr);
fts_ast_string_free(node->text.ptr);
node->text.ptr = NULL;
} else if (node->type == FTS_AST_TERM && node->term.ptr) {
ut_free(node->term.ptr);
fts_ast_string_free(node->term.ptr);
node->term.ptr = NULL;
}
@ -445,11 +438,13 @@ fts_ast_node_print(
{
switch (node->type) {
case FTS_AST_TEXT:
printf("TEXT: %s\n", node->text.ptr);
printf("TEXT: ");
fts_ast_string_print(node->text.ptr);
break;
case FTS_AST_TERM:
printf("TERM: %s\n", node->term.ptr);
printf("TERM: ");
fts_ast_string_print(node->term.ptr);
break;
case FTS_AST_LIST:
@ -628,3 +623,74 @@ fts_ast_visit(
return(error);
}
/**
Create an ast string object, with NUL-terminator, so the string
has one more byte than len
@param[in] str pointer to string
@param[in] len length of the string
@return ast string with NUL-terminator */
UNIV_INTERN
fts_ast_string_t*
fts_ast_string_create(
const byte* str,
ulint len)
{
fts_ast_string_t* ast_str;
ut_ad(len > 0);
ast_str = static_cast<fts_ast_string_t*>
(ut_malloc(sizeof(fts_ast_string_t)));
ast_str->str = static_cast<byte*>(ut_malloc(len + 1));
ast_str->len = len;
memcpy(ast_str->str, str, len);
ast_str->str[len] = '\0';
return(ast_str);
}
/**
Free an ast string instance
@param[in,out] ast_str string to free */
UNIV_INTERN
void
fts_ast_string_free(
fts_ast_string_t* ast_str)
{
if (ast_str != NULL) {
ut_free(ast_str->str);
ut_free(ast_str);
}
}
/**
Translate ast string of type FTS_AST_NUMB to unsigned long by strtoul
@param[in] str string to translate
@param[in] base the base
@return translated number */
UNIV_INTERN
ulint
fts_ast_string_to_ul(
const fts_ast_string_t* ast_str,
int base)
{
return(strtoul(reinterpret_cast<const char*>(ast_str->str),
NULL, base));
}
/**
Print the ast string
@param[in] str string to print */
UNIV_INTERN
void
fts_ast_string_print(
const fts_ast_string_t* ast_str)
{
for (ulint i = 0; i < ast_str->len; ++i) {
printf("%c", ast_str->str[i]);
}
printf("\n");
}

View file

@ -451,7 +451,7 @@ static yyconst flex_int16_t yy_chk[32] =
#line 1 "fts0blex.l"
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -806,7 +806,7 @@ case 3:
YY_RULE_SETUP
#line 53 "fts0blex.l"
{
val->token = strdup(fts0bget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner));
return(FTS_NUMB);
}
@ -815,7 +815,7 @@ case 4:
YY_RULE_SETUP
#line 59 "fts0blex.l"
{
val->token = strdup(fts0bget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner));
return(FTS_TERM);
}
@ -824,7 +824,7 @@ case 5:
YY_RULE_SETUP
#line 65 "fts0blex.l"
{
val->token = strdup(fts0bget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner));
return(FTS_TEXT);
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -51,19 +51,19 @@ this program; if not, write to the Free Software Foundation, Inc.,
}
[0-9]+ {
val->token = strdup(fts0bget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner));
return(FTS_NUMB);
}
[^" \n*()+\-<>~@%]* {
val->token = strdup(fts0bget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner));
return(FTS_TERM);
}
\"[^\"\n]*\" {
val->token = strdup(fts0bget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0bget_text(yyscanner)), fts0bget_leng(yyscanner));
return(FTS_TEXT);
}

View file

@ -608,8 +608,10 @@ fts_cache_init(
cache->total_size = 0;
mutex_enter((ib_mutex_t*) &cache->deleted_lock);
cache->deleted_doc_ids = ib_vector_create(
cache->sync_heap, sizeof(fts_update_t), 4);
mutex_exit((ib_mutex_t*) &cache->deleted_lock);
/* Reset the cache data for all the FTS indexes. */
for (i = 0; i < ib_vector_size(cache->indexes); ++i) {
@ -1137,7 +1139,10 @@ fts_cache_clear(
cache->sync_heap->arg = NULL;
cache->total_size = 0;
mutex_enter((ib_mutex_t*) &cache->deleted_lock);
cache->deleted_doc_ids = NULL;
mutex_exit((ib_mutex_t*) &cache->deleted_lock);
}
/*********************************************************************//**
@ -1954,10 +1959,15 @@ fts_create_one_index_table(
char* table_name = fts_get_table_name(fts_table);
dberr_t error;
CHARSET_INFO* charset;
ulint flags2 = 0;
ut_ad(index->type & DICT_FTS);
new_table = dict_mem_table_create(table_name, 0, 5, 1, 0);
if (srv_file_per_table) {
flags2 = DICT_TF2_USE_TABLESPACE;
}
new_table = dict_mem_table_create(table_name, 0, 5, 1, flags2);
field = dict_index_get_nth_field(index, 0);
charset = innobase_get_fts_charset(
@ -1986,7 +1996,7 @@ fts_create_one_index_table(
dict_mem_table_add_col(new_table, heap, "ilist", DATA_BLOB,
4130048, 0);
error = row_create_table_for_mysql(new_table, trx, true);
error = row_create_table_for_mysql(new_table, trx, false);
if (error != DB_SUCCESS) {
trx->error_state = error;
@ -2251,11 +2261,15 @@ static
fts_trx_t*
fts_trx_create(
/*===========*/
trx_t* trx) /*!< in: InnoDB transaction */
trx_t* trx) /*!< in/out: InnoDB
transaction */
{
fts_trx_t* ftt;
ib_alloc_t* heap_alloc;
mem_heap_t* heap = mem_heap_create(1024);
fts_trx_t* ftt;
ib_alloc_t* heap_alloc;
mem_heap_t* heap = mem_heap_create(1024);
trx_named_savept_t* savep;
ut_a(trx->fts_trx == NULL);
ftt = static_cast<fts_trx_t*>(mem_heap_alloc(heap, sizeof(fts_trx_t)));
ftt->trx = trx;
@ -2273,6 +2287,14 @@ fts_trx_create(
fts_savepoint_create(ftt->savepoints, NULL, NULL);
fts_savepoint_create(ftt->last_stmt, NULL, NULL);
/* Copy savepoints that already set before. */
for (savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
savep != NULL;
savep = UT_LIST_GET_NEXT(trx_savepoints, savep)) {
fts_savepoint_take(trx, ftt, savep->name);
}
return(ftt);
}
@ -4366,6 +4388,7 @@ fts_sync_commit(
/* We need to do this within the deleted lock since fts_delete() can
attempt to add a deleted doc id to the cache deleted id array. */
fts_cache_clear(cache);
DEBUG_SYNC_C("fts_deleted_doc_ids_clear");
fts_cache_init(cache);
rw_lock_x_unlock(&cache->lock);
@ -5167,6 +5190,12 @@ fts_cache_append_deleted_doc_ids(
mutex_enter((ib_mutex_t*) &cache->deleted_lock);
if (cache->deleted_doc_ids == NULL) {
mutex_exit((ib_mutex_t*) &cache->deleted_lock);
return;
}
for (i = 0; i < ib_vector_size(cache->deleted_doc_ids); ++i) {
fts_update_t* update;
@ -5452,16 +5481,15 @@ void
fts_savepoint_take(
/*===============*/
trx_t* trx, /*!< in: transaction */
fts_trx_t* fts_trx, /*!< in: fts transaction */
const char* name) /*!< in: savepoint name */
{
mem_heap_t* heap;
fts_trx_t* fts_trx;
fts_savepoint_t* savepoint;
fts_savepoint_t* last_savepoint;
ut_a(name != NULL);
fts_trx = trx->fts_trx;
heap = fts_trx->heap;
/* The implied savepoint must exist. */
@ -5778,7 +5806,7 @@ fts_savepoint_rollback(
ut_a(ib_vector_size(savepoints) > 0);
/* Restore the savepoint. */
fts_savepoint_take(trx, name);
fts_savepoint_take(trx, trx->fts_trx, name);
}
}

View file

@ -100,6 +100,8 @@ extern int ftserror(const char* p);
#define YYPARSE_PARAM state
#define YYLEX_PARAM ((fts_ast_state_t*) state)->lexer
#define YYTOKENFREE(token) fts_ast_string_free((token))
typedef int (*fts_scanner_alt)(YYSTYPE* val, yyscan_t yyscanner);
typedef int (*fts_scanner)();
@ -154,9 +156,9 @@ typedef union YYSTYPE
/* Line 293 of yacc.c */
#line 61 "fts0pars.y"
int oper;
char* token;
fts_ast_node_t* node;
int oper;
fts_ast_string_t* token;
fts_ast_node_t* node;
@ -632,6 +634,19 @@ while (YYID (0))
#define YYTERROR 1
#define YYERRCODE 256
#define YYERRCLEANUP \
do \
switch (yylastchar) \
{ \
case FTS_NUMB: \
case FTS_TEXT: \
case FTS_TERM: \
YYTOKENFREE(yylval.token); \
break; \
default: \
break; \
} \
while (YYID (0))
/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
If N is 0, then set CURRENT to the empty location which ends
@ -1169,6 +1184,8 @@ yyparse ()
{
/* The lookahead symbol. */
int yychar;
/* The backup of yychar when there is an error and we're in yyerrlab. */
int yylastchar;
/* The semantic value of the lookahead symbol. */
YYSTYPE yylval;
@ -1524,8 +1541,8 @@ yyreduce:
/* Line 1806 of yacc.c */
#line 141 "fts0pars.y"
{
fts_ast_term_set_distance((yyvsp[(1) - (3)].node), strtoul((yyvsp[(3) - (3)].token), NULL, 10));
free((yyvsp[(3) - (3)].token));
fts_ast_term_set_distance((yyvsp[(1) - (3)].node), fts_ast_string_to_ul((yyvsp[(3) - (3)].token), 10));
fts_ast_string_free((yyvsp[(3) - (3)].token));
}
break;
@ -1557,8 +1574,8 @@ yyreduce:
{
(yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node));
fts_ast_add_node((yyval.node), (yyvsp[(2) - (4)].node));
fts_ast_term_set_distance((yyvsp[(2) - (4)].node), strtoul((yyvsp[(4) - (4)].token), NULL, 10));
free((yyvsp[(4) - (4)].token));
fts_ast_term_set_distance((yyvsp[(2) - (4)].node), fts_ast_string_to_ul((yyvsp[(4) - (4)].token), 10));
fts_ast_string_free((yyvsp[(4) - (4)].token));
}
break;
@ -1623,7 +1640,7 @@ yyreduce:
#line 191 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token));
free((yyvsp[(1) - (1)].token));
fts_ast_string_free((yyvsp[(1) - (1)].token));
}
break;
@ -1633,7 +1650,7 @@ yyreduce:
#line 196 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token));
free((yyvsp[(1) - (1)].token));
fts_ast_string_free((yyvsp[(1) - (1)].token));
}
break;
@ -1652,7 +1669,7 @@ yyreduce:
#line 207 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_text(state, (yyvsp[(1) - (1)].token));
free((yyvsp[(1) - (1)].token));
fts_ast_string_free((yyvsp[(1) - (1)].token));
}
break;
@ -1700,6 +1717,8 @@ yyreduce:
| yyerrlab -- here on detecting error |
`------------------------------------*/
yyerrlab:
/* Backup yychar, in case we would change it. */
yylastchar = yychar;
/* Make sure we have latest lookahead translation. See comments at
user semantic actions for why this is necessary. */
yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
@ -1755,7 +1774,11 @@ yyerrlab:
{
/* Return failure if at end of input. */
if (yychar == YYEOF)
YYABORT;
{
/* Since we don't need the token, we have to free it first. */
YYERRCLEANUP;
YYABORT;
}
}
else
{
@ -1812,7 +1835,11 @@ yyerrlab1:
/* Pop the current state because it cannot handle the error token. */
if (yyssp == yyss)
YYABORT;
{
/* Since we don't need the error token, we have to free it first. */
YYERRCLEANUP;
YYABORT;
}
yydestruct ("Error: popping",

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -59,9 +59,9 @@ struct fts_lexer_struct {
%}
%union {
int oper;
char* token;
fts_ast_node_t* node;
int oper;
fts_ast_string_t* token;
fts_ast_node_t* node;
};
/* Enable re-entrant parser */
@ -139,8 +139,8 @@ expr : term {
}
| text '@' FTS_NUMB {
fts_ast_term_set_distance($1, strtoul($3, NULL, 10));
free($3);
fts_ast_term_set_distance($1, fts_ast_string_to_ul($3, 10));
fts_ast_string_free($3);
}
| prefix term '*' {
@ -157,8 +157,8 @@ expr : term {
| prefix text '@' FTS_NUMB {
$$ = fts_ast_create_node_list(state, $1);
fts_ast_add_node($$, $2);
fts_ast_term_set_distance($2, strtoul($4, NULL, 10));
free($4);
fts_ast_term_set_distance($2, fts_ast_string_to_ul($4, 10));
fts_ast_string_free($4);
}
| prefix text {
@ -190,12 +190,12 @@ prefix : '-' {
term : FTS_TERM {
$$ = fts_ast_create_node_term(state, $1);
free($1);
fts_ast_string_free($1);
}
| FTS_NUMB {
$$ = fts_ast_create_node_term(state, $1);
free($1);
fts_ast_string_free($1);
}
/* Ignore leading '*' */
@ -206,7 +206,7 @@ term : FTS_TERM {
text : FTS_TEXT {
$$ = fts_ast_create_node_text(state, $1);
free($1);
fts_ast_string_free($1);
}
;
%%

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -2800,20 +2800,19 @@ fts_query_get_token(
ulint str_len;
byte* new_ptr = NULL;
str_len = ut_strlen((char*) node->term.ptr);
str_len = node->term.ptr->len;
ut_a(node->type == FTS_AST_TERM);
token->f_len = str_len;
token->f_str = node->term.ptr;
token->f_str = node->term.ptr->str;
if (node->term.wildcard) {
token->f_str = static_cast<byte*>(ut_malloc(str_len + 2));
token->f_len = str_len + 1;
/* Need to copy the NUL character too. */
memcpy(token->f_str, node->term.ptr, str_len + 1);
memcpy(token->f_str, node->term.ptr->str, str_len);
token->f_str[str_len] = '%';
token->f_str[token->f_len] = 0;
@ -2848,8 +2847,8 @@ fts_query_visitor(
switch (node->type) {
case FTS_AST_TEXT:
token.f_str = node->text.ptr;
token.f_len = ut_strlen((char*) token.f_str);
token.f_str = node->text.ptr->str;
token.f_len = node->text.ptr->len;
if (query->oper == FTS_EXIST) {
ut_ad(query->intersection == NULL);
@ -2878,8 +2877,8 @@ fts_query_visitor(
break;
case FTS_AST_TERM:
token.f_str = node->term.ptr;
token.f_len = ut_strlen(reinterpret_cast<char*>(token.f_str));
token.f_str = node->term.ptr->str;
token.f_len = node->term.ptr->len;
/* Add the word to our RB tree that will be used to
calculate this terms per document frequency. */
@ -3191,13 +3190,9 @@ fts_query_read_node(
to assign the frequency on search string behalf. */
if (query->cur_node->type == FTS_AST_TERM
&& query->cur_node->term.wildcard) {
/* These cast are safe since we only care about the
terminating NUL character as an end of string marker. */
term.f_len = ut_strlen(reinterpret_cast<char*>
(query->cur_node->term.ptr));
term.f_len = query->cur_node->term.ptr->len;
ut_ad(FTS_MAX_WORD_LEN >= term.f_len);
memcpy(term.f_str, query->cur_node->term.ptr, term.f_len);
memcpy(term.f_str, query->cur_node->term.ptr->str, term.f_len);
} else {
term.f_len = word->f_len;
ut_ad(FTS_MAX_WORD_LEN >= word->f_len);
@ -3507,14 +3502,15 @@ fts_query_prepare_result(
doc_freq = rbt_value(fts_doc_freq_t, node);
/* Don't put deleted docs into result */
if (fts_bsearch(array, 0, static_cast<int>(size), doc_freq->doc_id)
>= 0) {
if (fts_bsearch(array, 0, static_cast<int>(size),
doc_freq->doc_id) >= 0) {
/* one less matching doc count */
--word_freq->doc_count;
continue;
}
ranking.doc_id = doc_freq->doc_id;
ranking.rank = static_cast<fts_rank_t>(
doc_freq->freq * word_freq->idf * word_freq->idf);
ranking.rank = static_cast<fts_rank_t>(doc_freq->freq);
ranking.words = NULL;
fts_query_add_ranking(query, result->rankings_by_id,
@ -3527,6 +3523,25 @@ fts_query_prepare_result(
}
}
/* Calculate IDF only after we exclude the deleted items */
fts_query_calculate_idf(query);
node = rbt_first(query->word_freqs);
word_freq = rbt_value(fts_word_freq_t, node);
/* Calculate the ranking for each doc */
for (node = rbt_first(result->rankings_by_id);
node != NULL;
node = rbt_next(result->rankings_by_id, node)) {
fts_ranking_t* ranking;
ranking = rbt_value(fts_ranking_t, node);
ranking->rank = static_cast<fts_rank_t>(
ranking->rank * word_freq->idf * word_freq->idf);
}
return(result);
}
@ -3900,6 +3915,7 @@ fts_query(
/* Get the deleted doc ids that are in the cache. */
fts_cache_append_deleted_doc_ids(
index->table->fts->cache, query.deleted->doc_ids);
DEBUG_SYNC_C("fts_deleted_doc_ids_append");
/* Sort the vector so that we can do a binary search over the ids. */
ib_vector_sort(query.deleted->doc_ids, fts_update_doc_id_cmp);
@ -3956,7 +3972,8 @@ fts_query(
}
/* Calculate the inverse document frequency of the terms. */
if (query.error == DB_SUCCESS) {
if (query.error == DB_SUCCESS
&& query.flags != FTS_OPT_RANKING) {
fts_query_calculate_idf(&query);
}

View file

@ -447,7 +447,7 @@ static yyconst flex_int16_t yy_chk[29] =
#line 1 "fts0tlex.l"
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -802,7 +802,7 @@ case 3:
YY_RULE_SETUP
#line 54 "fts0tlex.l"
{
val->token = strdup(fts0tget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner));
return(FTS_TEXT);
}
@ -811,7 +811,7 @@ case 4:
YY_RULE_SETUP
#line 60 "fts0tlex.l"
{
val->token = strdup(fts0tget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner));
return(FTS_TERM);
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -52,13 +52,13 @@ this program; if not, write to the Free Software Foundation, Inc.,
}
\"[^\"\n]*\" {
val->token = strdup(fts0tget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner));
return(FTS_TEXT);
}
[^" \n\%]* {
val->token = strdup(fts0tget_text(yyscanner));
val->token = fts_ast_string_create(reinterpret_cast<const byte*>(fts0tget_text(yyscanner)), fts0tget_leng(yyscanner));
return(FTS_TERM);
}

View file

@ -3572,7 +3572,7 @@ innobase_commit_ordered_2(
{
DBUG_ENTER("innobase_commit_ordered_2");
/* We need current binlog position for ibbackup to work.
/* We need current binlog position for mysqlbackup to work.
Note, the position is current because commit_ordered is guaranteed
to be called in same sequenece as writing to binlog. */
@ -4144,7 +4144,7 @@ innobase_savepoint(
error = trx_savepoint_for_mysql(trx, name, (ib_int64_t)0);
if (error == DB_SUCCESS && trx->fts_trx != NULL) {
fts_savepoint_take(trx, name);
fts_savepoint_take(trx, trx->fts_trx, name);
}
DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
@ -12169,9 +12169,13 @@ ha_innobase::get_foreign_key_list(
mutex_enter(&(dict_sys->mutex));
for (foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
for (dict_foreign_set::iterator it
= prebuilt->table->foreign_set.begin();
it != prebuilt->table->foreign_set.end();
++it) {
foreign = *it;
pf_key_info = get_foreign_key_info(thd, foreign);
if (pf_key_info) {
f_key_list->push_back(pf_key_info);
@ -12207,9 +12211,13 @@ ha_innobase::get_parent_foreign_key_list(
mutex_enter(&(dict_sys->mutex));
for (foreign = UT_LIST_GET_FIRST(prebuilt->table->referenced_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
for (dict_foreign_set::iterator it
= prebuilt->table->referenced_set.begin();
it != prebuilt->table->referenced_set.end();
++it) {
foreign = *it;
pf_key_info = get_foreign_key_info(thd, foreign);
if (pf_key_info) {
f_key_list->push_back(pf_key_info);
@ -12242,8 +12250,8 @@ ha_innobase::can_switch_engines(void)
"determining if there are foreign key constraints";
row_mysql_freeze_data_dictionary(prebuilt->trx);
can_switch = !UT_LIST_GET_FIRST(prebuilt->table->referenced_list)
&& !UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
can_switch = prebuilt->table->referenced_set.empty()
&& prebuilt->table->foreign_set.empty();
row_mysql_unfreeze_data_dictionary(prebuilt->trx);
prebuilt->trx->op_info = "";

View file

@ -590,15 +590,9 @@ innobase_init_foreign(
/* Check if any existing foreign key has the same id,
this is needed only if user supplies the constraint name */
for (const dict_foreign_t* existing_foreign
= UT_LIST_GET_FIRST(table->foreign_list);
existing_foreign != 0;
existing_foreign = UT_LIST_GET_NEXT(
foreign_list, existing_foreign)) {
if (ut_strcmp(existing_foreign->id, foreign->id) == 0) {
return(false);
}
if (table->foreign_set.find(foreign)
!= table->foreign_set.end()) {
return(false);
}
}
@ -2236,14 +2230,18 @@ innobase_check_foreigns_low(
const char* col_name,
bool drop)
{
dict_foreign_t* foreign;
ut_ad(mutex_own(&dict_sys->mutex));
/* Check if any FOREIGN KEY constraints are defined on this
column. */
for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST(
user_table->foreign_list);
foreign;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
for (dict_foreign_set::iterator it = user_table->foreign_set.begin();
it != user_table->foreign_set.end();
++it) {
foreign = *it;
if (!drop && !(foreign->type
& (DICT_FOREIGN_ON_DELETE_SET_NULL
| DICT_FOREIGN_ON_UPDATE_SET_NULL))) {
@ -2275,10 +2273,13 @@ innobase_check_foreigns_low(
/* Check if any FOREIGN KEY constraints in other tables are
referring to the column that is being dropped. */
for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST(
user_table->referenced_list);
foreign;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
for (dict_foreign_set::iterator it
= user_table->referenced_set.begin();
it != user_table->referenced_set.end();
++it) {
foreign = *it;
if (innobase_dropping_foreign(foreign, drop_fk, n_drop_fk)) {
continue;
}
@ -3598,11 +3599,12 @@ check_if_ok_to_rename:
continue;
}
for (dict_foreign_t* foreign = UT_LIST_GET_FIRST(
prebuilt->table->foreign_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(
foreign_list, foreign)) {
for (dict_foreign_set::iterator it
= prebuilt->table->foreign_set.begin();
it != prebuilt->table->foreign_set.end();
++it) {
dict_foreign_t* foreign = *it;
const char* fid = strchr(foreign->id, '/');
DBUG_ASSERT(fid);
@ -4443,10 +4445,12 @@ err_exit:
rename_foreign:
trx->op_info = "renaming column in SYS_FOREIGN_COLS";
for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST(
user_table->foreign_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
for (dict_foreign_set::iterator it = user_table->foreign_set.begin();
it != user_table->foreign_set.end();
++it) {
dict_foreign_t* foreign = *it;
for (unsigned i = 0; i < foreign->n_fields; i++) {
if (strcmp(foreign->foreign_col_names[i], from)) {
continue;
@ -4476,10 +4480,12 @@ rename_foreign:
}
}
for (const dict_foreign_t* foreign = UT_LIST_GET_FIRST(
user_table->referenced_list);
foreign != NULL;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
for (dict_foreign_set::iterator it
= user_table->referenced_set.begin();
it != user_table->referenced_set.end();
++it) {
dict_foreign_t* foreign = *it;
for (unsigned i = 0; i < foreign->n_fields; i++) {
if (strcmp(foreign->referenced_col_names[i], from)) {
continue;
@ -4803,8 +4809,8 @@ innobase_update_foreign_cache(
column names. No need to pass col_names or to drop
constraints from the data dictionary cache. */
DBUG_ASSERT(!ctx->col_names);
DBUG_ASSERT(UT_LIST_GET_LEN(user_table->foreign_list) == 0);
DBUG_ASSERT(UT_LIST_GET_LEN(user_table->referenced_list) == 0);
DBUG_ASSERT(user_table->foreign_set.empty());
DBUG_ASSERT(user_table->referenced_set.empty());
user_table = ctx->new_table;
} else {
/* Drop the foreign key constraints if the

View file

@ -447,7 +447,7 @@ buf_page_create(
mtr_t* mtr); /*!< in: mini-transaction handle */
#else /* !UNIV_HOTBACKUP */
/********************************************************************//**
Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
Inits a page to the buffer buf_pool, for use in mysqlbackup --restore. */
UNIV_INTERN
void
buf_page_init_for_backup_restore(

View file

@ -1160,12 +1160,6 @@ buf_page_hash_get_low(
ut_a(buf_page_in_file(bpage));
ut_ad(bpage->in_page_hash);
ut_ad(!bpage->in_zip_hash);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in
buf_page_t. On other systems, Valgrind could complain
about uninitialized pad bytes. */
UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
#endif
}
return(bpage);

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -124,28 +124,24 @@ dict_create_add_foreign_id(
const char* name, /*!< in: table name */
dict_foreign_t* foreign)/*!< in/out: foreign key */
__attribute__((nonnull));
/********************************************************************//**
Adds foreign key definitions to data dictionary tables in the database. We
look at table->foreign_list, and also generate names to constraints that were
not named by the user. A generated constraint has a name of the format
databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and are
given locally for this table, that is, the number is not global, as in the
old format constraints < 4.0.18 it used to be.
@return error code or DB_SUCCESS */
/** Adds the given set of foreign key objects to the dictionary tables
in the database. This function does not modify the dictionary cache. The
caller must ensure that all foreign key objects contain a valid constraint
name in foreign->id.
@param[in] local_fk_set set of foreign key objects, to be added to
the dictionary tables
@param[in] table table to which the foreign key objects in
local_fk_set belong to
@param[in,out] trx transaction
@return error code or DB_SUCCESS */
UNIV_INTERN
dberr_t
dict_create_add_foreigns_to_dictionary(
/*===================================*/
ulint start_id,/*!< in: if we are actually doing ALTER TABLE
ADD CONSTRAINT, we want to generate constraint
numbers which are bigger than in the table so
far; we number the constraints from
start_id + 1 up; start_id should be set to 0 if
we are creating a new table, or if the table
so far has no constraints for which the name
was generated here */
dict_table_t* table, /*!< in: table */
trx_t* trx) /*!< in: transaction */
const dict_foreign_set& local_fk_set,
const dict_table_t* table,
trx_t* trx)
__attribute__((nonnull, warn_unused_result));
/****************************************************************//**
Creates the tablespaces and datafiles system tables inside InnoDB

View file

@ -47,6 +47,8 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0types.h"
#include "fts0fts.h"
#include "os0once.h"
#include <set>
#include <algorithm>
/* Forward declaration. */
struct ib_rbt_t;
@ -706,12 +708,106 @@ struct dict_foreign_t{
does not generate new indexes
implicitly */
dict_index_t* referenced_index;/*!< referenced index */
UT_LIST_NODE_T(dict_foreign_t)
foreign_list; /*!< list node for foreign keys of the
table */
UT_LIST_NODE_T(dict_foreign_t)
referenced_list;/*!< list node for referenced
keys of the table */
};
/** 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
strict weak ordering it defines, and false otherwise. */
struct dict_foreign_compare {
bool operator()(
const dict_foreign_t* lhs,
const dict_foreign_t* rhs) const
{
return(ut_strcmp(lhs->id, rhs->id) < 0);
}
};
/** A function object to find a foreign key with the given index as the
referenced index. Return the foreign key with matching criteria or NULL */
struct dict_foreign_with_index {
dict_foreign_with_index(const dict_index_t* index)
: m_index(index)
{}
bool operator()(const dict_foreign_t* foreign) const
{
return(foreign->referenced_index == m_index);
}
const dict_index_t* m_index;
};
/* A function object to check if the foreign constraint is between different
tables. Returns true if foreign key constraint is between different tables,
false otherwise. */
struct dict_foreign_different_tables {
bool operator()(const dict_foreign_t* foreign) const
{
return(foreign->foreign_table != foreign->referenced_table);
}
};
/** A function object to check if the foreign key constraint has the same
name as given. If the full name of the foreign key constraint doesn't match,
then, check if removing the database name from the foreign key constraint
matches. Return true if it matches, false otherwise. */
struct dict_foreign_matches_id {
dict_foreign_matches_id(const char* id)
: m_id(id)
{}
bool operator()(const dict_foreign_t* foreign) const
{
if (0 == innobase_strcasecmp(foreign->id, m_id)) {
return(true);
}
if (const char* pos = strchr(foreign->id, '/')) {
if (0 == innobase_strcasecmp(m_id, pos + 1)) {
return(true);
}
}
return(false);
}
const char* m_id;
};
typedef std::set<dict_foreign_t*, dict_foreign_compare> dict_foreign_set;
/*********************************************************************//**
Frees a foreign key struct. */
inline
void
dict_foreign_free(
/*==============*/
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
{
mem_heap_free(foreign->heap);
}
/** The destructor will free all the foreign key constraints in the set
by calling dict_foreign_free() on each of the foreign key constraints.
This is used to free the allocated memory when a local set goes out
of scope. */
struct dict_foreign_set_free {
dict_foreign_set_free(const dict_foreign_set& foreign_set)
: m_foreign_set(foreign_set)
{}
~dict_foreign_set_free()
{
std::for_each(m_foreign_set.begin(),
m_foreign_set.end(),
dict_foreign_free);
}
const dict_foreign_set& m_foreign_set;
};
/** The flags for ON_UPDATE and ON_DELETE can be ORed; the default is that
@ -733,6 +829,8 @@ the table, DML from memcached will be blocked. */
/** Data structure for a database table. Most fields will be
initialized to 0, NULL or FALSE in dict_mem_table_create(). */
struct dict_table_t{
table_id_t id; /*!< id of the table */
mem_heap_t* heap; /*!< memory heap */
char* name; /*!< table name */
@ -787,13 +885,16 @@ struct dict_table_t{
hash_node_t id_hash; /*!< hash chain node */
UT_LIST_BASE_NODE_T(dict_index_t)
indexes; /*!< list of indexes of the table */
UT_LIST_BASE_NODE_T(dict_foreign_t)
foreign_list;/*!< list of foreign key constraints
dict_foreign_set foreign_set;
/*!< set of foreign key constraints
in the table; these refer to columns
in other tables */
UT_LIST_BASE_NODE_T(dict_foreign_t)
referenced_list;/*!< list of foreign key constraints
dict_foreign_set referenced_set;
/*!< list of foreign key constraints
which refer to this table */
UT_LIST_NODE_T(dict_table_t)
table_LRU; /*!< node of the LRU list of tables */
unsigned fk_max_recusive_level:8;
@ -1035,6 +1136,19 @@ struct dict_table_t{
#endif /* UNIV_DEBUG */
};
/** A function object to add the foreign key constraint to the referenced set
of the referenced table, if it exists in the dictionary cache. */
struct dict_foreign_add_to_referenced_table {
void operator()(dict_foreign_t* foreign) const
{
if (dict_table_t* table = foreign->referenced_table) {
std::pair<dict_foreign_set::iterator, bool> ret
= table->referenced_set.insert(foreign);
ut_a(ret.second);
}
}
};
#ifndef UNIV_NONINL
#include "dict0mem.ic"
#endif

View file

@ -48,7 +48,7 @@ struct fil_space_t;
typedef std::list<const char*> space_name_list_t;
/** When mysqld is run, the default directory "." is the mysqld datadir,
but in the MySQL Embedded Server Library and ibbackup it is not the default
but in the MySQL Embedded Server Library and mysqlbackup it is not the default
directory, and we must set the base file path explicitly */
extern const char* fil_path_to_mysql_datadir;
@ -426,8 +426,8 @@ exists and the space id in it matches. Replays the create operation if a file
at that path does not exist yet. If the database directory for the file to be
created does not exist, then we create the directory, too.
Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the
datadir that we should use in replaying the file operations.
Note that mysqlbackup --apply-log sets fil_path_to_mysql_datadir to point to
the datadir that we should use in replaying the file operations.
@return end of log record, or NULL if the record was not completely
contained between ptr and end_ptr */
UNIV_INTERN
@ -680,9 +680,9 @@ fil_space_for_table_exists_in_mem(
#else /* !UNIV_HOTBACKUP */
/********************************************************************//**
Extends all tablespaces to the size stored in the space header. During the
ibbackup --apply-log phase we extended the spaces on-demand so that log records
could be appllied, but that may have left spaces still too small compared to
the size stored in the space header. */
mysqlbackup --apply-log phase we extended the spaces on-demand so that log
records could be appllied, but that may have left spaces still too small
compared to the size stored in the space header. */
UNIV_INTERN
void
fil_extend_tablespaces_to_stored_len(void);

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2007, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -76,6 +76,7 @@ enum fts_ast_oper_t {
struct fts_lexer_t;
struct fts_ast_node_t;
struct fts_ast_state_t;
struct fts_ast_string_t;
typedef dberr_t (*fts_ast_callback)(fts_ast_oper_t, fts_ast_node_t*, void*);
@ -101,16 +102,16 @@ extern
fts_ast_node_t*
fts_ast_create_node_term(
/*=====================*/
void* arg, /*!< in: ast state */
const char* ptr); /*!< in: term string */
void* arg, /*!< in: ast state */
const fts_ast_string_t* ptr); /*!< in: term string */
/********************************************************************
Create an AST text node */
extern
fts_ast_node_t*
fts_ast_create_node_text(
/*=====================*/
void* arg, /*!< in: ast state */
const char* ptr); /*!< in: text string */
void* arg, /*!< in: ast state */
const fts_ast_string_t* ptr); /*!< in: text string */
/********************************************************************
Create an AST expr list node */
extern
@ -233,16 +234,66 @@ fts_lexer_free(
free */
__attribute__((nonnull));
/**
Create an ast string object, with NUL-terminator, so the string
has one more byte than len
@param[in] str pointer to string
@param[in] len length of the string
@return ast string with NUL-terminator */
UNIV_INTERN
fts_ast_string_t*
fts_ast_string_create(
const byte* str,
ulint len);
/**
Free an ast string instance
@param[in,out] ast_str string to free */
UNIV_INTERN
void
fts_ast_string_free(
fts_ast_string_t* ast_str);
/**
Translate ast string of type FTS_AST_NUMB to unsigned long by strtoul
@param[in] str string to translate
@param[in] base the base
@return translated number */
UNIV_INTERN
ulint
fts_ast_string_to_ul(
const fts_ast_string_t* ast_str,
int base);
/**
Print the ast string
@param[in] str string to print */
UNIV_INTERN
void
fts_ast_string_print(
const fts_ast_string_t* ast_str);
/* String of length len.
We always store the string of length len with a terminating '\0',
regardless of there is any 0x00 in the string itself */
struct fts_ast_string_t {
/*!< Pointer to string. */
byte* str;
/*!< Length of the string. */
ulint len;
};
/* Query term type */
struct fts_ast_term_t {
byte* ptr; /*!< Pointer to term string.*/
ibool wildcard; /*!< TRUE if wild card set.*/
fts_ast_string_t* ptr; /*!< Pointer to term string.*/
ibool wildcard; /*!< TRUE if wild card set.*/
};
/* Query text type */
struct fts_ast_text_t {
byte* ptr; /*!< Pointer to term string.*/
ulint distance; /*!< > 0 if proximity distance
fts_ast_string_t* ptr; /*!< Pointer to text string.*/
ulint distance; /*!< > 0 if proximity distance
set */
};

View file

@ -745,6 +745,7 @@ void
fts_savepoint_take(
/*===============*/
trx_t* trx, /*!< in: transaction */
fts_trx_t* fts_trx, /*!< in: fts transaction */
const char* name) /*!< in: savepoint name */
__attribute__((nonnull));
/**********************************************************************//**

View file

@ -53,9 +53,9 @@ typedef union YYSTYPE
/* Line 2068 of yacc.c */
#line 61 "fts0pars.y"
int oper;
char* token;
fts_ast_node_t* node;
int oper;
fts_ast_string_t* token;
fts_ast_node_t* node;

View file

@ -656,13 +656,13 @@ extern log_t* log_sys;
megabyte.
This information might have been used
since ibbackup version 0.35 but
since mysqlbackup version 0.35 but
before 1.41 to decide if unused ends of
non-auto-extending data files
in space 0 can be truncated.
This information was made obsolete
by ibbackup --compress. */
by mysqlbackup --compress. */
#define LOG_CHECKPOINT_FSP_MAGIC_N (12 + LOG_CHECKPOINT_ARRAY_END)
/*!< Not used (0);
This magic number tells if the
@ -691,7 +691,7 @@ extern log_t* log_sys;
/* a 32-byte field which contains
the string 'ibbackup' and the
creation time if the log file was
created by ibbackup --restore;
created by mysqlbackup --restore;
when mysqld is first time started
on the restored database, it can
print helpful info for the user */

View file

@ -126,7 +126,7 @@ enum os_file_create_t {
#define OS_FILE_READ_ONLY 333
#define OS_FILE_READ_WRITE 444
#define OS_FILE_READ_ALLOW_DELETE 555 /* for ibbackup */
#define OS_FILE_READ_ALLOW_DELETE 555 /* for mysqlbackup */
/* Options for file_create */
#define OS_FILE_AIO 61

View file

@ -357,6 +357,10 @@ Atomic compare-and-swap and increment for InnoDB. */
# define HAVE_ATOMIC_BUILTINS
# ifdef HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE
# define HAVE_ATOMIC_BUILTINS_BYTE
# endif
# ifdef HAVE_IB_GCC_ATOMIC_BUILTINS_64
# define HAVE_ATOMIC_BUILTINS_64
# endif
@ -440,6 +444,7 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
#elif defined(HAVE_IB_SOLARIS_ATOMICS)
# define HAVE_ATOMIC_BUILTINS
# define HAVE_ATOMIC_BUILTINS_BYTE
# define HAVE_ATOMIC_BUILTINS_64
/* If not compiling with GCC or GCC doesn't support the atomic
@ -524,6 +529,7 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
#elif defined(HAVE_WINDOWS_ATOMICS)
# define HAVE_ATOMIC_BUILTINS
# define HAVE_ATOMIC_BUILTINS_BYTE
# ifndef _WIN32
# define HAVE_ATOMIC_BUILTINS_64
@ -695,7 +701,15 @@ for synchronization */
} while (0);
/** barrier definitions for memory ordering */
#ifdef HAVE_IB_GCC_ATOMIC_THREAD_FENCE
#if defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64 || defined __WIN__
/* Performance regression was observed at some conditions for Intel
architecture. Disable memory barrier for Intel architecture for now. */
# define os_rmb do { } while(0)
# define os_wmb do { } while(0)
# define os_isync do { } while(0)
# define IB_MEMORY_BARRIER_STARTUP_MSG \
"Memory barrier is not used"
#elif defined(HAVE_IB_GCC_ATOMIC_THREAD_FENCE)
# define HAVE_MEMORY_BARRIER
# define os_rmb __atomic_thread_fence(__ATOMIC_ACQUIRE)
# define os_wmb __atomic_thread_fence(__ATOMIC_RELEASE)
@ -723,7 +737,7 @@ for synchronization */
# define os_wmb __machine_w_barrier()
# define os_isync os_rmb; os_wmb
# define IB_MEMORY_BARRIER_STARTUP_MSG \
"Soralis memory ordering functions are used for memory barrier"
"Solaris memory ordering functions are used for memory barrier"
#elif defined(HAVE_WINDOWS_MM_FENCE)
# define HAVE_MEMORY_BARRIER

View file

@ -93,6 +93,7 @@ rw_lock_set_waiter_flag(
(void) os_compare_and_swap_ulint(&lock->waiters, 0, 1);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 1;
os_wmb;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
}
@ -110,6 +111,7 @@ rw_lock_reset_waiter_flag(
(void) os_compare_and_swap_ulint(&lock->waiters, 1, 0);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 0;
os_wmb;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
}
@ -200,13 +202,16 @@ rw_lock_lock_word_decr(
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
lint local_lock_word;
os_rmb;
while ((local_lock_word= lock->lock_word) > 0) {
os_rmb;
local_lock_word = lock->lock_word;
while (local_lock_word > 0) {
if (os_compare_and_swap_lint(&lock->lock_word,
local_lock_word,
local_lock_word - amount)) {
return(TRUE);
}
local_lock_word = lock->lock_word;
}
return(FALSE);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */

View file

@ -49,6 +49,8 @@ extern "C" my_bool timed_mutexes;
#ifdef HAVE_WINDOWS_ATOMICS
typedef LONG lock_word_t; /*!< On Windows, InterlockedExchange operates
on LONG variable */
#elif defined(HAVE_ATOMIC_BUILTINS) && !defined(HAVE_ATOMIC_BUILTINS_BYTE)
typedef ulint lock_word_t;
#else
typedef byte lock_word_t;
#endif

View file

@ -80,7 +80,11 @@ ib_mutex_test_and_set(
ib_mutex_t* mutex) /*!< in: mutex */
{
#if defined(HAVE_ATOMIC_BUILTINS)
# if defined(HAVE_ATOMIC_BUILTINS_BYTE)
return(os_atomic_test_and_set_byte(&mutex->lock_word, 1));
# else
return(os_atomic_test_and_set_ulint(&mutex->lock_word, 1));
# endif
#else
ibool ret;
@ -92,7 +96,7 @@ ib_mutex_test_and_set(
ut_a(mutex->lock_word == 0);
mutex->lock_word = 1;
os_wmb;
os_wmb;
}
return((byte) ret);

View file

@ -44,7 +44,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 5
#define INNODB_VERSION_MINOR 6
#define INNODB_VERSION_BUGFIX 19
#define INNODB_VERSION_BUGFIX 20
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;

View file

@ -1249,7 +1249,7 @@ log_group_file_header_flush(
mach_write_to_4(buf + LOG_GROUP_ID, group->id);
mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn);
/* Wipe over possible label of ibbackup --restore */
/* Wipe over possible label of mysqlbackup --restore */
memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, " ", 4);
dest_offset = nth_file * group->file_size;
@ -1996,7 +1996,7 @@ log_reset_first_header_and_checkpoint(
lsn = start + LOG_BLOCK_HDR_SIZE;
/* Write the label of ibbackup --restore */
/* Write the label of mysqlbackup --restore */
strcpy((char*) hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP,
"ibbackup ");
ut_sprintf_timestamp((char*) hdr_buf

View file

@ -59,7 +59,7 @@ Created 9/20/1997 Heikki Tuuri
/** This is set to FALSE if the backup was originally taken with the
ibbackup --include regexp option: then we do not want to create tables in
mysqlbackup --include regexp option: then we do not want to create tables in
directories which were not included */
UNIV_INTERN ibool recv_replay_file_ops = TRUE;
#endif /* !UNIV_HOTBACKUP */
@ -2056,7 +2056,7 @@ recv_apply_log_recs_for_backup(void)
/* Extend the tablespace's last file if the page_no
does not fall inside its bounds; we assume the last
file is auto-extending, and ibbackup copied the file
file is auto-extending, and mysqlbackup copied the file
when it still was smaller */
success = fil_extend_space_to_desired_size(
@ -2427,10 +2427,10 @@ loop:
#ifdef UNIV_HOTBACKUP
if (recv_replay_file_ops) {
/* In ibbackup --apply-log, replay an .ibd file
operation, if possible; note that
fil_path_to_mysql_datadir is set in ibbackup to
point to the datadir we should use there */
/* In mysqlbackup --apply-log, replay an .ibd
file operation, if possible; note that
fil_path_to_mysql_datadir is set in mysqlbackup
to point to the datadir we should use there */
if (NULL == fil_op_log_parse_or_replay(
body, end_ptr, type,
@ -3090,17 +3090,17 @@ recv_recovery_from_checkpoint_start_func(
if (srv_read_only_mode) {
ib_logf(IB_LOG_LEVEL_ERROR,
"Cannot restore from ibbackup, InnoDB running "
"in read-only mode!");
"Cannot restore from mysqlbackup, InnoDB "
"running in read-only mode!");
return(DB_ERROR);
}
/* This log file was created by ibbackup --restore: print
/* This log file was created by mysqlbackup --restore: print
a note to the user about it */
ib_logf(IB_LOG_LEVEL_INFO,
"The log file was created by ibbackup --apply-log "
"The log file was created by mysqlbackup --apply-log "
"at %s. The following crash recovery is part of a "
"normal restore.",
log_hdr_buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP);

View file

@ -1816,7 +1816,7 @@ os_file_delete_if_exists_func(
bool ret;
ulint count = 0;
loop:
/* In Windows, deleting an .ibd file may fail if ibbackup is copying
/* In Windows, deleting an .ibd file may fail if mysqlbackup is copying
it */
ret = DeleteFile((LPCTSTR) name);
@ -1841,7 +1841,7 @@ loop:
ib_logf(IB_LOG_LEVEL_WARN, "Delete of file %s failed.", name);
}
os_thread_sleep(1000000); /* sleep for a second */
os_thread_sleep(500000); /* sleep for 0.5 second */
if (count > 2000) {
@ -1878,7 +1878,7 @@ os_file_delete_func(
BOOL ret;
ulint count = 0;
loop:
/* In Windows, deleting an .ibd file may fail if ibbackup is copying
/* In Windows, deleting an .ibd file may fail if mysqlbackup is copying
it */
ret = DeleteFile((LPCTSTR) name);
@ -1901,7 +1901,7 @@ loop:
fprintf(stderr,
"InnoDB: Warning: cannot delete file %s\n"
"InnoDB: Are you running ibbackup"
"InnoDB: Are you running mysqlbackup"
" to back up the file?\n", name);
}

View file

@ -3278,24 +3278,8 @@ page_zip_validate_low(
temp_page_buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
temp_page = static_cast<byte*>(ut_align(temp_page_buf, UNIV_PAGE_SIZE));
#ifdef UNIV_DEBUG_VALGRIND
/* Get detailed information on the valid bits in case the
UNIV_MEM_ASSERT_RW() checks fail. The v-bits of page[],
page_zip->data[] or page_zip could be viewed at temp_page[] or
temp_page_zip in a debugger when running valgrind --db-attach. */
(void) VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE);
UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
# if UNIV_WORD_SIZE == 4
VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip);
/* On 32-bit systems, there is no padding in page_zip_des_t.
On other systems, Valgrind could complain about uninitialized
pad bytes. */
UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip);
# endif
(void) VALGRIND_GET_VBITS(page_zip->data, temp_page,
page_zip_get_size(page_zip));
UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
#endif /* UNIV_DEBUG_VALGRIND */
temp_page_zip = *page_zip;
valid = page_zip_decompress(&temp_page_zip, temp_page, TRUE);

View file

@ -1711,12 +1711,11 @@ do_possible_lock_wait:
table case (check_ref == 0), since MDL lock will prevent
concurrent DDL and DML on the same table */
if (!check_ref) {
for (const dict_foreign_t* check_foreign
= UT_LIST_GET_FIRST( table->referenced_list);
check_foreign;
check_foreign = UT_LIST_GET_NEXT(
referenced_list, check_foreign)) {
if (check_foreign == foreign) {
for (dict_foreign_set::iterator it
= table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
if (*it == foreign) {
verified = true;
break;
}
@ -1764,12 +1763,15 @@ row_ins_check_foreign_constraints(
trx = thr_get_trx(thr);
foreign = UT_LIST_GET_FIRST(table->foreign_list);
DEBUG_SYNC_C_IF_THD(thr_get_trx(thr)->mysql_thd,
"foreign_constraint_check_for_ins");
while (foreign) {
for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
++it) {
foreign = *it;
if (foreign->foreign_index == index) {
dict_table_t* ref_table = NULL;
dict_table_t* foreign_table = foreign->foreign_table;
@ -1825,8 +1827,6 @@ row_ins_check_foreign_constraints(
return(err);
}
}
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
return(DB_SUCCESS);
@ -2858,7 +2858,7 @@ row_ins_clust_index_entry(
dberr_t err;
ulint n_uniq;
if (UT_LIST_GET_FIRST(index->table->foreign_list)) {
if (!index->table->foreign_set.empty()) {
err = row_ins_check_foreign_constraints(
index->table, index, entry, thr);
if (err != DB_SUCCESS) {
@ -2916,7 +2916,7 @@ row_ins_sec_index_entry(
mem_heap_t* offsets_heap;
mem_heap_t* heap;
if (UT_LIST_GET_FIRST(index->table->foreign_list)) {
if (!index->table->foreign_set.empty()) {
err = row_ins_check_foreign_constraints(index->table, index,
entry, thr);
if (err != DB_SUCCESS) {

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -63,6 +63,7 @@ Created 9/17/2000 Heikki Tuuri
#include "m_string.h"
#include "my_sys.h"
#include "ha_prototypes.h"
#include <algorithm>
/** Provide optional 4.x backwards compatibility for 5.0 and above */
UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
@ -1573,8 +1574,6 @@ init_fts_doc_id_for_ref(
{
dict_foreign_t* foreign;
foreign = UT_LIST_GET_FIRST(table->referenced_list);
table->fk_max_recusive_level = 0;
(*depth)++;
@ -1586,17 +1585,25 @@ init_fts_doc_id_for_ref(
/* Loop through this table's referenced list and also
recursively traverse each table's foreign table list */
while (foreign && foreign->foreign_table) {
if (foreign->foreign_table->fts) {
for (dict_foreign_set::iterator it = table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
foreign = *it;
if (foreign->foreign_table == NULL) {
break;
}
if (foreign->foreign_table->fts != NULL) {
fts_init_doc_id(foreign->foreign_table);
}
if (UT_LIST_GET_LEN(foreign->foreign_table->referenced_list)
> 0 && foreign->foreign_table != table) {
init_fts_doc_id_for_ref(foreign->foreign_table, depth);
if (!foreign->foreign_table->referenced_set.empty()
&& foreign->foreign_table != table) {
init_fts_doc_id_for_ref(
foreign->foreign_table, depth);
}
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
}
@ -2825,43 +2832,47 @@ row_discard_tablespace_foreign_key_checks(
const trx_t* trx, /*!< in: transaction handle */
const dict_table_t* table) /*!< in: table to be discarded */
{
const dict_foreign_t* foreign;
if (srv_read_only_mode || !trx->check_foreigns) {
return(DB_SUCCESS);
}
/* Check if the table is referenced by foreign key constraints from
some other table (not the table itself) */
dict_foreign_set::iterator it
= std::find_if(table->referenced_set.begin(),
table->referenced_set.end(),
dict_foreign_different_tables());
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
foreign && foreign->foreign_table == table;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
if (it == table->referenced_set.end()) {
return(DB_SUCCESS);
}
if (!srv_read_only_mode && foreign && trx->check_foreigns) {
const dict_foreign_t* foreign = *it;
FILE* ef = dict_foreign_err_file;
FILE* ef = dict_foreign_err_file;
ut_ad(foreign->foreign_table != table);
ut_ad(foreign->referenced_table == table);
/* We only allow discarding a referenced table if
FOREIGN_KEY_CHECKS is set to 0 */
/* We only allow discarding a referenced table if
FOREIGN_KEY_CHECKS is set to 0 */
mutex_enter(&dict_foreign_err_mutex);
mutex_enter(&dict_foreign_err_mutex);
rewind(ef);
rewind(ef);
ut_print_timestamp(ef);
ut_print_timestamp(ef);
fputs(" Cannot DISCARD table ", ef);
ut_print_name(stderr, trx, TRUE, table->name);
fputs("\n"
"because it is referenced by ", ef);
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
putc('\n', ef);
fputs(" Cannot DISCARD table ", ef);
ut_print_name(stderr, trx, TRUE, table->name);
fputs("\n"
"because it is referenced by ", ef);
ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
putc('\n', ef);
mutex_exit(&dict_foreign_err_mutex);
mutex_exit(&dict_foreign_err_mutex);
return(DB_CANNOT_DROP_CONSTRAINT);
}
return(DB_SUCCESS);
return(DB_CANNOT_DROP_CONSTRAINT);
}
/*********************************************************************//**
@ -3164,7 +3175,6 @@ row_truncate_table_for_mysql(
dict_table_t* table, /*!< in: table handle */
trx_t* trx) /*!< in: transaction handle */
{
dict_foreign_t* foreign;
dberr_t err;
mem_heap_t* heap;
byte* buf;
@ -3256,18 +3266,17 @@ row_truncate_table_for_mysql(
/* Check if the table is referenced by foreign key constraints from
some other table (not the table itself) */
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
foreign != 0 && foreign->foreign_table == table;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
/* Do nothing. */
}
dict_foreign_set::iterator it
= std::find_if(table->referenced_set.begin(),
table->referenced_set.end(),
dict_foreign_different_tables());
if (!srv_read_only_mode
&& foreign
&& it != table->referenced_set.end()
&& trx->check_foreigns) {
FILE* ef = dict_foreign_err_file;
FILE* ef = dict_foreign_err_file;
dict_foreign_t* foreign = *it;
/* We only allow truncating a referenced table if
FOREIGN_KEY_CHECKS is set to 0 */
@ -3868,42 +3877,45 @@ row_drop_table_for_mysql(
/* 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);
if (!srv_read_only_mode && trx->check_foreigns) {
while (foreign && foreign->foreign_table == table) {
check_next_foreign:
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
for (dict_foreign_set::iterator it
= table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
if (!srv_read_only_mode
&& foreign
&& trx->check_foreigns
&& !(drop_db && dict_tables_have_same_db(
name, foreign->foreign_table_name_lookup))) {
FILE* ef = dict_foreign_err_file;
foreign = *it;
/* We only allow dropping a referenced table if
FOREIGN_KEY_CHECKS is set to 0 */
const bool ref_ok = drop_db
&& dict_tables_have_same_db(
name,
foreign->foreign_table_name_lookup);
err = DB_CANNOT_DROP_CONSTRAINT;
if (foreign->foreign_table != table && !ref_ok) {
mutex_enter(&dict_foreign_err_mutex);
rewind(ef);
ut_print_timestamp(ef);
FILE* ef = dict_foreign_err_file;
fputs(" Cannot drop table ", ef);
ut_print_name(ef, trx, TRUE, name);
fputs("\n"
"because it is referenced by ", ef);
ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
putc('\n', ef);
mutex_exit(&dict_foreign_err_mutex);
/* We only allow dropping a referenced table
if FOREIGN_KEY_CHECKS is set to 0 */
goto funct_exit;
}
err = DB_CANNOT_DROP_CONSTRAINT;
if (foreign && trx->check_foreigns) {
goto check_next_foreign;
mutex_enter(&dict_foreign_err_mutex);
rewind(ef);
ut_print_timestamp(ef);
fputs(" Cannot drop table ", ef);
ut_print_name(ef, trx, TRUE, name);
fputs("\n"
"because it is referenced by ", ef);
ut_print_name(ef, trx, TRUE,
foreign->foreign_table_name);
putc('\n', ef);
mutex_exit(&dict_foreign_err_mutex);
goto funct_exit;
}
}
}
/* TODO: could we replace the counter n_foreign_key_checks_running

View file

@ -51,7 +51,7 @@ Created 12/27/1996 Heikki Tuuri
#include "pars0sym.h"
#include "eval0eval.h"
#include "buf0lru.h"
#include <algorithm>
/* What kind of latch and lock can we assume when the control comes to
-------------------------------------------------------------------
@ -136,12 +136,10 @@ row_upd_index_is_referenced(
trx_t* trx) /*!< in: transaction */
{
dict_table_t* table = index->table;
dict_foreign_t* foreign;
ibool froze_data_dict = FALSE;
ibool is_referenced = FALSE;
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
if (table->referenced_set.empty()) {
return(FALSE);
}
@ -150,19 +148,13 @@ row_upd_index_is_referenced(
froze_data_dict = TRUE;
}
foreign = UT_LIST_GET_FIRST(table->referenced_list);
dict_foreign_set::iterator it
= std::find_if(table->referenced_set.begin(),
table->referenced_set.end(),
dict_foreign_with_index(index));
while (foreign) {
if (foreign->referenced_index == index) {
is_referenced = (it != table->referenced_set.end());
is_referenced = TRUE;
goto func_exit;
}
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
func_exit:
if (froze_data_dict) {
row_mysql_unfreeze_data_dictionary(trx);
}
@ -200,7 +192,7 @@ row_upd_check_references_constraints(
dberr_t err;
ibool got_s_lock = FALSE;
if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
if (table->referenced_set.empty()) {
return(DB_SUCCESS);
}
@ -227,9 +219,13 @@ row_upd_check_references_constraints(
}
run_again:
foreign = UT_LIST_GET_FIRST(table->referenced_list);
while (foreign) {
for (dict_foreign_set::iterator it = table->referenced_set.begin();
it != table->referenced_set.end();
++it) {
foreign = *it;
/* Note that we may have an update which updates the index
record, but does NOT update the first fields which are
referenced in a foreign key constraint. Then the update does
@ -282,8 +278,6 @@ run_again:
goto func_exit;
}
}
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
}
err = DB_SUCCESS;

View file

@ -1647,6 +1647,19 @@ innobase_start_or_create_for_mysql(void)
ib_logf(IB_LOG_LEVEL_INFO,
"" IB_ATOMICS_STARTUP_MSG "");
ib_logf(IB_LOG_LEVEL_INFO,
"" IB_MEMORY_BARRIER_STARTUP_MSG "");
#ifndef HAVE_MEMORY_BARRIER
#if defined __i386__ || defined __x86_64__ || defined _M_IX86 || defined _M_X64 || defined __WIN__
#else
ib_logf(IB_LOG_LEVEL_WARN,
"MySQL was built without a memory barrier capability on this"
" architecture, which might allow a mutex/rw_lock violation"
" under high thread concurrency. This may cause a hang.");
#endif /* IA32 or AMD64 */
#endif /* HAVE_MEMORY_BARRIER */
ib_logf(IB_LOG_LEVEL_INFO,
"Compressed tables use zlib " ZLIB_VERSION
#ifdef UNIV_ZIP_DEBUG
@ -2631,13 +2644,6 @@ files_checked:
srv_undo_logs = ULONG_UNDEFINED;
}
/* Flush the changes made to TRX_SYS_PAGE by trx_sys_create_rsegs()*/
if (!srv_force_recovery && !srv_read_only_mode) {
bool success = buf_flush_list(ULINT_MAX, LSN_MAX, NULL);
ut_a(success);
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
}
if (!srv_read_only_mode) {
/* Create the thread which watches the timeouts
for lock waits */

View file

@ -749,6 +749,7 @@ sync_arr_cell_can_wake_up(
mutex = static_cast<ib_mutex_t*>(cell->wait_object);
os_rmb;
if (mutex_get_lock_word(mutex) == 0) {
return(TRUE);
@ -758,7 +759,7 @@ sync_arr_cell_can_wake_up(
lock = static_cast<rw_lock_t*>(cell->wait_object);
os_rmb;
os_rmb;
if (lock->lock_word > 0) {
/* Either unlocked or only read locked. */
@ -770,7 +771,7 @@ sync_arr_cell_can_wake_up(
lock = static_cast<rw_lock_t*>(cell->wait_object);
/* lock_word == 0 means all readers have left */
os_rmb;
os_rmb;
if (lock->lock_word == 0) {
return(TRUE);
@ -779,7 +780,7 @@ sync_arr_cell_can_wake_up(
lock = static_cast<rw_lock_t*>(cell->wait_object);
/* lock_word > 0 means no writer or reserved writer */
os_rmb;
os_rmb;
if (lock->lock_word > 0) {
return(TRUE);

View file

@ -388,7 +388,7 @@ lock_loop:
}
HMT_medium();
if (lock->lock_word <= 0) {
if (i >= SYNC_SPIN_ROUNDS) {
os_thread_yield();
}
@ -475,9 +475,9 @@ rw_lock_x_lock_wait(
counter_index = (size_t) os_thread_get_curr_id();
os_rmb;
ut_ad(lock->lock_word <= 0);
os_rmb;
HMT_low();
while (lock->lock_word < 0) {
if (srv_spin_wait_delay) {
@ -564,8 +564,11 @@ rw_lock_x_lock_low(
} else {
os_thread_id_t thread_id = os_thread_get_curr_id();
if (!pass)
if (!pass) {
os_rmb;
}
/* Decrement failed: relock or failed lock */
if (!pass && lock->recursive
&& os_thread_eq(lock->writer_thread, thread_id)) {
@ -657,7 +660,7 @@ lock_loop:
os_rmb;
}
HMT_medium();
if (i == SYNC_SPIN_ROUNDS) {
if (i >= SYNC_SPIN_ROUNDS) {
os_thread_yield();
} else {
goto lock_loop;

View file

@ -127,7 +127,7 @@ it and did not see the waiters byte set to 1, a case which would lead the
other thread to an infinite wait.
LEMMA 1: After a thread resets the event of a mutex (or rw_lock), some
=======
======
thread will eventually call os_event_set() on that particular event.
Thus no infinite wait is possible in this case.
@ -140,7 +140,7 @@ os_event_set() with the mutex as an argument.
Q.E.D.
LEMMA 2: If an os_event_set() call is made after some thread has called
=======
======
the os_event_reset() and before it starts wait on that event, the call
will not be lost to the second thread. This is true even if there is an
intervening call to os_event_reset() by another thread.
@ -504,16 +504,16 @@ mutex_loop:
spin_loop:
HMT_low();
os_rmb;
while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS) {
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
}
os_rmb; // Ensure future reads sees new values
i++;
}
HMT_medium();
if (i == SYNC_SPIN_ROUNDS) {
if (i >= SYNC_SPIN_ROUNDS) {
os_thread_yield();
}

View file

@ -952,7 +952,7 @@ trx_sys_print_mysql_binlog_offset_from_page(
== TRX_SYS_MYSQL_LOG_MAGIC_N) {
fprintf(stderr,
"ibbackup: Last MySQL binlog file position %lu %lu,"
"mysqlbackup: Last MySQL binlog file position %lu %lu,"
" file name %s\n",
(ulong) mach_read_from_4(
sys_header + TRX_SYS_MYSQL_LOG_INFO
@ -1003,9 +1003,9 @@ trx_sys_read_file_format_id(
ut_print_timestamp(stderr);
fprintf(stderr,
" ibbackup: Error: trying to read system tablespace "
"file format,\n"
" ibbackup: but could not open the tablespace "
" mysqlbackup: Error: trying to read system "
"tablespace file format,\n"
" mysqlbackup: but could not open the tablespace "
"file %s!\n", pathname);
return(FALSE);
}
@ -1022,9 +1022,9 @@ trx_sys_read_file_format_id(
ut_print_timestamp(stderr);
fprintf(stderr,
" ibbackup: Error: trying to read system tablespace "
"file format,\n"
" ibbackup: but failed to read the tablespace "
" mysqlbackup: Error: trying to read system "
"tablespace file format,\n"
" mysqlbackup: but failed to read the tablespace "
"file %s!\n", pathname);
os_file_close(file);
@ -1083,9 +1083,9 @@ trx_sys_read_pertable_file_format_id(
ut_print_timestamp(stderr);
fprintf(stderr,
" ibbackup: Error: trying to read per-table "
" mysqlbackup: Error: trying to read per-table "
"tablespace format,\n"
" ibbackup: but could not open the tablespace "
" mysqlbackup: but could not open the tablespace "
"file %s!\n", pathname);
return(FALSE);
@ -1102,9 +1102,9 @@ trx_sys_read_pertable_file_format_id(
ut_print_timestamp(stderr);
fprintf(stderr,
" ibbackup: Error: trying to per-table data file "
" mysqlbackup: Error: trying to per-table data file "
"format,\n"
" ibbackup: but failed to read the tablespace "
" mysqlbackup: but failed to read the tablespace "
"file %s!\n", pathname);
os_file_close(file);