summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <monty@mysql.com>2005-11-05 13:20:35 +0200
committerunknown <monty@mysql.com>2005-11-05 13:20:35 +0200
commit9314a20745060e4915c6a253d7e58828f46e63bd (patch)
tree460c9bc04fe66682e1873d2b1e848a224ae7eb8d
parent2361720c981fc2eb27bc97c1ea7e043b634ffae1 (diff)
downloadmariadb-git-9314a20745060e4915c6a253d7e58828f46e63bd.tar.gz
Fix of crashed 5.1 tree (wrong merge + wrong pullout patch forced us to create a new 5.1 tree)
This is a merge of 5.0 -> 5.1 + some code from old 5.1 tree to get all tests to work and keep the .frm format the same as the old 5.1 tree. BitKeeper/etc/ignore: added libmysqld/sql_plugin.cc include/Makefile.am: Added plugin.hd include/m_ctype.h: Added my_strchr include/my_base.h: Added HA_USES_PARSER Merge with old 5.1 tree libmysqld/Makefile.am: Added sql_plugin.cc mysql-test/r/ndb_gis.result: Fixed results after merge sql/Makefile.am: Addes sql_plugin.h and sql_plugin.cc sql/ha_heap.h: Indentation fix sql/ha_partition.cc: Made partition_hton visible outside After merge fixes (for call to get_new_handler) sql/handler.cc: Added partition_hton to handlerton sql/handler.h: Added partion to handlerton Updated mysql_unpack_partion() from old 5.1 tree sql/mysql_priv.h: Added sql_plugin.h sql/records.cc: After merge fix sql/share/errmsg.txt: Added new errors messages from old 5.1 tree sql/sql_partition.cc: Removed compiler warnings Updated mysql_unpack_partition() from latest 5.1 tree sql/structs.h: Update KEY from latest 5.1 tree (to get table.cc to compile) sql/table.cc: Merged .frm format from 5.0, new 5.1 and old 5.1 tree (We now use same format as the old 5.1 tree) Note that this patch includes code for HA_USE_PARSER which is not usable until rest of 5.1 tree is restored sql/unireg.cc: Merged .frm format from 5.0, new 5.1 and old 5.1 tree (We now use same format as the old 5.1 tree) Note that this patch includes code for HA_USE_PARSER which is not usable until rest of 5.1 tree is restored strings/Makefile.am: Added my_strchr.c include/plugin.h: New BitKeeper file ``include/plugin.h'' sql/sql_plugin.cc: New BitKeeper file ``sql/sql_plugin.cc'' sql/sql_plugin.h: New BitKeeper file ``sql/sql_plugin.h'' strings/my_strchr.c: New BitKeeper file ``strings/my_strchr.c''
-rw-r--r--.bzrignore1
-rw-r--r--include/Makefile.am2
-rw-r--r--include/m_ctype.h2
-rw-r--r--include/my_base.h6
-rw-r--r--include/plugin.h181
-rw-r--r--libmysqld/Makefile.am4
-rw-r--r--mysql-test/r/ndb_gis.result4
-rw-r--r--sql/Makefile.am7
-rw-r--r--sql/ha_heap.h4
-rw-r--r--sql/ha_partition.cc14
-rw-r--r--sql/handler.cc10
-rw-r--r--sql/handler.h6
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/records.cc2
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sql_partition.cc42
-rw-r--r--sql/sql_plugin.cc622
-rw-r--r--sql/sql_plugin.h63
-rw-r--r--sql/structs.h9
-rw-r--r--sql/table.cc92
-rw-r--r--sql/unireg.cc58
-rw-r--r--strings/Makefile.am8
-rw-r--r--strings/my_strchr.c48
23 files changed, 1104 insertions, 84 deletions
diff --git a/.bzrignore b/.bzrignore
index 7294be6cb60..d170e7f9027 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1537,3 +1537,4 @@ vio/test-ssl
vio/test-sslclient
vio/test-sslserver
vio/viotest-ssl
+libmysqld/sql_plugin.cc
diff --git a/include/Makefile.am b/include/Makefile.am
index 9f5570f8af4..8c3a575453d 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -22,7 +22,7 @@ pkginclude_HEADERS = my_dbug.h m_string.h my_sys.h my_list.h my_xml.h \
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\
diff --git a/include/m_ctype.h b/include/m_ctype.h
index b7361cb7d7b..7bc05e98d76 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -399,6 +399,8 @@ int my_wildcmp_unicode(CHARSET_INFO *cs,
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);
diff --git a/include/my_base.h b/include/my_base.h
index 4a6a384c438..c11e52fb996 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -209,12 +209,8 @@ enum ha_base_keytype {
#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
diff --git a/include/plugin.h b/include/plugin.h
new file mode 100644
index 00000000000..038fefce21e
--- /dev/null
+++ b/include/plugin.h
@@ -0,0 +1,181 @@
+/* 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
+
+/*************************************************************************
+ Plugin API. Common for all plugin types.
+*/
+
+#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0000
+
+/*
+ The allowable types of plugins
+*/
+#define MYSQL_UDF_PLUGIN 0 /* User-defined function */
+#define MYSQL_STORAGE_ENGINE_PLUGIN 1 /* Storage Engine */
+#define MYSQL_FTPARSER_PLUGIN 2 /* Full-text [pre]parser */
+#define MYSQL_MAX_PLUGIN_TYPE_NUM 3 /* The number of plugin types */
+
+/*
+ Macros for beginning and ending plugin declarations. Between
+ mysql_declare_plugin and mysql_declare_plugin_end there should
+ be a st_mysql_plugin struct for each plugin to be declared.
+*/
+
+#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}}
+
+/*
+ Plugin description structure.
+*/
+
+struct st_mysql_plugin
+{
+ int type; /* the plugin type (a MYSQL_XXX_PLUGIN value) */
+ void *info; /* pointer to type-specific plugin descriptor */
+ const char *name; /* plugin name */
+ const char *author; /* plugin author (for SHOW PLUGINS) */
+ const char *descr; /* general descriptive text (for SHOW PLUGINS ) */
+ int (*init)(void); /* the function to invoke when plugin is loaded */
+ int (*deinit)(void); /* the function to invoke when plugin is unloaded */
+};
+
+/*************************************************************************
+ API for Full-text [pre]parser plugin. (MYSQL_FTPARSER_PLUGIN)
+*/
+
+#define MYSQL_FTPARSER_INTERFACE_VERSION 0x0000
+
+/* Parsing modes. Set in MYSQL_FTPARSER_PARAM::mode */
+/*
+ The fast and simple mode. Parser is expected to return only those words that
+ go into the index. Stopwords or too short/long words should not be returned.
+ 'boolean_info' argument of mysql_add_word() does not have to be set.
+
+ This mode is used for indexing, and natural language queries.
+*/
+#define MYSQL_FTPARSER_SIMPLE_MODE 0
+
+/*
+ The parser is not allowed to ignore words in this mode. Every word should
+ be returned, including stopwords and words that are too short or long.
+ 'boolean_info' argument of mysql_add_word() does not have to be set.
+
+ This mode is used in boolean searches for "phrase matching."
+*/
+#define MYSQL_FTPARSER_WITH_STOPWORDS 1
+
+/*
+ Parse in boolean mode. The parser should provide a valid
+ MYSQL_FTPARSER_BOOLEAN_INFO structure in the 'boolean_info' argument
+ to mysql_add_word(). Usually that means that the parser should
+ recognize boolean operators in the parsing stream and set appropriate
+ fields in MYSQL_FTPARSER_BOOLEAN_INFO structure accordingly. As
+ for MYSQL_FTPARSER_WITH_STOPWORDS mode, no word should be ignored.
+ Instead, use FT_TOKEN_STOPWORD for the token type of such a word.
+
+ This mode is used to parse a boolean query string.
+*/
+#define MYSQL_FTPARSER_FULL_BOOLEAN_INFO 2
+
+enum enum_ft_token_type
+{
+ FT_TOKEN_EOF= 0,
+ FT_TOKEN_WORD= 1,
+ FT_TOKEN_LEFT_PAREN= 2,
+ FT_TOKEN_RIGHT_PAREN= 3,
+ FT_TOKEN_STOPWORD= 4
+};
+
+/*
+ This structure is used in boolean search mode only. It conveys
+ boolean-mode metadata to the MySQL search engine for every word in
+ the search query. A valid instance of this structure must be filled
+ in by the plugin parser and passed as an argument in the call to
+ mysql_add_word (the function from structure MYSQL_FTPARSER_PARAM)
+ when a query is parsed in boolean mode.
+*/
+
+typedef struct st_mysql_ftparser_boolean_info
+{
+ enum enum_ft_token_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;
+
+
+/*
+ An argument of the full-text parser plugin. This structure is
+ filled by MySQL server and passed to the parsing function of the
+ plugin as an in/out parameter.
+*/
+
+typedef struct st_mysql_ftparser_param
+{
+ /*
+ A fallback pointer to the built-in parser implementation
+ of the server. It's set by the server and can be used
+ by the parser plugin to invoke the MySQL default parser.
+ If plugin's role is to extract textual data from .doc,
+ .pdf or .xml content, it might use the default MySQL parser
+ to parse the extracted plaintext string.
+ */
+ int (*mysql_parse)(void *param, byte *doc, uint doc_len);
+ /*
+ A server callback to add a new word.
+ When parsing a document, the server sets this to point at
+ a function that adds the word to MySQL full-text index.
+ When parsing a search query, this function will
+ add the new word to the list of words to search for.
+ boolean_info can be NULL for all cases except
+ MYSQL_FTPARSER_FULL_BOOLEAN_INFO mode.
+ */
+ int (*mysql_add_word)(void *param, byte *word, uint word_len,
+ MYSQL_FTPARSER_BOOLEAN_INFO *boolean_info);
+ /* A pointer to the parser local state. This is an inout parameter. */
+ void *ftparser_state;
+ void *mysql_ftparam;
+ /* Character set of the document or the query */
+ CHARSET_INFO *cs;
+ /* A pointer to the document or the query to be parsed */
+ byte *doc;
+ /* Document/query length */
+ uint length;
+ /*
+ Parsing mode: with boolean operators, with stopwords, or nothing.
+ See MYSQL_FTPARSER_* constants above.
+ */
+ int mode;
+} 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
+
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index f5479bfb207..a59bf74e239 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -64,7 +64,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.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 \
- ha_blackhole.cc ha_archive.cc sql_partition.cc ha_partition.cc
+ ha_blackhole.cc ha_archive.cc sql_partition.cc ha_partition.cc \
+ sql_plugin.cc
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources) $(sqlexamplessources)
libmysqld_a_SOURCES=
@@ -83,7 +84,6 @@ INC_LIB= $(top_builddir)/regex/libregex.a \
$(top_builddir)/dbug/libdbug.a \
$(top_builddir)/vio/libvio.a \
@yassl_libs_with_path@
-
#
# To make it easy for the end user to use the embedded library we
diff --git a/mysql-test/r/ndb_gis.result b/mysql-test/r/ndb_gis.result
index 43075306bd2..f49572b893b 100644
--- a/mysql-test/r/ndb_gis.result
+++ b/mysql-test/r/ndb_gis.result
@@ -13,7 +13,7 @@ Table Create Table
gis_point CREATE TABLE `gis_point` (
`fid` int(11) default NULL,
`g` point default NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1
+) ENGINE=NDBCLUSTER DEFAULT CHARSET=latin1
SHOW FIELDS FROM gis_point;
Field Type Null Key Default Extra
fid int(11) YES NULL
@@ -471,7 +471,7 @@ Table Create Table
gis_point CREATE TABLE `gis_point` (
`fid` int(11) default NULL,
`g` point default NULL
-) ENGINE=ndbcluster DEFAULT CHARSET=latin1
+) ENGINE=NDBCLUSTER DEFAULT CHARSET=latin1
SHOW FIELDS FROM gis_point;
Field Type Null Key Default Extra
fid int(11) YES NULL
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 98d4d6b3d3a..f1d43c9c660 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -66,7 +66,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
sql_array.h sql_cursor.h \
examples/ha_example.h ha_archive.h \
examples/ha_tina.h ha_blackhole.h \
- ha_federated.h ha_partition.h
+ ha_federated.h ha_partition.h \
+ sql_plugin.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -104,8 +105,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
examples/ha_example.cc ha_archive.cc \
examples/ha_tina.cc ha_blackhole.cc \
ha_partition.cc sql_partition.cc \
- ha_federated.cc
-
+ ha_federated.cc \
+ sql_plugin.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
mysql_tzinfo_to_sql_SOURCES = mysql_tzinfo_to_sql.cc
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 24097460a24..4a01b3317f1 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -40,8 +40,8 @@ public:
}
const char *index_type(uint inx)
{
- return ((table->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ? "BTREE" :
- "HASH");
+ return ((table->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ?
+ "BTREE" : "HASH");
}
/* Rows also use a fixed-size format */
enum row_type get_row_type() const { return ROW_TYPE_FIXED; }
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 5bcd3b8eb52..a7cf6eea49c 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -67,10 +67,10 @@ static PARTITION_SHARE *get_share(const char *table_name, TABLE * table);
MODULE create/delete handler object
****************************************************************************/
-static handlerton partition_hton = {
+handlerton partition_hton = {
"partition",
SHOW_OPTION_YES,
- "", /* A comment used by SHOW to describe an engine */
+ "Partition engine", /* A comment used by SHOW to describe an engine */
DB_TYPE_PARTITION_DB,
0, /* Method that initizlizes a storage engine */
0, /* slot */
@@ -701,7 +701,8 @@ bool ha_partition::create_handlers()
bzero(m_file, alloc_len);
for (i= 0; i < m_tot_parts; i++)
{
- if (!(m_file[i]= get_new_handler(table, (enum db_type) m_engine_array[i])))
+ if (!(m_file[i]= get_new_handler(table, current_thd->mem_root,
+ (enum db_type) m_engine_array[i])))
DBUG_RETURN(TRUE);
DBUG_PRINT("info", ("engine_type: %u", m_engine_array[i]));
}
@@ -727,6 +728,7 @@ bool ha_partition::new_handlers_from_part_info()
partition_element *part_elem;
uint alloc_len= (m_tot_parts + 1) * sizeof(handler*);
List_iterator_fast <partition_element> part_it(m_part_info->partitions);
+ THD *thd= current_thd;
DBUG_ENTER("ha_partition::new_handlers_from_part_info");
if (!(m_file= (handler **) sql_alloc(alloc_len)))
@@ -743,14 +745,16 @@ bool ha_partition::new_handlers_from_part_info()
do
{
part_elem= part_it++;
- if (!(m_file[i]= get_new_handler(table, part_elem->engine_type)))
+ if (!(m_file[i]= get_new_handler(table, thd->mem_root,
+ part_elem->engine_type)))
goto error;
DBUG_PRINT("info", ("engine_type: %u", (uint) part_elem->engine_type));
if (m_is_sub_partitioned)
{
for (j= 0; j < m_part_info->no_subparts; j++)
{
- if (!(m_file[i]= get_new_handler(table, part_elem->engine_type)))
+ if (!(m_file[i]= get_new_handler(table, thd->mem_root,
+ part_elem->engine_type)))
goto error;
DBUG_PRINT("info", ("engine_type: %u", (uint) part_elem->engine_type));
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 1ec4ddf17b7..1b2cae7f7f2 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -62,6 +62,13 @@ handlerton example_hton = { "EXAMPLE", SHOW_OPTION_NO,
#endif
#ifdef HAVE_PARTITION_DB
#include "ha_partition.h"
+extern handlerton partition_hton;
+#else
+handlerton partition_hton = { "partition", SHOW_OPTION_NO,
+ "Partition engine",
+ DB_TYPE_EXAMPLE_DB, NULL, 0, 0, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ HTON_NO_FLAGS };
#endif
#ifdef HAVE_ARCHIVE_DB
#include "ha_archive.h"
@@ -155,6 +162,7 @@ handlerton *sys_table_types[]=
&myisammrg_hton,
&binlog_hton,
&isam_hton,
+ &partition_hton,
NULL
};
@@ -386,6 +394,8 @@ handler *get_new_handler(TABLE *table, MEM_ROOT *alloc, enum db_type db_type)
delete file;
file=0;
}
+ }
+ return file;
}
diff --git a/sql/handler.h b/sql/handler.h
index 8d749c5fc33..f5f0afa00d5 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -126,7 +126,7 @@
example + csv + heap + blackhole + federated + 0
(yes, the sum is deliberately inaccurate)
*/
-#define MAX_HA 14
+#define MAX_HA 15
/*
Bits in index_ddl_flags(KEY *wanted_index)
@@ -722,8 +722,8 @@ void get_full_part_id_from_key(const TABLE *table, byte *buf,
KEY *key_info,
const key_range *key_spec,
part_id_range *part_spec);
-bool mysql_unpack_partition(File file, THD *thd, uint part_info_len,
- TABLE *table, enum db_type default_db_type);
+bool mysql_unpack_partition(THD *thd, uchar *part_buf, uint part_info_len,
+ TABLE* table, enum db_type default_db_type);
#endif
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a967e2ee7fe..99cf2822ede 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -489,6 +489,7 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
#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;
diff --git a/sql/records.cc b/sql/records.cc
index 4958e39a5a0..ff0185195b0 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -65,7 +65,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
table->status=0; /* And it's always found */
if (!table->file->inited)
{
- table->file->ha_index_init(idx);
+ table->file->ha_index_init(idx, 1);
table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY);
}
/* read_record will be changed to rr_index in rr_index_first */
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 5c2cc77d66a..ded1c5e5f56 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5540,3 +5540,5 @@ ER_DROP_PARTITION_FAILURE
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 när en främmande nyckel är definierad på tabellen"
+ER_PLUGIN_IS_NOT_LOADED
+ eng "Plugin '%-.64s' is not loaded"
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 906d1cd40a8..ce73061271c 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -42,18 +42,18 @@
/*
Partition related functions declarations and some static constants;
*/
-static char *hash_str= "HASH";
-static char *range_str= "RANGE";
-static char *list_str= "LIST";
-static char *part_str= "PARTITION";
-static char *sub_str= "SUB";
-static char *by_str= "BY";
-static char *key_str= "KEY";
-static char *space_str= " ";
-static char *equal_str= "=";
-static char *end_paren_str= ")";
-static char *begin_paren_str= "(";
-static char *comma_str= ",";
+static const char *hash_str= "HASH";
+static const char *range_str= "RANGE";
+static const char *list_str= "LIST";
+static const char *part_str= "PARTITION";
+static const char *sub_str= "SUB";
+static const char *by_str= "BY";
+static const char *key_str= "KEY";
+static const char *space_str= " ";
+static const char *equal_str= "=";
+static const char *end_paren_str= ")";
+static const char *begin_paren_str= "(";
+static const char *comma_str= ",";
static char buff[22];
bool get_partition_id_list(partition_info *part_info,
@@ -571,7 +571,7 @@ static bool set_up_default_partitions(partition_info *part_info,
if (part_info->part_type != HASH_PARTITION)
{
- char *error_string;
+ const char *error_string;
if (part_info->part_type == RANGE_PARTITION)
error_string= range_str;
else
@@ -1704,7 +1704,7 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table)
}
else
{
- char *error_str;
+ const char *error_str;
if (part_info->part_type == RANGE_PARTITION)
{
error_str= range_str;
@@ -1764,7 +1764,7 @@ end:
static int add_write(File fptr, const char *buf, uint len)
{
- uint len_written= my_write(fptr, buf, len, MYF(0));
+ uint len_written= my_write(fptr, (const byte*)buf, len, MYF(0));
if (likely(len == len_written))
return 0;
else
@@ -2117,7 +2117,7 @@ char *generate_partition_syntax(partition_info *part_info,
if (!buf)
goto close_file;
- if (unlikely(my_read(fptr, buf, *buf_length, MYF(MY_FNABP))))
+ if (unlikely(my_read(fptr, (byte*)buf, *buf_length, MYF(MY_FNABP))))
{
if (!use_sql_alloc)
my_free(buf, MYF(0));
@@ -2896,7 +2896,8 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
{
partition_info *part_info= table->s->part_info;
uint no_parts= get_tot_partitions(part_info), i, part_id;
- uint sub_part= no_parts, part_part= no_parts;
+ uint sub_part= no_parts;
+ uint32 part_part= no_parts;
KEY *key_info= NULL;
bool found_part_field= FALSE;
DBUG_ENTER("get_partition_set");
@@ -3080,17 +3081,14 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
possible to retrace this given an item tree.
*/
-bool mysql_unpack_partition(File file, THD *thd, uint part_info_len,
+bool mysql_unpack_partition(THD *thd, uchar *part_buf, uint part_info_len,
TABLE* table, enum db_type default_db_type)
{
Item *thd_free_list= thd->free_list;
bool result= TRUE;
- uchar* part_buf= NULL;
partition_info *part_info;
LEX *old_lex= thd->lex, lex;
DBUG_ENTER("mysql_unpack_partition");
- if (read_string(file, (gptr*)&part_buf, part_info_len))
- DBUG_RETURN(result);
thd->lex= &lex;
lex_start(thd, part_buf, part_info_len);
/*
@@ -3160,7 +3158,6 @@ bool mysql_unpack_partition(File file, THD *thd, uint part_info_len,
result= FALSE;
end:
thd->free_list= thd_free_list;
- x_free((gptr)part_buf);
thd->lex= old_lex;
DBUG_RETURN(result);
}
@@ -3229,4 +3226,3 @@ void set_key_field_ptr(KEY *key_info, const byte *new_buf,
} while (++i < key_parts);
DBUG_VOID_RETURN;
}
-
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
new file mode 100644
index 00000000000..efe8f256af5
--- /dev/null
+++ b/sql/sql_plugin.cc
@@ -0,0 +1,622 @@
+/* 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_ptr;
+char opt_plugin_dir[FN_REFLEN];
+
+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 HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM];
+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");
+ 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, FN_LIBCHAR) ||
+ 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);
+ if (type == MYSQL_ANY_PLUGIN)
+ {
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ {
+ struct st_plugin_int *plugin= (st_plugin_int *)
+ hash_search(&plugin_hash[i], name->str, name->length);
+ if (plugin)
+ DBUG_RETURN(plugin);
+ }
+ }
+ else
+ DBUG_RETURN((st_plugin_int *)
+ hash_search(&plugin_hash[type], name->str, name->length));
+ DBUG_RETURN(0);
+}
+
+
+my_bool plugin_is_ready(LEX_STRING *name, int type)
+{
+ my_bool rc= FALSE;
+ struct st_plugin_int *plugin;
+ DBUG_ENTER("plugin_is_ready");
+ rw_rdlock(&THR_LOCK_plugin);
+ if ((plugin= plugin_find_internal(name, type)) &&
+ plugin->state == PLUGIN_IS_READY)
+ 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)))
+ {
+ if (rc->state == PLUGIN_IS_READY)
+ rc->ref_count++;
+ else
+ rc= 0;
+ }
+ 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->info; plugin++)
+ {
+ uint name_len= strlen(plugin->name);
+ if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM &&
+ ! 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));
+ goto err;
+ }
+ if (my_hash_insert(&plugin_hash[plugin->type],
+ (byte*)dynamic_element(&plugin_array,
+ plugin_array.elements - 1,
+ struct st_plugin_int *)))
+ {
+ struct st_plugin_int *tmp_plugin= dynamic_element(&plugin_array,
+ plugin_array.elements - 1, struct st_plugin_int *);
+ tmp_plugin->state= PLUGIN_IS_FREED;
+ 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));
+ goto err;
+ }
+ 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);
+err:
+ plugin_dl_del(dl);
+ DBUG_RETURN(TRUE);
+}
+
+
+static void plugin_del(LEX_STRING *name)
+{
+ uint i;
+ struct st_plugin_int *plugin;
+ DBUG_ENTER("plugin_del");
+ if ((plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
+ {
+ hash_delete(&plugin_hash[plugin->plugin->type], (byte*)plugin);
+ plugin_dl_del(&plugin->plugin_dl->dl);
+ plugin->state= PLUGIN_IS_FREED;
+ }
+ 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;
+}
+
+
+static byte *get_hash_key(const byte *buff, uint *length,
+ my_bool not_used __attribute__((unused)))
+{
+ struct st_plugin_int *plugin= (st_plugin_int *)buff;
+ *length= (uint)plugin->name.length;
+ return((byte *)plugin->name.str);
+}
+
+
+void plugin_init(void)
+{
+ TABLE_LIST tables;
+ TABLE *table;
+ READ_RECORD read_record_info;
+ int error, i;
+ 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;
+ }
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ {
+ if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0,
+ get_hash_key, NULL, 0))
+ {
+ 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);
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ hash_free(&plugin_hash[i]);
+ 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();
+ for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
+ hash_free(&plugin_hash[i]);
+ 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,
+ "Plugin initialization function failed.");
+ goto err;
+ }
+ tmp->state= PLUGIN_IS_READY;
+ }
+ if (! (table = open_ltable(thd, &tables, TL_WRITE)))
+ goto deinit;
+ restore_record(table, s->default_values);
+ 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);
+}
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
new file mode 100644
index 00000000000..8fb186b62de
--- /dev/null
+++ b/sql/sql_plugin.h
@@ -0,0 +1,63 @@
+/* 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>
+
+#define MYSQL_ANY_PLUGIN -1
+
+enum enum_plugin_state
+{
+ PLUGIN_IS_FREED= 0,
+ PLUGIN_IS_DELETED,
+ PLUGIN_IS_UNINITIALIZED,
+ PLUGIN_IS_READY
+};
+
+/* A handle for the dynamic library containing a plugin or plugins. */
+
+struct st_plugin_dl
+{
+ LEX_STRING dl;
+ void *handle;
+ struct st_mysql_plugin *plugins;
+ int version;
+ uint ref_count; /* number of plugins loaded from the library */
+};
+
+/* A handle of a plugin */
+
+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; /* number of threads using the plugin */
+};
+
+extern char *opt_plugin_dir_ptr;
+extern char opt_plugin_dir[FN_REFLEN];
+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
diff --git a/sql/structs.h b/sql/structs.h
index 3c651c491d3..77d0d435154 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -89,6 +89,15 @@ typedef struct st_key {
uint extra_length;
uint usable_key_parts; /* Should normally be = key_parts */
enum ha_key_alg algorithm;
+ /*
+ Note that parser is used when the table is opened for use, and
+ parser_name is used when the table is being created.
+ */
+ union
+ {
+ struct st_plugin_int *parser; /* Fulltext [pre]parser */
+ LEX_STRING *parser_name; /* Fulltext [pre]parser name */
+ };
KEY_PART_INFO *key_part;
char *name; /* Name of key */
/*
diff --git a/sql/table.cc b/sql/table.cc
index 776dcdf66fe..a163f671d01 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -70,7 +70,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
int j,error, errarg= 0;
uint rec_buff_length,n_length,int_length,records,key_parts,keys,
interval_count,interval_parts,read_length,db_create_options;
- uint key_info_length, com_length, part_info_len, extra_rec_buf_length;
+ uint key_info_length, com_length, part_info_len=0, extra_rec_buf_length;
ulong pos, record_offset;
char index_file[FN_REFLEN], *names, *keynames, *comment_pos;
uchar head[288],*disk_buff,new_field_pack_flag;
@@ -154,7 +154,6 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
goto err; /* purecov: inspected */
*fn_ext(index_file)='\0'; // Remove .frm extension
- part_info_len= uint4korr(head+55);
share->frm_version= head[2];
/*
Check if .frm file created by MySQL 5.0. In this case we want to
@@ -311,9 +310,9 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
{
/* Read extra data segment */
char *buff, *next_chunk, *buff_end;
+ DBUG_PRINT("info", ("extra segment size is %u bytes", n_length));
if (!(next_chunk= buff= my_malloc(n_length, MYF(MY_WME))))
goto err;
- buff_end= buff + n_length;
if (my_pread(file, (byte*)buff, n_length, record_offset + share->reclength,
MYF(MY_NABP)))
{
@@ -328,16 +327,82 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
goto err;
}
next_chunk+= share->connect_string.length + 2;
+ buff_end= buff + n_length;
if (next_chunk + 2 < buff_end)
{
uint str_db_type_length= uint2korr(next_chunk);
- share->db_type= ha_resolve_by_name(next_chunk + 2, str_db_type_length);
- DBUG_PRINT("enter", ("Setting dbtype to: %d - %d - '%.*s'\n",
- share->db_type,
- str_db_type_length, str_db_type_length,
- next_chunk + 2));
+ enum db_type tmp_db_type= ha_resolve_by_name(next_chunk + 2,
+ str_db_type_length);
+ if (tmp_db_type != DB_TYPE_UNKNOWN)
+ {
+ share->db_type= tmp_db_type;
+ DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)",
+ str_db_type_length, next_chunk + 2,
+ share->db_type));
+ }
+#ifdef HAVE_PARTITION_DB
+ else
+ {
+ if (!strncmp(next_chunk + 2, "partition", str_db_type_length))
+ {
+ /* Use partition handler */
+ share->db_type= DB_TYPE_PARTITION_DB;
+ DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)",
+ str_db_type_length, next_chunk + 2,
+ share->db_type));
+ }
+ }
+#endif
next_chunk+= str_db_type_length + 2;
}
+ if (next_chunk + 4 < buff_end)
+ {
+ part_info_len= uint4korr(next_chunk);
+ if (part_info_len > 0)
+ {
+#ifdef HAVE_PARTITION_DB
+ if (mysql_unpack_partition(thd, (uchar *)(next_chunk + 4),
+ part_info_len, outparam,
+ default_part_db_type))
+ {
+ DBUG_PRINT("info", ("mysql_unpack_partition failed"));
+ my_free(buff, MYF(0));
+ goto err;
+ }
+#else
+ DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE 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));
}
@@ -471,16 +536,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat,
if (keynames)
fix_type_pointers(&int_array, &share->keynames, 1, &keynames);
- if (part_info_len > 0)
- {
-#ifdef HAVE_PARTITION_DB
- if (mysql_unpack_partition(file, thd, part_info_len,
- outparam, default_part_db_type))
- goto err;
-#else
- goto err;
-#endif
- }
+
VOID(my_close(file,MYF(MY_WME)));
file= -1;
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 86f4b49292a..32f533a6072 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -77,14 +77,14 @@ bool mysql_create_frm(THD *thd, my_string file_name,
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;
uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames;
uchar *screen_buff;
- char buff[2];
+ char buff[5];
#ifdef HAVE_PARTITION_DB
partition_info *part_info= thd->lex->part_info;
#endif
@@ -127,8 +127,21 @@ bool mysql_create_frm(THD *thd, my_string file_name,
/* 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 +
2 + create_info->connect_string.length);
+ /* Partition */
+ create_info->extra_size+= 5;
+#ifdef HAVE_PARTITION_DB
+ if (part_info)
+ create_info->extra_size+= part_info->part_info_len;
+#endif
+
+ for (i= 0; i < keys; i++)
+ {
+ if (key_info[i].parser_name)
+ 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)
@@ -155,10 +168,7 @@ bool mysql_create_frm(THD *thd, my_string file_name,
#ifdef HAVE_PARTITION_DB
if (part_info)
- {
- int4store(fileinfo+55,part_info->part_info_len);
fileinfo[61]= (uchar) part_info->default_engine_type;
- }
#endif
int2store(fileinfo+59,db_file->extra_rec_buf_length());
if (my_pwrite(file,(byte*) fileinfo,64,0L,MYF_RW) ||
@@ -173,31 +183,49 @@ bool mysql_create_frm(THD *thd, my_string file_name,
goto err;
int2store(buff, create_info->connect_string.length);
- if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) ||
+ if (my_write(file, (const byte*)buff, 2, MYF(MY_NABP)) ||
my_write(file, (const byte*)create_info->connect_string.str,
create_info->connect_string.length, MYF(MY_NABP)))
goto err;
int2store(buff, str_db_type.length);
- if (my_write(file, (const byte*)buff, sizeof(buff), MYF(MY_NABP)) ||
+ if (my_write(file, (const byte*)buff, 2, MYF(MY_NABP)) ||
my_write(file, (const byte*)str_db_type.str,
str_db_type.length, 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) ||
- pack_fields(file, create_fields, data_offset))
- goto err;
#ifdef HAVE_PARTITION_DB
if (part_info)
{
- if (my_write(file, (byte*) part_info->part_info_string,
- part_info->part_info_len, MYF_RW))
+ int4store(buff, part_info->part_info_len);
+ 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
#endif
+ {
+ bzero(buff, 5);
+ if (my_write(file, (byte*) buff, 5, MYF_RW))
+ goto err;
+ }
+ for (i= 0; i < keys; i++)
+ {
+ if (key_info[i].parser_name)
+ {
+ if (my_write(file, (const byte*)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) ||
+ pack_fields(file, create_fields, data_offset))
+ goto err;
+
#ifdef HAVE_CRYPTED_FRM
if (create_info->password)
{
diff --git a/strings/Makefile.am b/strings/Makefile.am
index c43cf0f290a..b423d395778 100644
--- a/strings/Makefile.am
+++ b/strings/Makefile.am
@@ -22,19 +22,19 @@ pkglib_LIBRARIES = libmystrings.a
# 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 @@ EXTRA_DIST = ctype-big5.c ctype-cp932.c ctype-czech.c ctype-eucjpms.c ctype-euc
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
diff --git a/strings/my_strchr.c b/strings/my_strchr.c
new file mode 100644
index 00000000000..3a5fbea906d
--- /dev/null
+++ b/strings/my_strchr.c
@@ -0,0 +1,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);
+}
+