The world's most popular open source database
00001 /* Copyright (C) 2005 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #include "mysql_priv.h" 00018 #include <my_pthread.h> 00019 #define REPORT_TO_LOG 1 00020 #define REPORT_TO_USER 2 00021 00022 extern struct st_mysql_plugin *mysqld_builtins[]; 00023 00024 char *opt_plugin_dir_ptr; 00025 char opt_plugin_dir[FN_REFLEN]; 00026 const LEX_STRING plugin_type_names[MYSQL_MAX_PLUGIN_TYPE_NUM]= 00027 { 00028 { C_STRING_WITH_LEN("UDF") }, 00029 { C_STRING_WITH_LEN("STORAGE ENGINE") }, 00030 { C_STRING_WITH_LEN("FTPARSER") } 00031 }; 00032 00033 plugin_type_init plugin_type_initialize[MYSQL_MAX_PLUGIN_TYPE_NUM]= 00034 { 00035 0,ha_initialize_handlerton,0 00036 }; 00037 00038 static const char *plugin_interface_version_sym= 00039 "_mysql_plugin_interface_version_"; 00040 static const char *sizeof_st_plugin_sym= 00041 "_mysql_sizeof_struct_st_plugin_"; 00042 static const char *plugin_declarations_sym= "_mysql_plugin_declarations_"; 00043 static int min_plugin_interface_version= 0x0000; 00044 /* Note that 'int version' must be the first field of every plugin 00045 sub-structure (plugin->info). 00046 */ 00047 static int min_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= 00048 { 00049 0x0000, 00050 MYSQL_HANDLERTON_INTERFACE_VERSION, 00051 MYSQL_FTPARSER_INTERFACE_VERSION 00052 }; 00053 static int cur_plugin_info_interface_version[MYSQL_MAX_PLUGIN_TYPE_NUM]= 00054 { 00055 0x0000, /* UDF: not implemented */ 00056 MYSQL_HANDLERTON_INTERFACE_VERSION, 00057 MYSQL_FTPARSER_INTERFACE_VERSION 00058 }; 00059 00060 static DYNAMIC_ARRAY plugin_dl_array; 00061 static DYNAMIC_ARRAY plugin_array; 00062 static HASH plugin_hash[MYSQL_MAX_PLUGIN_TYPE_NUM]; 00063 static rw_lock_t THR_LOCK_plugin; 00064 static bool initialized= 0; 00065 00066 static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl) 00067 { 00068 uint i; 00069 DBUG_ENTER("plugin_dl_find"); 00070 for (i= 0; i < plugin_dl_array.elements; i++) 00071 { 00072 struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i, 00073 struct st_plugin_dl *); 00074 if (tmp->ref_count && 00075 ! my_strnncoll(files_charset_info, 00076 (const uchar *)dl->str, dl->length, 00077 (const uchar *)tmp->dl.str, tmp->dl.length)) 00078 DBUG_RETURN(tmp); 00079 } 00080 DBUG_RETURN(0); 00081 } 00082 00083 00084 static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl) 00085 { 00086 uint i; 00087 DBUG_ENTER("plugin_dl_insert_or_reuse"); 00088 for (i= 0; i < plugin_dl_array.elements; i++) 00089 { 00090 struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i, 00091 struct st_plugin_dl *); 00092 if (! tmp->ref_count) 00093 { 00094 memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl)); 00095 DBUG_RETURN(tmp); 00096 } 00097 } 00098 if (insert_dynamic(&plugin_dl_array, (gptr)plugin_dl)) 00099 DBUG_RETURN(0); 00100 DBUG_RETURN(dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1, 00101 struct st_plugin_dl *)); 00102 } 00103 00104 static inline void free_plugin_mem(struct st_plugin_dl *p) 00105 { 00106 #ifdef HAVE_DLOPEN 00107 if (p->handle) 00108 dlclose(p->handle); 00109 #endif 00110 my_free(p->dl.str, MYF(MY_ALLOW_ZERO_PTR)); 00111 if (p->version != MYSQL_PLUGIN_INTERFACE_VERSION) 00112 my_free((gptr)p->plugins, MYF(MY_ALLOW_ZERO_PTR)); 00113 } 00114 00115 static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) 00116 { 00117 #ifdef HAVE_DLOPEN 00118 char dlpath[FN_REFLEN]; 00119 uint plugin_dir_len, dummy_errors, dlpathlen; 00120 struct st_plugin_dl *tmp, plugin_dl; 00121 void *sym; 00122 DBUG_ENTER("plugin_dl_add"); 00123 plugin_dir_len= strlen(opt_plugin_dir); 00124 /* 00125 Ensure that the dll doesn't have a path. 00126 This is done to ensure that only approved libraries from the 00127 plugin directory are used (to make this even remotely secure). 00128 */ 00129 if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) || 00130 dl->length > NAME_LEN || 00131 plugin_dir_len + dl->length + 1 >= FN_REFLEN) 00132 { 00133 if (report & REPORT_TO_USER) 00134 my_error(ER_UDF_NO_PATHS, MYF(0)); 00135 if (report & REPORT_TO_LOG) 00136 sql_print_error(ER(ER_UDF_NO_PATHS)); 00137 DBUG_RETURN(0); 00138 } 00139 /* If this dll is already loaded just increase ref_count. */ 00140 if ((tmp= plugin_dl_find(dl))) 00141 { 00142 tmp->ref_count++; 00143 DBUG_RETURN(tmp); 00144 } 00145 bzero(&plugin_dl, sizeof(plugin_dl)); 00146 /* Compile dll path */ 00147 dlpathlen= 00148 strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS) - 00149 dlpath; 00150 plugin_dl.ref_count= 1; 00151 /* Open new dll handle */ 00152 if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW))) 00153 { 00154 const char *errmsg=dlerror(); 00155 if (!strncmp(dlpath, errmsg, dlpathlen)) 00156 { // if errmsg starts from dlpath, trim this prefix. 00157 errmsg+=dlpathlen; 00158 if (*errmsg == ':') errmsg++; 00159 if (*errmsg == ' ') errmsg++; 00160 } 00161 if (report & REPORT_TO_USER) 00162 my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, errno, errmsg); 00163 if (report & REPORT_TO_LOG) 00164 sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, errno, errmsg); 00165 DBUG_RETURN(0); 00166 } 00167 /* Determine interface version */ 00168 if (!(sym= dlsym(plugin_dl.handle, plugin_interface_version_sym))) 00169 { 00170 free_plugin_mem(&plugin_dl); 00171 if (report & REPORT_TO_USER) 00172 my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_interface_version_sym); 00173 if (report & REPORT_TO_LOG) 00174 sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_interface_version_sym); 00175 DBUG_RETURN(0); 00176 } 00177 plugin_dl.version= *(int *)sym; 00178 /* Versioning */ 00179 if (plugin_dl.version < min_plugin_interface_version || 00180 (plugin_dl.version >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8)) 00181 { 00182 free_plugin_mem(&plugin_dl); 00183 if (report & REPORT_TO_USER) 00184 my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dlpath, 0, 00185 "plugin interface version mismatch"); 00186 if (report & REPORT_TO_LOG) 00187 sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dlpath, 0, 00188 "plugin interface version mismatch"); 00189 DBUG_RETURN(0); 00190 } 00191 /* Find plugin declarations */ 00192 if (!(sym= dlsym(plugin_dl.handle, plugin_declarations_sym))) 00193 { 00194 free_plugin_mem(&plugin_dl); 00195 if (report & REPORT_TO_USER) 00196 my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), plugin_declarations_sym); 00197 if (report & REPORT_TO_LOG) 00198 sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), plugin_declarations_sym); 00199 DBUG_RETURN(0); 00200 } 00201 00202 if (plugin_dl.version != MYSQL_PLUGIN_INTERFACE_VERSION) 00203 { 00204 int i; 00205 uint sizeof_st_plugin; 00206 struct st_mysql_plugin *old, *cur; 00207 char *ptr= (char *)sym; 00208 00209 if ((sym= dlsym(plugin_dl.handle, sizeof_st_plugin_sym))) 00210 sizeof_st_plugin= *(int *)sym; 00211 else 00212 { 00213 #ifdef ERROR_ON_NO_SIZEOF_PLUGIN_SYMBOL 00214 free_plugin_mem(&plugin_dl); 00215 if (report & REPORT_TO_USER) 00216 my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), sizeof_st_plugin_sym); 00217 if (report & REPORT_TO_LOG) 00218 sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), sizeof_st_plugin_sym); 00219 DBUG_RETURN(0); 00220 #else 00221 /* 00222 When the following assert starts failing, we'll have to switch 00223 to the upper branch of the #ifdef 00224 */ 00225 DBUG_ASSERT(min_plugin_interface_version == 0); 00226 sizeof_st_plugin= (int)offsetof(struct st_mysql_plugin, version); 00227 #endif 00228 } 00229 00230 for (i= 0; 00231 ((struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info; 00232 i++) 00233 /* no op */; 00234 00235 cur= (struct st_mysql_plugin*) 00236 my_malloc(i*sizeof(struct st_mysql_plugin), MYF(MY_ZEROFILL|MY_WME)); 00237 if (!cur) 00238 { 00239 free_plugin_mem(&plugin_dl); 00240 if (report & REPORT_TO_USER) 00241 my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length); 00242 if (report & REPORT_TO_LOG) 00243 sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length); 00244 DBUG_RETURN(0); 00245 } 00246 /* 00247 All st_plugin fields not initialized in the plugin explicitly, are 00248 set to 0. It matches C standard behaviour for struct initializers that 00249 have less values than the struct definition. 00250 */ 00251 for (i=0; 00252 (old=(struct st_mysql_plugin *)(ptr+i*sizeof_st_plugin))->info; 00253 i++) 00254 memcpy(cur+i, old, min(sizeof(cur[i]), sizeof_st_plugin)); 00255 00256 sym= cur; 00257 } 00258 plugin_dl.plugins= (struct st_mysql_plugin *)sym; 00259 00260 /* Duplicate and convert dll name */ 00261 plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1; 00262 if (! (plugin_dl.dl.str= my_malloc(plugin_dl.dl.length, MYF(0)))) 00263 { 00264 free_plugin_mem(&plugin_dl); 00265 if (report & REPORT_TO_USER) 00266 my_error(ER_OUTOFMEMORY, MYF(0), plugin_dl.dl.length); 00267 if (report & REPORT_TO_LOG) 00268 sql_print_error(ER(ER_OUTOFMEMORY), plugin_dl.dl.length); 00269 DBUG_RETURN(0); 00270 } 00271 plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length, 00272 files_charset_info, dl->str, dl->length, system_charset_info, 00273 &dummy_errors); 00274 plugin_dl.dl.str[plugin_dl.dl.length]= 0; 00275 /* Add this dll to array */ 00276 if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl))) 00277 { 00278 free_plugin_mem(&plugin_dl); 00279 if (report & REPORT_TO_USER) 00280 my_error(ER_OUTOFMEMORY, MYF(0), sizeof(struct st_plugin_dl)); 00281 if (report & REPORT_TO_LOG) 00282 sql_print_error(ER(ER_OUTOFMEMORY), sizeof(struct st_plugin_dl)); 00283 DBUG_RETURN(0); 00284 } 00285 DBUG_RETURN(tmp); 00286 #else 00287 DBUG_ENTER("plugin_dl_add"); 00288 if (report & REPORT_TO_USER) 00289 my_error(ER_FEATURE_DISABLED, MYF(0), "plugin", "HAVE_DLOPEN"); 00290 if (report & REPORT_TO_LOG) 00291 sql_print_error(ER(ER_FEATURE_DISABLED), "plugin", "HAVE_DLOPEN"); 00292 DBUG_RETURN(0); 00293 #endif 00294 } 00295 00296 00297 static void plugin_dl_del(const LEX_STRING *dl) 00298 { 00299 #ifdef HAVE_DLOPEN 00300 uint i; 00301 DBUG_ENTER("plugin_dl_del"); 00302 for (i= 0; i < plugin_dl_array.elements; i++) 00303 { 00304 struct st_plugin_dl *tmp= dynamic_element(&plugin_dl_array, i, 00305 struct st_plugin_dl *); 00306 if (tmp->ref_count && 00307 ! my_strnncoll(files_charset_info, 00308 (const uchar *)dl->str, dl->length, 00309 (const uchar *)tmp->dl.str, tmp->dl.length)) 00310 { 00311 /* Do not remove this element, unless no other plugin uses this dll. */ 00312 if (! --tmp->ref_count) 00313 { 00314 free_plugin_mem(tmp); 00315 bzero(tmp, sizeof(struct st_plugin_dl)); 00316 } 00317 break; 00318 } 00319 } 00320 DBUG_VOID_RETURN; 00321 #endif 00322 } 00323 00324 00325 static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int type) 00326 { 00327 uint i; 00328 DBUG_ENTER("plugin_find_internal"); 00329 if (! initialized) 00330 DBUG_RETURN(0); 00331 if (type == MYSQL_ANY_PLUGIN) 00332 { 00333 for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++) 00334 { 00335 struct st_plugin_int *plugin= (st_plugin_int *) 00336 hash_search(&plugin_hash[i], (const byte *)name->str, name->length); 00337 if (plugin) 00338 DBUG_RETURN(plugin); 00339 } 00340 } 00341 else 00342 DBUG_RETURN((st_plugin_int *) 00343 hash_search(&plugin_hash[type], (const byte *)name->str, name->length)); 00344 DBUG_RETURN(0); 00345 } 00346 00347 00348 my_bool plugin_is_ready(const LEX_STRING *name, int type) 00349 { 00350 my_bool rc= FALSE; 00351 struct st_plugin_int *plugin; 00352 DBUG_ENTER("plugin_is_ready"); 00353 rw_rdlock(&THR_LOCK_plugin); 00354 if ((plugin= plugin_find_internal(name, type)) && 00355 plugin->state == PLUGIN_IS_READY) 00356 rc= TRUE; 00357 rw_unlock(&THR_LOCK_plugin); 00358 DBUG_RETURN(rc); 00359 } 00360 00361 00362 struct st_plugin_int *plugin_lock(const LEX_STRING *name, int type) 00363 { 00364 struct st_plugin_int *rc; 00365 DBUG_ENTER("plugin_lock"); 00366 rw_wrlock(&THR_LOCK_plugin); 00367 if ((rc= plugin_find_internal(name, type))) 00368 { 00369 if (rc->state == PLUGIN_IS_READY || rc->state == PLUGIN_IS_UNINITIALIZED) 00370 rc->ref_count++; 00371 else 00372 rc= 0; 00373 } 00374 rw_unlock(&THR_LOCK_plugin); 00375 DBUG_RETURN(rc); 00376 } 00377 00378 00379 static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin) 00380 { 00381 uint i; 00382 DBUG_ENTER("plugin_insert_or_reuse"); 00383 for (i= 0; i < plugin_array.elements; i++) 00384 { 00385 struct st_plugin_int *tmp= dynamic_element(&plugin_array, i, 00386 struct st_plugin_int *); 00387 if (tmp->state == PLUGIN_IS_FREED) 00388 { 00389 memcpy(tmp, plugin, sizeof(struct st_plugin_int)); 00390 DBUG_RETURN(tmp); 00391 } 00392 } 00393 if (insert_dynamic(&plugin_array, (gptr)plugin)) 00394 DBUG_RETURN(0); 00395 DBUG_RETURN(dynamic_element(&plugin_array, plugin_array.elements - 1, 00396 struct st_plugin_int *)); 00397 } 00398 00399 static my_bool plugin_add(const LEX_STRING *name, const LEX_STRING *dl, int report) 00400 { 00401 struct st_plugin_int tmp; 00402 struct st_mysql_plugin *plugin; 00403 DBUG_ENTER("plugin_add"); 00404 if (plugin_find_internal(name, MYSQL_ANY_PLUGIN)) 00405 { 00406 if (report & REPORT_TO_USER) 00407 my_error(ER_UDF_EXISTS, MYF(0), name->str); 00408 if (report & REPORT_TO_LOG) 00409 sql_print_error(ER(ER_UDF_EXISTS), name->str); 00410 DBUG_RETURN(TRUE); 00411 } 00412 if (! (tmp.plugin_dl= plugin_dl_add(dl, report))) 00413 DBUG_RETURN(TRUE); 00414 /* Find plugin by name */ 00415 for (plugin= tmp.plugin_dl->plugins; plugin->info; plugin++) 00416 { 00417 uint name_len= strlen(plugin->name); 00418 if (plugin->type >= 0 && plugin->type < MYSQL_MAX_PLUGIN_TYPE_NUM && 00419 ! my_strnncoll(system_charset_info, 00420 (const uchar *)name->str, name->length, 00421 (const uchar *)plugin->name, 00422 name_len)) 00423 { 00424 struct st_plugin_int *tmp_plugin_ptr; 00425 if (*(int*)plugin->info < 00426 min_plugin_info_interface_version[plugin->type] || 00427 ((*(int*)plugin->info) >> 8) > 00428 (cur_plugin_info_interface_version[plugin->type] >> 8)) 00429 { 00430 char buf[256]; 00431 strxnmov(buf, sizeof(buf) - 1, "API version for ", 00432 plugin_type_names[plugin->type].str, 00433 " plugin is too different", NullS); 00434 if (report & REPORT_TO_USER) 00435 my_error(ER_CANT_OPEN_LIBRARY, MYF(0), dl->str, 0, buf); 00436 if (report & REPORT_TO_LOG) 00437 sql_print_error(ER(ER_CANT_OPEN_LIBRARY), dl->str, 0, buf); 00438 goto err; 00439 } 00440 tmp.plugin= plugin; 00441 tmp.name.str= (char *)plugin->name; 00442 tmp.name.length= name_len; 00443 tmp.ref_count= 0; 00444 tmp.state= PLUGIN_IS_UNINITIALIZED; 00445 if (plugin->status_vars) 00446 { 00447 SHOW_VAR array[2]= { 00448 {plugin->name, (char*)plugin->status_vars, SHOW_ARRAY}, 00449 {0, 0, SHOW_UNDEF} 00450 }; 00451 if (add_status_vars(array)) // add_status_vars makes a copy 00452 goto err; 00453 } 00454 if (! (tmp_plugin_ptr= plugin_insert_or_reuse(&tmp))) 00455 goto err; 00456 if (my_hash_insert(&plugin_hash[plugin->type], (byte*)tmp_plugin_ptr)) 00457 { 00458 tmp_plugin_ptr->state= PLUGIN_IS_FREED; 00459 goto err; 00460 } 00461 DBUG_RETURN(FALSE); 00462 } 00463 } 00464 if (report & REPORT_TO_USER) 00465 my_error(ER_CANT_FIND_DL_ENTRY, MYF(0), name->str); 00466 if (report & REPORT_TO_LOG) 00467 sql_print_error(ER(ER_CANT_FIND_DL_ENTRY), name->str); 00468 err: 00469 if (plugin->status_vars) 00470 { 00471 SHOW_VAR array[2]= { 00472 {plugin->name, (char*)plugin->status_vars, SHOW_ARRAY}, 00473 {0, 0, SHOW_UNDEF} 00474 }; 00475 remove_status_vars(array); 00476 } 00477 plugin_dl_del(dl); 00478 DBUG_RETURN(TRUE); 00479 } 00480 00481 00482 static void plugin_del(const LEX_STRING *name) 00483 { 00484 uint i; 00485 struct st_plugin_int *plugin; 00486 DBUG_ENTER("plugin_del"); 00487 if ((plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN))) 00488 { 00489 if (plugin->plugin->status_vars) 00490 { 00491 SHOW_VAR array[2]= { 00492 {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY}, 00493 {0, 0, SHOW_UNDEF} 00494 }; 00495 remove_status_vars(array); 00496 } 00497 hash_delete(&plugin_hash[plugin->plugin->type], (byte*)plugin); 00498 plugin_dl_del(&plugin->plugin_dl->dl); 00499 plugin->state= PLUGIN_IS_FREED; 00500 } 00501 DBUG_VOID_RETURN; 00502 } 00503 00504 00505 void plugin_unlock(struct st_plugin_int *plugin) 00506 { 00507 DBUG_ENTER("plugin_unlock"); 00508 rw_wrlock(&THR_LOCK_plugin); 00509 DBUG_ASSERT(plugin && plugin->ref_count); 00510 plugin->ref_count--; 00511 if (plugin->state == PLUGIN_IS_DELETED && ! plugin->ref_count) 00512 { 00513 if (plugin->plugin->deinit) 00514 plugin->plugin->deinit(); 00515 plugin_del(&plugin->name); 00516 } 00517 rw_unlock(&THR_LOCK_plugin); 00518 DBUG_VOID_RETURN; 00519 } 00520 00521 00522 static int plugin_initialize(struct st_plugin_int *plugin) 00523 { 00524 DBUG_ENTER("plugin_initialize"); 00525 00526 if (plugin->plugin->init) 00527 { 00528 if (plugin->plugin->init()) 00529 { 00530 sql_print_error("Plugin '%s' init function returned error.", 00531 plugin->name.str); 00532 goto err; 00533 } 00534 } 00535 if (plugin_type_initialize[plugin->plugin->type] && 00536 (*plugin_type_initialize[plugin->plugin->type])(plugin)) 00537 { 00538 sql_print_error("Plugin '%s' registration as a %s failed.", 00539 plugin->name.str, plugin_type_names[plugin->plugin->type]); 00540 goto err; 00541 } 00542 00543 DBUG_RETURN(0); 00544 err: 00545 DBUG_RETURN(1); 00546 } 00547 00548 static int plugin_finalize(THD *thd, struct st_plugin_int *plugin) 00549 { 00550 int rc; 00551 DBUG_ENTER("plugin_finalize"); 00552 00553 if (plugin->ref_count) 00554 { 00555 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, 00556 "Plugin is busy and will be uninstalled on shutdown"); 00557 goto err; 00558 } 00559 00560 switch (plugin->plugin->type) 00561 { 00562 case MYSQL_STORAGE_ENGINE_PLUGIN: 00563 if (ha_finalize_handlerton(plugin)) 00564 { 00565 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, 00566 "Storage engine shutdown failed. " 00567 "It will be uninstalled on shutdown"); 00568 sql_print_warning("Storage engine '%s' shutdown failed. " 00569 "It will be uninstalled on shutdown", plugin->name.str); 00570 goto err; 00571 } 00572 break; 00573 default: 00574 break; 00575 } 00576 00577 if (plugin->plugin->deinit) 00578 { 00579 if ((rc= plugin->plugin->deinit())) 00580 { 00581 push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0, 00582 "Plugin deinit failed. " 00583 "It will be uninstalled on shutdown"); 00584 sql_print_warning("Plugin '%s' deinit failed. " 00585 "It will be uninstalled on shutdown", plugin->name.str); 00586 goto err; 00587 } 00588 } 00589 00590 DBUG_RETURN(0); 00591 err: 00592 DBUG_RETURN(1); 00593 } 00594 00595 static void plugin_call_initializer(void) 00596 { 00597 uint i; 00598 DBUG_ENTER("plugin_call_initializer"); 00599 for (i= 0; i < plugin_array.elements; i++) 00600 { 00601 struct st_plugin_int *tmp= dynamic_element(&plugin_array, i, 00602 struct st_plugin_int *); 00603 if (tmp->state == PLUGIN_IS_UNINITIALIZED) 00604 { 00605 if (plugin_initialize(tmp)) 00606 plugin_del(&tmp->name); 00607 else 00608 tmp->state= PLUGIN_IS_READY; 00609 } 00610 } 00611 DBUG_VOID_RETURN; 00612 } 00613 00614 00615 static void plugin_call_deinitializer(void) 00616 { 00617 uint i; 00618 DBUG_ENTER("plugin_call_deinitializer"); 00619 for (i= 0; i < plugin_array.elements; i++) 00620 { 00621 struct st_plugin_int *tmp= dynamic_element(&plugin_array, i, 00622 struct st_plugin_int *); 00623 if (tmp->state == PLUGIN_IS_READY) 00624 { 00625 if (tmp->plugin->deinit) 00626 { 00627 DBUG_PRINT("info", ("Deinitializing plugin: '%s'", tmp->name.str)); 00628 if (tmp->plugin->deinit()) 00629 { 00630 DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.", 00631 tmp->name.str)); 00632 } 00633 } 00634 tmp->state= PLUGIN_IS_UNINITIALIZED; 00635 } 00636 } 00637 DBUG_VOID_RETURN; 00638 } 00639 00640 00641 static byte *get_hash_key(const byte *buff, uint *length, 00642 my_bool not_used __attribute__((unused))) 00643 { 00644 struct st_plugin_int *plugin= (st_plugin_int *)buff; 00645 *length= (uint)plugin->name.length; 00646 return((byte *)plugin->name.str); 00647 } 00648 00649 00650 int plugin_init(void) 00651 { 00652 int i; 00653 struct st_mysql_plugin **builtins; 00654 struct st_mysql_plugin *plugin; 00655 DBUG_ENTER("plugin_init"); 00656 00657 if (initialized) 00658 DBUG_RETURN(0); 00659 00660 my_rwlock_init(&THR_LOCK_plugin, NULL); 00661 00662 if (my_init_dynamic_array(&plugin_dl_array, 00663 sizeof(struct st_plugin_dl),16,16) || 00664 my_init_dynamic_array(&plugin_array, 00665 sizeof(struct st_plugin_int),16,16)) 00666 goto err; 00667 00668 for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++) 00669 { 00670 if (hash_init(&plugin_hash[i], system_charset_info, 16, 0, 0, 00671 get_hash_key, NULL, 0)) 00672 goto err; 00673 } 00674 00675 /* Register all the built-in plugins */ 00676 for (builtins= mysqld_builtins; *builtins; builtins++) 00677 { 00678 for (plugin= *builtins; plugin->info; plugin++) 00679 { 00680 if (plugin_register_builtin(plugin)) 00681 goto err; 00682 struct st_plugin_int *tmp=dynamic_element(&plugin_array, 00683 plugin_array.elements-1, 00684 struct st_plugin_int *); 00685 if (plugin_initialize(tmp)) 00686 goto err; 00687 tmp->state= PLUGIN_IS_READY; 00688 } 00689 } 00690 00691 initialized= 1; 00692 00693 DBUG_RETURN(0); 00694 00695 err: 00696 DBUG_RETURN(1); 00697 } 00698 00699 00700 my_bool plugin_register_builtin(struct st_mysql_plugin *plugin) 00701 { 00702 struct st_plugin_int tmp; 00703 DBUG_ENTER("plugin_register_builtin"); 00704 00705 tmp.plugin= plugin; 00706 tmp.name.str= (char *)plugin->name; 00707 tmp.name.length= strlen(plugin->name); 00708 tmp.state= PLUGIN_IS_UNINITIALIZED; 00709 00710 /* Cannot be unloaded */ 00711 tmp.ref_count= 1; 00712 tmp.plugin_dl= 0; 00713 00714 if (insert_dynamic(&plugin_array, (gptr)&tmp)) 00715 DBUG_RETURN(1); 00716 00717 if (my_hash_insert(&plugin_hash[plugin->type], 00718 (byte*)dynamic_element(&plugin_array, 00719 plugin_array.elements - 1, 00720 struct st_plugin_int *))) 00721 DBUG_RETURN(1); 00722 00723 DBUG_RETURN(0); 00724 } 00725 00726 00727 void plugin_load(void) 00728 { 00729 TABLE_LIST tables; 00730 TABLE *table; 00731 READ_RECORD read_record_info; 00732 int error, i; 00733 MEM_ROOT mem; 00734 THD *new_thd; 00735 DBUG_ENTER("plugin_load"); 00736 00737 DBUG_ASSERT(initialized); 00738 00739 if (!(new_thd= new THD)) 00740 { 00741 sql_print_error("Can't allocate memory for plugin structures"); 00742 delete new_thd; 00743 DBUG_VOID_RETURN; 00744 } 00745 init_sql_alloc(&mem, 1024, 0); 00746 new_thd->thread_stack= (char*) &tables; 00747 new_thd->store_globals(); 00748 new_thd->db= my_strdup("mysql", MYF(0)); 00749 new_thd->db_length= 5; 00750 bzero((gptr)&tables, sizeof(tables)); 00751 tables.alias= tables.table_name= (char*)"plugin"; 00752 tables.lock_type= TL_READ; 00753 tables.db= new_thd->db; 00754 if (simple_open_n_lock_tables(new_thd, &tables)) 00755 { 00756 DBUG_PRINT("error",("Can't open plugin table")); 00757 sql_print_error("Can't open the mysql.plugin table. Please run the mysql_upgrade script to create it."); 00758 goto end; 00759 } 00760 table= tables.table; 00761 init_read_record(&read_record_info, new_thd, table, NULL, 1, 0); 00762 table->use_all_columns(); 00763 while (!(error= read_record_info.read_record(&read_record_info))) 00764 { 00765 DBUG_PRINT("info", ("init plugin record")); 00766 LEX_STRING name, dl; 00767 name.str= get_field(&mem, table->field[0]); 00768 name.length= strlen(name.str); 00769 dl.str= get_field(&mem, table->field[1]); 00770 dl.length= strlen(dl.str); 00771 if (plugin_add(&name, &dl, REPORT_TO_LOG)) 00772 DBUG_PRINT("warning", ("Couldn't load plugin named '%s' with soname '%s'.", 00773 name.str, dl.str)); 00774 } 00775 plugin_call_initializer(); 00776 if (error > 0) <

