Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug#1634932: Assertion failure in thread x in file fts0que.cc #1297

Merged
merged 2 commits into from
Feb 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions mysql-test/r/fulltext.result
Original file line number Diff line number Diff line change
Expand Up @@ -689,3 +689,10 @@ EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
End of 5.1 tests
# Bug#21140111: Explain ... match against: Assertion failed: ret ...
CREATE TABLE z(a INTEGER) engine=innodb;
CREATE TABLE q(b TEXT CHARSET latin1, fulltext(b)) engine=innodb;
explain format=json SELECT 1 FROM q
WHERE (SELECT MATCH(b) AGAINST ('*') FROM z);
ERROR HY000: Incorrect arguments to MATCH
DROP TABLE z, q;
37 changes: 37 additions & 0 deletions mysql-test/suite/innodb_fts/r/bug83648.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#
# Bug 1634932: Assertion failure in thread x in
# file fts0que.cc
#
SET @saved_innodb_ft_result_cache_limit= @@global.innodb_ft_result_cache_limit;
CREATE TABLE `t1` (
`FTS_DOC_ID` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`text_content` MEDIUMTEXT, PRIMARY KEY (`FTS_DOC_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE UNIQUE INDEX FTS_DOC_ID_INDEX ON t1(FTS_DOC_ID);
SET autocommit=0;
CREATE PROCEDURE populate_t1()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE (i <= 250) DO
INSERT INTO t1 (text_content) VALUES ("some_text_1234 aaa");
SET i = i + 1;
END WHILE;
END//
CALL populate_t1;
SET autocommit=1;
SET SESSION debug="+d,fts_instrument_result_cache_limit";
ALTER TABLE t1 ADD FULLTEXT INDEX `text_content_idx` (`text_content`);
SELECT FTS_DOC_ID, text_content
FROM t1
WHERE MATCH text_content AGAINST ('+some_text_1234' IN BOOLEAN MODE);
ERROR HY000: FTS query exceeds result cache limit
UPDATE t1
SET text_content='some_text_12345'
where MATCH text_content AGAINST ('+some_text_1234' IN BOOLEAN MODE);
ERROR HY000: FTS query exceeds result cache limit
DELETE FROM t1
WHERE MATCH text_content AGAINST ('+some_text_1234' IN BOOLEAN MODE);
ERROR HY000: FTS query exceeds result cache limit
SET GLOBAL innodb_ft_result_cache_limit = @saved_innodb_ft_result_cache_limit;
DROP TABLE t1;
DROP PROCEDURE populate_t1;
57 changes: 57 additions & 0 deletions mysql-test/suite/innodb_fts/t/bug83648.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
--echo #
--echo # Bug 1634932: Assertion failure in thread x in
--echo # file fts0que.cc
--echo #

--source include/have_innodb.inc
--source include/have_debug.inc

SET @saved_innodb_ft_result_cache_limit= @@global.innodb_ft_result_cache_limit;

CREATE TABLE `t1` (
`FTS_DOC_ID` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`text_content` MEDIUMTEXT, PRIMARY KEY (`FTS_DOC_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE UNIQUE INDEX FTS_DOC_ID_INDEX ON t1(FTS_DOC_ID);

SET autocommit=0;

DELIMITER //;
CREATE PROCEDURE populate_t1()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE (i <= 250) DO
INSERT INTO t1 (text_content) VALUES ("some_text_1234 aaa");
SET i = i + 1;
END WHILE;
END//

DELIMITER ;//

CALL populate_t1;
SET autocommit=1;

SET SESSION debug="+d,fts_instrument_result_cache_limit";

ALTER TABLE t1 ADD FULLTEXT INDEX `text_content_idx` (`text_content`);

# HA_ERR_FTS_EXCEED_RESULT_CACHE_LIMIT = 188
--error 188
SELECT FTS_DOC_ID, text_content
FROM t1
WHERE MATCH text_content AGAINST ('+some_text_1234' IN BOOLEAN MODE);

--error 188
UPDATE t1
SET text_content='some_text_12345'
where MATCH text_content AGAINST ('+some_text_1234' IN BOOLEAN MODE);

--error 188
DELETE FROM t1
WHERE MATCH text_content AGAINST ('+some_text_1234' IN BOOLEAN MODE);

SET GLOBAL innodb_ft_result_cache_limit = @saved_innodb_ft_result_cache_limit;

DROP TABLE t1;
DROP PROCEDURE populate_t1;
14 changes: 14 additions & 0 deletions mysql-test/t/fulltext.test
Original file line number Diff line number Diff line change
Expand Up @@ -632,3 +632,17 @@ DEALLOCATE PREPARE stmt;
DROP TABLE t1;

--echo End of 5.1 tests

--echo # Bug#21140111: Explain ... match against: Assertion failed: ret ...

CREATE TABLE z(a INTEGER) engine=innodb;
CREATE TABLE q(b TEXT CHARSET latin1, fulltext(b)) engine=innodb;

let $query=
SELECT 1 FROM q
WHERE (SELECT MATCH(b) AGAINST ('*') FROM z);

--error ER_WRONG_ARGUMENTS
eval explain format=json $query;

DROP TABLE z, q;
32 changes: 25 additions & 7 deletions sql/item_func.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6239,7 +6239,16 @@ void Item_func_get_system_var::cleanup()
}


void Item_func_match::init_search(bool no_order)
/**
Initialize searching within full-text index.

@param thd Thread handler
@param no_order set if FT should not be sorted

@returns false if success, true if error
*/

bool Item_func_match::init_search(THD *thd, bool no_order)
{
DBUG_ENTER("Item_func_match::init_search");

Expand All @@ -6248,7 +6257,7 @@ void Item_func_match::init_search(bool no_order)
with fix_field
*/
if (!fixed)
DBUG_VOID_RETURN;
DBUG_RETURN(false);

/* Check if init_search() has been called before */
if (ft_handler)
Expand All @@ -6261,16 +6270,19 @@ void Item_func_match::init_search(bool no_order)
*/
if (join_key)
table->file->ft_handler= ft_handler;
DBUG_VOID_RETURN;
DBUG_RETURN(false);
}

if (key == NO_SUCH_KEY)
{
List<Item> fields;
fields.push_back(new Item_string(" ",1, cmp_collation.collation));
if (fields.push_back(new Item_string(" ",1, cmp_collation.collation)))
DBUG_RETURN(true);
for (uint i=1; i < arg_count; i++)
fields.push_back(args[i]);
concat_ws=new Item_func_concat_ws(fields);
if (concat_ws == NULL)
DBUG_RETURN(true);
/*
Above function used only to get value and do not need fix_fields for it:
Item_string - basic constant
Expand All @@ -6283,10 +6295,13 @@ void Item_func_match::init_search(bool no_order)
if (master)
{
join_key=master->join_key=join_key|master->join_key;
master->init_search(no_order);
if (master->init_search(thd, no_order))
DBUG_RETURN(true);

ft_handler=master->ft_handler;
join_key=master->join_key;
DBUG_VOID_RETURN;

DBUG_RETURN(false);
}

String *ft_tmp= 0;
Expand All @@ -6310,10 +6325,13 @@ void Item_func_match::init_search(bool no_order)
flags|=FT_SORTED;
ft_handler=table->file->ft_init_ext(flags, key, ft_tmp);

if (thd->is_error())
DBUG_RETURN(true);

if (join_key)
table->file->ft_handler=ft_handler;

DBUG_VOID_RETURN;
DBUG_RETURN(false);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion sql/item_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -1895,7 +1895,7 @@ class Item_func_match :public Item_real_func
virtual void print(String *str, enum_query_type query_type);

bool fix_index();
void init_search(bool no_order);
bool init_search(THD *thd, bool no_order);

/**
Get number of matching rows from FT handler.
Expand Down
3 changes: 1 addition & 2 deletions sql/opt_sum.cc
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,7 @@ int opt_sum_query(THD *thd,
!((Item_sum_count*) item)->get_arg(0)->maybe_null) // 4
{
Item_func_match* fts_item= static_cast<Item_func_match*>(conds);
fts_item->init_search(true);
if (thd->is_error())
if (fts_item->init_search(thd, true))
break;
count= fts_item->get_count();
}
Expand Down
20 changes: 11 additions & 9 deletions sql/sql_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9539,17 +9539,19 @@ int setup_ftfuncs(SELECT_LEX *select_lex)

int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
{
if (select_lex->ftfunc_list->elements)
{
List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
Item_func_match *ifm;
DBUG_PRINT("info",("Performing FULLTEXT search"));
THD_STAGE_INFO(thd, stage_fulltext_initialization);
DBUG_ASSERT(select_lex->has_ft_funcs());

List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
DBUG_PRINT("info",("Performing FULLTEXT search"));
THD_STAGE_INFO(thd, stage_fulltext_initialization);

while ((ifm=li++))
ifm->init_search(no_order);
Item_func_match *ifm;
while ((ifm= li++))
{
if (ifm->init_search(thd, no_order))
return true;
}
return 0;
return false;
}


Expand Down
10 changes: 8 additions & 2 deletions sql/sql_delete.cc
Original file line number Diff line number Diff line change
Expand Up @@ -322,14 +322,18 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, Item *conds,
table->file->print_error(error, MYF(0));
goto exit_without_my_ok;
}

if (select_lex->has_ft_funcs() && init_ftfuncs(thd, select_lex, 1))
goto exit_without_my_ok;

if (usable_index==MAX_KEY || (select && select->quick))
error= init_read_record(&info, thd, table, select, 1, 1, FALSE);
else
error= init_read_record_idx(&info, thd, table, 1, usable_index, reverse);

if (error)
goto exit_without_my_ok;
init_ftfuncs(thd, select_lex, 1);

THD_STAGE_INFO(thd, stage_updating);

if (table->triggers &&
Expand Down Expand Up @@ -763,7 +767,9 @@ multi_delete::initialize_tables(JOIN *join)
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
}
init_ftfuncs(thd, thd->lex->current_select, 1);
if (thd->lex->current_select->has_ft_funcs() && init_ftfuncs(thd, thd->lex->current_select, 1))
DBUG_RETURN(true);

DBUG_RETURN(thd->is_fatal_error != 0);
}

Expand Down
2 changes: 1 addition & 1 deletion sql/sql_executor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ JOIN::exec()
if (prepare_result(&columns_list))
DBUG_VOID_RETURN;

if (select_lex->materialized_table_count)
if (select_lex->materialized_table_count && select_lex->has_ft_funcs())
init_ftfuncs(thd, select_lex, order);

if (!tables_list && (tables || !select_lex->with_sum_func))
Expand Down
5 changes: 5 additions & 0 deletions sql/sql_lex.h
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,11 @@ class st_select_lex: public st_select_lex_node
{
return &link_next;
}

/// @return true if query block references full-text functions
bool has_ft_funcs() const
{ return ftfunc_list->elements > 0; }

void invalidate();
void mark_as_dependent(st_select_lex *last);

Expand Down
5 changes: 3 additions & 2 deletions sql/sql_optimizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -763,9 +763,10 @@ JOIN::optimize()

/* Perform FULLTEXT search before all regular searches */
if (!(select_options & SELECT_DESCRIBE) &&
!select_lex->materialized_table_count)
!select_lex->materialized_table_count && select_lex->has_ft_funcs())
{
init_ftfuncs(thd, select_lex, order);
if (init_ftfuncs(thd, select_lex, order))
DBUG_RETURN(1);
optimize_fts_query();
}

Expand Down
8 changes: 6 additions & 2 deletions sql/sql_select.cc
Original file line number Diff line number Diff line change
Expand Up @@ -788,8 +788,12 @@ void JOIN::reset()
func->clear();
}

if (!(select_options & SELECT_DESCRIBE))
init_ftfuncs(thd, select_lex, MY_TEST(order));
if (!(select_options & SELECT_DESCRIBE) &&
select_lex->has_ft_funcs())
{
/* TODO: move the code to JOIN::exec */
(void)init_ftfuncs(thd, select_lex, MY_TEST(order));
}

DBUG_VOID_RETURN;
}
Expand Down
3 changes: 2 additions & 1 deletion sql/sql_update.cc
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,8 @@ int mysql_update(THD *thd,
goto exit_without_my_ok;
}
}
init_ftfuncs(thd, select_lex, 1);
if (select_lex->has_ft_funcs() && init_ftfuncs(thd, select_lex, 1))
goto exit_without_my_ok;

table->update_const_key_parts(conds);
order= simple_remove_const(order, conds);
Expand Down
20 changes: 20 additions & 0 deletions storage/innobase/fts/fts0que.cc
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,18 @@ fts_query_free_doc_ids(
query->total_size -= SIZEOF_RBT_CREATE;
}

/**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InnoDB code (everything in storage/innobase*) requires InnoDB-style code formatting:

  1. Tab characters must be used for indentation
  2. Blocks must be indented by 1 tab
  3. 1 tab = 8 spaces (set this in your editor)

SQL code (for instance sql/* and include/*) requires MySQL-style code formatting:

  1. Using spaces only for indentation.
  2. Blocks must be indented by 2 spaces.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Free the query intersection
@param[in] query query instance */
static
void
fts_query_free_intersection(
fts_query_t* query)
{
fts_query_free_doc_ids(query, query->intersection);
query->intersection = NULL;
}

/*******************************************************************//**
Add the word to the documents "list" of matching words from
the query. We make a copy of the word from the query heap. */
Expand Down Expand Up @@ -1311,6 +1323,7 @@ fts_query_intersect(
/* error is passed by 'query->error' */
if (query->error != DB_SUCCESS) {
ut_ad(query->error == DB_FTS_EXCEED_RESULT_CACHE_LIMIT);
fts_query_free_intersection(query);
return(query->error);
}

Expand Down Expand Up @@ -1339,6 +1352,8 @@ fts_query_intersect(

ut_a(!query->multi_exist || (query->multi_exist
&& rbt_size(query->doc_ids) <= n_doc_ids));
} else if (query->intersection != NULL) {
fts_query_free_intersection(query);
}
}

Expand Down Expand Up @@ -1557,6 +1572,11 @@ fts_merge_doc_ids(
query, ranking->doc_id, ranking->rank);

if (query->error != DB_SUCCESS) {
if (query->intersection != NULL)
{
ut_a(query->oper == FTS_EXIST);
fts_query_free_intersection(query);
}
DBUG_RETURN(query->error);
}

Expand Down