From df69309593b7e377d18d005147b485573f607f70 Mon Sep 17 00:00:00 2001
From: "serg@serg.mylan" <>
Date: Wed, 22 Oct 2003 17:57:09 +0200
Subject: [PATCH] MATCH ... AGAINST ("..." WITH QUERY EXPANSION) syntax

---
 include/ft_global.h        |  9 ++++++---
 myisam/ft_boolean_search.c |  2 +-
 myisam/ft_nlq_search.c     |  4 ++--
 myisam/ft_static.c         | 10 +++++-----
 myisam/ftdefs.h            |  4 ++--
 myisam/mi_write.c          |  2 +-
 mysql-test/t/fulltext.test |  4 ++--
 sql/ha_myisam.h            |  5 ++---
 sql/handler.h              |  3 +--
 sql/item_func.cc           | 14 +++++++-------
 sql/item_func.h            | 21 +++------------------
 sql/lex.h                  |  1 +
 sql/sql_yacc.yy            | 24 ++++++++++++++----------
 13 files changed, 47 insertions(+), 56 deletions(-)

diff --git a/include/ft_global.h b/include/ft_global.h
index 4aa916e91cf..afaad59ca50 100644
--- a/include/ft_global.h
+++ b/include/ft_global.h
@@ -57,9 +57,12 @@ extern const char *ft_boolean_syntax;
 int ft_init_stopwords(void);
 void ft_free_stopwords(void);
 
-#define FT_NL  0
-#define FT_BOOL 1
-FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, my_bool);
+#define FT_NL     0   /* this MUST be 0, see ft_init_search() */
+#define FT_BOOL   1   /* this MUST be 1, see ft_init_search() */
+#define FT_SORTED 2
+#define FT_EXPAND 4   /* query expansion */
+
+FT_INFO *ft_init_search(uint,void *, uint, byte *, uint);
 
 #ifdef  __cplusplus
 }
diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c
index 0b97eded872..bb9c2624691 100644
--- a/myisam/ft_boolean_search.c
+++ b/myisam/ft_boolean_search.c
@@ -341,7 +341,7 @@ static void _ftb_init_index_search(FT_INFO *ftb)
 
 FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
 				 uint query_len,
-				 my_bool presort __attribute__((unused)))
+				 uint flags __attribute__((unused)))
 {
   FTB       *ftb;
   FTB_EXPR  *ftbe;
diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c
index 690ad0fc453..efe735c3d16 100644
--- a/myisam/ft_nlq_search.c
+++ b/myisam/ft_nlq_search.c
@@ -175,7 +175,7 @@ static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b)
 
 
 FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
-			    uint query_len, my_bool presort)
+			    uint query_len, uint flags)
 {
   TREE	     allocated_wtree, *wtree=&allocated_wtree;
   ALL_IN_ONE  aio;
@@ -224,7 +224,7 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
   tree_walk(&aio.dtree, (tree_walk_action) &walk_and_copy,
 	    &dptr, left_root_right);
 
-  if (presort)
+  if (flags & FT_SORTED)
     qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp);
 
 err2:
diff --git a/myisam/ft_static.c b/myisam/ft_static.c
index 44e80847fd7..ca3054ae977 100644
--- a/myisam/ft_static.c
+++ b/myisam/ft_static.c
@@ -53,14 +53,14 @@ const struct _ft_vft _ft_vft_boolean = {
   ft_boolean_get_relevance,  ft_boolean_reinit_search
 };
 
-FT_INFO *(*_ft_init_vft[2])(MI_INFO *, uint, byte *, uint, my_bool) =
+FT_INFO *(*_ft_init_vft[2])(MI_INFO *, uint, byte *, uint, uint) =
 { ft_init_nlq_search, ft_init_boolean_search };
 
-FT_INFO *ft_init_search(uint mode, void *info, uint keynr,
-    byte *query, uint query_len, my_bool presort)
+FT_INFO *ft_init_search(uint flags, void *info, uint keynr,
+                        byte *query, uint query_len)
 {
-  return (*_ft_init_vft[mode])((MI_INFO *)info, keynr,
-          query, query_len, presort);
+  return (*_ft_init_vft[ flags&1 ])((MI_INFO *)info, keynr,
+          query, query_len, flags);
 }
 
 const char *ft_stopword_file = 0;
diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h
index 6e71f20e17c..2079a60f47d 100644
--- a/myisam/ftdefs.h
+++ b/myisam/ftdefs.h
@@ -128,7 +128,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *);
 uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record);
 
 extern const struct _ft_vft _ft_vft_nlq;
-FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, my_bool);
+FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, uint);
 int ft_nlq_read_next(FT_INFO *, char *);
 float ft_nlq_find_relevance(FT_INFO *, byte *, uint);
 void ft_nlq_close_search(FT_INFO *);
@@ -137,7 +137,7 @@ my_off_t ft_nlq_get_docid(FT_INFO *);
 void ft_nlq_reinit_search(FT_INFO *);
 
 extern const struct _ft_vft _ft_vft_boolean;
-FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, my_bool);
+FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, uint);
 int ft_boolean_read_next(FT_INFO *, char *);
 float ft_boolean_find_relevance(FT_INFO *, byte *, uint);
 void ft_boolean_close_search(FT_INFO *);
diff --git a/myisam/mi_write.c b/myisam/mi_write.c
index b6a7bf50dd0..155cf998a33 100644
--- a/myisam/mi_write.c
+++ b/myisam/mi_write.c
@@ -272,7 +272,7 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
     if (!error)
       error= _mi_ft_convert_to_ft2(info, keynr, key);
     delete_dynamic(info->ft1_to_ft2);
-    my_free(info->ft1_to_ft2, MYF(0));
+    my_free((gptr)info->ft1_to_ft2, MYF(0));
     info->ft1_to_ft2=0;
   }
   DBUG_RETURN(error);
diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test
index 56a27c83cf1..de706e80d6e 100644
--- a/mysql-test/t/fulltext.test
+++ b/mysql-test/t/fulltext.test
@@ -130,9 +130,9 @@ select * from t2 having MATCH inhalt AGAINST ('foobar');
 # check of fulltext errors
 #
 
---error 1279
+--error 1280
 CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i));
---error 1279
+--error 1280
 CREATE TABLE t3 (t int(11),i text,
                  j varchar(200) CHARACTER SET latin2,
                  fulltext tix (i,j));
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index e4e3192af10..8b10ce805da 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -89,9 +89,8 @@ class ha_myisam: public handler
     ft_handler->please->reinit_search(ft_handler);
     return 0;
   }
-  FT_INFO *ft_init_ext(uint mode, uint inx,const byte *key, uint keylen,
-		       bool presort)
-  { return ft_init_search(mode, file,inx,(byte*) key,keylen,presort); }
+  FT_INFO *ft_init_ext(uint flags, uint inx,const byte *key, uint keylen)
+  { return ft_init_search(flags,file,inx,(byte*) key,keylen); }
   int ft_read(byte *buf);
   int rnd_init(bool scan=1);
   int rnd_next(byte *buf);
diff --git a/sql/handler.h b/sql/handler.h
index 638125e23d0..26671bb5b11 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -271,8 +271,7 @@ public:
   }
   virtual int ft_init()
     { return -1; }
-  virtual FT_INFO *ft_init_ext(uint mode,uint inx,const byte *key, uint keylen,
-			    bool presort)
+  virtual FT_INFO *ft_init_ext(uint flags,uint inx,const byte *key, uint keylen)
     { return NULL; }
   virtual int ft_read(byte *buf) { return -1; }
   virtual int rnd_init(bool scan=1)=0;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 5a7aada8c1d..6392032850b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2587,10 +2587,10 @@ void Item_func_match::init_search(bool no_order)
     ft_tmp= &search_value;
   }
 
-  ft_handler=table->file->ft_init_ext(mode, key,
+  if (join_key && !no_order) flags|=FT_SORTED;
+  ft_handler=table->file->ft_init_ext(flags, key,
 				      (byte*) ft_tmp->ptr(),
-				      ft_tmp->length(),
-				      join_key && !no_order);
+				      ft_tmp->length());
 
   if (join_key)
     table->file->ft_handler=ft_handler;
@@ -2631,7 +2631,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
   /* check that all columns come from the same table */
   if (my_count_bits(used_tables_cache) != 1)
     key=NO_SUCH_KEY;
-  if (key == NO_SUCH_KEY && mode != FT_BOOL)
+  if (key == NO_SUCH_KEY && !(flags & FT_BOOL))
   {
     my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
     return 1;
@@ -2711,7 +2711,7 @@ bool Item_func_match::fix_index()
   }
 
 err:
-  if (mode == FT_BOOL)
+  if (flags & FT_BOOL)
   {
     key=NO_SUCH_KEY;
     return 0;
@@ -2723,8 +2723,8 @@ err:
 
 bool Item_func_match::eq(const Item *item, bool binary_cmp) const
 {
-  if (item->type() != FUNC_ITEM ||
-      func_name() != ((Item_func*)item)->func_name())
+  if (item->type() != FUNC_ITEM || ((Item_func*)item)->functype() != FT_FUNC ||
+      flags != ((Item_func_match*)item)->flags)
     return 0;
 
   Item_func_match *ifm=(Item_func_match*) item;
diff --git a/sql/item_func.h b/sql/item_func.h
index 33609694fe9..55c7a03108e 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -962,7 +962,7 @@ public:
 class Item_func_match :public Item_real_func
 {
 public:
-  uint key, mode;
+  uint key, flags;
   bool join_key;
   DTCollation cmp_collation;
   FT_INFO *ft_handler;
@@ -972,7 +972,7 @@ public:
   String value;              // value of concat
   String search_value;       // key_item()'s value converted to cmp_collation
 
-  Item_func_match(List<Item> &a): Item_real_func(a),
+  Item_func_match(List<Item> &a, uint b): Item_real_func(a), flags(b),
        table(0), master(0), ft_handler(0), concat(0), key(0), join_key(0) { }
   ~Item_func_match()
   {
@@ -988,6 +988,7 @@ public:
       delete concat;
   }
   enum Functype functype() const { return FT_FUNC; }
+  const char *func_name() const { return "match"; }
   void update_used_tables() {}
   table_map not_null_tables() const { return 0; }
   bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
@@ -1000,22 +1001,6 @@ public:
 };
 
 
-class Item_func_match_nl :public Item_func_match
-{
-public:
-  Item_func_match_nl(List<Item> &a) :Item_func_match(a) { mode=FT_NL; }
-  const char *func_name() const { return "match_nl"; }
-};
-
-
-class Item_func_match_bool :public Item_func_match
-{
-public:
-  Item_func_match_bool(List<Item> &a) :Item_func_match(a) { mode=FT_BOOL; }
-  const char *func_name() const { return "match_bool"; }
-};
-
-
 class Item_func_bit_xor : public Item_int_func
 {
 public:
diff --git a/sql/lex.h b/sql/lex.h
index 5d79e378d4f..7f3328fa7cb 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -153,6 +153,7 @@ static SYMBOL symbols[] = {
   { "EXECUTE",		SYM(EXECUTE_SYM),0,0},
   { "EXPLAIN",		SYM(DESCRIBE),0,0},
   { "EXISTS",		SYM(EXISTS),0,0},
+  { "EXPANSION",	SYM(EXPANSION_SYM),0,0},
   { "EXTENDED",		SYM(EXTENDED_SYM),0,0},
   { "FAST",		SYM(FAST_SYM),0,0},
   { "FIELDS",		SYM(COLUMNS),0,0},
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 04f5043839f..42ab755d0ba 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -135,6 +135,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
 %token	DROP
 %token	EVENTS_SYM
 %token	EXECUTE_SYM
+%token	EXPANSION_SYM
 %token	FLUSH_SYM
 %token  HELP_SYM
 %token	INSERT
@@ -168,7 +169,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
 %token	SUPER_SYM
 %token	TRUNCATE_SYM
 %token	UNLOCK_SYM
-%token	UNTIL_SYM 
+%token	UNTIL_SYM
 %token	UPDATE_SYM
 
 %token	ACTION
@@ -604,8 +605,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
 %type <num>
 	type int_type real_type order_dir opt_field_spec lock_option
 	udf_type if_exists opt_local opt_table_options table_options
-	table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type opt_var_ident_type
-	delete_option opt_temporary all_or_any opt_distinct opt_ignore_leaves
+        table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type
+        opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct
+        opt_ignore_leaves fulltext_options
 
 %type <ulong_num>
 	ULONG_NUM raid_types merge_insert_types
@@ -2448,14 +2450,10 @@ simple_expr:
 	| EXISTS exists_subselect { $$= $2; }
 	| singlerow_subselect   { $$= $1; }
 	| '{' ident expr '}'	{ $$= $3; }
-        | MATCH ident_list_arg AGAINST '(' expr ')'
+        | MATCH ident_list_arg AGAINST '(' expr fulltext_options ')'
           { $2->push_front($5);
-            Select->add_ftfunc_to_list((Item_func_match *)
-                   ($$=new Item_func_match_nl(*$2))); }
-        | MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')'
-          { $2->push_front($5);
-            Select->add_ftfunc_to_list((Item_func_match *)
-                   ($$=new Item_func_match_bool(*$2))); }
+            Select->add_ftfunc_to_list((Item_func_match*)
+                                        ($$=new Item_func_match(*$2,$6))); }
 	| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
 	| BINARY expr %prec NEG
 	  {
@@ -2843,6 +2841,12 @@ simple_expr:
 	| EXTRACT_SYM '(' interval FROM expr ')'
 	{ $$=new Item_extract( $3, $5); };
 
+fulltext_options:
+        /* nothing */                   { $$= FT_NL;  }
+        | WITH QUERY_SYM EXPANSION_SYM  { $$= FT_NL | FT_EXPAND; }
+        | IN_SYM BOOLEAN_SYM MODE_SYM   { $$= FT_BOOL; }
+        ;
+
 udf_expr_list:
 	/* empty */	{ $$= NULL; }
 	| expr_list	{ $$= $1;};