diff --git a/mysql-test/suite/innodb_fts/r/limit_union_2.result b/mysql-test/suite/innodb_fts/r/limit_union_2.result new file mode 100644 index 0000000..26d8c14 --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/limit_union_2.result @@ -0,0 +1,97 @@ +CREATE TABLE t1 ( +FTS_DOC_ID BIGINT UNSIGNED NOT NULL PRIMARY KEY, +contents TEXT, +FULLTEXT KEY fx_contents (contents) +) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 'xyz mnt'), (2, 'xyz mnt'), (3, 'xyz'), (4, 'mnt'), (5, 'mnt'); +SET GLOBAL innodb_ft_aux_table="test/t1"; +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE; +WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION +mnt 1 5 4 1 4 +mnt 1 5 4 2 4 +mnt 1 5 4 4 0 +mnt 1 5 4 5 0 +xyz 1 3 3 1 0 +xyz 1 3 3 2 0 +xyz 1 3 3 3 0 +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE; +WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION +SET GLOBAL innodb_ft_aux_table=default; +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE); +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 1; +FTS_DOC_ID contents +1 xyz mnt +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 3; +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 3; +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 5; +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +4 mnt +5 mnt +DROP TABLE t1; +CREATE TABLE t1 ( +FTS_DOC_ID BIGINT UNSIGNED NOT NULL PRIMARY KEY, +contents TEXT, +FULLTEXT KEY fx_contents (contents) WITH PARSER ngram +) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 'xyz mnt'), (2, 'xyz mnt'), (3, 'xyz'), (4, 'mnt'), (5, 'mnt'); +SET GLOBAL innodb_ft_aux_table="test/t1"; +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE; +WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION +mn 1 5 4 1 4 +mn 1 5 4 2 4 +mn 1 5 4 4 0 +mn 1 5 4 5 0 +nt 1 5 4 1 5 +nt 1 5 4 2 5 +nt 1 5 4 4 1 +nt 1 5 4 5 1 +xy 1 3 3 1 0 +xy 1 3 3 2 0 +xy 1 3 3 3 0 +yz 1 3 3 1 1 +yz 1 3 3 2 1 +yz 1 3 3 3 1 +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE; +WORD FIRST_DOC_ID LAST_DOC_ID DOC_COUNT DOC_ID POSITION +SET GLOBAL innodb_ft_aux_table=default; +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE); +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 1; +FTS_DOC_ID contents +1 xyz mnt +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 3; +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 3; +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 5; +FTS_DOC_ID contents +1 xyz mnt +2 xyz mnt +3 xyz +4 mnt +5 mnt +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/limit_union_2.test b/mysql-test/suite/innodb_fts/t/limit_union_2.test new file mode 100644 index 0000000..082c07c --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/limit_union_2.test @@ -0,0 +1,60 @@ +#Bug#87518 Server asserts when using n-gram full text searching with LIMIT + +# Test case 1 : wrong result without parser +CREATE TABLE t1 ( + FTS_DOC_ID BIGINT UNSIGNED NOT NULL PRIMARY KEY, + contents TEXT, + FULLTEXT KEY fx_contents (contents) +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (1, 'xyz mnt'), (2, 'xyz mnt'), (3, 'xyz'), (4, 'mnt'), (5, 'mnt'); + +SET GLOBAL innodb_ft_aux_table="test/t1"; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE; + +SET GLOBAL innodb_ft_aux_table=default; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE); + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 1; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 3; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 3; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 5; + +DROP TABLE t1; + + +# Test case 2 : core dump with parser +CREATE TABLE t1 ( + FTS_DOC_ID BIGINT UNSIGNED NOT NULL PRIMARY KEY, + contents TEXT, + FULLTEXT KEY fx_contents (contents) WITH PARSER ngram +) ENGINE=InnoDB; + +INSERT INTO t1 VALUES (1, 'xyz mnt'), (2, 'xyz mnt'), (3, 'xyz'), (4, 'mnt'), (5, 'mnt'); + +SET GLOBAL innodb_ft_aux_table="test/t1"; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE; + +SET GLOBAL innodb_ft_aux_table=default; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE); + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 1; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz' IN BOOLEAN MODE) LIMIT 3; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 3; + +SELECT * FROM t1 WHERE MATCH(contents) AGAINST ('xyz mnt' IN BOOLEAN MODE) LIMIT 5; + +DROP TABLE t1; diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc index 8e44850..930afd1 100644 --- a/storage/innobase/fts/fts0ast.cc +++ b/storage/innobase/fts/fts0ast.cc @@ -546,8 +546,7 @@ fts_ast_node_check_union( fts_ast_node_t* node) { if (node->type == FTS_AST_LIST - || node->type == FTS_AST_SUBEXP_LIST - || node->type == FTS_AST_PARSER_PHRASE_LIST) { + || node->type == FTS_AST_SUBEXP_LIST) { for (node = node->list.head; node; node = node->next) { if (!fts_ast_node_check_union(node)) { @@ -560,7 +559,8 @@ fts_ast_node_check_union( || node->oper == FTS_EXIST)) { return(false); - } else if (node->type == FTS_AST_TEXT) { + } else if (node->type == FTS_AST_TEXT + || node->type == FTS_AST_PARSER_PHRASE_LIST) { /* Distance or phrase search query. */ return(false); } diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc index 52b8765..2476876 100644 --- a/storage/innobase/fts/fts0que.cc +++ b/storage/innobase/fts/fts0que.cc @@ -746,6 +746,10 @@ fts_query_union_doc_id( query->total_size += SIZEOF_RBT_NODE_ADD + sizeof(fts_ranking_t) + RANKING_WORDS_INIT_LEN; + + if (query->limit != ULONG_UNDEFINED) { + query->n_docs++; + } } } @@ -3309,7 +3313,7 @@ fts_query_filter_doc_ids( } if (query->limit != ULONG_UNDEFINED - && query->limit <= ++query->n_docs) { + && query->n_docs >= query->limit) { goto func_exit; } } @@ -3321,7 +3325,6 @@ func_exit: if (query->total_size > fts_result_cache_limit) { return(DB_FTS_EXCEED_RESULT_CACHE_LIMIT); } else { - query->n_docs = 0; return(DB_SUCCESS); } } @@ -3919,6 +3922,10 @@ fts_query_can_optimize( return; } + if (query->limit != ULONG_UNDEFINED) { + return; + } + /* Check if it has only a term without oper */ ut_ad(node->type == FTS_AST_LIST); node = node->list.head;