diff options
author | monty@mysql.com <> | 2005-11-05 13:20:35 +0200 |
---|---|---|
committer | monty@mysql.com <> | 2005-11-05 13:20:35 +0200 |
commit | cdf64f0f5724077d58158ecc8894cfff85dbc9c0 (patch) | |
tree | 460c9bc04fe66682e1873d2b1e848a224ae7eb8d /sql | |
parent | a6f5375cb0cb40055f52e92d20ca04233ce70386 (diff) | |
download | mariadb-git-cdf64f0f5724077d58158ecc8894cfff85dbc9c0.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.
Diffstat (limited to 'sql')
-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 |
14 files changed, 862 insertions, 70 deletions
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) { |