MDEV-27582 Fulltext DDL decrements the FTS_DOC_ID value

- InnoDB FTS DDL decrements the FTS_DOC_ID when there is a
deleted marked record involved. FTS_DOC_ID must never be
reused. The purpose of FTS_DOC_ID is to be a unique row
identifier that will be changed whenever a fulltext indexed
column is updated.
parent 0635088d
...@@ -289,3 +289,32 @@ ENGINE=InnoDB; ...@@ -289,3 +289,32 @@ ENGINE=InnoDB;
ALTER TABLE t1 ADD c SERIAL; ALTER TABLE t1 ADD c SERIAL;
DROP TABLE t1; DROP TABLE t1;
# End of 10.3 tests # End of 10.3 tests
#
# MDEV-27582 Fulltext DDL decrements the FTS_DOC_ID value
#
CREATE TABLE t1 (
f1 INT NOT NULL PRIMARY KEY,
f2 VARCHAR(64), FULLTEXT ft(f2)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
connect con1,localhost,root,,,;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
connection default;
DELETE FROM t1 WHERE f1 = 2;
ALTER TABLE t1 DROP INDEX ft;
ALTER TABLE t1 ADD FULLTEXT INDEX ft (f2);
INSERT INTO t1 VALUES (3, 'innodb fts search');
SET GLOBAL innodb_optimize_fulltext_only=ON;
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize status OK
SET GLOBAL innodb_ft_aux_table = 'test/t1';
SELECT max(DOC_ID) FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
max(DOC_ID)
3
SELECT * FROM t1 WHERE MATCH(f2) AGAINST("+innodb +search" IN BOOLEAN MODE);
f1 f2
3 innodb fts search
DROP TABLE t1;
disconnect con1;
SET GLOBAL innodb_optimize_fulltext_only=OFF;
SET GLOBAL innodb_ft_aux_table = default;
--enable-plugin-innodb-sys-tables --enable-plugin-innodb-sys-tables
--innodb_ft_index_table
...@@ -357,3 +357,28 @@ ALTER TABLE t1 ADD c SERIAL; ...@@ -357,3 +357,28 @@ ALTER TABLE t1 ADD c SERIAL;
DROP TABLE t1; DROP TABLE t1;
--echo # End of 10.3 tests --echo # End of 10.3 tests
--echo #
--echo # MDEV-27582 Fulltext DDL decrements the FTS_DOC_ID value
--echo #
CREATE TABLE t1 (
f1 INT NOT NULL PRIMARY KEY,
f2 VARCHAR(64), FULLTEXT ft(f2)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,'foo'),(2,'bar');
connect(con1,localhost,root,,,);
START TRANSACTION WITH CONSISTENT SNAPSHOT;
connection default;
DELETE FROM t1 WHERE f1 = 2;
ALTER TABLE t1 DROP INDEX ft;
ALTER TABLE t1 ADD FULLTEXT INDEX ft (f2);
INSERT INTO t1 VALUES (3, 'innodb fts search');
SET GLOBAL innodb_optimize_fulltext_only=ON;
OPTIMIZE TABLE t1;
SET GLOBAL innodb_ft_aux_table = 'test/t1';
SELECT max(DOC_ID) FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE;
SELECT * FROM t1 WHERE MATCH(f2) AGAINST("+innodb +search" IN BOOLEAN MODE);
DROP TABLE t1;
disconnect con1;
SET GLOBAL innodb_optimize_fulltext_only=OFF;
SET GLOBAL innodb_ft_aux_table = default;
...@@ -243,18 +243,6 @@ fts_add_doc_by_id( ...@@ -243,18 +243,6 @@ fts_add_doc_by_id(
/*==============*/ /*==============*/
fts_trx_table_t*ftt, /*!< in: FTS trx table */ fts_trx_table_t*ftt, /*!< in: FTS trx table */
doc_id_t doc_id); /*!< in: doc id */ doc_id_t doc_id); /*!< in: doc id */
/******************************************************************//**
Update the last document id. This function could create a new
transaction to update the last document id.
@return DB_SUCCESS if OK */
static
dberr_t
fts_update_sync_doc_id(
/*===================*/
const dict_table_t* table, /*!< in: table */
doc_id_t doc_id, /*!< in: last document id */
trx_t* trx) /*!< in: update trx, or NULL */
MY_ATTRIBUTE((nonnull(1)));
/** Tokenize a document. /** Tokenize a document.
@param[in,out] doc document to tokenize @param[in,out] doc document to tokenize
...@@ -2552,27 +2540,6 @@ fts_get_max_cache_size( ...@@ -2552,27 +2540,6 @@ fts_get_max_cache_size(
} }
#endif #endif
/*********************************************************************//**
Update the next and last Doc ID in the CONFIG table to be the input
"doc_id" value (+ 1). We would do so after each FTS index build or
table truncate */
void
fts_update_next_doc_id(
/*===================*/
trx_t* trx, /*!< in/out: transaction */
const dict_table_t* table, /*!< in: table */
doc_id_t doc_id) /*!< in: DOC ID to set */
{
table->fts->cache->synced_doc_id = doc_id;
table->fts->cache->next_doc_id = doc_id + 1;
table->fts->cache->first_doc_id = table->fts->cache->next_doc_id;
fts_update_sync_doc_id(
table, table->fts->cache->synced_doc_id, trx);
}
/*********************************************************************//** /*********************************************************************//**
Get the next available document id. Get the next available document id.
@return DB_SUCCESS if OK */ @return DB_SUCCESS if OK */
...@@ -2731,17 +2698,17 @@ fts_cmp_set_sync_doc_id( ...@@ -2731,17 +2698,17 @@ fts_cmp_set_sync_doc_id(
return(error); return(error);
} }
/*********************************************************************//** /** Update the last document id. This function could create a new
Update the last document id. This function could create a new
transaction to update the last document id. transaction to update the last document id.
@return DB_SUCCESS if OK */ @param table table to be updated
static @param doc_id last document id
@param trx update trx or null
@retval DB_SUCCESS if OK */
dberr_t dberr_t
fts_update_sync_doc_id( fts_update_sync_doc_id(
/*===================*/ const dict_table_t* table,
const dict_table_t* table, /*!< in: table */ doc_id_t doc_id,
doc_id_t doc_id, /*!< in: last document id */ trx_t* trx)
trx_t* trx) /*!< in: update trx, or NULL */
{ {
byte id[FTS_MAX_ID_LEN]; byte id[FTS_MAX_ID_LEN];
pars_info_t* info; pars_info_t* info;
......
...@@ -402,17 +402,6 @@ fts_get_next_doc_id( ...@@ -402,17 +402,6 @@ fts_get_next_doc_id(
/*================*/ /*================*/
const dict_table_t* table, /*!< in: table */ const dict_table_t* table, /*!< in: table */
doc_id_t* doc_id);/*!< out: new document id */ doc_id_t* doc_id);/*!< out: new document id */
/*********************************************************************//**
Update the next and last Doc ID in the CONFIG table to be the input
"doc_id" value (+ 1). We would do so after each FTS index build or
table truncate */
void
fts_update_next_doc_id(
/*===================*/
trx_t* trx, /*!< in/out: transaction */
const dict_table_t* table, /*!< in: table */
doc_id_t doc_id) /*!< in: DOC ID to set */
MY_ATTRIBUTE((nonnull(2)));
/******************************************************************//** /******************************************************************//**
Create a new fts_doc_ids_t. Create a new fts_doc_ids_t.
...@@ -976,4 +965,16 @@ bool fts_check_aux_table(const char *name, ...@@ -976,4 +965,16 @@ bool fts_check_aux_table(const char *name,
table_id_t *table_id, table_id_t *table_id,
index_id_t *index_id); index_id_t *index_id);
/** Update the last document id. This function could create a new
transaction to update the last document id.
@param table table to be updated
@param doc_id last document id
@param trx update trx or null
@retval DB_SUCCESS if OK */
dberr_t
fts_update_sync_doc_id(const dict_table_t *table,
doc_id_t doc_id,
trx_t *trx)
MY_ATTRIBUTE((nonnull(1)));
#endif /*!< fts0fts.h */ #endif /*!< fts0fts.h */
...@@ -2862,7 +2862,21 @@ row_merge_read_clustered_index( ...@@ -2862,7 +2862,21 @@ row_merge_read_clustered_index(
err = fts_sync_table(const_cast<dict_table_t*>(new_table)); err = fts_sync_table(const_cast<dict_table_t*>(new_table));
if (err == DB_SUCCESS) { if (err == DB_SUCCESS) {
fts_update_next_doc_id(NULL, new_table, max_doc_id); new_table->fts->cache->synced_doc_id = max_doc_id;
/* Update the max value as next FTS_DOC_ID */
if (max_doc_id >= new_table->fts->cache->next_doc_id) {
new_table->fts->cache->next_doc_id =
max_doc_id + 1;
}
new_table->fts->cache->first_doc_id =
new_table->fts->cache->next_doc_id;
err= fts_update_sync_doc_id(
new_table,
new_table->fts->cache->synced_doc_id,
NULL);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment