List:Internals« Previous MessageNext Message »
From:svoj Date:October 15 2005 6:04pm
Subject:bk commit into 5.1 tree (svoj:1.1932)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of svoj. When svoj does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.1932 05/10/15 21:04:09 svoj@stripped +43 -0
  WL#2575 - Fulltext: Parser plugin for FTS
  WL#2763 - MySQL plugin interface: step 1

  strings/my_strchr.c
    1.1 05/10/15 21:03:48 svoj@stripped +48 -0
    New BitKeeper file ``strings/my_strchr.c''

  sql/sql_plugin.h
    1.1 05/10/15 21:03:48 svoj@stripped +54 -0
    New BitKeeper file ``sql/sql_plugin.h''

  sql/sql_plugin.cc
    1.1 05/10/15 21:03:48 svoj@stripped +577 -0
    New BitKeeper file ``sql/sql_plugin.cc''

  include/plugin.h
    1.1 05/10/15 21:03:48 svoj@stripped +89 -0
    New BitKeeper file ``include/plugin.h''

  BitKeeper/etc/ignore
    1.212 05/10/15 21:03:49 svoj@stripped +1 -0
    Added libmysqld/sql_plugin.cc to the ignore list

  strings/my_strchr.c
    1.0 05/10/15 21:03:48 svoj@stripped +0 -0
    BitKeeper file /home/svoj/devel/mysql/CNET/merge/mysql-5.1/strings/my_strchr.c

  strings/Makefile.am
    1.50 05/10/15 21:03:48 svoj@stripped +4 -4
    my_strchr.c added to CSRCS.

  storage/myisam/mi_open.c
    1.96 05/10/15 21:03:48 svoj@stripped +1 -0
    Set default parser.

  storage/myisam/ftdefs.h
    1.32 05/10/15 21:03:48 svoj@stripped +4 -11
    FTB_PARAM moved into plugin.h and renamed to MYSQL_FTPARSER_BOOLEAN_INFO.

  sql/sql_plugin.h
    1.0 05/10/15 21:03:48 svoj@stripped +0 -0
    BitKeeper file /home/svoj/devel/mysql/CNET/merge/mysql-5.1/sql/sql_plugin.h

  sql/sql_plugin.cc
    1.0 05/10/15 21:03:48 svoj@stripped +0 -0
    BitKeeper file /home/svoj/devel/mysql/CNET/merge/mysql-5.1/sql/sql_plugin.cc

  include/plugin.h
    1.0 05/10/15 21:03:48 svoj@stripped +0 -0
    BitKeeper file /home/svoj/devel/mysql/CNET/merge/mysql-5.1/include/plugin.h

  storage/myisam/ft_update.c
    1.39 05/10/15 21:03:47 svoj@stripped +3 -1
    Use fulltext parser.

  storage/myisam/ft_static.c
    1.33 05/10/15 21:03:47 svoj@stripped +11 -0
    Default fulltext parser added.

  storage/myisam/ft_parser.c
    1.48 05/10/15 21:03:47 svoj@stripped +83 -31
    Split functions so they can be used by fulltext parser.
    Use fulltext parser if specified.

  storage/myisam/ft_nlq_search.c
    1.41 05/10/15 21:03:47 svoj@stripped +1 -1
    Use fulltext parser.

  storage/myisam/ft_boolean_search.c
    1.96 05/10/15 21:03:47 svoj@stripped +306 -134
    Split functions so they can be used by fulltext parser.
    Use fulltext parser if specified.

  sql/unireg.cc
    1.70 05/10/15 21:03:47 svoj@stripped +35 -4
    Save fulltext parser in extra data segment

  sql/table.cc
    1.185 05/10/15 21:03:47 svoj@stripped +44 -2
    Save/restore fulltext parser in extra data segment.
    Added DBUG_PRINTs.

  sql/structs.h
    1.52 05/10/15 21:03:47 svoj@stripped +1 -0
    Added fulltext parser to KEY.

  sql/sql_yacc.yy
    1.417 05/10/15 21:03:47 svoj@stripped +61 -8
    INSTALL/UNINSTALL PLUGIN syntax.
    Added WITH PARSER syntax to CREATE/ALTER TABLE/INDEX.

  sql/sql_udf.cc
    1.56 05/10/15 21:03:47 svoj@stripped +7 -29
    dlopen related code moved into my_global.h.
    Implemented better check for UDF path.

  sql/sql_table.cc
    1.276 05/10/15 21:03:47 svoj@stripped +2 -0
    Pass fulltext parser from yacc to sql layer.

  sql/sql_show.cc
    1.275 05/10/15 21:03:47 svoj@stripped +6 -0
    SHOW CREATE TABLE: output parser name if index was created WITH PARSER.

  sql/sql_parse.cc
    1.480 05/10/15 21:03:47 svoj@stripped +9 -0
    INSTALL/UNINSTALL PLUGIN commands.

  sql/sql_lex.h
    1.201 05/10/15 21:03:47 svoj@stripped +1 -0
    INSTALL/UNINSTALL PLUGIN commands.

  sql/sql_class.h
    1.265 05/10/15 21:03:46 svoj@stripped +4 -2
    Added parser to Key class.

  sql/share/errmsg.txt
    1.50 05/10/15 21:03:46 svoj@stripped +4 -2
    Plugin related error messages.

  sql/set_var.cc
    1.140 05/10/15 21:03:46 svoj@stripped +1 -0
    plugin_dir added to SHOW VARIABLES.

  sql/mysqld.cc
    1.486 05/10/15 21:03:46 svoj@stripped +15 -3
    Initialize/deinitialize plugins, pass opt_plugin_dir.

  sql/mysql_priv.h
    1.338 05/10/15 21:03:46 svoj@stripped +1 -0
    Include sql_plugin.h

  sql/lex.h
    1.144 05/10/15 21:03:46 svoj@stripped +5 -1
    Plugin related symbols.

  sql/ha_myisam.cc
    1.159 05/10/15 21:03:46 svoj@stripped +9 -0
    Pass fulltext parser from sql to myisam layer.

  sql/Makefile.am
    1.116 05/10/15 21:03:46 svoj@stripped +4 -2
    Added sql_plugin.h and sql_plugin.cc.
    Added LIBDIR macro.

  scripts/mysql_fix_privilege_tables.sql
    1.26 05/10/15 21:03:46 svoj@stripped +6 -0
    Added mysql.plugin table.

  scripts/mysql_create_system_tables.sh
    1.24 05/10/15 21:03:46 svoj@stripped +20 -2
    Added mysql.plugin table.

  mysql-test/t/system_mysql_db_fix.test
    1.18 05/10/15 21:03:46 svoj@stripped +1 -1
    Test fixed: added plugin table

  mysql-test/r/system_mysql_db.result
    1.29 05/10/15 21:03:46 svoj@stripped +1 -0
    Test result fixed: added plugin table.

  mysql-test/r/information_schema.result
    1.85 05/10/15 21:03:46 svoj@stripped +3 -2
    Test result fixed: added plugin table.

  mysql-test/r/connect.result
    1.18 05/10/15 21:03:46 svoj@stripped +3 -0
    Test result fixed: added plugin table.

  libmysqld/Makefile.am
    1.67 05/10/15 21:03:46 svoj@stripped +4 -2
    add sql_plugin.cc to libmysqld.
    Added LIBDIR macro.

  include/myisam.h
    1.70 05/10/15 21:03:46 svoj@stripped +2 -0
    Added fulltext parser to MI_KEYDEF.

  include/my_global.h
    1.111 05/10/15 21:03:45 svoj@stripped +19 -0
    dlopen related code moved from sql_udf.cc into my_global.h

  include/my_base.h
    1.72 05/10/15 21:03:45 svoj@stripped +1 -5
    Removed obsolete code, added HA_USES_PARSER flag.

  include/m_ctype.h
    1.114 05/10/15 21:03:45 svoj@stripped +2 -0
    Added my_strchr function.

  include/ft_global.h
    1.30 05/10/15 21:03:45 svoj@stripped +1 -0
    Default parser added.

  include/Makefile.am
    1.54 05/10/15 21:03:45 svoj@stripped +1 -1
    plugin.h added to pkginclude_HEADERS.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	svoj
# Host:	svoj-laptop.mysql.com
# Root:	/home/svoj/devel/mysql/CNET/merge/mysql-5.1

--- 1.53/include/Makefile.am	2005-06-07 21:17:03 +05:00
+++ 1.54/include/Makefile.am	2005-10-15 21:03:45 +05:00
@@ -22,7 +22,7 @@
 			errmsg.h my_global.h my_net.h my_alloc.h \
 			my_getopt.h sslopt-longopts.h my_dir.h typelib.h \
 			sslopt-vars.h sslopt-case.h sql_common.h keycache.h \
-			mysql_time.h $(BUILT_SOURCES)
+			mysql_time.h plugin.h $(BUILT_SOURCES)
 noinst_HEADERS =	config-win.h config-os2.h config-netware.h \
 			heap.h my_bitmap.h\
 			myisam.h myisampack.h myisammrg.h ft_global.h\

--- 1.29/include/ft_global.h	2005-02-04 18:23:58 +04:00
+++ 1.30/include/ft_global.h	2005-10-15 21:03:45 +05:00
@@ -53,6 +53,7 @@
 extern ulong ft_max_word_len;
 extern ulong ft_query_expansion_limit;
 extern char  ft_boolean_syntax[15];
+extern struct st_mysql_ftparser ft_default_parser;
 
 int ft_init_stopwords(void);
 void ft_free_stopwords(void);

--- 1.113/include/m_ctype.h	2005-08-19 23:55:19 +05:00
+++ 1.114/include/m_ctype.h	2005-10-15 21:03:45 +05:00
@@ -398,6 +398,8 @@
 
 extern my_bool my_parse_charset_xml(const char *bug, uint len,
 				    int (*add)(CHARSET_INFO *cs));
+extern char *my_strchr(CHARSET_INFO *cs, const char *str, const char *end,
+                       char c);
 
 my_bool my_propagate_simple(CHARSET_INFO *cs, const uchar *str, uint len);
 my_bool my_propagate_complex(CHARSET_INFO *cs, const uchar *str, uint len);

--- 1.71/include/my_base.h	2005-07-18 16:30:07 +05:00
+++ 1.72/include/my_base.h	2005-10-15 21:03:45 +05:00
@@ -209,12 +209,8 @@
 #define HA_SPACE_PACK_USED	 4	/* Test for if SPACE_PACK used */
 #define HA_VAR_LENGTH_KEY	 8
 #define HA_NULL_PART_KEY	 64
-#ifndef ISAM_LIBRARY
+#define HA_USES_PARSER           16384  /* Fulltext index uses [pre]parser */
 #define HA_SORT_ALLOWS_SAME      512    /* Intern bit when sorting records */
-#else
-/* poor old NISAM has 8-bit flags :-( */
-#define HA_SORT_ALLOWS_SAME	 128	/* Intern bit when sorting records */
-#endif
 /*
   Key has a part that can have end space.  If this is an unique key
   we have to handle it differently from other unique keys as we can find

--- 1.69/include/myisam.h	2005-09-21 20:38:03 +05:00
+++ 1.70/include/myisam.h	2005-10-15 21:03:46 +05:00
@@ -32,6 +32,7 @@
 #include "keycache.h"
 #endif
 #include "my_handler.h"
+#include <plugin.h>
 
 	/* defines used by myisam-funktions */
 
@@ -196,6 +197,7 @@
   uint32 version;			/* For concurrent read/write */
 
   HA_KEYSEG *seg,*end;
+  struct st_mysql_ftparser *parser;     /* Fulltext [pre]parser */
   int (*bin_search)(struct st_myisam_info *info,struct st_mi_keydef *keyinfo,
 		    uchar *page,uchar *key,
 		    uint key_len,uint comp_flag,uchar * *ret_pos,

--- 1.47/storage/myisam/ft_parser.c	2005-04-08 03:54:34 +05:00
+++ 1.48/storage/myisam/ft_parser.c	2005-10-15 21:03:47 +05:00
@@ -24,6 +24,14 @@
   double sum;
 } FT_DOCSTAT;
 
+
+typedef struct st_my_ft_parser_param
+{
+  TREE *wtree;
+  my_bool with_alloc;
+} MY_FT_PARSER_PARAM;
+
+
 static int FT_WORD_cmp(CHARSET_INFO* cs, FT_WORD *w1, FT_WORD *w2)
 {
   return mi_compare_text(cs, (uchar*) w1->pos, w1->len,
@@ -102,13 +110,14 @@
   4 - stopword found
 */
 byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end,
-                 FT_WORD *word, FTB_PARAM *param)
+                 FT_WORD *word, MYSQL_FTPARSER_BOOLEAN_INFO *param)
 {
   byte *doc=*start;
   uint mwc, length, mbl;
 
   param->yesno=(FTB_YES==' ') ? 1 : (param->quot != 0);
-  param->plusminus=param->pmsign=0;
+  param->weight_adjust= param->wasign= 0;
+  param->type= FT_CHUNK_TYPE_EOF;
 
   while (doc<end)
   {
@@ -119,7 +128,8 @@
       {
         param->quot=doc;
         *start=doc+1;
-        return 3; /* FTB_RBR */
+        param->type= FT_CHUNK_TYPE_RBR;
+        goto ret;
       }
       if (!param->quot)
       {
@@ -128,21 +138,22 @@
           /* param->prev=' '; */
           *start=doc+1;
           if (*doc == FTB_LQUOT) param->quot=*start;
-          return (*doc == FTB_RBR)+2;
+          param->type= (*doc == FTB_RBR ? FT_CHUNK_TYPE_RBR : FT_CHUNK_TYPE_LBR);
+          goto ret;
         }
         if (param->prev == ' ')
         {
           if (*doc == FTB_YES ) { param->yesno=+1;    continue; } else
           if (*doc == FTB_EGAL) { param->yesno= 0;    continue; } else
           if (*doc == FTB_NO  ) { param->yesno=-1;    continue; } else
-          if (*doc == FTB_INC ) { param->plusminus++; continue; } else
-          if (*doc == FTB_DEC ) { param->plusminus--; continue; } else
-          if (*doc == FTB_NEG ) { param->pmsign=!param->pmsign; continue; }
+          if (*doc == FTB_INC ) { param->weight_adjust++; continue; } else
+          if (*doc == FTB_DEC ) { param->weight_adjust--; continue; } else
+          if (*doc == FTB_NEG ) { param->wasign= !param->wasign; continue; }
         }
       }
       param->prev=*doc;
       param->yesno=(FTB_YES==' ') ? 1 : (param->quot != 0);
-      param->plusminus=param->pmsign=0;
+      param->weight_adjust= param->wasign= 0;
     }
 
     mwc=length=0;
@@ -161,20 +172,24 @@
          || param->trunc) && length < ft_max_word_len)
     {
       *start=doc;
-      return 1;
+      param->type= FT_CHUNK_TYPE_WORD;
+      goto ret;
     }
     else if (length) /* make sure length > 0 (if start contains spaces only) */
     {
       *start= doc;
-      return 4;
+      param->type= FT_CHUNK_TYPE_STOPWORD;
+      goto ret;
     }
   }
   if (param->quot)
   {
     param->quot=*start=doc;
-    return 3; /* FTB_RBR */
+    param->type= 3; /* FT_RBR */
+    goto ret;
   }
-  return 0;
+ret:
+  return param->type;
 }
 
 byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, const byte *end,
@@ -220,30 +235,67 @@
   DBUG_VOID_RETURN;
 }
 
-int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc)
+
+static int ft_add_word(void *param, byte *word, uint word_len,
+             MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info __attribute__((unused)))
 {
-  byte   *end=doc+doclen;
+  TREE *wtree;
   FT_WORD w;
-  DBUG_ENTER("ft_parse");
-
-  while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE))
+  DBUG_ENTER("ft_add_word");
+  wtree= ((MY_FT_PARSER_PARAM *)param)->wtree;
+  if (((MY_FT_PARSER_PARAM *)param)->with_alloc)
   {
-    if (with_alloc)
-    {
-      byte *ptr;
-      /* allocating the data in the tree - to avoid mallocs and frees */
-      DBUG_ASSERT(wtree->with_delete==0);
-      ptr=(byte *)alloc_root(& wtree->mem_root,w.len);
-      memcpy(ptr, w.pos, w.len);
-      w.pos=ptr;
-    }
-    if (!tree_insert(wtree, &w, 0, wtree->custom_arg))
-      goto err;
+    byte *ptr;
+    /* allocating the data in the tree - to avoid mallocs and frees */
+    DBUG_ASSERT(wtree->with_delete == 0);
+    ptr= (byte *)alloc_root(&wtree->mem_root, word_len);
+    memcpy(ptr, word, word_len);
+    w.pos= ptr;
+  }
+  else
+    w.pos= word;
+  w.len= word_len;
+  if (!tree_insert(wtree, &w, 0, wtree->custom_arg))
+  {
+    delete_tree(wtree);
+    DBUG_RETURN(1);
   }
   DBUG_RETURN(0);
+}
 
-err:
-  delete_tree(wtree);
-  DBUG_RETURN(1);
+
+static int ft_parse_internal(void *param, byte *doc, uint doc_len)
+{
+  byte   *end=doc+doc_len;
+  FT_WORD w;
+  TREE *wtree;
+  DBUG_ENTER("ft_parse_internal");
+
+  wtree= ((MY_FT_PARSER_PARAM *)param)->wtree;
+  while (ft_simple_get_word(wtree->custom_arg, &doc, end, &w, TRUE))
+    if (ft_add_word(param, w.pos, w.len, 0))
+      DBUG_RETURN(1);
+  DBUG_RETURN(0);
 }
 
+
+int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc,
+                    struct st_mysql_ftparser *parser)
+{
+  MYSQL_FTPARSER_PARAM param;
+  MY_FT_PARSER_PARAM my_param;
+  DBUG_ENTER("ft_parse");
+  DBUG_ASSERT(parser);
+  my_param.wtree= wtree;
+  my_param.with_alloc= with_alloc;
+
+  param.mysql_parse= ft_parse_internal;
+  param.mysql_add_word= ft_add_word;
+  param.ftparser_state= 0;
+  param.mysql_ftparam= &my_param;
+  param.cs= wtree->custom_arg;
+  param.doc= doc;
+  param.length= doclen;
+  param.flags= MYSQL_FTPARSER_NL_MODE;
+  DBUG_RETURN(parser->parse(&param));
+}

--- 1.32/storage/myisam/ft_static.c	2005-04-08 03:54:34 +05:00
+++ 1.33/storage/myisam/ft_static.c	2005-10-15 21:03:47 +05:00
@@ -626,3 +626,14 @@
 #endif
 
   NULL };
+
+static int ft_default_parser_parse(MYSQL_FTPARSER_PARAM *param)
+{
+  return param->mysql_parse(param->mysql_ftparam, param->doc, param->length);
+}
+
+struct st_mysql_ftparser ft_default_parser=
+{
+  MYSQL_FTPARSER_INTERFACE_VERSION, ft_default_parser_parse, 0, 0
+};
+

--- 1.38/storage/myisam/ft_update.c	2005-04-08 03:54:34 +05:00
+++ 1.39/storage/myisam/ft_update.c	2005-10-15 21:03:47 +05:00
@@ -99,15 +99,17 @@
                   const byte *record, my_bool with_alloc)
 {
   FT_SEG_ITERATOR ftsi;
+  struct st_mysql_ftparser *parser;
   DBUG_ENTER("_mi_ft_parse");
 
   _mi_ft_segiterator_init(info, keynr, record, &ftsi);
 
   ft_parse_init(parsed, info->s->keyinfo[keynr].seg->charset);
+  parser= info->s->keyinfo[keynr].parser;
   while (_mi_ft_segiterator(&ftsi))
   {
     if (ftsi.pos)
-      if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len, with_alloc))
+      if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len, with_alloc, parser))
         DBUG_RETURN(1);
   }
   DBUG_RETURN(0);

--- 1.31/storage/myisam/ftdefs.h	2005-04-08 03:54:34 +05:00
+++ 1.32/storage/myisam/ftdefs.h	2005-10-15 21:03:48 +05:00
@@ -22,6 +22,7 @@
 #include <m_ctype.h>
 #include <my_tree.h>
 #include <queues.h>
+#include <plugin.h>
 
 #define true_word_char(s,X)	(my_isalnum(s,X) || (X)=='_')
 #define misc_word_char(X)	((X)=='\'')
@@ -98,20 +99,12 @@
   double weight;
 } FT_WORD;
 
-typedef struct st_ftb_param {
-  byte prev;
-  int  yesno;
-  int  plusminus;
-  bool pmsign;
-  bool trunc;
-  byte *quot;
-} FTB_PARAM;
-
 int is_stopword(char *word, uint len);
 
 uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t);
 
-byte ft_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *, FTB_PARAM *);
+byte ft_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *,
+                 MYSQL_FTPARSER_BOOLEAN_INFO *);
 byte ft_simple_get_word(CHARSET_INFO *, byte **, const byte *,
                         FT_WORD *, my_bool);
 
@@ -126,7 +119,7 @@
 uint _mi_ft_segiterator(FT_SEG_ITERATOR *);
 
 void ft_parse_init(TREE *, CHARSET_INFO *);
-int ft_parse(TREE *, byte *, int, my_bool);
+int ft_parse(TREE *, byte *, int, my_bool, struct st_mysql_ftparser *parser);
 FT_WORD * ft_linearize(TREE *);
 FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *);
 uint _mi_ft_parse(TREE *, MI_INFO *, uint, const byte *, my_bool);

--- 1.95/storage/myisam/mi_open.c	2005-10-06 13:26:05 +05:00
+++ 1.96/storage/myisam/mi_open.c	2005-10-15 21:03:48 +05:00
@@ -1047,6 +1047,7 @@
    keydef->block_size	= keydef->block_length/MI_MIN_KEY_BLOCK_LENGTH-1;
    keydef->underflow_block_length=keydef->block_length/3;
    keydef->version	= 0;			/* Not saved */
+   keydef->parser       = &ft_default_parser;
    return ptr;
 }
 

--- 1.115/sql/Makefile.am	2005-10-06 13:25:57 +05:00
+++ 1.116/sql/Makefile.am	2005-10-15 21:03:46 +05:00
@@ -19,6 +19,7 @@
 MYSQLDATAdir =		$(localstatedir)
 MYSQLSHAREdir =		$(pkgdatadir)
 MYSQLBASEdir=		$(prefix)
+MYSQLLIBdir=            $(pkglibdir)
 INCLUDES =		@ZLIB_INCLUDES@ \
 			@bdb_includes@ @innodb_includes@ @ndbcluster_includes@ \
 			-I$(top_builddir)/include -I$(top_srcdir)/include \
@@ -54,7 +55,7 @@
 			ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \
 			ha_ndbcluster.h opt_range.h protocol.h \
 			sql_select.h structs.h table.h sql_udf.h hash_filo.h\
-			lex.h lex_symbol.h sql_acl.h sql_crypt.h  \
+			lex.h lex_symbol.h sql_plugin.h sql_acl.h sql_crypt.h  \
 			log_event.h sql_repl.h slave.h rpl_filter.h \
 			stacktrace.h sql_sort.h sql_cache.h set_var.h \
 			spatial.h gstream.h client_settings.h tzfile.h \
@@ -86,7 +87,7 @@
 		   	records.cc filesort.cc handler.cc \
 		        ha_heap.cc ha_myisam.cc ha_myisammrg.cc \
 	                ha_berkeley.cc ha_innodb.cc \
-			ha_ndbcluster.cc \
+			ha_ndbcluster.cc sql_plugin.cc \
 			sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
 			sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
 			sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
@@ -113,6 +114,7 @@
 			-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
 			-DDATADIR="\"$(MYSQLDATAdir)\"" \
 			-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+			-DLIBDIR="\"$(MYSQLLIBdir)\"" \
 			@DEFS@
 
 BUILT_SOURCES =		sql_yacc.cc sql_yacc.h lex_hash.h

--- 1.158/sql/ha_myisam.cc	2005-10-06 13:25:58 +05:00
+++ 1.159/sql/ha_myisam.cc	2005-10-15 21:03:46 +05:00
@@ -280,6 +280,7 @@
 
 int ha_myisam::open(const char *name, int mode, uint test_if_locked)
 {
+  uint i;
   if (!(file=mi_open(name, mode, test_if_locked)))
     return (my_errno ? my_errno : -1);
   
@@ -292,6 +293,14 @@
     int_table_flags|=HA_REC_NOT_IN_SEQ;
   if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
     int_table_flags|=HA_HAS_CHECKSUM;
+
+  for (i= 0; i < table->s->keys; i++)
+  {
+    struct st_plugin_int *parser= table->key_info[i].parser;
+    if (table->key_info[i].flags & HA_USES_PARSER)
+      file->s->keyinfo[i].parser=
+        (struct st_mysql_ftparser *)parser->plugin->info;
+  }
   return (0);
 }
 

--- 1.143/sql/lex.h	2005-09-03 04:06:52 +05:00
+++ 1.144/sql/lex.h	2005-10-15 21:03:46 +05:00
@@ -246,6 +246,7 @@
   { "INSENSITIVE",      SYM(INSENSITIVE_SYM)},
   { "INSERT",		SYM(INSERT)},
   { "INSERT_METHOD",    SYM(INSERT_METHOD)},
+  { "INSTALL",          SYM(INSTALL_SYM)},
   { "INT",		SYM(INT_SYM)},
   { "INT1",		SYM(TINYINT)},
   { "INT2",		SYM(SMALLINT)},
@@ -370,6 +371,7 @@
   { "OUTER",		SYM(OUTER)},
   { "OUTFILE",		SYM(OUTFILE)},
   { "PACK_KEYS",	SYM(PACK_KEYS_SYM)},
+  { "PARSER",           SYM(PARSER_SYM)},
   { "PARTIAL",		SYM(PARTIAL)},
 #ifdef HAVE_PARTITION_DB
   { "PARTITION",        SYM(PARTITION_SYM)},
@@ -377,6 +379,7 @@
   { "PARTITIONS",       SYM(PARTITIONS_SYM)},
   { "PASSWORD",		SYM(PASSWORD)},
   { "PHASE",            SYM(PHASE_SYM)},
+  { "PLUGIN",           SYM(PLUGIN_SYM)},
   { "POINT",		SYM(POINT_SYM)},
   { "POLYGON",		SYM(POLYGON)},
   { "PRECISION",	SYM(PRECISION)},
@@ -454,7 +457,7 @@
   { "SNAPSHOT",         SYM(SNAPSHOT_SYM)},
   { "SMALLINT",		SYM(SMALLINT)},
   { "SOME",             SYM(ANY_SYM)},
-  { "SONAME",		SYM(UDF_SONAME_SYM)},
+  { "SONAME",		SYM(SONAME_SYM)},
   { "SOUNDS",		SYM(SOUNDS_SYM)},
   { "SPATIAL",		SYM(SPATIAL_SYM)},
   { "SPECIFIC",         SYM(SPECIFIC_SYM)},
@@ -525,6 +528,7 @@
   { "UNIQUE",		SYM(UNIQUE_SYM)},
   { "UNKNOWN",		SYM(UNKNOWN_SYM)},
   { "UNLOCK",		SYM(UNLOCK_SYM)},
+  { "UNINSTALL",        SYM(UNINSTALL_SYM)},
   { "UNSIGNED",		SYM(UNSIGNED)},
   { "UNTIL",		SYM(UNTIL_SYM)},
   { "UPDATE",		SYM(UPDATE_SYM)},

--- 1.337/sql/mysql_priv.h	2005-10-09 22:09:43 +05:00
+++ 1.338/sql/mysql_priv.h	2005-10-15 21:03:46 +05:00
@@ -489,6 +489,7 @@
 #include "sql_error.h"
 #include "field.h"				/* Field definitions */
 #include "protocol.h"
+#include "sql_plugin.h"
 #include "sql_udf.h"
 class user_var_entry;
 class Security_context;

--- 1.485/sql/mysqld.cc	2005-10-12 20:17:54 +05:00
+++ 1.486/sql/mysqld.cc	2005-10-15 21:03:46 +05:00
@@ -1059,10 +1059,13 @@
   lex_free();				/* Free some memory */
   set_var_free();
   free_charsets();
-#ifdef HAVE_DLOPEN
   if (!opt_noacl)
+  {
+#ifdef HAVE_DLOPEN
     udf_free();
 #endif
+    plugin_free();
+  }
   (void) ha_panic(HA_PANIC_CLOSE);	/* close all tables and logs */
   if (tc_log)
     tc_log->close();
@@ -3291,10 +3294,13 @@
   if (!opt_noacl)
     (void) grant_init();
 
-#ifdef HAVE_DLOPEN
   if (!opt_noacl)
+  {
+    plugin_init();
+#ifdef HAVE_DLOPEN
     udf_init();
 #endif
+  }
   if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
     opt_skip_slave_start= 1;
   /*
@@ -4448,7 +4454,8 @@
   OPT_TIMED_MUTEXES,
   OPT_OLD_STYLE_USER_LIMITS,
   OPT_LOG_SLOW_ADMIN_STATEMENTS,
-  OPT_TABLE_LOCK_WAIT_TIMEOUT
+  OPT_TABLE_LOCK_WAIT_TIMEOUT,
+  OPT_PLUGIN_DIR
 };
 
 
@@ -5597,6 +5604,10 @@
    (gptr*) &global_system_variables.optimizer_search_depth,
    (gptr*) &max_system_variables.optimizer_search_depth,
    0, GET_ULONG, OPT_ARG, MAX_TABLES+1, 0, MAX_TABLES+2, 0, 1, 0},
+  {"plugin-dir", OPT_PLUGIN_DIR,
+   "Directory for plugins.",
+   (gptr*) &opt_plugin_dir, (gptr*) &opt_plugin_dir, 0, GET_STR, REQUIRED_ARG,
+   0, 0, 0, 0, 0, 0},
    {"preload_buffer_size", OPT_PRELOAD_BUFFER_SIZE,
     "The size of the buffer that is allocated when preloading indexes",
     (gptr*) &global_system_variables.preload_buff_size,
@@ -6163,6 +6174,7 @@
 	  sizeof(mysql_real_data_home)-1);
   mysql_data_home_buff[0]=FN_CURLIB;	// all paths are relative from here
   mysql_data_home_buff[1]=0;
+  opt_plugin_dir= get_relative_path(LIBDIR);
 
   /* Replication parameters */
   master_user= (char*) "test";

--- 1.264/sql/sql_class.h	2005-10-09 22:09:46 +05:00
+++ 1.265/sql/sql_class.h	2005-10-15 21:03:46 +05:00
@@ -409,11 +409,13 @@
   List<key_part_spec> columns;
   const char *name;
   bool generated;
+  struct st_plugin_int *parser;
 
   Key(enum Keytype type_par, const char *name_arg, enum ha_key_alg alg_par,
-      bool generated_arg, List<key_part_spec> &cols)
+      bool generated_arg, List<key_part_spec> &cols,
+      struct st_plugin_int *parser_arg= (struct st_plugin_int*)0)
     :type(type_par), algorithm(alg_par), columns(cols), name(name_arg),
-    generated(generated_arg)
+    generated(generated_arg), parser(parser_arg)
   {}
   ~Key() {}
   /* Equality comparison of keys (ignoring name) */

--- 1.200/sql/sql_lex.h	2005-10-14 12:44:29 +05:00
+++ 1.201/sql/sql_lex.h	2005-10-15 21:03:47 +05:00
@@ -91,6 +91,7 @@
   SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
   SQLCOM_XA_START, SQLCOM_XA_END, SQLCOM_XA_PREPARE,
   SQLCOM_XA_COMMIT, SQLCOM_XA_ROLLBACK, SQLCOM_XA_RECOVER,
+  SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN,
   /* This should be the last !!! */
 
   SQLCOM_END

--- 1.479/sql/sql_parse.cc	2005-10-12 20:17:55 +05:00
+++ 1.480/sql/sql_parse.cc	2005-10-15 21:03:47 +05:00
@@ -4742,6 +4742,15 @@
   case SQLCOM_XA_RECOVER:
     res= mysql_xa_recover(thd);
     break;
+  case SQLCOM_INSTALL_PLUGIN:
+    if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
+                                     &thd->lex->ident)))
+      send_ok(thd);
+    break;
+  case SQLCOM_UNINSTALL_PLUGIN:
+    if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
+      send_ok(thd);
+    break;
   default:
     DBUG_ASSERT(0);                             /* Impossible */
     send_ok(thd);

--- 1.274/sql/sql_show.cc	2005-10-12 20:17:55 +05:00
+++ 1.275/sql/sql_show.cc	2005-10-15 21:03:47 +05:00
@@ -948,6 +948,12 @@
       }
     }
     packet->append(')');
+    if (key_info->parser)
+    {
+      packet->append(" WITH PARSER ", 13);
+      append_identifier(thd, packet, key_info->parser->name.str,
+                        key_info->parser->name.length);
+    }
   }
 
   /*

--- 1.275/sql/sql_table.cc	2005-10-12 20:17:55 +05:00
+++ 1.276/sql/sql_table.cc	2005-10-15 21:03:47 +05:00
@@ -1081,6 +1081,8 @@
 	break;
     case Key::FULLTEXT:
 	key_info->flags= HA_FULLTEXT;
+	if ((key_info->parser= key->parser))
+          key_info->flags|= HA_USES_PARSER;
 	break;
     case Key::SPATIAL:
 #ifdef HAVE_SPATIAL

--- 1.55/sql/sql_udf.cc	2005-09-14 12:39:45 +05:00
+++ 1.56/sql/sql_udf.cc	2005-10-15 21:03:47 +05:00
@@ -38,36 +38,10 @@
 #ifdef HAVE_DLOPEN
 extern "C"
 {
-#if defined(__WIN__)
-  void* dlsym(void* lib,const char* name)
-  {
-    return GetProcAddress((HMODULE)lib,name);
-  }
-  void* dlopen(const char* libname,int unused)
-  {
-    return LoadLibraryEx(libname,NULL,0);
-  }
-  void dlclose(void* lib)
-  {
-    FreeLibrary((HMODULE)lib);
-  }
-
-#elif !defined(OS2)
-#include <dlfcn.h>
-#endif
-
 #include <stdarg.h>
 #include <hash.h>
 }
 
-#ifndef RTLD_NOW
-#define RTLD_NOW 1				// For FreeBSD 2.2.2
-#endif
-
-#ifndef HAVE_DLERROR
-#define dlerror() ""
-#endif
-
 static bool initialized = 0;
 static MEM_ROOT mem;
 static HASH udf_hash;
@@ -194,8 +168,10 @@
       This is done to ensure that only approved dll from the system
       directories are used (to make this even remotely secure).
     */
-    if (strchr(dl_name, '/') ||
-        IF_WIN(strchr(dl_name, '\\'),0) ||
+    if (my_strchr(files_charset_info, dl_name,
+                  dl_name + strlen(dl_name), '/') ||
+        IF_WIN(my_strchr(files_charset_info, dl_name,
+                         dl_name + strlen(dl_name), '\\'),0) ||
         strlen(name.str) > NAME_LEN)
     {
       sql_print_error("Invalid row in mysql.func table for function '%.64s'",
@@ -412,7 +388,9 @@
     This is done to ensure that only approved dll from the system
     directories are used (to make this even remotely secure).
   */
-  if (strchr(udf->dl, '/') || IF_WIN(strchr(udf->dl, '\\'),0))
+  if (my_strchr(files_charset_info, udf->dl, udf->dl + strlen(udf->dl), '/') ||
+      IF_WIN(strchr(files_charset_info, udf->dl,
+                    udf->dl + strlen(udf->dl), '\\'),0))
   {
     my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0));
     DBUG_RETURN(1);

--- 1.416/sql/sql_yacc.yy	2005-10-14 12:44:29 +05:00
+++ 1.417/sql/sql_yacc.yy	2005-10-15 21:03:47 +05:00
@@ -108,6 +108,7 @@
   struct { int vars, conds, hndlrs, curs; } spblock;
   sp_name *spname;
   struct st_lex *lex;
+  struct st_plugin_int *plugin;
 }
 
 %{
@@ -335,6 +336,7 @@
 %token  INSENSITIVE_SYM
 %token  INSERT
 %token  INSERT_METHOD
+%token  INSTALL_SYM
 %token  INTERVAL_SYM
 %token  INTO
 %token  INT_SYM
@@ -470,12 +472,14 @@
 %token  OUTFILE
 %token  OUT_SYM
 %token  PACK_KEYS_SYM
+%token  PARSER_SYM
 %token  PARTIAL
 %token  PARTITION_SYM
 %token  PARTITIONS_SYM
 %token  PASSWORD
 %token  PARAM_MARKER
 %token  PHASE_SYM
+%token  PLUGIN_SYM
 %token  POINTFROMTEXT
 %token  POINT_SYM
 %token  POLYFROMTEXT
@@ -560,6 +564,7 @@
 %token  SLAVE
 %token  SMALLINT
 %token  SNAPSHOT_SYM
+%token  SONAME_SYM
 %token  SOUNDS_SYM
 %token  SPATIAL_SYM
 %token  SPECIFIC_SYM
@@ -621,13 +626,13 @@
 %token  TYPES_SYM
 %token  TYPE_SYM
 %token  UDF_RETURNS_SYM
-%token  UDF_SONAME_SYM
 %token  ULONGLONG_NUM
 %token  UNCOMMITTED_SYM
 %token  UNDEFINED_SYM
 %token  UNDERSCORE_CHARSET
 %token  UNDO_SYM
 %token  UNICODE_SYM
+%token  UNINSTALL_SYM
 %token  UNION_SYM
 %token  UNIQUE_SYM
 %token  UNIQUE_USERS
@@ -808,6 +813,8 @@
 
 %type <boolfunc2creator> comp_op
 
+%type <plugin> opt_fulltext_parser
+
 %type <NONE>
 	query verb_clause create change select do drop insert replace insert2
 	insert_values update delete truncate rename
@@ -844,7 +851,7 @@
 	statement sp_suid opt_view_list view_list or_replace algorithm
 	sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
         load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
-        view_user view_suid
+        install uninstall view_user view_suid
         partition_entry
 END_OF_INPUT
 
@@ -906,6 +913,7 @@
 	| handler
 	| help
 	| insert
+        | install
 	| kill
 	| load
 	| lock
@@ -930,6 +938,7 @@
 	| slave
 	| start
 	| truncate
+        | uninstall
 	| unlock
 	| update
 	| use
@@ -1187,11 +1196,15 @@
 	    lex->col_list.empty();
 	    lex->change=NullS;
 	  }
-	   '(' key_list ')'
+	   '(' key_list ')' opt_fulltext_parser
 	  {
 	    LEX *lex=Lex;
-
-	    lex->key_list.push_back(new Key($2,$4.str, $5, 0, lex->col_list));
+	    if ($2 != Key::FULLTEXT && $12)
+	    {
+	      yyerror(ER(ER_SYNTAX_ERROR));
+	      YYABORT;
+	    }
+	    lex->key_list.push_back(new Key($2,$4.str,$5,0,lex->col_list,$12));
 	    lex->col_list.empty();
 	  }
 	| CREATE DATABASE opt_if_not_exists ident
@@ -1381,7 +1394,7 @@
 	;
 
 create_function_tail:
-	  RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
+	  RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
 	  {
 	    LEX *lex=Lex;
 	    lex->sql_command = SQLCOM_CREATE_FUNCTION;
@@ -3289,10 +3302,15 @@
 	;
 
 key_def:
-	key_type opt_ident key_alg '(' key_list ')'
+	key_type opt_ident key_alg '(' key_list ')' opt_fulltext_parser
 	  {
 	    LEX *lex=Lex;
-	    lex->key_list.push_back(new Key($1,$2, $3, 0, lex->col_list));
+	    if ($1 != Key::FULLTEXT && $7)
+	    {
+	      yyerror(ER(ER_SYNTAX_ERROR));
+	      YYABORT;
+	    }
+	    lex->key_list.push_back(new Key($1,$2, $3, 0, lex->col_list, $7));
 	    lex->col_list.empty();		/* Alloced by sql_alloc */
 	  }
 	| opt_constraint constraint_key_type opt_ident key_alg '(' key_list ')'
@@ -3327,6 +3345,21 @@
 	  }
 	;
 
+opt_fulltext_parser:
+        /* empty */               { $$= (struct st_plugin_int*)0; }
+	| WITH PARSER_SYM IDENT_sys
+          {
+            struct st_plugin_int *plugin;
+            if ((plugin= plugin_lock(&$3, MYSQL_FTPARSER_PLUGIN)))
+              $$= plugin;
+            else
+            {
+              my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), $3.str);
+              YYABORT;
+            }
+          }
+        ;
+
 opt_check_constraint:
 	/* empty */
 	| check_constraint
@@ -8117,10 +8150,13 @@
 	| FLUSH_SYM		{}
 	| HANDLER_SYM		{}
 	| HELP_SYM		{}
+        | INSTALL_SYM           {}
 	| LANGUAGE_SYM          {}
 	| NO_SYM		{}
 	| OPEN_SYM		{}
+        | PARSER_SYM            {}
 	| PARTITION_SYM		{}
+        | PLUGIN_SYM            {}
         | PREPARE_SYM           {}
 	| REPAIR		{}
 	| RESET_SYM		{}
@@ -8130,10 +8166,12 @@
 	| SECURITY_SYM		{}
 	| SIGNED_SYM		{}
 	| SLAVE			{}
+        | SONAME_SYM            {}
 	| START_SYM		{}
 	| STOP_SYM		{}
 	| TRUNCATE_SYM		{}
 	| UNICODE_SYM		{}
+        | UNINSTALL_SYM         {}
         | XA_SYM                {}
 	;
 
@@ -9674,4 +9712,19 @@
     | FOR_SYM MIGRATE_SYM   { Lex->xa_opt=XA_FOR_MIGRATE; }
     ;
 
+install:
+  INSTALL_SYM PLUGIN_SYM IDENT_sys SONAME_SYM TEXT_STRING_sys
+  {
+    LEX *lex= Lex;
+    lex->sql_command= SQLCOM_INSTALL_PLUGIN;
+    lex->comment= $3;
+    lex->ident= $5;
+  };
 
+uninstall:
+  UNINSTALL_SYM PLUGIN_SYM IDENT_sys
+  {
+    LEX *lex= Lex;
+    lex->sql_command= SQLCOM_UNINSTALL_PLUGIN;
+    lex->comment= $3;
+  };

--- 1.51/sql/structs.h	2005-10-12 20:17:55 +05:00
+++ 1.52/sql/structs.h	2005-10-15 21:03:47 +05:00
@@ -89,6 +89,7 @@
   uint  extra_length;
   uint	usable_key_parts;		/* Should normally be = key_parts */
   enum  ha_key_alg algorithm;
+  struct st_plugin_int *parser;         /* Fulltext [pre]parser */
   KEY_PART_INFO *key_part;
   char	*name;				/* Name of key */
   /*

--- 1.184/sql/table.cc	2005-10-14 15:32:27 +05:00
+++ 1.185/sql/table.cc	2005-10-15 21:03:47 +05:00
@@ -310,11 +310,16 @@
   {
     /* Read extra data segment */
     char *buff, *next_chunk, *buff_end;
+    DBUG_PRINT("EDS", ("size is %d bytes", n_length));
     if (!(next_chunk= buff= my_malloc(n_length, MYF(MY_WME))))
+    {
+      DBUG_PRINT("EDS", ("not enough memory"));
       goto err;
+    }
     if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength,
                  MYF(MY_NABP)))
     {
+      DBUG_PRINT("EDS", ("my_pread failed"));
       my_free(buff, MYF(0));
       goto err;
     }
@@ -322,6 +327,7 @@
     if (! (share->connect_string.str= strmake_root(&outparam->mem_root,
             next_chunk + 2, share->connect_string.length)))
     {
+      DBUG_PRINT("EDS", ("strmake_root failed for connect_string"));
       my_free(buff, MYF(0));
       goto err;
     }
@@ -335,8 +341,8 @@
       if (tmp_db_type != DB_TYPE_UNKNOWN)
       {
         share->db_type= tmp_db_type;
-        DBUG_PRINT("enter", ("Setting dbtype to: %d - %d - '%.*s'\n", share->db_type,
-              str_db_type_length, str_db_type_length, next_chunk + 2));
+        DBUG_PRINT("EDS", ("setting dbtype to '%.*s' (%d)",
+              str_db_type_length, next_chunk + 2, share->db_type));
       }
       next_chunk+= str_db_type_length + 2;
     }
@@ -349,16 +355,44 @@
         if (mysql_unpack_partition(thd, (uchar *)(next_chunk + 4),
                          part_info_len, outparam, default_part_db_type))
         {
+          DBUG_PRINT("EDS", ("mysql_unpack_partition failed"));
           my_free(buff, MYF(0));
           goto err;
         }
 #else
+        DBUG_PRINT("EDS", ("HAVE_PARTITION_DB is not defined"));
         my_free(buff, MYF(0));
         goto err;
 #endif
       }
       next_chunk+= part_info_len + 5;
     }
+    keyinfo= outparam->key_info;
+    for (i= 0; i < keys; i++, keyinfo++)
+    {
+      if (keyinfo->flags & HA_USES_PARSER)
+      {
+        LEX_STRING parser_name;
+        if (next_chunk >= buff_end)
+        {
+          DBUG_PRINT("EDS",
+              ("fulltext key uses parser that is not defined in .frm"));
+          my_free(buff, MYF(0));
+          goto err;
+        }
+        parser_name.str= next_chunk;
+        parser_name.length= strlen(next_chunk);
+        keyinfo->parser= plugin_lock(&parser_name, MYSQL_FTPARSER_PLUGIN);
+        if (! keyinfo->parser)
+        {
+          DBUG_PRINT("EDS", ("parser plugin is not loaded"));
+          my_free(buff, MYF(0));
+          my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), parser_name.str);
+          error_reported= 1;
+          goto err;
+        }
+      }
+    }
     my_free(buff, MYF(0));
   }
   error=4;
@@ -1011,9 +1045,17 @@
 int closefrm(register TABLE *table)
 {
   int error=0;
+  uint idx;
+  KEY *key_info;
   DBUG_ENTER("closefrm");
   if (table->db_stat)
     error=table->file->close();
+  key_info= table->key_info;
+  for (idx= table->s->keys; idx; idx--, key_info++)
+  {
+    if (key_info->flags & HA_USES_PARSER)
+      plugin_unlock(key_info->parser);
+  }
   my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR));
   table->alias= 0;
   if (table->field)

--- 1.69/sql/unireg.cc	2005-10-14 15:32:28 +05:00
+++ 1.70/sql/unireg.cc	2005-10-15 21:03:47 +05:00
@@ -77,7 +77,7 @@
 		      handler *db_file)
 {
   LEX_STRING str_db_type;
-  uint reclength,info_length,screens,key_info_length,maxlength;
+  uint reclength,info_length,screens,key_info_length,maxlength,i;
   ulong key_buff_length;
   File file;
   ulong filepos, data_offset;
@@ -127,13 +127,23 @@
   /* Calculate extra data segment length */
   str_db_type.str= (char *)ha_get_storage_engine(create_info->db_type);
   str_db_type.length= strlen(str_db_type.str);
+  /* str_db_type */
   create_info->extra_size= 2 + str_db_type.length;
+  /* connect_string */
   create_info->extra_size+= create_info->connect_string.length + 2;
+  /* Partition */
+  create_info->extra_size+= 5;
 #ifdef HAVE_PARTITION_DB
   if (part_info)
-    create_info->extra_size+= 5 + part_info->part_info_len;
+    create_info->extra_size+= part_info->part_info_len;
 #endif
 
+  for (i= 0; i < keys; i++)
+  {
+    if (key_info[i].parser)
+      create_info->extra_size+= key_info[i].parser->name.length + 1;
+  }
+
   if ((file=create_frm(thd, file_name, db, table, reclength, fileinfo,
 		       create_info, keys)) < 0)
   {
@@ -192,10 +202,31 @@
     if (my_write(file, (const byte*)buff, 4, MYF_RW) ||
         my_write(file, (const byte*)part_info->part_info_string,
                  part_info->part_info_len + 1, MYF_RW))
+      goto err;
+  }
+  else
+  {
+    int4store(buff, 0);
+    if (my_write(file, (const byte*)buff, 4, MYF_RW) ||
+        my_write(file, (const byte*)"", 1, MYF_RW))
+      goto err;
+  }
+#else
+  int4store(buff, 0);
+  if (my_write(file, (const byte*)buff, 4, MYF_RW) ||
+      my_write(file, (const byte*)"", 1, MYF_RW))
     goto err;
- }
 #endif
- 
+  for (i= 0; i < keys; i++)
+  {
+    if (key_info[i].parser)
+    {
+      if (my_write(file, key_info[i].parser->name.str,
+                   key_info[i].parser->name.length + 1, MYF(MY_NABP)))
+        goto err;
+    }
+  }
+        
   VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
   if (my_write(file,(byte*) forminfo,288,MYF_RW) ||
       my_write(file,(byte*) screen_buff,info_length,MYF_RW) ||

--- 1.49/strings/Makefile.am	2005-08-11 16:18:38 +05:00
+++ 1.50/strings/Makefile.am	2005-10-15 21:03:48 +05:00
@@ -22,19 +22,19 @@
 # Exact one of ASSEMBLER_X
 if ASSEMBLER_x86
 ASRCS		= strings-x86.s longlong2str-x86.s my_strtoll10-x86.s
-CSRCS		= bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c
strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c
ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c
ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c
ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c
my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c longlong2str_asm.c
+CSRCS		= bfill.c bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c
strtod.c bcmp.c strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c
ctype-simple.c ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c
ctype-euc_kr.c ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c
ctype-utf8.c ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c
my_vsnprintf.c xml.c decimal.c ctype-extra.c str_alloc.c longlong2str_asm.c my_strchr.c
 else
 if ASSEMBLER_sparc32
 # These file MUST all be on the same line!! Otherwise automake
 # generats a very broken makefile
 ASRCS		= bmove_upp-sparc.s strappend-sparc.s strend-sparc.s strinstr-sparc.s
strmake-sparc.s strmov-sparc.s strnmov-sparc.s strstr-sparc.s
-CSRCS		= strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c
bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c
strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c
ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c
ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c
ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c
xml.c decimal.c ctype-extra.c my_strtoll10.c str_alloc.c
+CSRCS		= strcont.c strfill.c strcend.c is_prefix.c longlong2str.c bfill.c bmove.c
bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c strtol.c
strtoul.c strtoll.c strtoull.c llstr.c strnlen.c strxmov.c ctype.c ctype-simple.c
ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c
ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c
ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c
xml.c decimal.c ctype-extra.c my_strtoll10.c str_alloc.c my_strchr.c
 else
 #no assembler
 ASRCS		=
 # These file MUST all be on the same line!! Otherwise automake
 # generats a very broken makefile
-CSRCS		= strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c
is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c
bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c
strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c
ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c
ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c
ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c
xml.c decimal.c ctype-extra.c my_strtoll10.c str_alloc.c
+CSRCS		= strxmov.c bmove_upp.c strappend.c strcont.c strend.c strfill.c strcend.c
is_prefix.c strstr.c strinstr.c strmake.c strnmov.c strmov.c longlong2str.c bfill.c
bmove.c bmove512.c bchange.c strxnmov.c int2str.c str2int.c r_strinstr.c strtod.c bcmp.c
strtol.c strtoul.c strtoll.c strtoull.c llstr.c strnlen.c ctype.c ctype-simple.c
ctype-mb.c ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc_kr.c
ctype-gb2312.c ctype-gbk.c ctype-sjis.c ctype-tis620.c ctype-ujis.c ctype-utf8.c
ctype-ucs2.c ctype-uca.c ctype-win1250ch.c ctype-bin.c ctype-latin1.c my_vsnprintf.c
xml.c decimal.c ctype-extra.c my_strtoll10.c str_alloc.c my_strchr.c
 endif
 endif
 
@@ -53,7 +53,7 @@
 			bmove_upp-sparc.s strappend-sparc.s strend-sparc.s \
 			strinstr-sparc.s strmake-sparc.s strmov-sparc.s \
 			strnmov-sparc.s strstr-sparc.s strxmov-sparc.s \
-			t_ctype.h
+			t_ctype.h my_strchr.c
 
 libmystrings_a_LIBADD=
 conf_to_src_SOURCES = conf_to_src.c xml.c ctype.c bcmp.c

--- 1.49/sql/share/errmsg.txt	2005-10-06 13:49:29 +05:00
+++ 1.50/sql/share/errmsg.txt	2005-10-15 21:03:46 +05:00
@@ -3006,7 +3006,7 @@
 	cze "Nemohu naj-Bt funkci '%-.64s' v knihovn'"
 	dan "Kan ikke finde funktionen '%-.64s' i bibliotek'"
 	nla "Kan functie '%-.64s' niet in library vinden"
-	eng "Can't find function '%-.64s' in library'"
+	eng "Can't find symbol '%-.64s' in library'"
 	jps "function '%-.64s'
Cu[Ɍ©t¯鎖ªł«܂¹",
 	est "Ei leia funktsiooni '%-.64s' antud teegis"
 	fre "Impossible de trouver la fonction '%-.64s' dans la bibliothque'"
@@ -3018,7 +3018,7 @@
 	kor "¶̹®¿¡¼­ '%-.64s' Լ ã
¼ ¾ϴ."
 	por "No pode encontrar a funo '%-.64s' na biblioteca"
 	rum "Nu pot gasi functia '%-.64s' in libraria"
-	rus "   '%-.64s'  "
+	rus "   '%-.64s'  "
 	serbian "Ne mogu da pronadjem funkciju '%-.64s' u biblioteci"
 	slo "Nemem njs» funkciu '%-.64s' v kni¾nici'"
 	spa "No puedo encontrar funcin '%-.64s' en libraria'"
@@ -5539,3 +5539,5 @@
 ER_DROP_PARTITION_WHEN_FK_DEFINED
         eng "Cannot drop a partition when a foreign key constraint is defined on the
table"
         swe "Kan inte ta bort en partition nr en frmmande nyckel r definierad p
tabellen"
+ER_PLUGIN_IS_NOT_LOADED
+	eng "Plugin '%-.64s' is not loaded"

--- 1.84/mysql-test/r/information_schema.result	2005-10-08 04:48:54 +05:00
+++ 1.85/mysql-test/r/information_schema.result	2005-10-15 21:03:46 +05:00
@@ -60,6 +60,7 @@
 help_relation
 help_topic
 host
+plugin
 proc
 procs_priv
 tables_priv
@@ -709,7 +710,7 @@
 CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1;
 CREATE VIEW a2 AS SELECT t_CRASHME FROM a1;
 count(*)
-101
+102
 drop view a2, a1;
 drop table t_crashme;
 select table_schema,table_name, column_name from
@@ -779,7 +780,7 @@
 SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA;
 table_schema	count(*)
 information_schema	16
-mysql	17
+mysql	18
 create table t1 (i int, j int);
 create trigger trg1 before insert on t1 for each row
 begin

--- 1.110/include/my_global.h	2005-10-06 13:25:56 +05:00
+++ 1.111/include/my_global.h	2005-10-15 21:03:45 +05:00
@@ -1361,4 +1361,23 @@
 #define NO_EMBEDDED_ACCESS_CHECKS
 #endif
 
+#ifdef HAVE_DLOPEN
+#if defined(__WIN__)
+#define dlsym(lib, name) GetProcAddress((HMODULE)lib, name)
+#define dlopen(libname, unused) LoadLibraryEx(libname, NULL, 0)
+#define dlclose(lib) FreeLibrary((HMODULE)lib)
+#elif !defined(OS2)
+#include <dlfcn.h>
+#endif
+#endif
+
+/* FreeBSD 2.2.2 does not define RTLD_NOW) */
+#ifndef RTLD_NOW
+#define RTLD_NOW 1
+#endif
+
+#ifndef HAVE_DLERROR
+#define dlerror() ""
+#endif
+
 #endif /* my_global_h */

--- 1.139/sql/set_var.cc	2005-10-14 12:44:28 +05:00
+++ 1.140/sql/set_var.cc	2005-10-15 21:03:46 +05:00
@@ -781,6 +781,7 @@
   {sys_optimizer_search_depth.name,(char*) &sys_optimizer_search_depth,
    SHOW_SYS},
   {"pid_file",                (char*) pidfile_name,                 SHOW_CHAR},
+  {"plugin_dir",              (char*) opt_plugin_dir,               SHOW_CHAR},
   {"port",                    (char*) &mysqld_port,                  SHOW_INT},
   {sys_preload_buff_size.name, (char*) &sys_preload_buff_size,      SHOW_SYS},
   {"protocol_version",        (char*) &protocol_version,            SHOW_INT},

--- 1.25/scripts/mysql_fix_privilege_tables.sql	2005-10-06 13:25:57 +05:00
+++ 1.26/scripts/mysql_fix_privilege_tables.sql	2005-10-15 21:03:46 +05:00
@@ -19,6 +19,12 @@
   PRIMARY KEY (name)
 ) CHARACTER SET utf8 COLLATE utf8_bin;
 
+CREATE TABLE IF NOT EXISTS plugin (
+  name char(64) binary DEFAULT '' NOT NULL,
+  dl char(128) DEFAULT '' NOT NULL,
+  PRIMARY KEY (name)
+) CHARACTER SET utf8 COLLATE utf8_bin;
+
 ALTER TABLE user add File_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL;
 
 -- Detect whether or not we had the Grant_priv column

--- 1.66/libmysqld/Makefile.am	2005-10-06 15:45:16 +05:00
+++ 1.67/libmysqld/Makefile.am	2005-10-15 21:03:46 +05:00
@@ -20,11 +20,13 @@
 MYSQLDATAdir =		$(localstatedir)
 MYSQLSHAREdir =		$(pkgdatadir)
 MYSQLBASEdir=		$(prefix)
+MYSQLLIBdir=            $(libdir)
 
 DEFS =			-DEMBEDDED_LIBRARY -DMYSQL_SERVER \
 			-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
 			-DDATADIR="\"$(MYSQLDATAdir)\"" \
-			-DSHAREDIR="\"$(MYSQLSHAREdir)\""
+			-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+			-DLIBDIR="\"$(MYSQLLIBdir)\""
 INCLUDES=		@bdb_includes@ \
 			-I$(top_builddir)/include -I$(top_srcdir)/include \
 			-I$(top_srcdir)/sql -I$(top_srcdir)/sql/examples \
@@ -63,7 +65,7 @@
 	spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
 	sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
 	parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
-        rpl_filter.cc \
+        rpl_filter.cc sql_plugin.cc \
 	ha_blackhole.cc ha_archive.cc sql_partition.cc ha_partition.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
$(sqlexamplessources)

--- 1.95/storage/myisam/ft_boolean_search.c	2005-10-06 13:26:05 +05:00
+++ 1.96/storage/myisam/ft_boolean_search.c	2005-10-15 21:03:47 +05:00
@@ -91,6 +91,7 @@
   float     weight;
   float     cur_weight;
   LIST     *phrase;               /* phrase words */
+  LIST     *document;             /* for phrase search */
   uint      yesses;               /* number of "yes" words matched */
   uint      nos;                  /* number of "no"  words matched */
   uint      ythresh;              /* number of "yes" words in expr */
@@ -154,85 +155,160 @@
   return i;
 }
 
-static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
-                      FTB_EXPR *up, uint depth, byte *up_quot)
+
+typedef struct st_my_ftb_param
 {
-  byte        res;
-  FTB_PARAM   param;
-  FT_WORD     w;
-  FTB_WORD   *ftbw;
-  FTB_EXPR   *ftbe;
-  FTB_EXPR   *tmp_expr;
-  FT_WORD    *phrase_word;
-  LIST       *phrase_list;
-  uint  extra=HA_FT_WLEN+ftb->info->s->rec_reflength; /* just a shortcut */
+  FTB *ftb;
+  FTB_EXPR *ftbe;
+  byte *up_quot;
+  uint depth;
+} MY_FTB_PARAM;
+
+
+static int ftb_query_add_word(void *param, byte *word, uint word_len,
+                              MYSQL_FTPARSER_BOOLEAN_INFO *info)
+{
+  MY_FTB_PARAM *ftb_param= (MY_FTB_PARAM *)param;
+  FTB_WORD *ftbw;
+  FTB_EXPR *ftbe, *tmp_expr;
+  FT_WORD *phrase_word;
+  LIST *tmp_element;
+  int r= info->weight_adjust;
+  float weight= (float)
+        (info->wasign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];
+
+  switch (info->type) {
+    case FT_CHUNK_TYPE_WORD:
+      ftbw= (FTB_WORD *)alloc_root(&ftb_param->ftb->mem_root,
+                                   sizeof(FTB_WORD) +
+                                   (info->trunc ? MI_MAX_KEY_BUFF :
+                                    word_len * ftb_param->ftb->charset->mbmaxlen
+
+                                    HA_FT_WLEN +
+                                    ftb_param->ftb->info->s->rec_reflength));
+      ftbw->len= word_len + 1;
+      ftbw->flags= 0;
+      ftbw->off= 0;
+      if (info->yesno > 0) ftbw->flags|= FTB_FLAG_YES;
+      if (info->yesno < 0) ftbw->flags|= FTB_FLAG_NO;
+      if (info->trunc) ftbw->flags|= FTB_FLAG_TRUNC;
+      ftbw->weight= weight;
+      ftbw->up= ftb_param->ftbe;
+      ftbw->docid[0]= ftbw->docid[1]= HA_OFFSET_ERROR;
+      ftbw->ndepth= (info->yesno < 0) + ftb_param->depth;
+      ftbw->key_root= HA_OFFSET_ERROR;
+      memcpy(ftbw->word + 1, word, word_len);
+      ftbw->word[0]= word_len;
+      if (info->yesno > 0) ftbw->up->ythresh++;
+      queue_insert(&ftb_param->ftb->queue, (byte *)ftbw);
+      ftb_param->ftb->with_scan|= (info->trunc & FTB_FLAG_TRUNC);
+      for (tmp_expr= ftb_param->ftbe; tmp_expr->up; tmp_expr= tmp_expr->up)
+        if (! (tmp_expr->flags & FTB_FLAG_YES))
+          break;
+      ftbw->max_docid= &tmp_expr->max_docid;
+      /* fall through */
+    case FT_CHUNK_TYPE_STOPWORD:
+      if (! ftb_param->up_quot) break;
+      phrase_word= (FT_WORD *)alloc_root(&ftb_param->ftb->mem_root,
sizeof(FT_WORD));
+      tmp_element= (LIST *)alloc_root(&ftb_param->ftb->mem_root, sizeof(LIST));
+      phrase_word->pos= word;
+      phrase_word->len= word_len;
+      tmp_element->data= (void *)phrase_word;
+      ftb_param->ftbe->phrase= list_add(ftb_param->ftbe->phrase,
tmp_element);
+      /* Allocate document list at this point.
+         It allows to avoid huge amount of allocs/frees for each row.*/
+      tmp_element= (LIST *)alloc_root(&ftb_param->ftb->mem_root, sizeof(LIST));
+      tmp_element->data= alloc_root(&ftb_param->ftb->mem_root,
sizeof(FT_WORD));
+      ftb_param->ftbe->document=
+        list_add(ftb_param->ftbe->document, tmp_element);
+      break;
+    case FT_CHUNK_TYPE_LBR:
+      ftbe=(FTB_EXPR *)alloc_root(&ftb_param->ftb->mem_root, sizeof(FTB_EXPR));
+      ftbe->flags= 0;
+      if (info->yesno > 0) ftbe->flags|= FTB_FLAG_YES;
+      if (info->yesno < 0) ftbe->flags|= FTB_FLAG_NO;
+      ftbe->weight= weight;
+      ftbe->up= ftb_param->ftbe;
+      ftbe->max_docid= ftbe->ythresh= ftbe->yweaks= 0;
+      ftbe->docid[0]= ftbe->docid[1]= HA_OFFSET_ERROR;
+      ftbe->phrase= NULL;
+      ftbe->document= 0;
+      if (info->quot) ftb_param->ftb->with_scan|= 2;
+      if (info->yesno > 0) ftbe->up->ythresh++;
+      ftb_param->ftbe= ftbe;
+      ftb_param->depth++;
+      ftb_param->up_quot= info->quot;
+      break;
+    case FT_CHUNK_TYPE_RBR:
+      if (ftb_param->ftbe->document)
+      {
+        /* Circuit document list */
+        for (tmp_element= ftb_param->ftbe->document;
+             tmp_element->next; tmp_element= tmp_element->next) /* no-op */;
+        tmp_element->next= ftb_param->ftbe->document;
+        ftb_param->ftbe->document->prev= tmp_element;
+      }
+      info->quot= 0;
+      if (ftb_param->ftbe->up)
+      {
+        DBUG_ASSERT(ftb_param->depth);
+        ftb_param->ftbe= ftb_param->ftbe->up;
+        ftb_param->depth--;
+        ftb_param->up_quot= 0;
+      }
+      break;
+    case FT_CHUNK_TYPE_EOF:
+    default:
+      break;
+  }
+  return(0);
+}
+
+
+static int ftb_parse_query_internal(void *param, byte *query, uint len)
+{
+  MY_FTB_PARAM *ftb_param= (MY_FTB_PARAM *)param;
+  MYSQL_FTPARSER_BOOLEAN_INFO info;
+  CHARSET_INFO *cs= ftb_param->ftb->charset;
+  byte **start= &query;
+  byte *end= query + len;
+  FT_WORD w;
+
+  info.prev= ' ';
+  info.quot= 0;
+  while (ft_get_word(cs, start, end, &w, &info))
+    ftb_query_add_word(param, w.pos, w.len, &info);
+  return(0);
+}
+
+
+static void _ftb_parse_query(FTB *ftb, byte *query, uint len,
+                             struct st_mysql_ftparser *parser)
+{
+  MYSQL_FTPARSER_PARAM param;
+  MY_FTB_PARAM ftb_param;
+  DBUG_ENTER("_ftb_parse_query");
+  DBUG_ASSERT(parser);
 
   if (ftb->state != UNINITIALIZED)
     return;
 
-  param.prev=' ';
-  param.quot= up_quot;
-  while ((res=ft_get_word(ftb->charset,start,end,&w,&param)))
-  {
-    int   r=param.plusminus;
-    float weight= (float) (param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)];
-    switch (res) {
-      case 1: /* word found */
-        ftbw=(FTB_WORD *)alloc_root(&ftb->mem_root,
-                                    sizeof(FTB_WORD) +
-                                    (param.trunc ? MI_MAX_KEY_BUFF :
-                                     w.len*ftb->charset->mbmaxlen+extra));
-        ftbw->len=w.len+1;
-        ftbw->flags=0;
-        ftbw->off=0;
-        if (param.yesno>0) ftbw->flags|=FTB_FLAG_YES;
-        if (param.yesno<0) ftbw->flags|=FTB_FLAG_NO;
-        if (param.trunc)   ftbw->flags|=FTB_FLAG_TRUNC;
-        ftbw->weight=weight;
-        ftbw->up=up;
-        ftbw->docid[0]=ftbw->docid[1]=HA_OFFSET_ERROR;
-        ftbw->ndepth= (param.yesno<0) + depth;
-        ftbw->key_root=HA_OFFSET_ERROR;
-        memcpy(ftbw->word+1, w.pos, w.len);
-        ftbw->word[0]=w.len;
-        if (param.yesno > 0) up->ythresh++;
-        queue_insert(& ftb->queue, (byte *)ftbw);
-        ftb->with_scan|=(param.trunc & FTB_FLAG_TRUNC);
-        for (tmp_expr= up; tmp_expr->up; tmp_expr= tmp_expr->up)
-          if (! (tmp_expr->flags & FTB_FLAG_YES))
-            break;
-        ftbw->max_docid= &tmp_expr->max_docid;
-      case 4: /* not indexed word (stopword or too short/long) */
-        if (! up_quot) break;
-        phrase_word= (FT_WORD *)alloc_root(&ftb->mem_root, sizeof(FT_WORD));
-        phrase_list= (LIST *)alloc_root(&ftb->mem_root, sizeof(LIST));
-        phrase_word->pos= w.pos;
-        phrase_word->len= w.len;
-        phrase_list->data= (void *)phrase_word;
-        up->phrase= list_add(up->phrase, phrase_list);
-        break;
-      case 2: /* left bracket */
-        ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR));
-        ftbe->flags=0;
-        if (param.yesno>0) ftbe->flags|=FTB_FLAG_YES;
-        if (param.yesno<0) ftbe->flags|=FTB_FLAG_NO;
-        ftbe->weight=weight;
-        ftbe->up=up;
-        ftbe->max_docid= ftbe->ythresh= ftbe->yweaks= 0;
-        ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
-        ftbe->phrase= NULL;
-        if (param.quot) ftb->with_scan|=2;
-        if (param.yesno > 0) up->ythresh++;
-        _ftb_parse_query(ftb, start, end, ftbe, depth+1, param.quot);
-        param.quot=0;
-        break;
-      case 3: /* right bracket */
-        if (up_quot) up->phrase= list_reverse(up->phrase);
-        return;
-    }
-  }
-  return;
+  ftb_param.ftb= ftb;
+  ftb_param.depth= 0;
+  ftb_param.ftbe= ftb->root;
+  ftb_param.up_quot= 0;
+
+  param.mysql_parse= ftb_parse_query_internal;
+  param.mysql_add_word= ftb_query_add_word;
+  param.ftparser_state= 0;
+  param.mysql_ftparam= (void *)&ftb_param;
+  param.cs= ftb->charset;
+  param.doc= query;
+  param.length= len;
+  param.flags= MYSQL_FTPARSER_BOOLEAN_MODE;
+  parser->parse(&param);
+  DBUG_VOID_RETURN;
 }
+ 
 
 static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)),
                              const void *a,const void *b)
@@ -463,8 +539,11 @@
   ftbe->max_docid= ftbe->ythresh= ftbe->yweaks= 0;
   ftbe->docid[0]=ftbe->docid[1]=HA_OFFSET_ERROR;
   ftbe->phrase= NULL;
+  ftbe->document= 0;
   ftb->root=ftbe;
-  _ftb_parse_query(ftb, &query, query+query_len, ftbe, 0, NULL);
+  _ftb_parse_query(ftb, query, query_len, keynr == NO_SUCH_KEY ?
+                                          &ft_default_parser :
+                                          info->s->keyinfo[keynr].parser);
   ftb->list=(FTB_WORD **)alloc_root(&ftb->mem_root,
                                      sizeof(FTB_WORD *)*ftb->queue.elements);
   memcpy(ftb->list, ftb->queue.root+1, sizeof(FTB_WORD *)*ftb->queue.elements);
@@ -480,6 +559,62 @@
 }
 
 
+typedef struct st_my_ftb_phrase_param
+{
+  LIST *phrase;
+  LIST *document;
+  CHARSET_INFO *cs;
+  uint phrase_length;
+  uint document_length;
+  uint match;
+} MY_FTB_PHRASE_PARAM;
+
+
+static int ftb_phrase_add_word(void *param, byte *word, uint word_len,
+    MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info __attribute__((unused)))
+{
+  MY_FTB_PHRASE_PARAM *phrase_param= (MY_FTB_PHRASE_PARAM *)param;
+  FT_WORD *w= (FT_WORD *)phrase_param->document->data;
+  LIST *phrase, *document;
+  w->pos= word;
+  w->len= word_len;
+  phrase_param->document= phrase_param->document->prev;
+  if (phrase_param->phrase_length > phrase_param->document_length)
+  {
+    phrase_param->document_length++;
+    return 0;
+  }
+  /* TODO: rewrite phrase search to avoid
+     comparing the same word twice. */
+  for (phrase= phrase_param->phrase, document= phrase_param->document->next;
+       phrase; phrase= phrase->next, document= document->next)
+  {
+    FT_WORD *phrase_word= (FT_WORD *)phrase->data;
+    FT_WORD *document_word= (FT_WORD *)document->data;
+    if (my_strnncoll(phrase_param->cs, phrase_word->pos, phrase_word->len,
+                     document_word->pos, document_word->len))
+      return 0;
+  }
+  phrase_param->match++;
+  return 0;
+}
+
+
+static int ftb_check_phrase_internal(void *param, byte *document, uint len)
+{
+  FT_WORD word;
+  MY_FTB_PHRASE_PARAM *phrase_param= (MY_FTB_PHRASE_PARAM *)param;
+  const byte *docend= document + len;
+  while (ft_simple_get_word(phrase_param->cs, &document, docend, &word,
FALSE))
+  {
+    ftb_phrase_add_word(param, word.pos, word.len, 0);
+    if (phrase_param->match)
+      return 1;
+  }
+  return 0;
+}
+
+
 /*
   Checks if given buffer matches phrase list.
 
@@ -494,32 +629,31 @@
     1 is returned if phrase found, 0 else.
 */
 
-static int _ftb_check_phrase(const byte *s0, const byte *e0,
-                LIST *phrase, CHARSET_INFO *cs)
-{
-  FT_WORD h_word;
-  const byte *h_start= s0;
-  DBUG_ENTER("_ftb_strstr");
-  DBUG_ASSERT(phrase);
-
-  while (ft_simple_get_word(cs, (byte **)&h_start, e0, &h_word, FALSE))
-  {
-    FT_WORD *n_word;
-    LIST *phrase_element= phrase;
-    const byte *h_start1= h_start;
-    for (;;)
-    {
-      n_word= (FT_WORD *)phrase_element->data;
-      if (my_strnncoll(cs, (const uchar *) h_word.pos, h_word.len,
-		       (const uchar *) n_word->pos, n_word->len))
-        break;
-      if (! (phrase_element= phrase_element->next))
-        DBUG_RETURN(1);
-      if (! ft_simple_get_word(cs, (byte **)&h_start1, e0, &h_word, FALSE))
-        DBUG_RETURN(0);
-    }
-  }
-  DBUG_RETURN(0);
+static int _ftb_check_phrase(const byte *document, uint len,
+                FTB_EXPR *ftbe, CHARSET_INFO *cs,
+                struct st_mysql_ftparser *parser)
+{
+  MY_FTB_PHRASE_PARAM ftb_param;
+  MYSQL_FTPARSER_PARAM param;
+  DBUG_ENTER("_ftb_check_phrase");
+  DBUG_ASSERT(parser);
+  ftb_param.phrase= ftbe->phrase;
+  ftb_param.document= ftbe->document;
+  ftb_param.cs= cs;
+  ftb_param.phrase_length= list_length(ftbe->phrase);
+  ftb_param.document_length= 1;
+  ftb_param.match= 0;
+
+  param.mysql_parse= ftb_check_phrase_internal;
+  param.mysql_add_word= ftb_phrase_add_word;
+  param.ftparser_state= 0;
+  param.mysql_ftparam= (void *)&ftb_param;
+  param.cs= cs;
+  param.doc= (byte *)document;
+  param.length= len;
+  param.flags= MYSQL_FTPARSER_DOCUMENT_MODE;
+  parser->parse(&param);
+  DBUG_RETURN(ftb_param.match ? 1 : 0);
 }
 
 
@@ -530,6 +664,9 @@
   float weight=ftbw->weight;
   int  yn=ftbw->flags, ythresh, mode=(ftsi_orig != 0);
   my_off_t curdoc=ftbw->docid[mode];
+  struct st_mysql_ftparser *parser= ftb->keynr == NO_SUCH_KEY ?
+                                    &ft_default_parser :
+                                    ftb->info->s->keyinfo[ftb->keynr].parser;
 
   for (ftbe=ftbw->up; ftbe; ftbe=ftbe->up)
   {
@@ -559,8 +696,8 @@
           {
             if (!ftsi.pos)
               continue;
-            not_found = ! _ftb_check_phrase(ftsi.pos, ftsi.pos+ftsi.len,
-                                      ftbe->phrase, ftb->charset);
+            not_found = ! _ftb_check_phrase(ftsi.pos, ftsi.len,
+                                      ftbe, ftb->charset, parser);
           }
           if (not_found) break;
         } /* ftbe->quot */
@@ -667,14 +804,67 @@
 }
 
 
-float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
+typedef struct st_my_ftb_find_param
 {
-  FT_WORD word;
+  FT_INFO *ftb;
+  FT_SEG_ITERATOR *ftsi;
+} MY_FTB_FIND_PARAM;
+
+
+static int ftb_find_relevance_add_word(void *param, byte *word, uint len,
+             MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info __attribute__((unused)))
+{
+  MY_FTB_FIND_PARAM *ftb_param= (MY_FTB_FIND_PARAM *)param;
+  FT_INFO *ftb= ftb_param->ftb;
   FTB_WORD *ftbw;
+  int a, b, c;
+  for (a= 0, b= ftb->queue.elements, c= (a+b)/2; b-a>1; c= (a+b)/2)
+  {
+    ftbw= ftb->list[c];
+    if (mi_compare_text(ftb->charset, (uchar*)word, len,
+                        (uchar*)ftbw->word+1, ftbw->len-1,
+                        (my_bool)(ftbw->flags&FTB_FLAG_TRUNC), 0) > 0)
+      b= c;
+    else
+      a= c;
+  }
+  for (; c >= 0; c--)
+  {
+    ftbw= ftb->list[c];
+    if (mi_compare_text(ftb->charset, (uchar*)word, len,
+                        (uchar*)ftbw->word + 1,ftbw->len - 1,
+                        (my_bool)(ftbw->flags & FTB_FLAG_TRUNC), 0))
+      break;
+    if (ftbw->docid[1] == ftb->info->lastpos)
+      continue;
+    ftbw->docid[1]= ftb->info->lastpos;
+     _ftb_climb_the_tree(ftb, ftbw, ftb_param->ftsi);
+  }
+  return(0);
+}
+
+
+static int ftb_find_relevance_parse(void *param, byte *doc, uint len)
+{
+  FT_INFO *ftb= ((MY_FTB_FIND_PARAM *)param)->ftb;
+  byte *end= doc + len;
+  FT_WORD w;
+  while (ft_simple_get_word(ftb->charset, &doc, end, &w, TRUE))
+    ftb_find_relevance_add_word(param, w.pos, w.len, 0);
+  return(0);
+}
+
+
+float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length)
+{
   FTB_EXPR *ftbe;
   FT_SEG_ITERATOR ftsi, ftsi2;
-  const byte *end;
   my_off_t  docid=ftb->info->lastpos;
+  MY_FTB_FIND_PARAM ftb_param;
+  MYSQL_FTPARSER_PARAM param;
+  struct st_mysql_ftparser *parser= ftb->keynr == NO_SUCH_KEY ?
+                                    &ft_default_parser :
+                                    ftb->info->s->keyinfo[ftb->keynr].parser;
 
   if (docid == HA_OFFSET_ERROR)
     return -2.0;
@@ -702,41 +892,23 @@
     _mi_ft_segiterator_init(ftb->info, ftb->keynr, record, &ftsi);
   memcpy(&ftsi2, &ftsi, sizeof(ftsi));
 
+  ftb_param.ftb= ftb;
+  ftb_param.ftsi= &ftsi2;
+  param.mysql_parse= ftb_find_relevance_parse;
+  param.mysql_add_word= ftb_find_relevance_add_word;
+  param.ftparser_state= 0;
+  param.mysql_ftparam= (void *)&ftb_param;
+  param.cs= ftb->charset;
+  param.flags= MYSQL_FTPARSER_DOCUMENT_MODE;
   while (_mi_ft_segiterator(&ftsi))
   {
     if (!ftsi.pos)
       continue;
 
-    end=ftsi.pos+ftsi.len;
-    while (ft_simple_get_word(ftb->charset, (byte **) &ftsi.pos,
-                              (byte *) end, &word, TRUE))
-    {
-      int a, b, c;
-      for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2)
-      {
-        ftbw=ftb->list[c];
-        if (mi_compare_text(ftb->charset, (uchar*) word.pos, word.len,
-                            (uchar*) ftbw->word+1, ftbw->len-1,
-                            (my_bool) (ftbw->flags&FTB_FLAG_TRUNC),0) >0)
-          b=c;
-        else
-          a=c;
-      }
-      for (; c>=0; c--)
-      {
-        ftbw=ftb->list[c];
-        if (mi_compare_text(ftb->charset, (uchar*) word.pos, word.len,
-                            (uchar*) ftbw->word+1,ftbw->len-1,
-                            (my_bool) (ftbw->flags&FTB_FLAG_TRUNC),0))
-          break;
-        if (ftbw->docid[1] == docid)
-          continue;
-        ftbw->docid[1]=docid;
-        _ftb_climb_the_tree(ftb, ftbw, &ftsi2);
-      }
-    }
+    param.doc= (byte *)ftsi.pos;
+    param.length= ftsi.len;
+    parser->parse(&param);
   }
-
   ftbe=ftb->root;
   if (ftbe->docid[1]==docid && ftbe->cur_weight>0 &&
       ftbe->yesses>=ftbe->ythresh && !ftbe->nos)

--- 1.40/storage/myisam/ft_nlq_search.c	2005-10-09 22:09:47 +05:00
+++ 1.41/storage/myisam/ft_nlq_search.c	2005-10-15 21:03:47 +05:00
@@ -230,7 +230,7 @@
             NULL, NULL);
 
   ft_parse_init(&wtree, aio.charset);
-  if (ft_parse(&wtree,query,query_len,0))
+  if (ft_parse(&wtree, query, query_len, 0, info->s->keyinfo[keynr].parser))
     goto err;
 
   if (tree_walk(&wtree, (tree_walk_action)&walk_and_match, &aio,

--- 1.17/mysql-test/r/connect.result	2005-09-09 12:44:06 +05:00
+++ 1.18/mysql-test/r/connect.result	2005-10-15 21:03:46 +05:00
@@ -9,6 +9,7 @@
 help_relation
 help_topic
 host
+plugin
 proc
 procs_priv
 tables_priv
@@ -32,6 +33,7 @@
 help_relation
 help_topic
 host
+plugin
 proc
 procs_priv
 tables_priv
@@ -59,6 +61,7 @@
 help_relation
 help_topic
 host
+plugin
 proc
 procs_priv
 tables_priv

--- 1.211/BitKeeper/etc/ignore	2005-10-06 13:25:15 +05:00
+++ 1.212/BitKeeper/etc/ignore	2005-10-15 21:03:49 +05:00
@@ -1537,3 +1537,4 @@
 vio/test-sslclient
 vio/test-sslserver
 vio/viotest-ssl
+libmysqld/sql_plugin.cc
--- New file ---
+++ include/plugin.h	05/10/15 21:03:48
/* Copyright (C) 2005 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef _my_plugin_h
#define _my_plugin_h
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0000
#define MYSQL_UDF_PLUGIN             0
#define MYSQL_STORAGE_ENGINE_PLUGIN  1
#define MYSQL_FTPARSER_PLUGIN        2
#define MYSQL_MAX_PLUGIN             3
#define MYSQL_ANY_PLUGIN             -1
#define mysql_declare_plugin                                          \
int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \
struct st_mysql_plugin _mysql_plugin_declarations_[]= {
#define mysql_declare_plugin_end ,{0,0,0,0,0,0,0}}

struct st_mysql_plugin
{
  int type;
  void *info;
  const char *name;
  const char *author;
  const char *descr;
  int (*init)(void);
  int (*deinit)(void);
};

/* Fulltext [pre]parser */
#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0000
#define MYSQL_FTPARSER_WITH_BOOLEAN_OPERATORS  1
#define MYSQL_FTPARSER_BOOLEAN_MODE            1
#define MYSQL_FTPARSER_NL_MODE                 0
#define MYSQL_FTPARSER_DOCUMENT_MODE           2
#define MYSQL_FTPARSER_QUERY_MODE              0
enum enum_ft_chunk_type
{
  FT_CHUNK_TYPE_EOF= 0,
  FT_CHUNK_TYPE_WORD= 1,
  FT_CHUNK_TYPE_LBR= 2,
  FT_CHUNK_TYPE_RBR= 3,
  FT_CHUNK_TYPE_STOPWORD= 4
};

typedef struct st_mysql_ftparser_boolean_info
{
  enum enum_ft_chunk_type type;
  int yesno;
  int weight_adjust;
  bool wasign;
  bool trunc;
  /* These are parser state and must be removed. */
  byte prev;
  byte *quot;
} MYSQL_FTPARSER_BOOLEAN_INFO;

typedef struct st_mysql_ftparser_param
{
  int (*mysql_parse)(void *param, byte *doc, uint doc_len);
  int (*mysql_add_word)(void *param, byte *word, uint word_len,
                        MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);
  void *ftparser_state;
  void *mysql_ftparam;
  CHARSET_INFO *cs;
  byte *doc;
  uint length;
  int flags;
} MYSQL_FTPARSER_PARAM;

struct st_mysql_ftparser
{
  int interface_version;
  int (*parse)(MYSQL_FTPARSER_PARAM *param);
  int (*init)(MYSQL_FTPARSER_PARAM *param);
  int (*deinit)(MYSQL_FTPARSER_PARAM *param);
};
#endif

--- New file ---
+++ sql/sql_plugin.cc	05/10/15 21:03:48
/* Copyright (C) 2005 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "mysql_priv.h"
#include <my_pthread.h>
#define REPORT_TO_LOG  1
#define REPORT_TO_USER 2

char *opt_plugin_dir;
static const char *plugin_interface_version_sym=
                   "_mysql_plugin_interface_version_";
static const char *plugin_declarations_sym= "_mysql_plugin_declarations_";
static int min_plugin_interface_version= 0x0000;

static DYNAMIC_ARRAY plugin_dl_array;
static DYNAMIC_ARRAY plugin_array;
static rw_lock_t THR_LOCK_plugin;
static bool initialized= 0;


static struct st_plugin_dl *plugin_dl_find(LEX_STRING *dl)
{
  uint i;
  DBUG_ENTER("plugin_dl_find");
  for (i= 0; i < plugin_dl_array.elements; i++)
  {
    struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
                                              struct st_plugin_dl *);
    if (tmp->ref_count &&
        ! my_strnncoll(files_charset_info,
                       (const uchar *)dl->str, dl->length,
                       (const uchar *)tmp->dl.str, tmp->dl.length))
      DBUG_RETURN(tmp);
  }
  DBUG_RETURN(0);
}


static st_plugin_dl *plugin_dl_add(LEX_STRING *dl, int report)
{
#ifdef HAVE_DLOPEN
  char dlpath[FN_REFLEN];
  uint plugin_dir_len, dummy_errors;
  struct st_plugin_dl *tmp, plugin_dl;
  void *sym;
  DBUG_ENTER("plugin_dl_add");
  DBUG_ASSERT(opt_plugin_dir);
  plugin_dir_len= strlen(opt_plugin_dir);
  /*
    Ensure that the dll doesn't have a path.
    This is done to ensure that only approved libraries from the
    plugin directory are used (to make this even remotely secure).
  */
  if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, '/') ||
      IF_WIN(my_strchr(files_charset_info, dl->str,
                       dl->str + dl->length, '\\'), 0) ||
      dl->length > NAME_LEN ||
      plugin_dir_len + dl->length + 1 >= FN_REFLEN)
  {
    if (report & REPORT_TO_USER)
      my_error(ER_UDF_NO_PATHS, MYF(0));
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_UDF_NO_PATHS));
    DBUG_RETURN(0);
  }
  /* If this dll is already loaded just increase ref_count. */
  if ((tmp= plugin_dl_find(dl)))
  {
    tmp->ref_count++;
    DBUG_RETURN(tmp);
  }
  /* Compile dll path */
  strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS);
  plugin_dl.ref_count= 1;
  /* Open new dll handle */
  if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
  {
    if (report & REPORT_TO_USER)
      my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, dlerror());
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, dlerror());
    DBUG_RETURN(0);
  }
  /* Determine interface version */
  if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym)))
  {
    dlclose(plugin_dl.handle);
    if (report & REPORT_TO_USER)
      my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_interface_version_sym);
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_interface_version_sym);
    DBUG_RETURN(0);
  }
  plugin_dl.version= *(int *)sym;
  /* Versioning */
  if (plugin_dl.version < min_plugin_interface_version ||
      (plugin_dl.version >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8))
  {
    dlclose(plugin_dl.handle);
    if (report & REPORT_TO_USER)
      my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, 0,
               "plugin interface version mismatch");
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, 0,
                      "plugin interface version mismatch");
    DBUG_RETURN(0);
  }
  /* Find plugin declarations */
  if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym)))
  {
    dlclose(plugin_dl.handle);
    if (report & REPORT_TO_USER)
      my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym);
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym);
    DBUG_RETURN(0);
  }
  plugin_dl.plugins= (struct st_mysql_plugin *)sym;
  /* Duplicate and convert dll name */
  plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
  if (! (plugin_dl.dl.str= my_malloc(plugin_dl.dl.length, MYF(0))))
  {
    dlclose(plugin_dl.handle);
    if (report & REPORT_TO_USER)
      my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length);
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length);
    DBUG_RETURN(0);
  }
  plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length,
    files_charset_info, dl->str, dl->length, system_charset_info,
    &dummy_errors);
  plugin_dl.dl.str[plugin_dl.dl.length]= 0;
  /* Add this dll to array */
  if (insert_dynamic(&plugin_dl_array, (gptr)&plugin_dl))
  {
    dlclose(plugin_dl.handle);
    my_free(plugin_dl.dl.str, MYF(0));
    if (report & REPORT_TO_USER)
      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl));
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl));
    DBUG_RETURN(0);
  }
  DBUG_RETURN(dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
                              struct st_plugin_dl *));
#else
  DBUG_ENTER("plugin_dl_add");
  if (report & REPORT_TO_USER)
    my_error(ER_FEATURE_DISABLED, MYF(0), "plugin", "HAVE_DLOPEN");
  if (report & REPORT_TO_LOG)
    sql_print_error(ER(ER_FEATURE_DISABLED), "plugin", "HAVE_DLOPEN");
  DBUG_RETURN(0);
#endif
}


static void plugin_dl_del(LEX_STRING *dl)
{
#ifdef HAVE_DLOPEN
  uint i;
  DBUG_ENTER("plugin_dl_del");
  for (i= 0; i < plugin_dl_array.elements; i++)
  {
    struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
                                              struct st_plugin_dl *);
    if (tmp->ref_count &&
        ! my_strnncoll(files_charset_info,
                       (const uchar *)dl->str, dl->length,
                       (const uchar *)tmp->dl.str, tmp->dl.length))
    {
      /* Do not remove this element, unless no other plugin uses this dll. */
      if (! --tmp->ref_count)
      {
        dlclose(tmp->handle);
        my_free(tmp->dl.str, MYF(0));
        bzero(tmp, sizeof(struct st_plugin_dl));
      }
      break;
    }
  }
  DBUG_VOID_RETURN;
#endif
}


static struct st_plugin_int *plugin_find_internal(LEX_STRING *name, int type)
{
  uint i;
  DBUG_ENTER("plugin_find_internal");
  if (! initialized)
    DBUG_RETURN(0);
  for (i= 0; i < plugin_array.elements; i++)
  {
    struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
                                               struct st_plugin_int *);
    if (tmp->state == PLUGIN_IS_READY &&
        (type < 0 || type == tmp->plugin->type) &&
        ! my_strnncoll(system_charset_info,
                       (const uchar *)name->str, name->length,
                       (const uchar *)tmp->name.str, tmp->name.length))
      DBUG_RETURN(tmp);
  }
  DBUG_RETURN(0);
}


my_bool plugin_is_ready(LEX_STRING *name, int type)
{
  my_bool rc= FALSE;
  DBUG_ENTER("plugin_is_ready");
  rw_rdlock(&THR_LOCK_plugin);
  if (plugin_find_internal(name, type))
    rc= TRUE;
  rw_unlock(&THR_LOCK_plugin);
  DBUG_RETURN(rc);
}


struct st_plugin_int *plugin_lock(LEX_STRING *name, int type)
{
  struct st_plugin_int *rc;
  DBUG_ENTER("plugin_find");
  rw_wrlock(&THR_LOCK_plugin);
  if ((rc= plugin_find_internal(name, type)))
    rc->ref_count++;
  rw_unlock(&THR_LOCK_plugin);
  DBUG_RETURN(rc);
}


static my_bool plugin_add(LEX_STRING *name, LEX_STRING *dl, int report)
{
  struct st_plugin_int tmp;
  struct st_mysql_plugin *plugin;
  DBUG_ENTER("plugin_add");
  if (plugin_find_internal(name, MYSQL_ANY_PLUGIN))
  {
    if (report & REPORT_TO_USER)
      my_error(ER_UDF_EXISTS, MYF(0), name->str);
    if (report & REPORT_TO_LOG)
      sql_print_error(ER(ER_UDF_EXISTS), name->str);
    DBUG_RETURN(TRUE);
  }
  if (! (tmp.plugin_dl= plugin_dl_add(dl, report)))
    DBUG_RETURN(TRUE);
  /* Find plugin by name */
  for (plugin= tmp.plugin_dl->plugins; plugin->type; plugin++)
  {
    uint name_len= strlen(plugin->name);
    if (! my_strnncoll(system_charset_info,
                       (const uchar *)name->str, name->length,
                       (const uchar *)plugin->name,
                       name_len))
    {
      tmp.plugin= plugin;
      tmp.name.str= (char *)plugin->name;
      tmp.name.length= name_len;
      tmp.ref_count= 0;
      tmp.state= PLUGIN_IS_UNINITIALIZED;
      if (insert_dynamic(&plugin_array, (gptr)&tmp))
      {
        if (report & REPORT_TO_USER)
          my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_int));
        if (report & REPORT_TO_LOG)
          sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_int));
        break;
      }
      DBUG_RETURN(FALSE);
    }
  }
  if (report & REPORT_TO_USER)
    my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str);
  if (report & REPORT_TO_LOG)
    sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str);
  plugin_dl_del(dl);
  DBUG_RETURN(TRUE);
}


static void plugin_del(LEX_STRING *name)
{
  uint i;
  DBUG_ENTER("plugin_del");
  for (i= 0; i < plugin_array.elements; i++)
  {
    struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
                                               struct st_plugin_int *);
    if (tmp->state != PLUGIN_IS_FREED &&
        ! my_strnncoll(system_charset_info,
                       (const uchar *)name->str, name->length,
                       (const uchar *)tmp->name.str, tmp->name.length))
    {
      plugin_dl_del(&tmp->plugin_dl->dl);
      tmp->state= PLUGIN_IS_FREED;
      break;
    }
  }
  DBUG_VOID_RETURN;
}


void plugin_unlock(struct st_plugin_int *plugin)
{
  DBUG_ENTER("plugin_release");
  rw_wrlock(&THR_LOCK_plugin);
  DBUG_ASSERT(plugin && plugin->ref_count);
  plugin->ref_count--;
  if (plugin->state == PLUGIN_IS_DELETED && ! plugin->ref_count)
  {
    if (plugin->plugin->deinit)
      plugin->plugin->deinit();
    plugin_del(&plugin->name);
  }
  rw_unlock(&THR_LOCK_plugin);
  DBUG_VOID_RETURN;
}


static void plugin_call_initializer(void)
{
  uint i;
  DBUG_ENTER("plugin_call_initializer");
  for (i= 0; i < plugin_array.elements; i++)
  {
    struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
                                               struct st_plugin_int *);
    if (tmp->state == PLUGIN_IS_UNINITIALIZED && tmp->plugin->init)
    {
      DBUG_PRINT("info", ("Initializing plugin: '%s'", tmp->name.str));
      if (tmp->plugin->init())
      {
        sql_print_error("Plugin '%s' init function returned error.",
                        tmp->name.str);
        DBUG_PRINT("warning", ("Plugin '%s' init function returned error.",
                               tmp->name.str))
        plugin_del(&tmp->name);
      }
    }
    if (tmp->state == PLUGIN_IS_UNINITIALIZED)
      tmp->state= PLUGIN_IS_READY;
  }
  DBUG_VOID_RETURN;
}


static void plugin_call_deinitializer(void)
{
  uint i;
  DBUG_ENTER("plugin_call_deinitializer");
  for (i= 0; i < plugin_array.elements; i++)
  {
    struct st_plugin_int *tmp= dynamic_element(&plugin_array, i,
                                               struct st_plugin_int *);
    if (tmp->state == PLUGIN_IS_READY)
    {
      if (tmp->plugin->deinit)
      {
        DBUG_PRINT("info", ("Deinitializing plugin: '%s'", tmp->name.str));
        if (tmp->plugin->deinit())
        {
          DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
                                 tmp->name.str))
        }
      }
      tmp->state= PLUGIN_IS_UNINITIALIZED;
    }
  }
  DBUG_VOID_RETURN;
}


void plugin_init(void)
{
  TABLE_LIST tables;
  TABLE *table;
  READ_RECORD read_record_info;
  int error;
  MEM_ROOT mem;
  DBUG_ENTER("plugin_init");
  if (initialized)
    DBUG_VOID_RETURN;
  my_rwlock_init(&THR_LOCK_plugin, NULL);
  THD *new_thd = new THD;
  if (!new_thd ||
      my_init_dynamic_array(&plugin_dl_array,sizeof(struct st_plugin_dl),16,16) ||
      my_init_dynamic_array(&plugin_array,sizeof(struct st_plugin_int),16,16))
  {
    sql_print_error("Can't allocate memory for plugin structures");
    delete new_thd;
    delete_dynamic(&plugin_dl_array);
    delete_dynamic(&plugin_array);
    DBUG_VOID_RETURN;
  }
  init_sql_alloc(&mem, 1024, 0);
  initialized= 1;
  new_thd->store_globals();
  new_thd->db= my_strdup("mysql", MYF(0));
  new_thd->db_length= 5;
  bzero((gptr)&tables, sizeof(tables));
  tables.alias= tables.table_name= (char*)"plugin";
  tables.lock_type= TL_READ;
  tables.db= new_thd->db;
  if (simple_open_n_lock_tables(new_thd, &tables))
  {
    DBUG_PRINT("error",("Can't open plugin table"));
    sql_print_error("Can't open the mysql.plugin table. Please run the mysql_install_db
script to create it.");
    delete_dynamic(&plugin_dl_array);
    delete_dynamic(&plugin_array);
    goto end;
  }
  table= tables.table;
  init_read_record(&read_record_info, new_thd, table, NULL, 1, 0);
  while (!(error= read_record_info.read_record(&read_record_info)))
  {
    DBUG_PRINT("info", ("init plugin record"));
    LEX_STRING name, dl;
    name.str= get_field(&mem, table->field[0]);
    name.length= strlen(name.str);
    dl.str= get_field(&mem, table->field[1]);
    dl.length= strlen(dl.str);
    if (plugin_add(&name, &dl, REPORT_TO_LOG))
      DBUG_PRINT("warning", ("Couldn't load plugin named '%s' with soname '%s'.",
                             name.str, dl.str));
  }
  plugin_call_initializer();
  if (error > 0)
    sql_print_error(ER(ER_GET_ERRNO), my_errno);
  end_read_record(&read_record_info);
  new_thd->version--; // Force close to free memory
end:
  free_root(&mem, MYF(0));
  close_thread_tables(new_thd);
  delete new_thd;
  /* Remember that we don't have a THD */
  my_pthread_setspecific_ptr(THR_THD, 0);
  DBUG_VOID_RETURN;
}


void plugin_free(void)
{
  uint i;
  DBUG_ENTER("plugin_free");
  plugin_call_deinitializer();
  delete_dynamic(&plugin_array);
  for (i= 0; i < plugin_dl_array.elements; i++)
  {
    struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i,
                                              struct st_plugin_dl *);
#ifdef HAVE_DLOPEN
    if (tmp->handle)
    {
      dlclose(tmp->handle);
      my_free(tmp->dl.str, MYF(0));
    }
#endif
  }
  delete_dynamic(&plugin_dl_array);
  if (initialized)
  {
    initialized= 0;
    rwlock_destroy(&THR_LOCK_plugin);
  }
  DBUG_VOID_RETURN;
}


my_bool mysql_install_plugin(THD *thd, LEX_STRING *name, LEX_STRING *dl)
{
  TABLE_LIST tables;
  TABLE *table;
  int error;
  struct st_plugin_int *tmp;
  DBUG_ENTER("mysql_install_plugin");
  bzero(&tables, sizeof(tables));
  tables.db= (char *)"mysql";
  tables.table_name= tables.alias= (char *)"plugin";
  if (check_table_access(thd, INSERT_ACL, &tables, 0))
    DBUG_RETURN(TRUE);
  rw_wrlock(&THR_LOCK_plugin);
  if (plugin_add(name, dl, REPORT_TO_USER))
    goto err;
  tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN);
  if (tmp->plugin->init)
  {
    if (tmp->plugin->init())
    {
      my_error(ER_CANT_INITIALIZE_UDF, MYF(0), name->str, ER(ER_UNKNOWN_ERROR));
      goto err;
    }
    tmp->state= PLUGIN_IS_READY;
  }
  if (! (table = open_ltable(thd, &tables, TL_WRITE)))
    goto deinit;
  table->field[0]->store(name->str, name->length, system_charset_info);
  table->field[1]->store(dl->str, dl->length, files_charset_info);
  error= table->file->write_row(table->record[0]);
  if (error)
  {
    table->file->print_error(error, MYF(0));
    goto deinit;
  }
  rw_unlock(&THR_LOCK_plugin);
  DBUG_RETURN(FALSE);
deinit:
  if (tmp->plugin->deinit)
    tmp->plugin->deinit();
err:
  plugin_del(name);
  rw_unlock(&THR_LOCK_plugin);
  DBUG_RETURN(TRUE);
}


my_bool mysql_uninstall_plugin(THD *thd, LEX_STRING *name)
{
  TABLE *table;
  TABLE_LIST tables;
  struct st_plugin_int *plugin;
  DBUG_ENTER("mysql_uninstall_plugin");
  rw_wrlock(&THR_LOCK_plugin);
  if (! (plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
  {
    my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
    goto err;
  }
  if (plugin->ref_count)
  {
    plugin->state= PLUGIN_IS_DELETED;
    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
                 "Plugin is not deleted, waiting on tables.");
  }
  else
  {
    if (plugin->plugin->deinit)
      plugin->plugin->deinit();
    plugin_del(name);
  }
  bzero(&tables, sizeof(tables));
  tables.db= (char *)"mysql";
  tables.table_name= tables.alias= (char *)"plugin";
  if (! (table= open_ltable(thd, &tables, TL_WRITE)))
    goto err;
  table->field[0]->store(name->str, name->length, system_charset_info);
  table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
  if (! table->file->index_read_idx(table->record[0], 0,
                                    (byte *)table->field[0]->ptr,
                                    table->key_info[0].key_length,
                                    HA_READ_KEY_EXACT))
  {
    int error;
    if ((error= table->file->delete_row(table->record[0])))
    {
      table->file->print_error(error, MYF(0));
      goto err;
    }
  }
  rw_unlock(&THR_LOCK_plugin);
  DBUG_RETURN(FALSE);
err:
  rw_unlock(&THR_LOCK_plugin);
  DBUG_RETURN(TRUE);
}

--- New file ---
+++ sql/sql_plugin.h	05/10/15 21:03:48
/* Copyright (C) 2005 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef _sql_plugin_h
#define _sql_plugin_h
#include <plugin.h>
enum enum_plugin_state
{
  PLUGIN_IS_FREED= 0,
  PLUGIN_IS_DELETED,
  PLUGIN_IS_UNINITIALIZED,
  PLUGIN_IS_READY
};

struct st_plugin_dl
{
  LEX_STRING dl;
  void *handle;
  struct st_mysql_plugin *plugins;
  int version;
  uint ref_count;
};

struct st_plugin_int
{
  LEX_STRING name;
  struct st_mysql_plugin *plugin;
  struct st_plugin_dl *plugin_dl;
  enum enum_plugin_state state;
  uint ref_count;
};

extern char *opt_plugin_dir;
extern void plugin_init(void);
extern void plugin_free(void);
extern my_bool plugin_is_ready(LEX_STRING *name, int type);
extern st_plugin_int *plugin_lock(LEX_STRING *name, int type);
extern void plugin_unlock(struct st_plugin_int *plugin);
extern my_bool mysql_install_plugin(THD *thd, LEX_STRING *name, LEX_STRING *dl);
extern my_bool mysql_uninstall_plugin(THD *thd, LEX_STRING *name);
#endif

--- New file ---
+++ strings/my_strchr.c	05/10/15 21:03:48
/* Copyright (C) 2005 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/*
  my_strchr(cs, str, end, c) returns a pointer to the first place in
  str where c (1-byte character) occurs, or NULL if c does not occur
  in str. This function is multi-byte safe.
  TODO: should be moved to CHARSET_INFO if it's going to be called
  frequently.
*/

#include <my_global.h>
#include "m_string.h"
#include "m_ctype.h"


byte *my_strchr(CHARSET_INFO *cs, const char *str, const char *end,
                       char c)
{
  uint mbl;
  while (str < end)
  {
    mbl= my_mbcharlen(cs, *(uchar *)str);
    if (mbl < 2)
    {
      if (*str == c)
        return((char *)str);
      str++;
    }
    else
      str+= mbl;
  }
  return(0);
}



--- 1.28/mysql-test/r/system_mysql_db.result	2005-09-27 23:10:55 +05:00
+++ 1.29/mysql-test/r/system_mysql_db.result	2005-10-15 21:03:46 +05:00
@@ -9,6 +9,7 @@
 help_relation
 help_topic
 host
+plugin
 proc
 procs_priv
 tables_priv

--- 1.17/mysql-test/t/system_mysql_db_fix.test	2005-09-16 00:17:37 +05:00
+++ 1.18/mysql-test/t/system_mysql_db_fix.test	2005-10-15 21:03:46 +05:00
@@ -85,7 +85,7 @@
 
 -- disable_query_log
 
-DROP TABLE db, host, user, func, tables_priv, columns_priv, procs_priv, help_category,
help_keyword, help_relation, help_topic, proc, time_zone, time_zone_leap_second,
time_zone_name, time_zone_transition, time_zone_transition_type;
+DROP TABLE db, host, user, func, plugin, tables_priv, columns_priv, procs_priv,
help_category, help_keyword, help_relation, help_topic, proc, time_zone,
time_zone_leap_second, time_zone_name, time_zone_transition, time_zone_transition_type;
 
 -- enable_query_log
 

--- 1.23/scripts/mysql_create_system_tables.sh	2005-10-06 13:25:57 +05:00
+++ 1.24/scripts/mysql_create_system_tables.sh	2005-10-15 21:03:46 +05:00
@@ -39,8 +39,8 @@
 c_hr="" 
 c_hk="" 
 i_ht=""
-c_tzn="" c_tz="" c_tzt="" c_tztt="" c_tzls=""
-i_tzn="" i_tz="" i_tzt="" i_tztt="" i_tzls=""
+c_tzn="" c_tz="" c_tzt="" c_tztt="" c_tzls="" c_pl=""
+i_tzn="" i_tz="" i_tzt="" i_tztt="" i_tzls="" i_pl=""
 c_p="" c_pp=""
 
 # Check for old tables
@@ -202,6 +202,21 @@
   c_f="$c_f   comment='User defined functions';"
 fi
 
+if test ! -f $mdata/plugin.frm
+then
+  if test "$1" = "verbose" ; then
+    echo "Preparing plugin table" 1>&2;
+  fi
+
+  c_pl="$c_pl CREATE TABLE plugin ("
+  c_pl="$c_pl   name char(64) binary DEFAULT '' NOT NULL,"
+  c_pl="$c_pl   dl char(128) DEFAULT '' NOT NULL,"
+  c_pl="$c_pl   PRIMARY KEY (name)"
+  c_pl="$c_pl ) engine=MyISAM"
+  c_pl="$c_pl CHARACTER SET utf8 COLLATE utf8_bin"
+  c_pl="$c_pl   comment='MySQL plugins';"
+fi
+
 if test ! -f $mdata/tables_priv.frm
 then
   if test "$1" = "verbose" ; then
@@ -740,6 +755,9 @@
 
 $c_f
 $i_f
+
+$c_pl
+$i_pl
 
 $c_t
 $c_c
Thread
bk commit into 5.1 tree (svoj:1.1932)svoj15 Oct