Bug #120539 Duplicate FULLTEXT index on a column returns wrong MATCH...AGAINST results when combined with a STORED generated column

Submitted: 24 May 15:26
Reporter: Li Zeyan Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Server: FULLTEXT search Severity:S2 (Serious)
Version:9.6.0 OS:Linux
Assigned to: CPU Architecture:Any

[24 May 15:26] Li Zeyan
Description:
When a table has a FULLTEXT index on a VARCHAR column, adding a STORED generated column (via ALTER TABLE) and a functional index, then creating a SECOND FULLTEXT index on the same column, corrupts the fulltext search state. After the second FULLTEXT index is created, MATCH(c5) AGAINST (... IN BOOLEAN MODE) queries return 0 rows instead of the correct non-zero count. The underlying data is intact -- a LIKE query on the same column and same pattern returns the correct result.

Specifically, the following sequence triggers the bug:

  1. Create a table with an INT column (c0), an INT column (c4), and a
     VARCHAR(255) column (c5).
  2. Insert one row where c5 = '1828091703'.
  3. Create a first FULLTEXT index on c5 -- queries work correctly at
     this point.
  4. ALTER TABLE to add a STORED generated column defined as
     IFNULL(c0, 0) + 1.
  5. Create a functional index on the expression (c4 + 1).
  6. Create a SECOND FULLTEXT index on c5 -- this corrupts fulltext
     search.

After step 6, the query:

  SELECT COUNT(*) FROM idx_t0
    WHERE MATCH(c5) AGAINST('1828091703*' IN BOOLEAN MODE);

returns 0 instead of 1. The control query using LIKE still returns 1:

  SELECT COUNT(*) FROM idx_t0 WHERE c5 LIKE '1828091703%';

The bug requires all three preconditions to be present simultaneously:
(a) an existing FULLTEXT index on the column,
(b) a STORED generated column on the table, and
(c) a functional index on the table.
Removing any one of these conditions prevents the bug from manifesting.

How to repeat:
DROP DATABASE IF EXISTS test_ft_min;
CREATE DATABASE test_ft_min;
USE test_ft_min;

-- Step 1: Create table with 1 row
CREATE TABLE idx_t0 (
    c0 INT NOT NULL,
    c4 INT NOT NULL,
    c5 VARCHAR(255) NOT NULL
);
INSERT INTO idx_t0 VALUES (286586734, 1717882338, '1828091703');

-- Step 2: Create FIRST fulltext index (works correctly)
CREATE FULLTEXT INDEX ft_0_c5 ON idx_t0 (c5);

-- Step 3: Add STORED generated column (triggers bug condition 1)
ALTER TABLE idx_t0 ADD COLUMN gen_col BIGINT GENERATED ALWAYS AS (IFNULL(c0, 0) + 1) STORED;

-- Step 4: Create functional index (triggers bug condition 2)
CREATE INDEX func_idx ON idx_t0 ((c4 + 1));

-- Step 5: Create SECOND fulltext index on same column (triggers the bug!)
CREATE FULLTEXT INDEX ft_idx_3122 ON idx_t0 (c5);

-- Verify: both queries should return 1
SELECT 'FT BUG (should be 1)' AS test, COUNT(*) AS result
    FROM idx_t0 WHERE MATCH(c5) AGAINST('1828091703*' IN BOOLEAN MODE);

SELECT 'LIKE ctrl (should be 1)' AS test, COUNT(*) AS result
    FROM idx_t0 WHERE c5 LIKE '1828091703%';

SHOW INDEX FROM idx_t0 WHERE Index_type = 'FULLTEXT';

FULLTEXT result:
+----------------------+--------+
| test                 | result |
+----------------------+--------+
| FT BUG (should be 1) |      0 |  <- WRONG! Missing 1 row!
+----------------------+--------+
1 row in set (0.001 sec)

LIKE control result:
+-------------------------+--------+
| test                    | result |
+-------------------------+--------+
| LIKE ctrl (should be 1) |      1 | <- CORRECT
+-------------------------+--------+
1 row in set (0.001 sec)

Expected output for the MATCH query: COUNT(*) = 1
Actual output: COUNT(*) = 0

Suggested fix:
The second CREATE FULLTEXT INDEX statement appears to corrupt the
internal fulltext index state (possibly the FT index cache or token
mapping) when the table contains both a STORED generated column and
a functional index. The InnoDB fulltext index creation/rebuild logic
should be reviewed for the code path that handles tables with generated
columns and functional indexes.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.038 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.