1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

MDEV-19445 heap-use-after-free related to innodb_ft_aux_table

Try to fix the race conditions between
SET GLOBAL innodb_ft_aux_table = ...;
and access to the INFORMATION_SCHEMA tables that depend on
this variable.

innodb_ft_aux_table: Replaces
fts_internal_tbl_name,fts_internal_tbl_name2. Just store the
user-specified parameter as is.

innodb_ft_aux_table_id: The table_id corresponding to
SET GLOBAL innodb_ft_aux_table, or 0 if the table does not exist
or does not contain FULLTEXT INDEX. If the table is renamed later,
the INFORMATION_SCHEMA tables will continue to refer to the table.
If the table is dropped or rebuilt, the INFORMATION_SCHEMA tables
will not find the table.
This commit is contained in:
Marko Mäkelä
2019-05-13 17:16:42 +03:00
parent 1c97e07f8f
commit 2647fd101d
14 changed files with 339 additions and 316 deletions

View File

@@ -319,14 +319,24 @@ the
www
select * from information_schema.innodb_ft_deleted;
DOC_ID
Warnings:
Warning 1012 InnoDB: SELECTing from INFORMATION_SCHEMA.innodb_ft_deleted but the InnoDB storage engine is not installed
select * from information_schema.innodb_ft_being_deleted;
DOC_ID
Warnings:
Warning 1012 InnoDB: SELECTing from INFORMATION_SCHEMA.innodb_ft_being_deleted but the InnoDB storage engine is not installed
select * from information_schema.innodb_ft_index_cache;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
Warnings:
Warning 1012 InnoDB: SELECTing from INFORMATION_SCHEMA.innodb_ft_index_cache but the InnoDB storage engine is not installed
select * from information_schema.innodb_ft_index_table;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
Warnings:
Warning 1012 InnoDB: SELECTing from INFORMATION_SCHEMA.innodb_ft_index_table but the InnoDB storage engine is not installed
select * from information_schema.innodb_ft_config;
KEY VALUE
Warnings:
Warning 1012 InnoDB: SELECTing from INFORMATION_SCHEMA.innodb_ft_config but the InnoDB storage engine is not installed
select * from information_schema.innodb_buffer_page;
POOL_ID BLOCK_ID SPACE PAGE_NUMBER PAGE_TYPE FLUSH_TYPE FIX_COUNT IS_HASHED NEWEST_MODIFICATION OLDEST_MODIFICATION ACCESS_TIME TABLE_NAME INDEX_NAME NUMBER_RECORDS DATA_SIZE COMPRESSED_SIZE PAGE_STATE IO_FIX IS_OLD FREE_PAGE_CLOCK
Warnings:

View File

@@ -0,0 +1,116 @@
CREATE TABLE t1 (v VARCHAR(100), FULLTEXT INDEX (v)) ENGINE=InnoDB;
insert into t1 VALUES('First record'),('Second record'),('Third record');
SET @save_ft_aux_table = @@GLOBAL.innodb_ft_aux_table;
SET GLOBAL innodb_ft_aux_table = 'test/t0';
ERROR 42000: Variable 'innodb_ft_aux_table' can't be set to the value of 'test/t0'
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;
value
a
about
an
are
as
at
be
by
com
de
en
for
from
how
i
in
is
it
la
of
on
or
that
the
this
to
was
what
when
where
who
will
with
und
the
www
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
KEY VALUE
SET GLOBAL innodb_ft_aux_table = 'test/t1';
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
first 1 1 1 1 0
record 1 3 3 1 6
record 1 3 3 2 7
record 1 3 3 3 6
second 2 2 1 2 0
third 3 3 1 3 0
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
KEY VALUE
optimize_checkpoint_limit 180
synced_doc_id 0
stopword_table_name
use_stopword 1
SELECT @@GLOBAL.innodb_ft_aux_table;
@@GLOBAL.innodb_ft_aux_table
test/t1
RENAME TABLE t1 TO t2;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
first 1 1 1 1 0
record 1 3 3 1 6
record 1 3 3 2 7
record 1 3 3 3 6
second 2 2 1 2 0
third 3 3 1 3 0
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
KEY VALUE
optimize_checkpoint_limit 180
synced_doc_id 0
stopword_table_name
use_stopword 1
SELECT @@GLOBAL.innodb_ft_aux_table;
@@GLOBAL.innodb_ft_aux_table
test/t1
DROP TABLE t2;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
DOC_ID
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
KEY VALUE
SELECT @@GLOBAL.innodb_ft_aux_table;
@@GLOBAL.innodb_ft_aux_table
test/t1
SET GLOBAL innodb_ft_aux_table = @save_ft_aux_table;

View File

@@ -0,0 +1,6 @@
--innodb_ft_default_stopword
--innodb_ft_deleted
--innodb_ft_being_deleted
--innodb_ft_index_cache
--innodb_ft_index_table
--innodb_ft_config

View File

@@ -0,0 +1,43 @@
--source include/have_innodb.inc
CREATE TABLE t1 (v VARCHAR(100), FULLTEXT INDEX (v)) ENGINE=InnoDB;
insert into t1 VALUES('First record'),('Second record'),('Third record');
SET @save_ft_aux_table = @@GLOBAL.innodb_ft_aux_table;
connect (con1,localhost,root,,);
--error ER_WRONG_VALUE_FOR_VAR
SET GLOBAL innodb_ft_aux_table = 'test/t0';
connection default;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
connection con1;
SET GLOBAL innodb_ft_aux_table = 'test/t1';
disconnect con1;
connection default;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
SELECT @@GLOBAL.innodb_ft_aux_table;
RENAME TABLE t1 TO t2;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
SELECT @@GLOBAL.innodb_ft_aux_table;
DROP TABLE t2;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_CONFIG;
SELECT @@GLOBAL.innodb_ft_aux_table;
SET GLOBAL innodb_ft_aux_table = @save_ft_aux_table;

View File

@@ -107,11 +107,6 @@ UNIV_INTERN mysql_pfs_key_t fts_doc_id_mutex_key;
UNIV_INTERN mysql_pfs_key_t fts_pll_tokenize_mutex_key;
#endif /* UNIV_PFS_MUTEX */
/** variable to record innodb_fts_internal_tbl_name for information
schema table INNODB_FTS_INSERTED etc. */
UNIV_INTERN char* fts_internal_tbl_name = NULL;
UNIV_INTERN char* fts_internal_tbl_name2 = NULL;
/** InnoDB default stopword list:
There are different versions of stopwords, the stop words listed
below comes from "Google Stopword" list. Reference:

View File

@@ -17118,98 +17118,36 @@ innodb_stopword_table_validate(
return(ret);
}
/*************************************************************//**
Check whether valid argument given to "innodb_fts_internal_tbl_name"
This function is registered as a callback with MySQL.
@return 0 for valid stopword table */
static
int
innodb_internal_table_validate(
/*===========================*/
THD* thd, /*!< in: thread handle */
struct st_mysql_sys_var* var, /*!< in: pointer to system
variable */
void* save, /*!< out: immediate result
for update function */
struct st_mysql_value* value) /*!< in: incoming string */
/** The latest assigned innodb_ft_aux_table name */
static char* innodb_ft_aux_table;
/** Update innodb_ft_aux_table_id on SET GLOBAL innodb_ft_aux_table.
@param[out] save new value of innodb_ft_aux_table
@param[in] value user-specified value */
static int innodb_ft_aux_table_validate(THD*, st_mysql_sys_var*,
void* save, st_mysql_value* value)
{
const char* table_name;
char buff[STRING_BUFFER_USUAL_SIZE];
int len = sizeof(buff);
int ret = 1;
dict_table_t* user_table;
char buf[STRING_BUFFER_USUAL_SIZE];
int len = sizeof buf;
ut_a(save != NULL);
ut_a(value != NULL);
table_name = value->val_str(value, buff, &len);
if (!table_name) {
*static_cast<const char**>(save) = NULL;
return(0);
}
user_table = dict_table_open_on_name(
table_name, FALSE, TRUE, DICT_ERR_IGNORE_NONE);
if (user_table) {
if (dict_table_has_fts_index(user_table)) {
*static_cast<const char**>(save) = table_name;
ret = 0;
if (const char* table_name = value->val_str(value, buf, &len)) {
if (dict_table_t* table = dict_table_open_on_name(
table_name, FALSE, TRUE, DICT_ERR_IGNORE_NONE)) {
const table_id_t id = dict_table_has_fts_index(table)
? table->id : 0;
dict_table_close(table, FALSE, FALSE);
if (id) {
innodb_ft_aux_table_id = id;
*static_cast<const char**>(save) = table_name;
return 0;
}
}
dict_table_close(user_table, FALSE, TRUE);
DBUG_EXECUTE_IF("innodb_evict_autoinc_table",
mutex_enter(&dict_sys->mutex);
dict_table_remove_from_cache_low(user_table, TRUE);
mutex_exit(&dict_sys->mutex);
);
}
return(ret);
}
/****************************************************************//**
Update global variable "fts_internal_tbl_name" with the "saved"
stopword table name value. This function is registered as a callback
with MySQL. */
static
void
innodb_internal_table_update(
/*=========================*/
THD* thd, /*!< in: thread handle */
struct st_mysql_sys_var* var, /*!< in: pointer to
system variable */
void* var_ptr,/*!< out: where the
formal string goes */
const void* save) /*!< in: immediate result
from check function */
{
const char* table_name;
char* old;
ut_a(save != NULL);
ut_a(var_ptr != NULL);
table_name = *static_cast<const char*const*>(save);
old = *(char**) var_ptr;
if (table_name) {
*(char**) var_ptr = my_strdup(table_name, MYF(0));
return 1;
} else {
*(char**) var_ptr = NULL;
}
if (old) {
my_free(old);
}
fts_internal_tbl_name2 = *(char**) var_ptr;
if (fts_internal_tbl_name2 == NULL) {
fts_internal_tbl_name = const_cast<char*>("default");
} else {
fts_internal_tbl_name = fts_internal_tbl_name2;
*static_cast<char**>(save) = NULL;
innodb_ft_aux_table_id = 0;
return 0;
}
}
@@ -19476,11 +19414,10 @@ static MYSQL_SYSVAR_BOOL(disable_sort_file_cache, srv_disable_sort_file_cache,
"Whether to disable OS system file cache for sort I/O",
NULL, NULL, FALSE);
static MYSQL_SYSVAR_STR(ft_aux_table, fts_internal_tbl_name2,
PLUGIN_VAR_NOCMDARG,
static MYSQL_SYSVAR_STR(ft_aux_table, innodb_ft_aux_table,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_MEMALLOC,
"FTS internal auxiliary table to be checked",
innodb_internal_table_validate,
innodb_internal_table_update, NULL);
innodb_ft_aux_table_validate, NULL, NULL);
static MYSQL_SYSVAR_ULONG(ft_cache_size, fts_max_cache_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,

View File

@@ -64,6 +64,9 @@ Modified Dec 29, 2014 Jan Lindström (Added sys_semaphore_waits)
#include "fil0fil.h"
#include "fil0crypt.h"
/** The latest successfully looked up innodb_fts_aux_table */
UNIV_INTERN table_id_t innodb_ft_aux_table_id;
/** structure associates a name string with a file page type and/or buffer
page state. */
struct buf_page_desc_t{
@@ -2934,25 +2937,21 @@ i_s_fts_deleted_generic_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
/* Prevent DDL to drop fts aux tables. */
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
} else if (!dict_table_has_fts_index(user_table)) {
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
@@ -2967,6 +2966,12 @@ i_s_fts_deleted_generic_fill(
fts_table_fetch_doc_ids(trx, &fts_table, deleted);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
trx_free_for_background(trx);
fields = table->field;
int ret = 0;
@@ -2981,14 +2986,8 @@ i_s_fts_deleted_generic_fill(
BREAK_IF(ret = schema_table_store_record(thd, table));
}
trx_free_for_background(trx);
fts_doc_ids_free(deleted);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(ret);
}
@@ -3348,32 +3347,33 @@ i_s_fts_index_cache_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
no_fts:
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
if (user_table->fts == NULL || user_table->fts->cache == NULL) {
if (!user_table->fts || !user_table->fts->cache) {
dict_table_close(user_table, FALSE, FALSE);
DBUG_RETURN(0);
goto no_fts;
}
cache = user_table->fts->cache;
ut_a(cache);
int ret = 0;
fts_string_t conv_str;
conv_str.f_len = system_charset_info->mbmaxlen
* FTS_MAX_WORD_LEN_IN_CHAR;
conv_str.f_str = static_cast<byte*>(ut_malloc(conv_str.f_len));
byte word[HA_FT_MAXBYTELEN + 1];
conv_str.f_len = sizeof word;
conv_str.f_str = word;
for (ulint i = 0; i < ib_vector_size(cache->indexes); i++) {
fts_index_cache_t* index_cache;
@@ -3385,9 +3385,8 @@ i_s_fts_index_cache_fill(
index_cache, thd, &conv_str, tables));
}
ut_free(conv_str.f_str);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(ret);
}
@@ -3801,19 +3800,17 @@ i_s_fts_index_table_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
/* Prevent DDL to drop fts aux tables. */
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
@@ -3966,32 +3963,28 @@ i_s_fts_config_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
DEBUG_SYNC_C("i_s_fts_config_fille_check");
fields = table->field;
/* Prevent DDL to drop fts aux tables. */
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
no_fts:
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
} else if (!dict_table_has_fts_index(user_table)) {
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
if (!dict_table_has_fts_index(user_table)) {
dict_table_close(user_table, FALSE, FALSE);
goto no_fts;
}
fields = table->field;
trx = trx_allocate_for_background();
trx->op_info = "Select for FTS CONFIG TABLE";
@@ -4043,12 +4036,12 @@ i_s_fts_config_fill(
fts_sql_commit(trx);
trx_free_for_background(trx);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
trx_free_for_background(trx);
DBUG_RETURN(ret);
}

View File

@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyrigth (c) 2014, 2017, MariaDB Corporation.
Copyrigth (c) 2014, 2019, MariaDB Corporation.
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
@@ -27,6 +27,7 @@ Modified Dec 29, 2014 Jan Lindström
#ifndef i_s_h
#define i_s_h
#include "dict0types.h"
const char plugin_author[] = "Oracle Corporation";
const char maria_plugin_author[] = "MariaDB Corporation";
@@ -64,6 +65,9 @@ extern struct st_maria_plugin i_s_innodb_tablespaces_encryption;
extern struct st_maria_plugin i_s_innodb_tablespaces_scrubbing;
extern struct st_maria_plugin i_s_innodb_sys_semaphore_waits;
/** The latest successfully looked up innodb_fts_aux_table */
extern table_id_t innodb_ft_aux_table_id;
/** maximum number of buffer page info we would cache. */
#define MAX_BUF_INFO_CACHED 10000

View File

@@ -367,11 +367,6 @@ extern bool fts_need_sync;
/** Maximum possible Fulltext word length (in characters) */
#define FTS_MAX_WORD_LEN_IN_CHAR HA_FT_MAXCHARLEN
/** Variable specifying the table that has Fulltext index to display its
content through information schema table */
extern char* fts_internal_tbl_name;
extern char* fts_internal_tbl_name2;
#define fts_que_graph_free(graph) \
do { \
mutex_enter(&dict_sys->mutex); \

View File

@@ -107,11 +107,6 @@ UNIV_INTERN mysql_pfs_key_t fts_doc_id_mutex_key;
UNIV_INTERN mysql_pfs_key_t fts_pll_tokenize_mutex_key;
#endif /* UNIV_PFS_MUTEX */
/** variable to record innodb_fts_internal_tbl_name for information
schema table INNODB_FTS_INSERTED etc. */
UNIV_INTERN char* fts_internal_tbl_name = NULL;
UNIV_INTERN char* fts_internal_tbl_name2 = NULL;
/** InnoDB default stopword list:
There are different versions of stopwords, the stop words listed
below comes from "Google Stopword" list. Reference:

View File

@@ -17839,98 +17839,36 @@ innodb_stopword_table_validate(
return(ret);
}
/*************************************************************//**
Check whether valid argument given to "innodb_fts_internal_tbl_name"
This function is registered as a callback with MySQL.
@return 0 for valid stopword table */
static
int
innodb_internal_table_validate(
/*===========================*/
THD* thd, /*!< in: thread handle */
struct st_mysql_sys_var* var, /*!< in: pointer to system
variable */
void* save, /*!< out: immediate result
for update function */
struct st_mysql_value* value) /*!< in: incoming string */
/** The latest assigned innodb_ft_aux_table name */
static char* innodb_ft_aux_table;
/** Update innodb_ft_aux_table_id on SET GLOBAL innodb_ft_aux_table.
@param[out] save new value of innodb_ft_aux_table
@param[in] value user-specified value */
static int innodb_ft_aux_table_validate(THD*, st_mysql_sys_var*,
void* save, st_mysql_value* value)
{
const char* table_name;
char buff[STRING_BUFFER_USUAL_SIZE];
int len = sizeof(buff);
int ret = 1;
dict_table_t* user_table;
char buf[STRING_BUFFER_USUAL_SIZE];
int len = sizeof buf;
ut_a(save != NULL);
ut_a(value != NULL);
table_name = value->val_str(value, buff, &len);
if (!table_name) {
*static_cast<const char**>(save) = NULL;
return(0);
}
user_table = dict_table_open_on_name(
table_name, FALSE, TRUE, DICT_ERR_IGNORE_NONE);
if (user_table) {
if (dict_table_has_fts_index(user_table)) {
*static_cast<const char**>(save) = table_name;
ret = 0;
if (const char* table_name = value->val_str(value, buf, &len)) {
if (dict_table_t* table = dict_table_open_on_name(
table_name, FALSE, TRUE, DICT_ERR_IGNORE_NONE)) {
const table_id_t id = dict_table_has_fts_index(table)
? table->id : 0;
dict_table_close(table, FALSE, FALSE);
if (id) {
innodb_ft_aux_table_id = id;
*static_cast<const char**>(save) = table_name;
return 0;
}
}
dict_table_close(user_table, FALSE, TRUE);
DBUG_EXECUTE_IF("innodb_evict_autoinc_table",
mutex_enter(&dict_sys->mutex);
dict_table_remove_from_cache_low(user_table, TRUE);
mutex_exit(&dict_sys->mutex);
);
}
return(ret);
}
/****************************************************************//**
Update global variable "fts_internal_tbl_name" with the "saved"
stopword table name value. This function is registered as a callback
with MySQL. */
static
void
innodb_internal_table_update(
/*=========================*/
THD* thd, /*!< in: thread handle */
struct st_mysql_sys_var* var, /*!< in: pointer to
system variable */
void* var_ptr,/*!< out: where the
formal string goes */
const void* save) /*!< in: immediate result
from check function */
{
const char* table_name;
char* old;
ut_a(save != NULL);
ut_a(var_ptr != NULL);
table_name = *static_cast<const char*const*>(save);
old = *(char**) var_ptr;
if (table_name) {
*(char**) var_ptr = my_strdup(table_name, MYF(0));
return 1;
} else {
*(char**) var_ptr = NULL;
}
if (old) {
my_free(old);
}
fts_internal_tbl_name2 = *(char**) var_ptr;
if (fts_internal_tbl_name2 == NULL) {
fts_internal_tbl_name = const_cast<char*>("default");
} else {
fts_internal_tbl_name = fts_internal_tbl_name2;
*static_cast<char**>(save) = NULL;
innodb_ft_aux_table_id = 0;
return 0;
}
}
@@ -20693,11 +20631,10 @@ static MYSQL_SYSVAR_BOOL(disable_sort_file_cache, srv_disable_sort_file_cache,
"Whether to disable OS system file cache for sort I/O",
NULL, NULL, FALSE);
static MYSQL_SYSVAR_STR(ft_aux_table, fts_internal_tbl_name2,
PLUGIN_VAR_NOCMDARG,
static MYSQL_SYSVAR_STR(ft_aux_table, innodb_ft_aux_table,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_MEMALLOC,
"FTS internal auxiliary table to be checked",
innodb_internal_table_validate,
innodb_internal_table_update, NULL);
innodb_ft_aux_table_validate, NULL, NULL);
static MYSQL_SYSVAR_ULONG(ft_cache_size, fts_max_cache_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,

View File

@@ -75,6 +75,9 @@ Modified Dec 29, 2014 Jan Lindström (Added sys_semaphore_waits)
#include "fil0fil.h"
#include "fil0crypt.h"
/** The latest successfully looked up innodb_fts_aux_table */
UNIV_INTERN table_id_t innodb_ft_aux_table_id;
/** structure associates a name string with a file page type and/or buffer
page state. */
struct buf_page_desc_t{
@@ -2928,25 +2931,21 @@ i_s_fts_deleted_generic_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
/* Prevent DDL to drop fts aux tables. */
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
} else if (!dict_table_has_fts_index(user_table)) {
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
@@ -2961,6 +2960,12 @@ i_s_fts_deleted_generic_fill(
fts_table_fetch_doc_ids(trx, &fts_table, deleted);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
trx_free_for_background(trx);
fields = table->field;
int ret = 0;
@@ -2975,14 +2980,8 @@ i_s_fts_deleted_generic_fill(
BREAK_IF(ret = schema_table_store_record(thd, table));
}
trx_free_for_background(trx);
fts_doc_ids_free(deleted);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(ret);
}
@@ -3340,32 +3339,33 @@ i_s_fts_index_cache_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
no_fts:
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
if (user_table->fts == NULL || user_table->fts->cache == NULL) {
if (!user_table->fts || !user_table->fts->cache) {
dict_table_close(user_table, FALSE, FALSE);
DBUG_RETURN(0);
goto no_fts;
}
cache = user_table->fts->cache;
ut_a(cache);
int ret = 0;
fts_string_t conv_str;
conv_str.f_len = system_charset_info->mbmaxlen
* FTS_MAX_WORD_LEN_IN_CHAR;
conv_str.f_str = static_cast<byte*>(ut_malloc(conv_str.f_len));
byte word[HA_FT_MAXBYTELEN + 1];
conv_str.f_len = sizeof word;
conv_str.f_str = word;
for (ulint i = 0; i < ib_vector_size(cache->indexes); i++) {
fts_index_cache_t* index_cache;
@@ -3377,9 +3377,8 @@ i_s_fts_index_cache_fill(
index_cache, thd, &conv_str, tables));
}
ut_free(conv_str.f_str);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(ret);
}
@@ -3792,19 +3791,17 @@ i_s_fts_index_table_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
/* Prevent DDL to drop fts aux tables. */
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
@@ -3956,32 +3953,28 @@ i_s_fts_config_fill(
DBUG_RETURN(0);
}
if (!fts_internal_tbl_name) {
DBUG_RETURN(0);
}
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
DEBUG_SYNC_C("i_s_fts_config_fille_check");
fields = table->field;
/* Prevent DDL to drop fts aux tables. */
/* Prevent DROP of the internal tables for fulltext indexes.
FIXME: acquire DDL-blocking MDL on the user table name! */
rw_lock_s_lock(&dict_operation_lock);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
user_table = dict_table_open_on_id(
innodb_ft_aux_table_id, FALSE, DICT_TABLE_OP_NORMAL);
if (!user_table) {
no_fts:
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
} else if (!dict_table_has_fts_index(user_table)) {
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
DBUG_RETURN(0);
}
if (!dict_table_has_fts_index(user_table)) {
dict_table_close(user_table, FALSE, FALSE);
goto no_fts;
}
fields = table->field;
trx = trx_allocate_for_background();
trx->op_info = "Select for FTS CONFIG TABLE";
@@ -4033,12 +4026,12 @@ i_s_fts_config_fill(
fts_sql_commit(trx);
trx_free_for_background(trx);
dict_table_close(user_table, FALSE, FALSE);
rw_lock_s_unlock(&dict_operation_lock);
trx_free_for_background(trx);
DBUG_RETURN(ret);
}

View File

@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2007, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyrigth (c) 2014, 2017, MariaDB Corporation.
Copyrigth (c) 2014, 2019, MariaDB Corporation.
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
@@ -27,6 +27,7 @@ Modified Dec 29, 2014 Jan Lindström
#ifndef i_s_h
#define i_s_h
#include "dict0types.h"
const char plugin_author[] = "Oracle Corporation";
const char maria_plugin_author[] = "MariaDB Corporation";
@@ -69,6 +70,9 @@ extern struct st_maria_plugin i_s_innodb_tablespaces_scrubbing;
extern struct st_mysql_plugin i_s_innodb_sys_semaphore_waits;
extern struct st_mysql_plugin i_s_innodb_changed_page_bitmaps;
/** The latest successfully looked up innodb_fts_aux_table */
extern table_id_t innodb_ft_aux_table_id;
/** maximum number of buffer page info we would cache. */
#define MAX_BUF_INFO_CACHED 10000

View File

@@ -367,11 +367,6 @@ extern bool fts_need_sync;
/** Maximum possible Fulltext word length (in characters) */
#define FTS_MAX_WORD_LEN_IN_CHAR HA_FT_MAXCHARLEN
/** Variable specifying the table that has Fulltext index to display its
content through information schema table */
extern char* fts_internal_tbl_name;
extern char* fts_internal_tbl_name2;
#define fts_que_graph_free(graph) \
do { \
mutex_enter(&dict_sys->mutex); \