Commit 3c763afc authored by unknown's avatar unknown

BUG#25729 - boolean full text search is confused by NULLs produced by

            LEFT JOIN
Fixed that in certain situations MATCH ... AGAINST returns false hits
for NULLs produced by LEFT JOIN when there is no fulltext index
available.


mysql-test/r/fulltext_left_join.result:
  A test case for BUG#25729.
mysql-test/t/fulltext_left_join.test:
  A test case for BUG#25729.
sql/item_func.cc:
  concat_ws(NULL) returns empty string instead of NULL. There is not much
  sense to calculate relevance for empty strings, thus return 0 immediately
  if we got NULL or empty string from concat_ws.
sql/item_func.h:
  Item_func_match::concat renamed to concat_ws.
parent cd4670a7
...@@ -90,3 +90,10 @@ id link name relevance ...@@ -90,3 +90,10 @@ id link name relevance
1 1 string 0 1 1 string 0
2 0 string 0 2 0 string 0
DROP TABLE t1,t2; DROP TABLE t1,t2;
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (b INT, c TEXT, KEY(b));
INSERT INTO t1 VALUES(1);
INSERT INTO t2(b,c) VALUES(2,'castle'),(3,'castle');
SELECT * FROM t1 LEFT JOIN t2 ON a=b WHERE MATCH(c) AGAINST('+castle' IN BOOLEAN MODE);
a b c
DROP TABLE t1, t2;
...@@ -87,3 +87,14 @@ SELECT t1.*, MATCH(t1.name) AGAINST('string') AS relevance ...@@ -87,3 +87,14 @@ SELECT t1.*, MATCH(t1.name) AGAINST('string') AS relevance
DROP TABLE t1,t2; DROP TABLE t1,t2;
# End of 4.1 tests # End of 4.1 tests
#
# BUG#25729 - boolean full text search is confused by NULLs produced by LEFT
# JOIN
#
CREATE TABLE t1 (a INT);
CREATE TABLE t2 (b INT, c TEXT, KEY(b));
INSERT INTO t1 VALUES(1);
INSERT INTO t2(b,c) VALUES(2,'castle'),(3,'castle');
SELECT * FROM t1 LEFT JOIN t2 ON a=b WHERE MATCH(c) AGAINST('+castle' IN BOOLEAN MODE);
DROP TABLE t1, t2;
...@@ -4597,14 +4597,14 @@ void Item_func_match::init_search(bool no_order) ...@@ -4597,14 +4597,14 @@ void Item_func_match::init_search(bool no_order)
fields.push_back(new Item_string(" ",1, cmp_collation.collation)); fields.push_back(new Item_string(" ",1, cmp_collation.collation));
for (uint i=1; i < arg_count; i++) for (uint i=1; i < arg_count; i++)
fields.push_back(args[i]); fields.push_back(args[i]);
concat=new Item_func_concat_ws(fields); concat_ws=new Item_func_concat_ws(fields);
/* /*
Above function used only to get value and do not need fix_fields for it: Above function used only to get value and do not need fix_fields for it:
Item_string - basic constant Item_string - basic constant
fields - fix_fields() was already called for this arguments fields - fix_fields() was already called for this arguments
Item_func_concat_ws - do not need fix_fields() to produce value Item_func_concat_ws - do not need fix_fields() to produce value
*/ */
concat->quick_fix_field(); concat_ws->quick_fix_field();
} }
if (master) if (master)
...@@ -4819,8 +4819,8 @@ double Item_func_match::val_real() ...@@ -4819,8 +4819,8 @@ double Item_func_match::val_real()
if (key == NO_SUCH_KEY) if (key == NO_SUCH_KEY)
{ {
String *a= concat->val_str(&value); String *a= concat_ws->val_str(&value);
if ((null_value= (a == 0))) if ((null_value= (a == 0)) || !a->length())
DBUG_RETURN(0); DBUG_RETURN(0);
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, DBUG_RETURN(ft_handler->please->find_relevance(ft_handler,
(byte *)a->ptr(), a->length())); (byte *)a->ptr(), a->length()));
......
...@@ -1308,12 +1308,12 @@ class Item_func_match :public Item_real_func ...@@ -1308,12 +1308,12 @@ class Item_func_match :public Item_real_func
FT_INFO *ft_handler; FT_INFO *ft_handler;
TABLE *table; TABLE *table;
Item_func_match *master; // for master-slave optimization Item_func_match *master; // for master-slave optimization
Item *concat; // Item_func_concat_ws Item *concat_ws; // Item_func_concat_ws
String value; // value of concat String value; // value of concat_ws
String search_value; // key_item()'s value converted to cmp_collation String search_value; // key_item()'s value converted to cmp_collation
Item_func_match(List<Item> &a, uint b): Item_real_func(a), key(0), flags(b), Item_func_match(List<Item> &a, uint b): Item_real_func(a), key(0), flags(b),
join_key(0), ft_handler(0), table(0), master(0), concat(0) { } join_key(0), ft_handler(0), table(0), master(0), concat_ws(0) { }
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_func_match"); DBUG_ENTER("Item_func_match");
...@@ -1321,7 +1321,7 @@ class Item_func_match :public Item_real_func ...@@ -1321,7 +1321,7 @@ class Item_func_match :public Item_real_func
if (!master && ft_handler) if (!master && ft_handler)
ft_handler->please->close_search(ft_handler); ft_handler->please->close_search(ft_handler);
ft_handler= 0; ft_handler= 0;
concat= 0; concat_ws= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
enum Functype functype() const { return FT_FUNC; } enum Functype functype() const { return FT_FUNC; }
......
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