Skip to content

Commit e78f3cb

Browse files
committed
Bug#21140111: Explain ... match against: Assertion failed: ret ...
The problem here is missing error check in Item_func_match::init_search() after the handler call ft_init_ext_with_hints(), and missing error propagation in the call stack. The fix also includes a new inlined query block property function has_ft_funcs() that is used to avoid an unnecessary and costly function call to optimize full-text searches.
1 parent b49864f commit e78f3cb

13 files changed

+91
-34
lines changed

mysql-test/r/fulltext.result

+7
Original file line numberDiff line numberDiff line change
@@ -730,3 +730,10 @@ EXECUTE stmt;
730730
DEALLOCATE PREPARE stmt;
731731
DROP TABLE t1;
732732
End of 5.1 tests
733+
# Bug#21140111: Explain ... match against: Assertion failed: ret ...
734+
CREATE TABLE z(a INTEGER) engine=innodb;
735+
CREATE TABLE q(b TEXT CHARSET latin1, fulltext(b)) engine=innodb;
736+
explain format=json SELECT 1 FROM q
737+
WHERE (SELECT MATCH(b) AGAINST ('*') FROM z);
738+
ERROR 42000: syntax error, unexpected $end, expecting FTS_TERM or FTS_NUMB or '*'
739+
DROP TABLE z, q;

mysql-test/t/fulltext.test

+14
Original file line numberDiff line numberDiff line change
@@ -642,3 +642,17 @@ DEALLOCATE PREPARE stmt;
642642
DROP TABLE t1;
643643

644644
--echo End of 5.1 tests
645+
646+
--echo # Bug#21140111: Explain ... match against: Assertion failed: ret ...
647+
648+
CREATE TABLE z(a INTEGER) engine=innodb;
649+
CREATE TABLE q(b TEXT CHARSET latin1, fulltext(b)) engine=innodb;
650+
651+
let $query=
652+
SELECT 1 FROM q
653+
WHERE (SELECT MATCH(b) AGAINST ('*') FROM z);
654+
655+
--error ER_PARSE_ERROR
656+
eval explain format=json $query;
657+
658+
DROP TABLE z, q;

sql/item_func.cc

+23-8
Original file line numberDiff line numberDiff line change
@@ -7303,7 +7303,15 @@ bool Item_func_match::itemize(Parse_context *pc, Item **res)
73037303
}
73047304

73057305

7306-
void Item_func_match::init_search()
7306+
/**
7307+
Initialize searching within full-text index.
7308+
7309+
@param thd Thread handler
7310+
7311+
@returns false if success, true if error
7312+
*/
7313+
7314+
bool Item_func_match::init_search(THD *thd)
73077315
{
73087316
DBUG_ENTER("Item_func_match::init_search");
73097317

@@ -7312,7 +7320,7 @@ void Item_func_match::init_search()
73127320
with fix_field
73137321
*/
73147322
if (!fixed)
7315-
DBUG_VOID_RETURN;
7323+
DBUG_RETURN(false);
73167324

73177325
TABLE *const table= table_ref->table;
73187326
/* Check if init_search() has been called before */
@@ -7326,16 +7334,19 @@ void Item_func_match::init_search()
73267334
*/
73277335
if (join_key)
73287336
table->file->ft_handler= ft_handler;
7329-
DBUG_VOID_RETURN;
7337+
DBUG_RETURN(false);
73307338
}
73317339

73327340
if (key == NO_SUCH_KEY)
73337341
{
73347342
List<Item> fields;
7335-
fields.push_back(new Item_string(" ",1, cmp_collation.collation));
7343+
if (fields.push_back(new Item_string(" ",1, cmp_collation.collation)))
7344+
DBUG_RETURN(true);
73367345
for (uint i= 0; i < arg_count; i++)
73377346
fields.push_back(args[i]);
73387347
concat_ws=new Item_func_concat_ws(fields);
7348+
if (concat_ws == NULL)
7349+
DBUG_RETURN(true);
73397350
/*
73407351
Above function used only to get value and do not need fix_fields for it:
73417352
Item_string - basic constant
@@ -7347,9 +7358,11 @@ void Item_func_match::init_search()
73477358

73487359
if (master)
73497360
{
7350-
master->init_search();
7361+
if (master->init_search(thd))
7362+
DBUG_RETURN(true);
7363+
73517364
ft_handler=master->ft_handler;
7352-
DBUG_VOID_RETURN;
7365+
DBUG_RETURN(false);
73537366
}
73547367

73557368
String *ft_tmp= 0;
@@ -7372,16 +7385,18 @@ void Item_func_match::init_search()
73727385
if (!table->is_created())
73737386
{
73747387
my_error(ER_NO_FT_MATERIALIZED_SUBQUERY, MYF(0));
7375-
DBUG_VOID_RETURN;
7388+
DBUG_RETURN(true);
73767389
}
73777390

73787391
DBUG_ASSERT(master == NULL);
73797392
ft_handler= table->file->ft_init_ext_with_hints(key, ft_tmp, get_hints());
7393+
if (thd->is_error())
7394+
DBUG_RETURN(true);
73807395

73817396
if (join_key)
73827397
table->file->ft_handler=ft_handler;
73837398

7384-
DBUG_VOID_RETURN;
7399+
DBUG_RETURN(false);
73857400
}
73867401

73877402

sql/item_func.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -2376,7 +2376,7 @@ class Item_func_match :public Item_real_func
23762376
virtual void print(String *str, enum_query_type query_type);
23772377

23782378
bool fix_index();
2379-
void init_search();
2379+
bool init_search(THD *thd);
23802380
bool check_gcol_func_processor(uchar *int_arg)
23812381
{
23822382
/* TODO: consider adding in support for the MATCH-based generated columns */

sql/opt_sum.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,7 @@ int opt_sum_query(THD *thd,
374374
{
375375
Item_func_match* fts_item= static_cast<Item_func_match*>(conds);
376376
fts_item->set_hints(NULL, FT_NO_RANKING, HA_POS_ERROR, false);
377-
fts_item->init_search();
378-
if (thd->is_error())
377+
if (fts_item->init_search(thd))
379378
break;
380379
count= fts_item->get_count();
381380
}

sql/sql_base.cc

+12-10
Original file line numberDiff line numberDiff line change
@@ -9694,19 +9694,21 @@ int setup_ftfuncs(SELECT_LEX *select_lex)
96949694
}
96959695

96969696

9697-
int init_ftfuncs(THD *thd, SELECT_LEX *select_lex)
9697+
bool init_ftfuncs(THD *thd, SELECT_LEX *select_lex)
96989698
{
9699-
if (select_lex->ftfunc_list->elements)
9700-
{
9701-
List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
9702-
Item_func_match *ifm;
9703-
DBUG_PRINT("info",("Performing FULLTEXT search"));
9704-
THD_STAGE_INFO(thd, stage_fulltext_initialization);
9699+
DBUG_ASSERT(select_lex->has_ft_funcs());
9700+
9701+
List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
9702+
DBUG_PRINT("info",("Performing FULLTEXT search"));
9703+
THD_STAGE_INFO(thd, stage_fulltext_initialization);
97059704

9706-
while ((ifm=li++))
9707-
ifm->init_search();
9705+
Item_func_match *ifm;
9706+
while ((ifm= li++))
9707+
{
9708+
if (ifm->init_search(thd))
9709+
return true;
97089710
}
9709-
return 0;
9711+
return false;
97109712
}
97119713

97129714

sql/sql_base.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ void update_non_unique_table_error(TABLE_LIST *update,
279279
const char *operation,
280280
TABLE_LIST *duplicate);
281281
int setup_ftfuncs(SELECT_LEX* select);
282-
int init_ftfuncs(THD *thd, SELECT_LEX* select);
282+
bool init_ftfuncs(THD *thd, SELECT_LEX* select);
283283
int run_before_dml_hook(THD *thd);
284284
bool lock_table_names(THD *thd, TABLE_LIST *table_list,
285285
TABLE_LIST *table_list_end, ulong lock_wait_timeout,

sql/sql_delete.cc

+11-4
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,9 @@ bool Sql_cmd_delete::mysql_delete(THD *thd, ha_rows limit)
404404
goto exit_without_my_ok;
405405
}
406406

407-
init_ftfuncs(thd, select_lex);
407+
if (select_lex->has_ft_funcs() && init_ftfuncs(thd, select_lex))
408+
goto exit_without_my_ok;
409+
408410
THD_STAGE_INFO(thd, stage_updating);
409411

410412
if (table->triggers &&
@@ -834,7 +836,9 @@ bool Query_result_delete::initialize_tables(JOIN *join)
834836
{
835837
DBUG_ENTER("Query_result_delete::initialize_tables");
836838
ASSERT_BEST_REF_IN_JOIN_ORDER(join);
837-
DBUG_ASSERT(join == unit->first_select()->join);
839+
840+
SELECT_LEX *const select= unit->first_select();
841+
DBUG_ASSERT(join == select->join);
838842

839843
if ((thd->variables.option_bits & OPTION_SAFE_UPDATES) &&
840844
error_if_full_join(join))
@@ -924,8 +928,11 @@ bool Query_result_delete::initialize_tables(JOIN *join)
924928
DBUG_RETURN(true); /* purecov: inspected */
925929
*(table_ptr++)= table;
926930
}
927-
DBUG_ASSERT(unit->first_select() == thd->lex->current_select());
928-
init_ftfuncs(thd, unit->first_select());
931+
DBUG_ASSERT(select == thd->lex->current_select());
932+
933+
if (select->has_ft_funcs() && init_ftfuncs(thd, select))
934+
DBUG_RETURN(true);
935+
929936
DBUG_RETURN(thd->is_fatal_error != 0);
930937
}
931938

sql/sql_lex.h

+4
Original file line numberDiff line numberDiff line change
@@ -1161,6 +1161,10 @@ class st_select_lex: public Sql_alloc
11611161
bool has_limit() const
11621162
{ return select_limit != NULL; }
11631163

1164+
/// @return true if query block references full-text functions
1165+
bool has_ft_funcs() const
1166+
{ return ftfunc_list->elements > 0; }
1167+
11641168
void invalidate();
11651169

11661170
bool set_braces(bool value);

sql/sql_optimizer.cc

+5-5
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,8 @@ JOIN::optimize()
481481
no_jbuf_after= 0;
482482

483483
/* Perform FULLTEXT search before all regular searches */
484-
optimize_fts_query();
484+
if (select_lex->has_ft_funcs() && optimize_fts_query())
485+
DBUG_RETURN(1);
485486

486487
/*
487488
By setting child_subquery_can_materialize so late we gain the following:
@@ -10282,12 +10283,11 @@ void JOIN::optimize_keyuse()
1028210283
and checks if FT index can be used as covered.
1028310284
*/
1028410285

10285-
void JOIN::optimize_fts_query()
10286+
bool JOIN::optimize_fts_query()
1028610287
{
1028710288
ASSERT_BEST_REF_IN_JOIN_ORDER(this);
1028810289

10289-
if (!select_lex->ftfunc_list->elements)
10290-
return;
10290+
DBUG_ASSERT(select_lex->has_ft_funcs());
1029110291

1029210292
for (uint i= const_tables; i < tables; i++)
1029310293
{
@@ -10333,7 +10333,7 @@ void JOIN::optimize_fts_query()
1033310333
!order ? m_select_limit : HA_POS_ERROR, false);
1033410334
}
1033510335

10336-
init_ftfuncs(thd, select_lex);
10336+
return init_ftfuncs(thd, select_lex);
1033710337
}
1033810338

1033910339

sql/sql_optimizer.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ class JOIN :public Sql_alloc
710710
Function sets FT hints, initializes FT handlers and
711711
checks if FT index can be used as covered.
712712
*/
713-
void optimize_fts_query();
713+
bool optimize_fts_query();
714714

715715
bool prune_table_partitions();
716716

sql/sql_select.cc

+9-1
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,15 @@ void JOIN::reset()
864864
func->clear();
865865
}
866866

867-
init_ftfuncs(thd, select_lex);
867+
if (select_lex->has_ft_funcs())
868+
{
869+
#ifdef DBUG_OFF
870+
(void)init_ftfuncs(thd, select_lex);
871+
#else
872+
// Should not return an error on second execution
873+
DBUG_ASSERT(!init_ftfuncs(thd, select_lex));
874+
#endif
875+
}
868876

869877
DBUG_VOID_RETURN;
870878
}

sql/sql_update.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,8 @@ bool mysql_update(THD *thd,
525525
goto exit_without_my_ok;
526526
}
527527
}
528-
init_ftfuncs(thd, select_lex);
528+
if (select_lex->has_ft_funcs() && init_ftfuncs(thd, select_lex))
529+
goto exit_without_my_ok;
529530

530531
table->update_const_key_parts(conds);
531532
order= simple_remove_const(order, conds);

0 commit comments

Comments
 (0)