diff options
author | unknown <monty@mysql.com> | 2005-11-05 13:20:35 +0200 |
---|---|---|
committer | unknown <monty@mysql.com> | 2005-11-05 13:20:35 +0200 |
commit | 9314a20745060e4915c6a253d7e58828f46e63bd (patch) | |
tree | 460c9bc04fe66682e1873d2b1e848a224ae7eb8d | |
parent | 2361720c981fc2eb27bc97c1ea7e043b634ffae1 (diff) | |
download | mariadb-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-- | .bzrignore | 1 | ||||
-rw-r--r-- | include/Makefile.am | 2 | ||||
-rw-r--r-- | include/m_ctype.h | 2 | ||||
-rw-r--r-- | include/my_base.h | 6 | ||||
-rw-r--r-- | include/plugin.h | 181 | ||||
-rw-r--r-- | libmysqld/Makefile.am | 4 | ||||
-rw-r--r-- | mysql-test/r/ndb_gis.result | 4 | ||||
-rw-r--r-- | sql/Makefile.am | 7 | ||||
-rw-r--r-- | sql/ha_heap.h | 4 | ||||
-rw-r--r-- | sql/ha_partition.cc | 14 | ||||
-rw-r--r-- | sql/handler.cc | 10 | ||||
-rw-r--r-- | sql/handler.h | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/records.cc | 2 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sql_partition.cc | 42 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 622 | ||||
-rw-r--r-- | sql/sql_plugin.h | 63 | ||||
-rw-r--r-- | sql/structs.h | 9 | ||||
-rw-r--r-- | sql/table.cc | 92 | ||||
-rw-r--r-- | sql/unireg.cc | 58 | ||||
-rw-r--r-- | strings/Makefile.am | 8 | ||||
-rw-r--r-- | strings/my_strchr.c | 48 |
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); +} + |