List:Commits« Previous MessageNext Message »
From:chuck.bell Date:May 26 2011 7:25pm
Subject:bzr commit into mysql-5.5 branch (chuck.bell:3409) WL#5710
View as plain text  
#At file:///Users/cbell/source/bzr/mysql-wl-5710/ based on revid:sven.sandberg@strippedxw4a12u

 3409 chuck.bell@stripped	2011-05-26
      WL#5710 : mysql_plugin - enable or disable plugins
      
      This patch adds a new client utility that enables or disables plugin 
      features. Currently, the client can enable or disable the thread_pool
      and daemon_example plugins by default but the user can specify new plugins
      via a configuration file.

    added:
      client/mysql_plugin.c
      mysql-test/r/mysql_plugin.result
      mysql-test/t/mysql_plugin-master.opt
      mysql-test/t/mysql_plugin.test
    modified:
      client/CMakeLists.txt
      include/my_global.h
      mysql-test/mysql-test-run.pl
=== modified file 'client/CMakeLists.txt'
--- a/client/CMakeLists.txt	2010-09-20 14:17:32 +0000
+++ b/client/CMakeLists.txt	2011-05-26 19:25:47 +0000
@@ -54,6 +54,9 @@ ADD_DEPENDENCIES(mysql_upgrade GenFixPri
 MYSQL_ADD_EXECUTABLE(mysqlshow mysqlshow.c)
 TARGET_LINK_LIBRARIES(mysqlshow mysqlclient)
 
+MYSQL_ADD_EXECUTABLE(mysql_plugin mysql_plugin.c)
+TARGET_LINK_LIBRARIES(mysql_plugin mysqlclient)
+
 MYSQL_ADD_EXECUTABLE(mysqlbinlog mysqlbinlog.cc)
 TARGET_LINK_LIBRARIES(mysqlbinlog mysqlclient)
 
@@ -69,7 +72,7 @@ IF(WIN32)
   MYSQL_ADD_EXECUTABLE(echo echo.c)
 ENDIF(WIN32)
 
-SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap 
+SET_TARGET_PROPERTIES (mysqlcheck mysqldump mysqlimport mysql_upgrade mysqlshow mysqlslap mysql_plugin 
 PROPERTIES HAS_CXX TRUE)
 
 ADD_DEFINITIONS(-DHAVE_DLOPEN)

=== added file 'client/mysql_plugin.c'
--- a/client/mysql_plugin.c	1970-01-01 00:00:00 +0000
+++ b/client/mysql_plugin.c	2011-05-26 19:25:47 +0000
@@ -0,0 +1,963 @@
+/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+   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; version 2 of the License.
+
+   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 <m_string.h>
+#include <mysql.h>
+#include <my_getopt.h>
+#include <sys/stat.h>
+#include <my_global.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#define SHOW_VERSION "1.0.0"
+#define PRINT_VERSION do { printf("%s  Ver %s Distrib %s\n",    \
+                        my_progname, SHOW_VERSION, MYSQL_SERVER_VERSION);    \
+                      } while(0)
+
+/* Global variables. */
+static uint my_end_arg= 0;
+static uint opt_verbose=0;
+static uint opt_no_defaults= 0;
+static uint opt_print_defaults= 0;
+static char *opt_datadir=0, *opt_basedir=0,
+            *opt_plugin_dir=0, *opt_plugin_ini=0;
+static char bootstrap[FN_REFLEN];
+
+
+/* plugin struct */
+struct st_plugin
+{
+  const char *name;        /* plugin name */
+  const char *so_name;     /* plugin so (library) name */
+  const char *symbols[16]; /* symbols to load */
+};
+
+
+struct st_plugin *plugins_supported[256];
+int num_plugins;
+
+/*
+  plugins (plugins) supported.
+
+  NOTE: To add a new plugin, add rows to the #define below to define
+        and add a new element to this array. The code is designed to act
+        on these entries to insert/delete the correct values in the
+        mysql.plugin table.
+*/
+static struct st_plugin default_plugins[]= {
+  {
+    "thread_pool", "thread_pool" FN_SOEXT,
+    {
+      "thread_pool",
+      "TP_THREAD_STATE",
+      "TP_THREAD_GROUP_STATE",
+      "TP_THREAD_GROUP_STATS",
+      NULL
+    }
+  },
+  {
+    "daemon_example", "libdaemon_example" FN_SOEXT,
+    {
+      "daemon_example",
+      NULL
+    }
+  }
+};
+
+
+/* Options */
+static struct my_option my_long_options[] =
+{
+  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
+    0, 0, 0, 0, 0, 0},
+  {"basedir", 'b', "The basedir for the server.",
+    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"datadir", 'd', "The datadir for the server.",
+    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"plugin-dir", 'p', "The plugin dir for the server.",
+    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"plugin-ini", 'i', "Read plugin information from configuration file "
+   "specified instead of from <plugin_dir>/plugin.ini.",
+    0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},  
+  {"no-defaults", 'n', "Do not read values from configuration file.",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"print-defaults", 'P', "Show default values from configuration file.",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"verbose", 'v',
+    "More verbose output; you can use this multiple times to get even more "
+    "verbose output.",
+    0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
+    NO_ARG, 0, 0, 0, 0, 0, 0},
+  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+/* Methods */
+static my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+               char *argument);
+static int check_options(int argc, char **argv, char *operation,
+             struct st_plugin **plugin);
+static int find_tool(const char *tool_name, char *tool_path);
+static int find_plugin(struct st_plugin *plugin, char *tp_path);
+static int run_command(char* cmd, char *mode);
+static int make_tempfile(char *filename, char *ext);
+static int get_default_values();
+static int load_plugin_data();
+
+
+int main(int argc,char *argv[])
+{
+  int i= 0;
+  int error= 0;
+  int ret= 0;
+  FILE *file;
+  char tp_path[FN_REFLEN];
+  char server_path[FN_REFLEN];
+  char query_str[512];
+  char operation[16];
+  char bootstrap_cmd[FN_REFLEN];
+  struct st_plugin *plugin= 0;
+
+  bzero(plugins_supported, 256);
+  MY_INIT(argv[0]);
+
+  /* Process options */
+  if ((handle_options(&argc, &argv, my_long_options, get_one_option)))
+  {
+    error= 1;
+    goto exit;
+  }
+  
+  if (opt_print_defaults)
+  {
+    goto exit;
+  }
+ 
+  if (!opt_no_defaults && ((error= get_default_values())))
+  {
+    goto exit;
+  }
+   
+  strcpy(operation, "");
+  if ((error = check_options(argc, argv, operation, &plugin)))
+  {
+    goto exit;
+  }
+  if (!plugin)
+  {
+    fprintf(stderr, "ERROR: No plugin specified or plugin does not " 
+            "match information in plugin.ini file.\n");
+    error= 1;
+    goto exit;
+  }
+
+  i= (int)strlength(opt_basedir);
+  if (opt_basedir[i-1] != FN_LIBCHAR || opt_basedir[i-1] != FN_LIBCHAR2)
+  {
+    strcat(opt_basedir, FN_DIRSEP);
+  }
+
+  if (opt_verbose)
+  {
+    printf("#    basedir = %s\n", opt_basedir);
+    printf("# plugin_dir = %s\n", opt_plugin_dir);
+    printf("#    datadir = %s\n", opt_datadir);
+    printf("# plugin_ini = %s\n", opt_plugin_ini);
+  }
+  
+  /* Attempt to access these directories. Error if access denied. */
+  if ((error= my_access(opt_basedir, F_OK)))
+  {
+    fprintf(stderr, "ERROR: Cannot access basedir at '%s'.\n",
+            opt_basedir);
+    error= 1;
+    goto exit;
+  }
+  if ((error= my_access(opt_plugin_dir, F_OK)))
+  {
+    fprintf(stderr, "ERROR: Cannot access plugin_dir at '%s'.\n",
+            opt_plugin_dir);
+    error= 1;
+    goto exit;
+  }
+  if ((error= my_access(opt_datadir, F_OK)))
+  {
+    fprintf(stderr, "ERROR: Cannot access datadir at '%s'.\n",
+            opt_datadir);
+    error= 1;
+    goto exit;
+  }
+  if ((error= my_access(opt_plugin_ini, F_OK)))
+  {
+    fprintf(stderr, "ERROR: Cannot access plugin_ini at '%s'.\n",
+            opt_plugin_ini);
+    error= 1;
+    goto exit;
+  }
+
+  /* Look for the utilities we need: mysqladmin, mysqld, and mysql. */
+  if (!find_tool("mysqld" FN_EXEEXT, server_path))
+  {
+    fprintf(stderr, "ERROR: Cannot find dependent tools. Ensure basedir is "
+                    "set correctly.\n");
+    error= 1;
+    goto exit;
+  }
+
+  /* Look for the plugin. Abort if not found. */
+  if ((error= find_plugin(plugin, tp_path)))
+  {
+    fprintf(stderr, "ERROR: The plugin library %s is missing or in a different"
+            " location.\n", tp_path);
+    error= 1;
+    goto exit;
+  }
+
+  /* Create bootstrap file using a temporary file name */
+  if (!make_tempfile(bootstrap, "sql"))
+  {
+    error= 1;
+    goto exit;
+  }
+  file= fopen(bootstrap, "w+");
+  if (strcasecmp(operation, "enable") == 0)
+  {
+    /* Here we must do a 'safe' enable in case plugin is already enabled. */
+    int i= 0;
+    fprintf(file, "INSERT IGNORE INTO mysql.plugin VALUES ");
+    for (i= 0; i < array_elements(plugin->symbols); i++)
+    {
+      if (plugin->symbols[i] == NULL)
+      {
+        break;
+      }
+      if (i > 0)
+      {
+        fprintf(file, ", ");
+      }
+      fprintf(file, "('%s','%s')", plugin->symbols[i], plugin->so_name);
+    }
+    fprintf(file, ";\n");
+    if (opt_verbose)
+    {
+      printf("# Enabling %s...\n", plugin->name);
+    }
+  }
+  else
+  {
+    fprintf(file,
+            "DELETE FROM mysql.plugin WHERE name = '%s';", plugin->name);
+    {
+      printf("# Disabling %s...\n", plugin->name);
+    }
+  }
+  fclose(file);
+  if (opt_verbose)
+  {
+    char *ret= 0;
+    file = fopen(bootstrap, "r");
+    ret= fgets(query_str, 512, file);
+    if (ret == 0)
+    {
+      fprintf(stderr, "ERROR: Cannot read bootstrap file\n");
+      error= 1;
+      goto exit;
+    }
+    printf("# Query: %s", query_str);
+    fclose(file);
+  }
+
+  /* Build bootstrap command. */
+  snprintf(bootstrap_cmd, sizeof(bootstrap_cmd),
+           "%s --no-defaults --bootstrap --datadir=%s --basedir=%s"
+           " < %s", server_path, opt_datadir, opt_basedir, bootstrap);
+
+  /* Execute the command */
+  if (opt_verbose > 1)
+  {
+    printf("# Command: %s\n", bootstrap_cmd);
+  }
+  ret= run_command(bootstrap_cmd, "r");
+  if (ret != 0)
+  {
+    fprintf(stderr,
+            "ERROR: Unexpected result from bootstrap. Error code: %d.\n",
+            ret);
+    error= 1;
+  }
+
+  /* Remove file */
+  my_delete(bootstrap, MYF(0));
+  if (opt_verbose && error == 0)
+  {
+    printf("# Operation succeeded.\n");
+  }
+
+exit:
+  my_end(my_end_arg);
+  exit(error ? 1 : 0);
+  return 0;        /* No compiler warnings */
+}
+
+
+/**
+  Get a temporary file name.
+  
+  @param[out]  filename   The file name of the temporary file
+  @param[in]   ext        An extension for the file (optional)
+  
+  @retval int error = 1, success = 0
+*/
+static int make_tempfile(char *filename, char *ext)
+{
+  int fd= 0;
+  
+  if ((fd=create_temp_file(filename, NullS, ext, O_CREAT | O_WRONLY,
+         MYF(MY_WME))) < 0)
+  {
+    fprintf(stderr, "ERROR: Cannot generate temporary file. Error code: %d.\n",
+            fd);
+    return 0;
+  }
+  my_close(fd, MYF(0));
+  return 1;
+}
+
+
+/**
+  Get the value of an option from a string read from my_print_defaults output.
+  
+  @param[in]  line   The line (string) read from the file
+  @param[in]  item   The option to search for (e.g. --datadir)
+  
+  @returns NULL if not found, string containing value if found
+*/
+static char *get_value(char *line, char *item)
+{
+  char *destination= 0;
+  int item_len= (int)strlen(item);
+  int line_len = (int)strlen(line);
+  
+  if ((strncasecmp(line, item, item_len) == 0))
+  {
+    int start= 0;
+    char *s= 0;
+    
+    s = line + item_len + 1;
+    destination= my_strndup(s, line_len - start, MYF(MY_FAE));
+    destination[line_len - item_len - 2]= 0;
+  }
+  return destination;
+}
+
+/**
+  Get the default values from the my.cnf file.
+
+  @retval int error = 1, success = 0
+*/
+static int get_default_values()
+{
+  char tool_path[FN_REFLEN];
+  char defaults_cmd[FN_REFLEN];
+  char defaults_file[FN_REFLEN];
+  char line[FN_REFLEN];
+  int error= 0;
+  int ret= 0;
+  FILE *file;
+
+  if (!find_tool("my_print_defaults" FN_EXEEXT, tool_path))
+  {
+    fprintf(stderr, "WARNING: Cannot find my_print_defaults.\n");
+  }
+  else
+  {
+    if (!make_tempfile(defaults_file, "txt"))
+    {
+      error= 1;
+      goto exit;
+    }
+    snprintf(defaults_cmd, sizeof(defaults_cmd),
+             "%s mysqld > %s", tool_path, defaults_file);
+  
+    /* Execute the command */
+    if (opt_verbose > 1)
+    {
+      printf("# Command: %s\n", defaults_cmd);
+    }
+    ret= run_command(defaults_cmd, "r");
+    if (ret != 0)
+    {
+      fprintf(stderr, "ERROR: my_print_defaults failed. Error code: %d.\n",
+              ret);
+      error= 1;
+      goto exit;
+    }
+    /* Now open the file and read the defaults we want. */
+    file= fopen(defaults_file, "r");
+    while (fgets(line, FN_REFLEN, file) != NULL)
+    {
+      char *value= 0;
+      
+      if ((opt_datadir == 0) && ((value= get_value(line, "--datadir"))))
+      {
+          opt_datadir= my_strdup(value, MYF(MY_FAE));
+      }
+      if ((opt_basedir == 0) && ((value= get_value(line, "--basedir"))))
+      {
+          opt_basedir= my_strdup(value, MYF(MY_FAE));
+      }
+      if ((opt_plugin_dir == 0) && ((value= get_value(line, "--plugin_dir"))))
+      {
+          opt_plugin_dir= my_strdup(value, MYF(MY_FAE));
+      }
+      if ((opt_plugin_ini == 0) && ((value= get_value(line, "--plugin_ini"))))
+      {
+          opt_plugin_ini= my_strdup(value, MYF(MY_FAE));
+      }
+    }
+    fclose(file);
+    /* Remove file */
+    my_delete(defaults_file, MYF(0));
+  }
+exit:
+  return error;
+}
+
+/**
+  Print usage.
+*/
+static void usage(void)
+{
+  int i= 0;
+
+  PRINT_VERSION;
+  puts("Copyright (c) 2011, Oracle and/or its affiliates. "
+       "All rights reserved.\n");
+  puts("Enable or disable plugins.");
+  if (opt_plugin_dir)
+  {
+    /* load plugin data from plugin.ini file */
+    load_plugin_data();
+  }
+  else
+  {
+    /* load defaults */
+    for (i= 0; i < array_elements(default_plugins); i++)
+    {
+      plugins_supported[i]= &default_plugins[i];
+      num_plugins= i + 1;
+    }
+  }
+  puts("\nPlugins supported:");
+  for (i= 0; i < num_plugins; i++)
+  {
+    printf("    %s\n", plugins_supported[i]->name);
+  }
+  printf("\nUsage: %s [options] <plugin> ENABLE|DISABLE\n\nOptions:\n",
+     my_progname);
+  my_print_help(my_long_options);
+  puts("\n");
+}
+
+
+/**
+  Print the default values as read from the my.cnf file.
+*/
+static void print_default_values(void)
+{
+  printf("%s would have been started with the following arguments:\n",
+         my_progname);
+  get_default_values();
+  if (opt_datadir)
+  {
+    printf("--datadir=%s ", opt_datadir);
+  }
+  if (opt_basedir)
+  {
+    printf("--basedir=%s ", opt_basedir);
+  }
+  if (opt_plugin_dir)
+  {
+    printf("--plugin_dir=%s ", opt_plugin_dir);
+  }
+  printf("\n");
+}
+
+/**
+  Process the arguments and identify an option and store its value.
+
+  @param[in]  optid      The single character shortcut for the argument.
+  @param[in]  my_option  Structure of legal options.
+  @param[in]  argument   The argument value to process.
+*/
+static my_bool
+get_one_option(int optid,
+               const struct my_option *opt __attribute__((unused)),
+               char *argument)
+{
+  switch(optid) {
+  case 'n':
+    opt_no_defaults++;
+    break;
+  case 'P':
+    opt_print_defaults++;
+    print_default_values();
+    break;
+  case 'v':
+    opt_verbose++;
+    break;
+  case 'V':
+    PRINT_VERSION;
+    exit(0);
+    break;
+  case '?':
+  case 'I':          /* Info */
+    usage();
+    exit(0);
+  case 'd':
+    opt_datadir= my_strdup(argument, MYF(MY_FAE));
+    break;
+  case 'b':
+    opt_basedir= my_strdup(argument, MYF(MY_FAE));
+    break;
+  case 'p':
+    opt_plugin_dir= my_strdup(argument, MYF(MY_FAE));
+    break;
+  case 'i':
+    opt_plugin_ini= my_strdup(argument, MYF(MY_FAE));
+    break;
+  }
+  return 0;
+}
+
+
+/**
+  Run a command in a shell.
+
+  This function will attempt to execute the command specified.
+
+  @param[in]  cmd   The command to execute.
+  @param[in]  mode  The mode for popen() (e.g. "r", "w", "rw")
+
+  @return int error code or 0 for success.
+*/
+static int run_command(char* cmd, char *mode)
+{
+  char buf[512]= {0};
+  FILE *res_file;
+  int error;
+
+  if (!(res_file= popen(cmd, mode)))
+    return -1;
+
+  if (opt_verbose)
+  {
+    while (fgets(buf, sizeof(buf), res_file))
+    {
+      fprintf(stdout, "%s", buf);
+    }
+  }
+  error= pclose(res_file);
+  return error;
+}
+
+
+/**
+  Check to see if a file exists.
+
+  @param[in]  filename  File to locate.
+
+  @retval int file not found = 1, file found = 0
+*/
+static int file_exists (char * filename)
+{
+  struct stat buf;
+  int i = stat (filename, &buf);
+  /* File found */
+  if (i == 0)
+  {
+    return 1;
+  }
+  return 0;
+}
+
+
+/**
+  Search a specific path and sub directory for a file name.
+
+  @param[in]  base_path  Original path to use.
+  @param[in]  tool_name  Name of the tool to locate.
+  @param[in]  subdir     The sub directory to search.
+  @param[out] tool_path  If tool found, return complete path.
+
+  @retval int error = 1, success = 0
+*/
+static int search_dir(char * base_path, const char *tool_name,
+                      const char *subdir, char *tool_path)
+{
+  char new_path[FN_REFLEN];
+
+  strcpy(new_path, base_path);
+  strcat(new_path, subdir);
+  fn_format(new_path, new_path, "", tool_name, MY_UNPACK_FILENAME);
+  if (file_exists(new_path))
+  {
+    strcpy(tool_path, new_path);
+    return 1;
+  }
+  return 0;
+}
+
+
+/**
+  Search known common paths and sub directories for a file name.
+
+  @param[in]  base_path  Original path to use.
+  @param[in]  tool_name  Name of the tool to locate.
+  @param[out] tool_path  If tool found, return complete path.
+
+  @retval int error = 1, success = 0
+*/
+static int search_paths(char *base_path, const char *tool_name,
+                        char *tool_path)
+{
+  int i= 0;
+
+  static const char *paths[]= {
+    "", "/share/",  "/scripts/", "/bin/", "/sbin/", "/libexec/", 
+    "/mysql/", "/sql/",
+  };
+  for (i = 0 ; i < array_elements(paths); i++)
+  {
+    if (search_dir(base_path, tool_name, paths[i], tool_path))
+      return 1;
+  }
+  return 0;
+}
+
+
+/**
+  Locate the tool and form tool path.
+  
+  @param[in]  tool_name  Name of the tool to locate.
+  @param[out] tool_path  If tool found, return complete path.
+  
+  @retval int error = 1, success = 0
+*/
+static int find_tool(const char *tool_name, char *tool_path)
+{
+  int i= 0;
+
+  char *paths[]= {
+    opt_basedir, "/usr", "/usr/local/mysql", "/usr/sbin", "/usr/share",
+  };
+  for (i= 0; i < array_elements(paths); i++)
+  {
+    if (paths[i] && (search_paths(paths[i], tool_name, tool_path)))
+      goto found;
+  }
+  return 0;
+found:
+  if (opt_verbose)
+    printf("# Found tool '%s' as '%s'.\n", tool_name, tool_path);
+  return 1;
+}
+
+
+/**
+  Check the options for validity.
+  
+  This function checks the arguments for validity issuing the appropriate
+  error message if arguments are missing or invalid. On success, @operation
+  is set to either "ENABLE" or "DISABLE".
+  
+  @param[in]  argc       The number of arguments.
+  @param[in]  argv       The arguments.
+  @param[out] operation  The operation chosen (enable|disable)
+  @param[out] plugin     The plugin selected
+  
+  @retval int error = 1, success = 0
+*/
+static int check_options(int argc, char **argv, char *operation,
+             struct st_plugin **plugin)
+{
+  int i= 0;                   // loop counter
+  int j= 0;
+  int num_found= 0;           // number of options found (shortcut loop)
+
+  for (i = 0; i < argc && num_found < 5; i++)
+  {
+    if (!argv[i])
+    {
+      continue;
+    }
+    if ((strcasecmp(argv[i], "ENABLE") == 0) ||
+        (strcasecmp(argv[i], "DISABLE") == 0))
+    {
+      strcpy(operation, argv[i]);
+      num_found++;
+    }
+    else if ((strncasecmp(argv[i], "--basedir=", 10) == 0) &&
+             !opt_basedir)
+    {
+      opt_basedir= my_strndup(argv[i]+10, strlen(argv[i])-10, MYF(MY_FAE));
+      num_found++;
+    }
+    else if ((strncasecmp(argv[i], "--datadir=", 10) == 0) &&
+             !opt_datadir)
+    {
+      opt_datadir= my_strndup(argv[i]+10, strlen(argv[i])-10, MYF(MY_FAE));
+      num_found++;
+    }
+    else if ((strncasecmp(argv[i], "--plugin-dir=", 13) == 0) &&
+             !opt_plugin_dir)
+    {
+      opt_plugin_dir= my_strndup(argv[i]+13, strlen(argv[i])-13, MYF(MY_FAE));
+      num_found++;
+    }
+    else
+    {
+      if (load_plugin_data())
+      {
+        return 1;
+      }
+      for (j= 0; j < num_plugins; j++)
+      {
+        if (strcasecmp(plugins_supported[j]->name, argv[i]) == 0)
+        {
+          *plugin = plugins_supported[j];
+          num_found++;
+        }
+      }
+    }
+  }
+
+  if (!opt_basedir)
+  {
+    fprintf(stderr, "ERROR: Missing --basedir option.\n");
+    return 1;
+  }
+
+  if (!opt_datadir)
+  {
+    fprintf(stderr, "ERROR: Missing --datadir option.\n");
+    return 1;
+  }
+
+  if (!opt_plugin_dir)
+  {
+    fprintf(stderr, "ERROR: Missing --plugin_dir option.\n");
+    return 1;
+  }
+
+  if ((strlen(operation) == 0))
+  {
+    fprintf(stderr, "ERROR: missing operation. Please specify either "
+            "'<plugin> ENABLE' or '<plugin> DISABLE'.\n");
+    return 1;
+  }
+
+  return 0;
+}
+
+
+/**
+  Find the plugin library.
+  
+  This function attempts to use the @c plugin_dir option passed on the
+  command line to locate the plugin.
+  
+  @param[in]  plugin    The plugin to find.
+  @param[out] tp_path   The actual path to plugin with FN_SOEXT applied.
+  
+  @retval st_plugin error = NULL, success = st_plugin data
+*/
+static int find_plugin(struct st_plugin *plugin, char *tp_path)
+{
+  /* Check for existance of plugin */
+  fn_format(tp_path, plugin->so_name, opt_plugin_dir, "", MYF(0));
+  if (!file_exists(tp_path))
+  {
+    return 1;
+  }
+  else if (opt_verbose)
+  {
+    printf("# Found plugin '%s' as '%s'\n", plugin->name, tp_path);
+  }
+  return 0;
+}
+
+
+/**
+  Read a plugin data element
+  
+  This method takes as input a line from the plugin.ini file and splits it
+  into the st_plugin structure.
+  
+  @retval int error = 1, success = 0
+*/
+void *read_plugin_data(char *line)
+{
+  const char delimiters[]= " ,";
+  char *token, *cp;
+  struct st_plugin *plugin_data;
+  int i= 0;
+  
+  plugin_data= my_malloc(sizeof(struct st_plugin), MYF(MY_ZEROFILL));
+  cp= my_strdup(line, MYF(MY_FAE));
+  token= strtok (cp, delimiters);
+  if (token != NULL)
+  {
+    // read name
+    plugin_data->name= my_strdup(token, MYF(MY_WME));
+    // read so_name
+    token = strtok(NULL, delimiters);
+    if (token == NULL)
+    {
+      goto error;
+    }
+    plugin_data->so_name= my_strdup(token, MYF(MY_WME));
+    // read symbols
+    while (token != NULL)
+    {
+      token= strtok (NULL, delimiters);
+      if ((token != NULL) && (token[0] != '\n'))
+      {
+        plugin_data->symbols[i]= my_strdup(token, MYF(MY_WME));
+        i++;
+      }
+      else
+      {
+        plugin_data->symbols[i]= NULL;
+      }
+    }
+  }
+  else
+  {
+    goto error;
+  }
+  return plugin_data;
+
+error:
+  my_free(plugin_data);
+  return NULL;
+}
+
+
+/**
+  Read the plugin ini file.
+  
+  This function attempts to read the plugin.ini file from the plugin_dir
+  path. If the file is not found, a new plugin.ini file will be created and
+  the default values inserted.
+  
+  @retval int error = 1, success = 0
+*/
+static int load_plugin_data(void)
+{
+  FILE *file_ptr;
+  char path[FN_REFLEN];
+  char line[1024];
+  int i= 0;
+  int j= 0;
+  struct st_plugin *pi= 0;
+  
+  if (opt_plugin_ini == 0)
+  {
+    fn_format(path, "plugin.ini", opt_plugin_dir, "", MYF(0));
+    opt_plugin_ini= my_strdup(path, MYF(MY_FAE));
+  }
+  if (!file_exists(opt_plugin_ini))
+  {
+    file_ptr = fopen(opt_plugin_ini, "w");
+    if (file_ptr == NULL)
+    {
+      fprintf(stderr, "ERROR: Cannot create %s. Check permissions.\n",
+              opt_plugin_ini);
+      return 1;
+    }
+    /* add comments for format first */
+    fputs("#\n", file_ptr);
+    fputs("# Plugin initialization file. Format using comma-separated "
+          "values:\n", file_ptr);
+    fputs("# name, libname, symbol, [symbol, ]\n", file_ptr);
+    fputs("# Note: trailing comma is required.\n", file_ptr);
+    fputs("#\n", file_ptr);
+    for (i= 0; i < array_elements(default_plugins); i++)
+    {
+      // write name
+      fputs(default_plugins[i].name, file_ptr);
+      fputs(", ", file_ptr);
+      // write so_name
+      fputs(default_plugins[i].so_name, file_ptr);
+      fputs(", ", file_ptr);
+      for (j=0; j < array_elements(default_plugins[i].symbols); j++)
+      {
+        if (default_plugins[i].symbols[j] != NULL)
+        {
+          fputs(default_plugins[i].symbols[j], file_ptr);
+          fputs(", ", file_ptr);
+        }
+      }
+      fputs("\n", file_ptr);
+    }
+    fclose(file_ptr);
+  }
+  
+  file_ptr= fopen(opt_plugin_ini, "r");
+  if (file_ptr == NULL)
+  {
+    fprintf(stderr, "ERROR: Cannot read plugin.ini file.\n");
+    return 1;
+  }
+  i = 0;
+  while (1)
+  {
+    char *res;
+    res= fgets(line, sizeof(line), file_ptr);
+    if (res == NULL)
+    {
+      break;
+    }
+    if (line[0] == '#') // skip comment lines
+    {
+      continue; 
+    }
+    pi= read_plugin_data(line);
+    if (pi != NULL)
+    {
+      plugins_supported[i]= pi;
+      i++;
+      num_plugins= i;
+      if (num_plugins >= 256)
+      {
+        fprintf(stderr, "ERROR: Max plugins reached.\n");
+        return 1;
+      }
+    }
+    else
+    {
+      break;
+    }
+  }
+  fclose(file_ptr);
+  return 0;
+}
+
+

=== modified file 'include/my_global.h'
--- a/include/my_global.h	2011-04-13 19:05:26 +0000
+++ b/include/my_global.h	2011-05-26 19:25:47 +0000
@@ -602,6 +602,8 @@ typedef SOCKET_SIZE_TYPE size_socket;
 #define FN_LIBCHAR	'\\'
 #define FN_LIBCHAR2	'/'
 #define FN_DIRSEP       "/\\"               /* Valid directory separators */
+#define FN_EXEEXT   ".exe"
+#define FN_SOEXT    ".dll"
 #define FN_ROOTDIR	"\\"
 #define FN_DEVCHAR	':'
 #define FN_NETWORK_DRIVES	/* Uses \\ to indicate network drives */
@@ -610,6 +612,8 @@ typedef SOCKET_SIZE_TYPE size_socket;
 #define FN_LIBCHAR	'/'
 #define FN_LIBCHAR2	'/'
 #define FN_DIRSEP       "/"     /* Valid directory separators */
+#define FN_EXEEXT   ""
+#define FN_SOEXT    ".so"
 #define FN_ROOTDIR	"/"
 #endif
 

=== modified file 'mysql-test/mysql-test-run.pl'
--- a/mysql-test/mysql-test-run.pl	2011-05-25 14:07:16 +0000
+++ b/mysql-test/mysql-test-run.pl	2011-05-26 19:25:47 +0000
@@ -168,6 +168,7 @@ my $opt_suites;
 
 our $opt_verbose= 0;  # Verbose output, enable with --verbose
 our $exe_mysql;
+our $exe_mysql_plugin;
 our $exe_mysqladmin;
 our $exe_mysqltest;
 our $exe_libtool;
@@ -1944,6 +1945,7 @@ sub executable_setup () {
   # Look for the client binaries
   $exe_mysqladmin=     mtr_exe_exists("$path_client_bindir/mysqladmin");
   $exe_mysql=          mtr_exe_exists("$path_client_bindir/mysql");
+  $exe_mysql_plugin=   mtr_exe_exists("$path_client_bindir/mysql_plugin");
 
   if ( ! $opt_skip_ndbcluster )
   {
@@ -2219,6 +2221,19 @@ sub environment_setup {
     push(@ld_library_paths,  "$basedir/storage/ndb/src/.libs");
   }
 
+  # Add the path where daemon_example can be found
+  # --------------------------------------------------------------------------
+  if (my $lib_plugin= find_plugin("libdaemon_example", "plugin/daemon_example"))
+  {
+    my $lib_dirname= dirname($lib_plugin);
+    $ENV{'DAEMONEXAMPLE_PLUGIN_DIR'}= $lib_dirname;
+  }
+  else
+  {
+    $ENV{'DAEMON_EXAMPLE_PLUGIN_DIR'}="";
+  }
+
+  # --------------------------------------------------------------------------
   # Plugin settings should no longer be added here, instead
   # place definitions in include/plugin.defs.
   # See comment in that file for details.
@@ -2349,6 +2364,7 @@ sub environment_setup {
   $ENV{'MYSQLADMIN'}=               native_path($exe_mysqladmin);
   $ENV{'MYSQL_CLIENT_TEST'}=        mysql_client_test_arguments();
   $ENV{'EXE_MYSQL'}=                $exe_mysql;
+  $ENV{'MYSQL_PLUGIN'}=             $exe_mysql_plugin;
 
   # ----------------------------------------------------
   # bug25714 executable may _not_ exist in

=== added file 'mysql-test/r/mysql_plugin.result'
--- a/mysql-test/r/mysql_plugin.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/mysql_plugin.result	2011-05-26 19:25:47 +0000
@@ -0,0 +1,82 @@
+#
+# Ensure the plugin isn't loaded.
+#
+SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name;
+name	dl
+#
+# Enable the plugin...
+#
+#
+# Ensure the plugin is now loaded.
+#
+SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name;
+name	dl
+daemon_example	libdaemon_example.so
+#
+# Disable the plugin...
+#
+# Disabling daemon_example...
+#
+# Ensure the plugin isn't loaded.
+#
+SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name;
+name	dl
+#
+# Attempt to load non-existant plugin
+#
+ERROR: No plugin specified or plugin does not match information in plugin.ini file.
+#
+# Attempt to use non-existant plugin.ini file
+#
+ERROR: Cannot create /NOT/THERE/pi.ini. Check permissions.
+# 
+# Attempt to omit the plugin
+#
+ERROR: No plugin specified or plugin does not match information in plugin.ini file.
+# 
+# Attempt to omit DISABLE|ENABLE
+#
+ERROR: missing operation. Please specify either '<plugin> ENABLE' or '<plugin> DISABLE'.
+# 
+# Attempt to use bad paths - datadir
+#
+ERROR: Cannot access datadir at '/data_not_there/'.
+# 
+# Attempt to use bad paths - basedir
+#
+ERROR: Cannot access basedir at '/basedir_not_there/'.
+# 
+# Attempt to use bad paths - plugin_dir
+#
+ERROR: Cannot create /plugin_not_there/plugin.ini. Check permissions.
+#
+# Show the help.
+#
+mysql_plugin  Ver 1.0.0 Distrib 5.5.14
+Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+
+Enable or disable plugins.
+
+Plugins supported:
+    thread_pool
+    daemon_example
+
+Usage: mysql_plugin [options] <plugin> ENABLE|DISABLE
+
+Options:
+  -?, --help          Display this help and exit.
+  -b, --basedir=name  The basedir for the server.
+  -d, --datadir=name  The datadir for the server.
+  -p, --plugin-dir=name 
+                      The plugin dir for the server.
+  -i, --plugin-ini=name 
+                      Read plugin information from configuration file specified
+                      instead of from <plugin_dir>/plugin.ini.
+  -n, --no-defaults   Do not read values from configuration file.
+  -P, --print-defaults 
+                      Show default values from configuration file.
+  -v, --verbose       More verbose output; you can use this multiple times to
+                      get even more verbose output.
+  -V, --version       Output version information and exit.
+
+

=== added file 'mysql-test/t/mysql_plugin-master.opt'
--- a/mysql-test/t/mysql_plugin-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/mysql_plugin-master.opt	2011-05-26 19:25:47 +0000
@@ -0,0 +1 @@
+--plugin-dir=$DAEMONEXAMPLE_PLUGIN_DIR

=== added file 'mysql-test/t/mysql_plugin.test'
--- a/mysql-test/t/mysql_plugin.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/mysql_plugin.test	2011-05-26 19:25:47 +0000
@@ -0,0 +1,169 @@
+#
+# Test mysql_plugin tool
+#
+
+#
+# Test currently does not run on Windows because in Windows build trees,
+# mysqld.exe is not placed in the ./sql folder - it is placed either
+# in ./sql/Debug or ./sql/release. If this behaviour is changed, this test
+# can run on Windows.
+#
+--source include/not_windows.inc
+
+# Add the datadir, basedir, plugin_dir to the bootstrap command
+let $MYSQLD_DATADIR= `select @@datadir`;
+let $MYSQLD_BASEDIR= `select @@basedir`;
+let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_PLUGIN_DIR;
+
+--echo #
+--echo # Ensure the plugin isn't loaded.
+--echo #
+SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name;
+
+--echo #
+--echo # Enable the plugin...
+--echo #
+let $expect_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+# MTR will remove this file later, but this might be too late.
+--error 0,1
+--remove_file $expect_file
+--write_file $expect_file
+wait
+EOF
+--shutdown_server 10
+--source include/wait_until_disconnected.inc
+
+#
+# Enable the plugin
+#
+--exec $MYSQLD_BOOTSTRAP_CMD ENABLE daemon_example
+
+#
+# Ensure enabling an enabled plugin doesn't fail
+--exec $MYSQLD_BOOTSTRAP_CMD ENABLE daemon_example
+
+#
+# Restart the server
+#
+--append_file $expect_file
+restart
+EOF
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--echo #
+--echo # Ensure the plugin is now loaded.
+--echo #
+--replace_regex /\.dll/.so/
+SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name;
+
+--echo #
+--echo # Disable the plugin...
+--echo #
+# MTR will remove this file later, but this might be too late.
+--error 0,1
+--remove_file $expect_file
+--write_file $expect_file
+wait
+EOF
+--shutdown_server 10
+--source include/wait_until_disconnected.inc
+
+#
+# Disable the plugin
+#
+--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example
+
+#
+# Restart the server
+#
+--append_file $expect_file
+restart
+EOF
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+--echo #
+--echo # Ensure the plugin isn't loaded.
+--echo #
+SELECT * FROM mysql.plugin WHERE name = 'daemon_example' ORDER BY name;
+
+#
+# Stop the server for error conditions
+#
+let $expect_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
+# MTR will remove this file later, but this might be too late.
+--error 0,1
+--remove_file $expect_file
+--write_file $expect_file
+wait
+EOF
+--shutdown_server 10
+--source include/wait_until_disconnected.inc
+
+--echo #
+--echo # Attempt to load non-existant plugin
+--echo #
+--error 1,2,256
+--exec $MYSQLD_BOOTSTRAP_CMD DISABLE NOT_THERE_AT_ALL 2>&1
+
+--echo #
+--echo # Attempt to use non-existant plugin.ini file
+--echo #
+--error 1,2,256
+--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example --plugin-ini=/NOT/THERE/pi.ini 2>&1
+
+--echo # 
+--echo # Attempt to omit the plugin
+--echo #
+--error 1,2,256
+--exec $MYSQLD_BOOTSTRAP_CMD DISABLE 2>&1
+
+--echo # 
+--echo # Attempt to omit DISABLE|ENABLE
+--echo #
+--error 1,2,256
+--exec $MYSQLD_BOOTSTRAP_CMD daemon_example 2>&1
+
+--echo # 
+--echo # Attempt to use bad paths - datadir
+--echo #
+let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=/data_not_there/ --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=$DAEMONEXAMPLE_PLUGIN_DIR;
+--error 1,2,256
+--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1
+
+--echo # 
+--echo # Attempt to use bad paths - basedir
+--echo #
+let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=/basedir_not_there/ --plugin-dir=$DAEMONEXAMPLE_PLUGIN_DIR;
+--error 1,2,256
+--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1
+
+--echo # 
+--echo # Attempt to use bad paths - plugin_dir
+--echo #
+let $MYSQLD_BOOTSTRAP_CMD= $MYSQL_PLUGIN -n --datadir=$MYSQLD_DATADIR --basedir=$MYSQLD_BASEDIR/sql --plugin-dir=/plugin_not_there/;
+--error 1,2,256
+--exec $MYSQLD_BOOTSTRAP_CMD DISABLE daemon_example 2>&1
+
+--echo #
+--echo # Show the help.
+--echo #
+replace_result $MYSQL_PLUGIN mysql_plugin;
+--exec $MYSQL_PLUGIN --help
+
+#
+# Restart the server
+#
+--append_file $expect_file
+restart
+EOF
+--enable_reconnect
+--source include/wait_until_connected_again.inc
+
+#
+# Cleanup
+# MTR will remove this file later, but this might be too late.
+--error 0,1
+--remove_file $expect_file
+

Attachment: [text/bzr-bundle] bzr/chuck.bell@oracle.com-20110526192547-z4abvt8klp00i0v3.bundle
Thread
bzr commit into mysql-5.5 branch (chuck.bell:3409) WL#5710chuck.bell26 May
  • Re: bzr commit into mysql-5.5 branch (chuck.bell:3409) WL#5710Bjorn Munch27 May