00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <config.h>
00017
00018 #include <dlfcn.h>
00019
00020 #include <cstdio>
00021 #include <string>
00022 #include <vector>
00023 #include <map>
00024 #include <algorithm>
00025 #include <iostream>
00026
00027 #include <boost/program_options.hpp>
00028
00029 #include <drizzled/option.h>
00030 #include <drizzled/internal/m_string.h>
00031
00032 #include <drizzled/plugin.h>
00033 #include <drizzled/module/load_list.h>
00034 #include <drizzled/module/library.h>
00035 #include <drizzled/module/registry.h>
00036 #include <drizzled/module/option_context.h>
00037 #include <drizzled/sql_parse.h>
00038 #include <drizzled/show.h>
00039 #include <drizzled/cursor.h>
00040 #include <drizzled/set_var.h>
00041 #include <drizzled/session.h>
00042 #include <drizzled/item/null.h>
00043 #include <drizzled/error.h>
00044 #include <drizzled/gettext.h>
00045 #include <drizzled/errmsg_print.h>
00046 #include <drizzled/pthread_globals.h>
00047 #include <drizzled/util/tokenize.h>
00048
00049 #include <boost/foreach.hpp>
00050
00051
00052 #ifndef RTLD_NOW
00053 #define RTLD_NOW 1
00054 #endif
00055
00056 namespace po=boost::program_options;
00057
00058 using namespace std;
00059
00061 typedef drizzled::module::Manifest drizzled_builtin_list[];
00062 extern drizzled_builtin_list PANDORA_BUILTIN_SYMBOLS_LIST;
00063 extern drizzled_builtin_list PANDORA_BUILTIN_LOAD_SYMBOLS_LIST;
00064 drizzled::module::Manifest *drizzled_builtins[]=
00065 {
00066 PANDORA_BUILTIN_SYMBOLS_LIST, NULL
00067 };
00068 drizzled::module::Manifest *drizzled_load_builtins[]=
00069 {
00070 PANDORA_BUILTIN_LOAD_SYMBOLS_LIST, NULL
00071 };
00072
00073 namespace drizzled {
00074
00075
00076 typedef vector<string> PluginOptions;
00077 static PluginOptions opt_plugin_load;
00078 static PluginOptions opt_plugin_add;
00079 static PluginOptions opt_plugin_remove;
00080 const char *builtin_plugins= PANDORA_BUILTIN_LIST;
00081 const char *builtin_load_plugins= PANDORA_BUILTIN_LOAD_LIST;
00082
00083
00084
00085
00086
00087 static bool initialized= false;
00088
00089
00090 static bool reap_needed= false;
00091
00092
00093
00094
00095
00096 static memory::Root plugin_mem_root(4096);
00097 static uint32_t global_variables_dynamic_size= 0;
00098
00099
00100
00101
00102
00103
00104 struct st_item_value_holder : public drizzle_value
00105 {
00106 Item *item;
00107 };
00108
00109 class Bookmark
00110 {
00111 public:
00112 Bookmark() :
00113 type_code(0),
00114 offset(0),
00115 version(0),
00116 key("")
00117 {}
00118 uint8_t type_code;
00119 int offset;
00120 uint32_t version;
00121 string key;
00122 };
00123
00124 typedef boost::unordered_map<string, Bookmark> bookmark_unordered_map;
00125 static bookmark_unordered_map bookmark_hash;
00126
00127
00128
00129
00130 static void plugin_prune_list(vector<string> &plugin_list,
00131 const vector<string> &plugins_to_remove);
00132 static bool plugin_load_list(module::Registry ®istry,
00133 memory::Root *tmp_root,
00134 const set<string> &plugin_list,
00135 po::options_description &long_options,
00136 bool builtin= false);
00137 static int test_plugin_options(memory::Root *, module::Module *,
00138 po::options_description &long_options);
00139 static void unlock_variables(Session *session, drizzle_system_variables *vars);
00140 static void cleanup_variables(drizzle_system_variables *vars);
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 static bool plugin_add(module::Registry ®istry, memory::Root *tmp_root,
00155 module::Library *library,
00156 po::options_description &long_options)
00157 {
00158 if (! initialized)
00159 return true;
00160
00161 if (registry.find(library->getName()))
00162 {
00163 errmsg_printf(error::WARN, ER(ER_PLUGIN_EXISTS),
00164 library->getName().c_str());
00165 return false;
00166 }
00167
00168
00169 const module::Manifest *manifest= library->getManifest();
00170
00171 if (registry.find(manifest->name))
00172 {
00173 errmsg_printf(error::ERROR,
00174 _("Plugin '%s' contains the name '%s' in its manifest, which "
00175 "has already been registered.\n"),
00176 library->getName().c_str(),
00177 manifest->name);
00178 return true;
00179 }
00180
00181 module::Module* tmp= new (std::nothrow) module::Module(manifest, library);
00182 if (tmp == NULL)
00183 return true;
00184
00185 if (!test_plugin_options(tmp_root, tmp, long_options))
00186 {
00187 registry.add(tmp);
00188 return false;
00189 }
00190 errmsg_printf(error::ERROR, ER(ER_CANT_FIND_DL_ENTRY),
00191 library->getName().c_str());
00192 return true;
00193 }
00194
00195
00196 static void reap_plugins(module::Registry ®istry)
00197 {
00198 BOOST_FOREACH(module::Registry::ModuleMap::const_reference module, registry.getModulesMap())
00199 delete module.second;
00200 }
00201
00202
00203 static bool plugin_initialize(module::Registry ®istry,
00204 module::Module *module)
00205 {
00206 assert(module->isInited == false);
00207
00208 module::Context loading_context(registry, module);
00209 if (module->getManifest().init)
00210 {
00211 if (module->getManifest().init(loading_context))
00212 {
00213 errmsg_printf(error::ERROR,
00214 _("Plugin '%s' init function returned error.\n"),
00215 module->getName().c_str());
00216 return true;
00217 }
00218 }
00219 module->isInited= true;
00220 return false;
00221 }
00222
00223 static void compose_plugin_options(vector<string> &target,
00224 vector<string> options)
00225 {
00226 BOOST_FOREACH(vector<string>::reference it, options)
00227 tokenize(it, target, ",", true);
00228 BOOST_FOREACH(vector<string>::reference it, target)
00229 std::replace(it.begin(), it.end(), '-', '_');
00230 }
00231
00232 void compose_plugin_add(vector<string> options)
00233 {
00234 compose_plugin_options(opt_plugin_add, options);
00235 }
00236
00237 void compose_plugin_remove(vector<string> options)
00238 {
00239 compose_plugin_options(opt_plugin_remove, options);
00240 }
00241
00242 void notify_plugin_load(string in_plugin_load)
00243 {
00244 tokenize(in_plugin_load, opt_plugin_load, ",", true);
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254 bool plugin_init(module::Registry ®istry,
00255 po::options_description &long_options)
00256 {
00257 if (initialized)
00258 return false;
00259
00260 initialized= true;
00261
00262 PluginOptions builtin_load_list;
00263 tokenize(builtin_load_plugins, builtin_load_list, ",", true);
00264
00265 PluginOptions builtin_list;
00266 tokenize(builtin_plugins, builtin_list, ",", true);
00267
00268 bool load_failed= false;
00269
00270 if (opt_plugin_add.size() > 0)
00271 {
00272 for (PluginOptions::iterator iter= opt_plugin_add.begin();
00273 iter != opt_plugin_add.end();
00274 ++iter)
00275 {
00276 if (find(builtin_list.begin(),
00277 builtin_list.end(), *iter) != builtin_list.end())
00278 {
00279 builtin_load_list.push_back(*iter);
00280 }
00281 else
00282 {
00283 opt_plugin_load.push_back(*iter);
00284 }
00285 }
00286 }
00287
00288 if (opt_plugin_remove.size() > 0)
00289 {
00290 plugin_prune_list(opt_plugin_load, opt_plugin_remove);
00291 plugin_prune_list(builtin_load_list, opt_plugin_remove);
00292 }
00293
00294 memory::Root tmp_root(4096);
00295
00296
00297
00298 const set<string> builtin_list_set(builtin_load_list.begin(),
00299 builtin_load_list.end());
00300 load_failed= plugin_load_list(registry, &tmp_root,
00301 builtin_list_set, long_options, true);
00302 if (load_failed)
00303 {
00304 tmp_root.free_root(MYF(0));
00305 return true;
00306 }
00307
00308
00309 const set<string> plugin_list_set(opt_plugin_load.begin(),
00310 opt_plugin_load.end());
00311
00312
00313 load_failed= plugin_load_list(registry, &tmp_root,
00314 plugin_list_set, long_options);
00315 if (load_failed)
00316 {
00317 tmp_root.free_root(MYF(0));
00318 return true;
00319 }
00320
00321 tmp_root.free_root(MYF(0));
00322
00323 return false;
00324 }
00325
00326 bool plugin_finalize(module::Registry ®istry)
00327 {
00328
00329
00330
00331 BOOST_FOREACH(module::Registry::ModuleList::const_reference module, registry.getList())
00332 {
00333 if (not module->isInited && plugin_initialize(registry, module))
00334 {
00335 registry.remove(module);
00336 delete module;
00337 return true;
00338 }
00339 }
00340 BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
00341 {
00342 value.second->prime();
00343 }
00344 return false;
00345 }
00346
00347
00348
00349
00350 void plugin_startup_window(module::Registry ®istry, drizzled::Session &session)
00351 {
00352 BOOST_FOREACH(plugin::Plugin::map::value_type value, registry.getPluginsMap())
00353 {
00354 value.second->startup(session);
00355 }
00356 }
00357
00358 class PrunePlugin :
00359 public unary_function<string, bool>
00360 {
00361 const string to_match;
00362 PrunePlugin();
00363 PrunePlugin& operator=(const PrunePlugin&);
00364 public:
00365 explicit PrunePlugin(const string &match_in) :
00366 to_match(match_in)
00367 { }
00368
00369 result_type operator()(const string &match_against)
00370 {
00371 return match_against == to_match;
00372 }
00373 };
00374
00375 static void plugin_prune_list(vector<string> &plugin_list,
00376 const vector<string> &plugins_to_remove)
00377 {
00378 for (vector<string>::const_iterator iter= plugins_to_remove.begin();
00379 iter != plugins_to_remove.end();
00380 ++iter)
00381 {
00382 plugin_list.erase(remove_if(plugin_list.begin(),
00383 plugin_list.end(),
00384 PrunePlugin(*iter)),
00385 plugin_list.end());
00386 }
00387 }
00388
00389
00390
00391
00392 static bool plugin_load_list(module::Registry ®istry,
00393 memory::Root *tmp_root,
00394 const set<string> &plugin_list,
00395 po::options_description &long_options,
00396 bool builtin)
00397 {
00398 BOOST_FOREACH(const string& plugin_name, plugin_list)
00399 {
00400 module::Library* library= registry.addLibrary(plugin_name, builtin);
00401 if (library == NULL)
00402 {
00403 errmsg_printf(error::ERROR,
00404 _("Couldn't load plugin library named '%s'.\n"),
00405 plugin_name.c_str());
00406 return true;
00407 }
00408
00409 tmp_root->free_root(MYF(memory::MARK_BLOCKS_FREE));
00410 if (plugin_add(registry, tmp_root, library, long_options))
00411 {
00412 registry.removeLibrary(plugin_name);
00413 errmsg_printf(error::ERROR,
00414 _("Couldn't load plugin named '%s'.\n"),
00415 plugin_name.c_str());
00416 return true;
00417 }
00418 }
00419 return false;
00420 }
00421
00422
00423 void module_shutdown(module::Registry ®istry)
00424 {
00425
00426 if (initialized)
00427 {
00428 reap_needed= true;
00429
00430 reap_plugins(registry);
00431 unlock_variables(NULL, &global_system_variables);
00432 unlock_variables(NULL, &max_system_variables);
00433
00434 cleanup_variables(&global_system_variables);
00435 cleanup_variables(&max_system_variables);
00436
00437 initialized= 0;
00438 }
00439
00440
00441 plugin_mem_root.free_root(MYF(0));
00442
00443 global_variables_dynamic_size= 0;
00444 }
00445
00446
00447
00448
00449
00450
00451
00452
00453 void plugin_sessionvar_init(Session *session)
00454 {
00455 session->variables.storage_engine= NULL;
00456 cleanup_variables(&session->variables);
00457
00458 session->variables= global_system_variables;
00459 session->variables.storage_engine= NULL;
00460
00461
00462 session->variables.dynamic_variables_version= 0;
00463 session->variables.dynamic_variables_size= 0;
00464 session->variables.dynamic_variables_ptr= 0;
00465
00466 session->variables.storage_engine= global_system_variables.storage_engine;
00467 }
00468
00469
00470
00471
00472
00473 static void unlock_variables(Session *, struct drizzle_system_variables *vars)
00474 {
00475 vars->storage_engine= NULL;
00476 }
00477
00478
00479
00480
00481
00482
00483
00484
00485 static void cleanup_variables(drizzle_system_variables *vars)
00486 {
00487 assert(vars->storage_engine == NULL);
00488
00489 free(vars->dynamic_variables_ptr);
00490 vars->dynamic_variables_ptr= NULL;
00491 vars->dynamic_variables_size= 0;
00492 vars->dynamic_variables_version= 0;
00493 }
00494
00495
00496 void plugin_sessionvar_cleanup(Session *session)
00497 {
00498 unlock_variables(session, &session->variables);
00499 cleanup_variables(&session->variables);
00500 }
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 static int test_plugin_options(memory::Root *,
00516 module::Module *test_module,
00517 po::options_description &long_options)
00518 {
00519
00520 if (test_module->getManifest().init_options != NULL)
00521 {
00522 string plugin_section_title("Options used by ");
00523 plugin_section_title.append(test_module->getName());
00524 po::options_description module_options(plugin_section_title);
00525 module::option_context opt_ctx(test_module->getName(),
00526 module_options.add_options());
00527 test_module->getManifest().init_options(opt_ctx);
00528 long_options.add(module_options);
00529 }
00530
00531 return 0;
00532 }
00533
00534
00535
00536
00537
00538
00539 class OptionCmp
00540 {
00541 public:
00542 bool operator() (const option &a, const option &b)
00543 {
00544 return my_strcasecmp(&my_charset_utf8_general_ci, a.name, b.name);
00545 }
00546 };
00547
00548
00549 void my_print_help_inc_plugins(option *main_options)
00550 {
00551 module::Registry ®istry= module::Registry::singleton();
00552 vector<option> all_options;
00553 memory::Root mem_root(4096);
00554
00555
00556 if (initialized)
00557 {
00558 std::map<std::string, module::Module *>::const_iterator modules=
00559 registry.getModulesMap().begin();
00560
00561 while (modules != registry.getModulesMap().end())
00562 {
00563 module::Module *p= (*modules).second;
00564 ++modules;
00565
00566
00567
00568 if (p->getManifest().init_options != NULL)
00569 continue;
00570
00571 }
00572 }
00573
00574 for (;main_options->id; main_options++)
00575 {
00576 if (main_options->comment)
00577 {
00578 all_options.push_back(*main_options);
00579 }
00580 }
00581
00588
00589 all_options.push_back(*main_options);
00590
00591 my_print_help(&*(all_options.begin()));
00592
00593 mem_root.free_root(MYF(0));
00594 }
00595
00596 }
00597
00598