mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
InnoDB 5.6.20
This commit is contained in:
commit
75796d9ecb
51 changed files with 1027 additions and 659 deletions
|
@ -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;
|
||||
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
;
|
||||
%%
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 = "";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -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));
|
||||
/**********************************************************************//**
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue