Commit message: MDEV-26323 use-after-poison issue of MariaDB server
CVE: CVE-2022-27383
CWE: CWE-416
Vulnerability description: MariaDB Server v10.6 and below was discovered to contain an use-after-free in the component my_strcasecmp_8bit, which is exploited via specially crafted SQL statements.

Project: server

static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
                          void *save, st_mysql_value *value)
{
  my_bool fixed1, fixed2;
  long long orig, val;
  struct my_option options;
  value->val_int(value, &orig);
  val= orig;
  plugin_opt_set_limits(&options, var);

  if (var->flags & PLUGIN_VAR_UNSIGNED)
  {
    if ((fixed1= (!value->is_unsigned(value) && val < 0)))
      val=0;
    *(ulong *)save= (ulong) getopt_ull_limit_value((ulonglong) val, &options,
                                                   &fixed2);
  }
  else
  {
    if ((fixed1= (value->is_unsigned(value) && val < 0)))
      val=LONGLONG_MAX;
    *(long *)save= (long) getopt_ll_limit_value(val, &options, &fixed2);
  }

  return throw_bounds_warning(thd, var->name, fixed1 || fixed2,
                              value->is_unsigned(value), (longlong) orig);
}

Project: server

static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
                               int *argc, char **argv)
{
  struct sys_var_chain chain= { NULL, NULL };
  bool disable_plugin;
  enum_plugin_load_option plugin_load_option= tmp->load_option;

  MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
                      &tmp->mem_root : &plugin_vars_mem_root;
  st_mysql_sys_var **opt;
  my_option *opts= NULL;
  int error= 1;
  struct st_bookmark *var;
  uint len=0, count= EXTRA_OPTIONS;
  st_ptr_backup *tmp_backup= 0;
  DBUG_ENTER("test_plugin_options");
  DBUG_ASSERT(tmp->plugin && tmp->name.str);

  if (tmp->plugin->system_vars || (*argc > 1))
  {
    for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
    {
      len++;
      if (!((*opt)->flags & PLUGIN_VAR_NOCMDOPT))
        count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
    }

    if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
    {
      sql_print_error("Out of memory for plugin '%s'.", tmp->name.str);
      DBUG_RETURN(-1);
    }
    bzero(opts, sizeof(my_option) * count);

    if (construct_options(tmp_root, tmp, opts))
    {
      sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
      DBUG_RETURN(-1);
    }

    if (tmp->plugin->system_vars)
    {
      tmp_backup= (st_ptr_backup *)my_alloca(len * sizeof(tmp_backup[0]));
      DBUG_ASSERT(tmp->nbackups == 0);
      DBUG_ASSERT(tmp->ptr_backup == 0);

      for (opt= tmp->plugin->system_vars; *opt; opt++)
      {
        st_mysql_sys_var *o= *opt;
        char *varname;
        sys_var *v;

        if (o->flags & PLUGIN_VAR_NOSYSVAR)
          continue;

        tmp_backup[tmp->nbackups++].save(&o->name);
        if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
        {
          varname= var->key + 1;
          var->loaded= TRUE;
        }
        else
        {
          var= NULL;
          len= tmp->name.length + strlen(o->name) + 2;
          varname= (char*) alloc_root(mem_root, len);
          strxmov(varname, tmp->name.str, "-", o->name, NullS);
          my_casedn_str(&my_charset_latin1, varname);
          convert_dash_to_underscore(varname, len-1);
        }
        v= new (mem_root) sys_var_pluginvar(&chain, varname, tmp, o);
        v->test_load= (var ? &var->loaded : &static_unload);
        DBUG_ASSERT(static_unload == FALSE);

        if (!(o->flags & PLUGIN_VAR_NOCMDOPT))
        {
          // update app_type, used for I_S.SYSTEM_VARIABLES
          for (my_option *mo=opts; mo->name; mo++)
            if (mo->app_type == o)
              mo->app_type= v;
        }
      }

      if (tmp->nbackups)
      {
        size_t bytes= tmp->nbackups * sizeof(tmp->ptr_backup[0]);
        tmp->ptr_backup= (st_ptr_backup *)alloc_root(mem_root, bytes);
        if (!tmp->ptr_backup)
        {
          restore_ptr_backup(tmp->nbackups, tmp_backup);
          my_afree(tmp_backup);
          goto err;
        }
        memcpy(tmp->ptr_backup, tmp_backup, bytes);
      }
      my_afree(tmp_backup);
    }

    /*
      We adjust the default value to account for the hardcoded exceptions
      we have set for the federated and ndbcluster storage engines.
    */
    if (!plugin_is_forced(tmp))
      opts[0].def_value= opts[1].def_value= plugin_load_option;

    error= handle_options(argc, &argv, opts, mark_changed);
    (*argc)++; /* add back one for the program name */

    if (error)
    {
       sql_print_error("Parsing options for plugin '%s' failed.",
                       tmp->name.str);
       goto err;
    }
    /*
     Set plugin loading policy from option value. First element in the option
     list is always the <plugin name> option value.
    */
    if (!plugin_is_forced(tmp))
      plugin_load_option= (enum_plugin_load_option) *(ulong*) opts[0].value;
  }

  disable_plugin= (plugin_load_option == PLUGIN_OFF);
  tmp->load_option= plugin_load_option;

  error= 1;

  /*
    If the plugin is disabled it should not be initialized.
  */
  if (disable_plugin)
  {
    if (global_system_variables.log_warnings)
      sql_print_information("Plugin '%s' is disabled.",
                            tmp->name.str);
    goto err;
  }

  if (tmp->plugin->system_vars)
  {
    for (opt= tmp->plugin->system_vars; *opt; opt++)
    {
      /*
        PLUGIN_VAR_STR command-line options without PLUGIN_VAR_MEMALLOC, point
        directly to values in the argv[] array. For plugins started at the
        server startup, argv[] array is allocated with load_defaults(), and
        freed when the server is shut down.  But for plugins loaded with
        INSTALL PLUGIN, the memory allocated with load_defaults() is freed with
        free() at the end of mysql_install_plugin(). Which means we cannot
        allow any pointers into that area.
        Thus, for all plugins loaded after the server was started,
        we copy string values to a plugin's memroot.
      */
      if (mysqld_server_started &&
          (((*opt)->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_NOCMDOPT |
                             PLUGIN_VAR_MEMALLOC)) == PLUGIN_VAR_STR))
      {
        sysvar_str_t* str= (sysvar_str_t *)*opt;
        if (*str->value)
          *str->value= strdup_root(mem_root, *str->value);
      }
    }

    if (chain.first)
    {
      chain.last->next = NULL;
      if (mysql_add_sys_var_chain(chain.first))
      {
        sql_print_error("Plugin '%s' has conflicting system variables",
                        tmp->name.str);
        goto err;
      }
      tmp->system_vars= chain.first;
    }
  }

  DBUG_RETURN(0);

err:
  if (opts)
    my_cleanup_options(opts);
  DBUG_RETURN(error);
}

Project: server

void plugin_unlock(THD *thd, plugin_ref plugin)
{
  LEX *lex= thd ? thd->lex : 0;
  DBUG_ENTER("plugin_unlock");
  if (!plugin)
    DBUG_VOID_RETURN;
#ifdef DBUG_OFF
  /* built-in plugins don't need ref counting */
  if (!plugin_dlib(plugin))
    DBUG_VOID_RETURN;
#endif
  mysql_mutex_lock(&LOCK_plugin);
  intern_plugin_unlock(lex, plugin);
  reap_plugins();
  mysql_mutex_unlock(&LOCK_plugin);
  DBUG_VOID_RETURN;
}

Project: server

uchar* sys_var_pluginvar::real_value_ptr(THD *thd, enum_var_type type)
{
  if (type == OPT_DEFAULT)
  {
    switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
    case PLUGIN_VAR_BOOL:
      thd->sys_var_tmp.my_bool_value= (my_bool)option.def_value;
      return (uchar*) &thd->sys_var_tmp.my_bool_value;
    case PLUGIN_VAR_INT:
      thd->sys_var_tmp.int_value= (int)option.def_value;
      return (uchar*) &thd->sys_var_tmp.int_value;
    case PLUGIN_VAR_LONG:
    case PLUGIN_VAR_ENUM:
      thd->sys_var_tmp.long_value= (long)option.def_value;
      return (uchar*) &thd->sys_var_tmp.long_value;
    case PLUGIN_VAR_LONGLONG:
    case PLUGIN_VAR_SET:
      return (uchar*) &option.def_value;
    case PLUGIN_VAR_STR:
      thd->sys_var_tmp.ptr_value= (void*) option.def_value;
      return (uchar*) &thd->sys_var_tmp.ptr_value;
    case PLUGIN_VAR_DOUBLE:
      thd->sys_var_tmp.double_value= getopt_ulonglong2double(option.def_value);
      return (uchar*) &thd->sys_var_tmp.double_value;
    default:
      DBUG_ASSERT(0);
    }
  }

  DBUG_ASSERT(thd || (type == OPT_GLOBAL));
  if (plugin_var->flags & PLUGIN_VAR_THDLOCAL)
  {
    if (type == OPT_GLOBAL)
      thd= NULL;

    return intern_sys_var_ptr(thd, *(int*) (plugin_var+1), false);
  }
  return *(uchar**) (plugin_var+1);
}

Project: server

static void plugin_dl_del(struct st_plugin_dl *plugin_dl)
{
  DBUG_ENTER("plugin_dl_del");

  if (!plugin_dl)
    DBUG_VOID_RETURN;

  mysql_mutex_assert_owner(&LOCK_plugin);

  /* Do not remove this element, unless no other plugin uses this dll. */
  if (! --plugin_dl->ref_count)
  {
    free_plugin_mem(plugin_dl);
    bzero(plugin_dl, sizeof(struct st_plugin_dl));
  }

  DBUG_VOID_RETURN;
}

Project: server

bool mysql_install_plugin(THD *thd, const LEX_STRING *name,
                          const LEX_STRING *dl_arg)
{
  TABLE_LIST tables;
  TABLE *table;
  LEX_STRING dl= *dl_arg;
  bool error;
  int argc=orig_argc;
  char **argv=orig_argv;
  unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
  { MYSQL_AUDIT_GENERAL_CLASSMASK };
  DBUG_ENTER("mysql_install_plugin");

  tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);
  if (!opt_noacl && check_table_access(thd, INSERT_ACL, &tables, FALSE, 1, FALSE))
    DBUG_RETURN(TRUE);
  WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);

  /* need to open before acquiring LOCK_plugin or it will deadlock */
  if (! (table = open_ltable(thd, &tables, TL_WRITE,
                             MYSQL_LOCK_IGNORE_TIMEOUT)))
    DBUG_RETURN(TRUE);

  if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL))
  {
    report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str);
    DBUG_RETURN(TRUE);
  }

  /*
    Pre-acquire audit plugins for events that may potentially occur
    during [UN]INSTALL PLUGIN.

    When audit event is triggered, audit subsystem acquires interested
    plugins by walking through plugin list. Evidently plugin list
    iterator protects plugin list by acquiring LOCK_plugin, see
    plugin_foreach_with_mask().

    On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
    rather for a long time.

    When audit event is triggered during [UN]INSTALL PLUGIN, plugin
    list iterator acquires the same lock (within the same thread)
    second time.

    This hack should be removed when LOCK_plugin is fixed so it
    protects only what it supposed to protect.

    See also mysql_uninstall_plugin() and initialize_audit_plugin()
  */
  if (mysql_audit_general_enabled())
    mysql_audit_acquire_plugins(thd, event_class_mask);

  mysql_mutex_lock(&LOCK_plugin);
  error= plugin_add(thd->mem_root, name, &dl, REPORT_TO_USER);
  if (error)
    goto err;

  if (name->str)
    error= finalize_install(thd, table, name, &argc, argv);
  else
  {
    st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
    struct st_maria_plugin *plugin;
    for (plugin= plugin_dl->plugins; plugin->info; plugin++)
    {
      LEX_STRING str= { const_cast<char*>(plugin->name), strlen(plugin->name) };
      error|= finalize_install(thd, table, &str, &argc, argv);
    }
  }

  if (error)
  {
    reap_needed= true;
    reap_plugins();
  }
err:
  global_plugin_version++;
  mysql_mutex_unlock(&LOCK_plugin);
  if (argv)
    free_defaults(argv);
  DBUG_RETURN(error);

WSREP_ERROR_LABEL:
  DBUG_RETURN(TRUE);
}

Project: server

static inline void convert_underscore_to_dash(char *str, int len)
{
  for (char *p= str; p <= str+len; p++)
    if (*p == '_')
      *p= '-';
}

Project: server

static void update_func_longlong(THD *thd, struct st_mysql_sys_var *var,
                             void *tgt, const void *save)
{
  *(longlong *)tgt= *(ulonglong *) save;
}

Project: server

static int *mysql_sys_var_int(THD* thd, int offset)
{
  return (int *) intern_sys_var_ptr(thd, offset, true);
}

Project: server

static st_plugin_int *plugin_insert_or_reuse(struct st_plugin_int *plugin)
{
  uint i;
  struct st_plugin_int *tmp;
  DBUG_ENTER("plugin_insert_or_reuse");
  for (i= 0; i < plugin_array.elements; i++)
  {
    tmp= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
    if (tmp->state == PLUGIN_IS_FREED)
    {
      memcpy(tmp, plugin, sizeof(struct st_plugin_int));
      DBUG_RETURN(tmp);
    }
  }
  if (insert_dynamic(&plugin_array, (uchar*)&plugin))
    DBUG_RETURN(0);
  tmp= *dynamic_element(&plugin_array, plugin_array.elements - 1,
                        struct st_plugin_int **)=
       (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)plugin,
                                            sizeof(struct st_plugin_int));
  DBUG_RETURN(tmp);
}

Project: server

void add_plugin_options(DYNAMIC_ARRAY *options, MEM_ROOT *mem_root)
{
  struct st_plugin_int *p;
  my_option *opt;

  if (!initialized)
    return;

  for (uint idx= 0; idx < plugin_array.elements; idx++)
  {
    p= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);

    if (!(opt= construct_help_options(mem_root, p)))
      continue;

    /* Only options with a non-NULL comment are displayed in help text */
    for (;opt->name; opt++)
      if (opt->comment)
        insert_dynamic(options, (uchar*) opt);
  }
}

Project: server

static my_option *construct_help_options(MEM_ROOT *mem_root,
                                         struct st_plugin_int *p)
{
  st_mysql_sys_var **opt;
  my_option *opts;
  uint count= EXTRA_OPTIONS;
  DBUG_ENTER("construct_help_options");

  for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2)
    ;

  if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
    DBUG_RETURN(NULL);

  bzero(opts, sizeof(my_option) * count);

  /**
    some plugin variables (those that don't have PLUGIN_VAR_NOSYSVAR flag)
    have their names prefixed with the plugin name. Restore the names here
    to get the correct (not double-prefixed) help text.
    We won't need @@sysvars anymore and don't care about their proper names.
  */
  restore_ptr_backup(p->nbackups, p->ptr_backup);

  if (construct_options(mem_root, p, opts))
    DBUG_RETURN(NULL);

  DBUG_RETURN(opts);
}

Project: server

static void plugin_del(struct st_plugin_int *plugin)
{
  DBUG_ENTER("plugin_del");
  mysql_mutex_assert_owner(&LOCK_plugin);
  /* Free allocated strings before deleting the plugin. */
  plugin_vars_free_values(plugin->system_vars);
  restore_ptr_backup(plugin->nbackups, plugin->ptr_backup);
  if (plugin->plugin_dl)
  {
    my_hash_delete(&plugin_hash[plugin->plugin->type], (uchar*)plugin);
    plugin_dl_del(plugin->plugin_dl);
    plugin->state= PLUGIN_IS_FREED;
    free_root(&plugin->mem_root, MYF(0));
  }
  else
    plugin->state= PLUGIN_IS_UNINITIALIZED;
  DBUG_VOID_RETURN;
}

Project: server

static long long *mysql_sys_var_longlong(THD* thd, int offset)
{
  return (long long *) intern_sys_var_ptr(thd, offset, true);
}

Project: server

bool plugin_dl_foreach(THD *thd, const LEX_STRING *dl,
                       plugin_foreach_func *func, void *arg)
{
  bool err= 0;

  if (dl)
  {
    mysql_mutex_lock(&LOCK_plugin);
    st_plugin_dl *plugin_dl= plugin_dl_add(dl, REPORT_TO_USER);
    mysql_mutex_unlock(&LOCK_plugin);

    if (!plugin_dl)
      return 1;

    err= plugin_dl_foreach_internal(thd, plugin_dl, plugin_dl->plugins,
                                    func, arg);

    mysql_mutex_lock(&LOCK_plugin);
    plugin_dl_del(plugin_dl);
    mysql_mutex_unlock(&LOCK_plugin);
  }
  else
  {
    struct st_maria_plugin **builtins;
    for (builtins= mysql_mandatory_plugins; !err && *builtins; builtins++)
      err= plugin_dl_foreach_internal(thd, 0, *builtins, func, arg);
    for (builtins= mysql_optional_plugins; !err && *builtins; builtins++)
      err= plugin_dl_foreach_internal(thd, 0, *builtins, func, arg);
  }
  return err;
}

Project: server

void wsrep_plugins_pre_init()
{
  wsrep_dummy_plugin_ptr= &wsrep_dummy_plugin;
  wsrep_dummy_plugin.state= PLUGIN_IS_DISABLED;
  global_system_variables.table_plugin=
    plugin_int_to_ref(wsrep_dummy_plugin_ptr);
}

Project: server

static int check_func_str(THD *thd, struct st_mysql_sys_var *var,
                          void *save, st_mysql_value *value)
{
  char buff[STRING_BUFFER_USUAL_SIZE];
  const char *str;
  int length;

  length= sizeof(buff);
  if ((str= value->val_str(value, buff, &length)))
    str= thd->strmake(str, length);
  *(const char**)save= str;
  return 0;
}

Project: server

static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *)
{
  return 0;
}

Project: server

bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
                       int type, uint state_mask, void *arg)
{
  uint idx, total= 0;
  struct st_plugin_int *plugin;
  plugin_ref *plugins;
  my_bool res= FALSE;
  DBUG_ENTER("plugin_foreach_with_mask");

  if (!initialized)
    DBUG_RETURN(FALSE);

  mysql_mutex_lock(&LOCK_plugin);
  /*
    Do the alloca out here in case we do have a working alloca:
    leaving the nested stack frame invalidates alloca allocation.
  */
  if (type == MYSQL_ANY_PLUGIN)
  {
    plugins= (plugin_ref*) my_alloca(plugin_array.elements * sizeof(plugin_ref));
    for (idx= 0; idx < plugin_array.elements; idx++)
    {
      plugin= *dynamic_element(&plugin_array, idx, struct st_plugin_int **);
      if ((plugins[total]= intern_plugin_lock(0, plugin_int_to_ref(plugin),
                                              state_mask)))
        total++;
    }
  }
  else
  {
    HASH *hash= plugin_hash + type;
    plugins= (plugin_ref*) my_alloca(hash->records * sizeof(plugin_ref));
    for (idx= 0; idx < hash->records; idx++)
    {
      plugin= (struct st_plugin_int *) my_hash_element(hash, idx);
      if ((plugins[total]= intern_plugin_lock(0, plugin_int_to_ref(plugin),
                                              state_mask)))
        total++;
    }
  }
  mysql_mutex_unlock(&LOCK_plugin);

  for (idx= 0; idx < total; idx++)
  {
    /* It will stop iterating on first engine error when "func" returns TRUE */
    if ((res= func(thd, plugins[idx], arg)))
        break;
  }

  plugin_unlock_list(0, plugins, total);
  my_afree(plugins);
  DBUG_RETURN(res);
}

Project: server

static bool register_builtin(struct st_maria_plugin *plugin,
                             struct st_plugin_int *tmp,
                             struct st_plugin_int **ptr)
{
  DBUG_ENTER("register_builtin");
  tmp->ref_count= 0;
  tmp->plugin_dl= 0;

  if (insert_dynamic(&plugin_array, (uchar*)&tmp))
    DBUG_RETURN(1);

  *ptr= *dynamic_element(&plugin_array, plugin_array.elements - 1,
                         struct st_plugin_int **)=
        (struct st_plugin_int *) memdup_root(&plugin_mem_root, (uchar*)tmp,
                                             sizeof(struct st_plugin_int));

  if (my_hash_insert(&plugin_hash[plugin->type],(uchar*) *ptr))
    DBUG_RETURN(1);

  DBUG_RETURN(0);
}

Project: server

static int check_func_set(THD *thd, struct st_mysql_sys_var *var,
                          void *save, st_mysql_value *value)
{
  char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
  const char *str;
  TYPELIB *typelib;
  ulonglong result;
  uint error_len= 0;                            // init as only set on error
  bool not_used;
  int length;

  if (var->flags & PLUGIN_VAR_THDLOCAL)
    typelib= ((thdvar_set_t*) var)->typelib;
  else
    typelib= ((sysvar_set_t*)var)->typelib;

  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
  {
    length= sizeof(buff);
    if (!(str= value->val_str(value, buff, &length)))
      goto err;
    result= find_set(typelib, str, length, NULL,
                     &error, &error_len, &not_used);
    if (error_len)
      goto err;
  }
  else
  {
    if (value->val_int(value, (long long *)&result))
      goto err;
    if (unlikely((result >= (1ULL << typelib->count)) &&
                 (typelib->count < sizeof(long)*8)))
      goto err;
  }
  *(ulonglong*)save= result;
  return 0;
err:
  return 1;
}

Project: server

static void update_func_int(THD *thd, struct st_mysql_sys_var *var,
                             void *tgt, const void *save)
{
  *(int *)tgt= *(int *) save;
}

Project: server

static void update_func_double(THD *thd, struct st_mysql_sys_var *var,
                               void *tgt, const void *save)
{
  *(double *) tgt= *(double *) save;
}

Project: server

static void report_error(int where_to, uint error, ...)
{
  va_list args;
  DBUG_ASSERT(where_to & (REPORT_TO_USER | REPORT_TO_LOG));
  if (where_to & REPORT_TO_USER)
  {
    va_start(args, error);
    my_printv_error(error, ER(error), MYF(0), args);
    va_end(args);
  }
  if (where_to & REPORT_TO_LOG)
  {
    va_start(args, error);
    error_log_print(ERROR_LEVEL, ER_DEFAULT(error), args);
    va_end(args);
  }
}

Project: server

static void plugin_deinitialize(struct st_plugin_int *plugin, bool ref_check)
{
  /*
    we don't want to hold the LOCK_plugin mutex as it may cause
    deinitialization to deadlock if plugins have worker threads
    with plugin locks
  */
  mysql_mutex_assert_not_owner(&LOCK_plugin);

  if (plugin->plugin->status_vars)
  {
    /*
      historical ndb behavior caused MySQL plugins to specify
      status var names in full, with the plugin name prefix.
      this was never fixed in MySQL.
      MariaDB fixes that but supports MySQL style too.
    */
    SHOW_VAR *show_vars= plugin->plugin->status_vars;
    SHOW_VAR tmp_array[2]= {
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
      {0, 0, SHOW_UNDEF}
    };
    if (strncasecmp(show_vars->name, plugin->name.str, plugin->name.length))
      show_vars= tmp_array;

    remove_status_vars(show_vars);
  }

  if (plugin_type_deinitialize[plugin->plugin->type])
  {
    if ((*plugin_type_deinitialize[plugin->plugin->type])(plugin))
    {
      sql_print_error("Plugin '%s' of type %s failed deinitialization",
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
    }
  }
  else if (plugin->plugin->deinit)
  {
    DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
    if (plugin->plugin->deinit(plugin))
    {
      DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
                             plugin->name.str));
    }
  }
  plugin->state= PLUGIN_IS_UNINITIALIZED;

  if (ref_check && plugin->ref_count)
    sql_print_error("Plugin '%s' has ref_count=%d after deinitialization.",
                    plugin->name.str, plugin->ref_count);
  plugin_variables_deinit(plugin);
}

Project: server

static bool plugin_load_list(MEM_ROOT *tmp_root, const char *list)
{
  char buffer[FN_REFLEN];
  LEX_STRING name= {buffer, 0}, dl= {NULL, 0}, *str= &name;
  char *p= buffer;
  DBUG_ENTER("plugin_load_list");
  while (list)
  {
    if (p == buffer + sizeof(buffer) - 1)
    {
      sql_print_error("plugin-load parameter too long");
      DBUG_RETURN(TRUE);
    }

    switch ((*(p++)= *(list++))) {
    case '\0':
      list= NULL; /* terminate the loop */
      /* fall through */
    case ';':
#ifndef __WIN__
    case ':':     /* can't use this as delimiter as it may be drive letter */
#endif
      str->str[str->length]= '\0';
      if (str == &name)  // load all plugins in named module
      {
        if (!name.length)
        {
          p--;    /* reset pointer */
          continue;
        }

        dl= name;
        mysql_mutex_lock(&LOCK_plugin);
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
        name.str= 0; // load everything
        if (plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG))
          goto error;
      }
      else
      {
        free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
        mysql_mutex_lock(&LOCK_plugin);
        if (plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG))
          goto error;
      }
      mysql_mutex_unlock(&LOCK_plugin);
      name.length= dl.length= 0;
      dl.str= NULL; name.str= p= buffer;
      str= &name;
      continue;
    case '=':
    case '#':
      if (str == &name)
      {
        name.str[name.length]= '\0';
        str= &dl;
        str->str= p;
        continue;
      }
      /* fall through */
    default:
      str->length++;
      continue;
    }
  }
  DBUG_RETURN(FALSE);
error:
  mysql_mutex_unlock(&LOCK_plugin);
  if (name.str)
    sql_print_error("Couldn't load plugin '%s' from '%s'.",
                    name.str, dl.str);
  else
    sql_print_error("Couldn't load plugins from '%s'.", dl.str);
  DBUG_RETURN(TRUE);
}

Project: server

static void plugin_load(MEM_ROOT *tmp_root)
{
  TABLE_LIST tables;
  TABLE *table;
  READ_RECORD read_record_info;
  int error;
  THD *new_thd= new THD(0);
  bool result;
  DBUG_ENTER("plugin_load");

  if (global_system_variables.log_warnings >= 9)
    sql_print_information("Initializing installed plugins");

  new_thd->thread_stack= (char*) &tables;
  new_thd->store_globals();
  new_thd->db= my_strdup("mysql", MYF(0));
  new_thd->db_length= 5;
  bzero((char*) &new_thd->net, sizeof(new_thd->net));
  tables.init_one_table(STRING_WITH_LEN("mysql"), STRING_WITH_LEN("plugin"),
                        "plugin", TL_READ);
  tables.open_strategy= TABLE_LIST::OPEN_NORMAL;

  result= open_and_lock_tables(new_thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT);

  table= tables.table;
  if (result)
  {
    DBUG_PRINT("error",("Can't open plugin table"));
    if (!opt_help)
      sql_print_error("Could not open mysql.plugin table. "
                      "Some plugins may be not loaded");
    else
      sql_print_warning("Could not open mysql.plugin table. "
                        "Some options may be missing from the help text");
    goto end;
  }

  if (init_read_record(&read_record_info, new_thd, table, NULL, NULL, 1, 0,
                       FALSE))
  {
    sql_print_error("Could not initialize init_read_record; Plugins not "
                    "loaded");
    goto end;
  }
  table->use_all_columns();
  while (!(error= read_record_info.read_record(&read_record_info)))
  {
    DBUG_PRINT("info", ("init plugin record"));
    String str_name, str_dl;
    get_field(tmp_root, table->field[0], &str_name);
    get_field(tmp_root, table->field[1], &str_dl);

    LEX_STRING name= {(char *)str_name.ptr(), str_name.length()};
    LEX_STRING dl= {(char *)str_dl.ptr(), str_dl.length()};

    if (!name.length || !dl.length)
      continue;

    /*
      there're no other threads running yet, so we don't need a mutex.
      but plugin_add() before is designed to work in multi-threaded
      environment, and it uses mysql_mutex_assert_owner(), so we lock
      the mutex here to satisfy the assert
    */
    mysql_mutex_lock(&LOCK_plugin);
    plugin_add(tmp_root, &name, &dl, REPORT_TO_LOG);
    free_root(tmp_root, MYF(MY_MARK_BLOCKS_FREE));
    mysql_mutex_unlock(&LOCK_plugin);
  }
  if (error > 0)
    sql_print_error(ER_THD(new_thd, ER_GET_ERRNO), my_errno,
                           table->file->table_type());
  end_read_record(&read_record_info);
  table->mark_table_for_reopen();
  close_mysql_tables(new_thd);
end:
  delete new_thd;
  DBUG_VOID_RETURN;
}

Project: server

static void restore_ptr_backup(uint n, st_ptr_backup *backup)
{
  while (n--)
    (backup++)->restore();
}

Project: server

void thd_key_delete(MYSQL_THD_KEY_T *key)
{
  *key= INVALID_THD_KEY;
}

Project: server

  uchar* session_value_ptr(THD *thd, const LEX_STRING *base)
  { return do_value_ptr(thd, OPT_SESSION, base); }

Project: server

static bool do_uninstall(THD *thd, TABLE *table, const LEX_STRING *name)
{
  struct st_plugin_int *plugin;
  mysql_mutex_assert_owner(&LOCK_plugin);

  if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)) ||
      plugin->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_DYING))
  {
    // maybe plugin is in mysql.plugin present so postpond the error
    plugin= NULL;
  }

  if (plugin)
  {
    if (!plugin->plugin_dl)
    {
      my_error(ER_PLUGIN_DELETE_BUILTIN, MYF(0));
      return 1;
    }
    if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT)
    {
      my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str);
      return 1;
    }

    plugin->state= PLUGIN_IS_DELETED;
    if (plugin->ref_count)
      push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
          WARN_PLUGIN_BUSY, ER_THD(thd, WARN_PLUGIN_BUSY));
    else
      reap_needed= true;
  }

  uchar user_key[MAX_KEY_LENGTH];
  table->use_all_columns();
  table->field[0]->store(name->str, name->length, system_charset_info);
  key_copy(user_key, table->record[0], table->key_info,
           table->key_info->key_length);
  if (! table->file->ha_index_read_idx_map(table->record[0], 0, user_key,
                                           HA_WHOLE_KEY, HA_READ_KEY_EXACT))
  {
    int error;
    /*
      We do not replicate the UNINSTALL PLUGIN statement. Disable binlogging
      of the delete from the plugin table, so that it is not replicated in
      row based mode.
    */
    tmp_disable_binlog(thd);
    error= table->file->ha_delete_row(table->record[0]);
    reenable_binlog(thd);
    if (error)
    {
      table->file->print_error(error, MYF(0));
      return 1;
    }
  }
  else if (!plugin)
  {
    my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str);
    return 1;
  }
  return 0;
}

Project: server

static void plugin_vars_free_values(sys_var *vars)
{
  DBUG_ENTER("plugin_vars_free_values");

  for (sys_var *var= vars; var; var= var->next)
  {
    sys_var_pluginvar *piv= var->cast_pluginvar();
    if (piv &&
        ((piv->plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
        (piv->plugin_var->flags & PLUGIN_VAR_MEMALLOC))
    {
      /* Free the string from global_system_variables. */
      char **valptr= (char**) piv->real_value_ptr(NULL, OPT_GLOBAL);
      DBUG_PRINT("plugin", ("freeing value for: '%s'  addr: %p",
                            var->name.str, valptr));
      my_free(*valptr);
      *valptr= NULL;
    }
  }
  DBUG_VOID_RETURN;
}

Project: server

static void unlock_variables(THD *thd, struct system_variables *vars)
{
  intern_plugin_unlock(NULL, vars->table_plugin);
  intern_plugin_unlock(NULL, vars->tmp_table_plugin);
  intern_plugin_unlock(NULL, vars->enforced_table_plugin);
  vars->table_plugin= vars->tmp_table_plugin= vars->enforced_table_plugin= NULL;
}

Project: server

static plugin_ref intern_plugin_lock(LEX *lex, plugin_ref rc,
                                     uint state_mask= PLUGIN_IS_READY |
                                                      PLUGIN_IS_UNINITIALIZED |
                                                      PLUGIN_IS_DELETED)
{
  st_plugin_int *pi= plugin_ref_to_int(rc);
  DBUG_ENTER("intern_plugin_lock");

  mysql_mutex_assert_owner(&LOCK_plugin);

  if (pi->state & state_mask)
  {
    plugin_ref plugin;
#ifdef DBUG_OFF
    /*
      In optimized builds we don't do reference counting for built-in
      (plugin->plugin_dl == 0) plugins.
    */
    if (!pi->plugin_dl)
      DBUG_RETURN(pi);

    plugin= pi;
#else
    /*
      For debugging, we do an additional malloc which allows the
      memory manager and/or valgrind to track locked references and
      double unlocks to aid resolving reference counting problems.
    */
    if (!(plugin= (plugin_ref) my_malloc(sizeof(pi), MYF(MY_WME))))
      DBUG_RETURN(NULL);

    *plugin= pi;
#endif
    pi->ref_count++;
    DBUG_PRINT("lock",("thd: %p  plugin: \"%s\" LOCK ref_count: %d",
                       current_thd, pi->name.str, pi->ref_count));

    if (lex)
      insert_dynamic(&lex->plugins, (uchar*)&plugin);
    DBUG_RETURN(plugin);
  }
  DBUG_RETURN(NULL);
}

Project: server

void plugin_mutex_init()
{
#ifdef HAVE_PSI_INTERFACE
  init_plugin_psi_keys();
#endif
  mysql_mutex_init(key_LOCK_plugin, &LOCK_plugin, MY_MUTEX_INIT_FAST);
}

Project: server

static int plugin_initialize(MEM_ROOT *tmp_root, struct st_plugin_int *plugin,
                             int *argc, char **argv, bool options_only)
{
  int ret= 1;
  DBUG_ENTER("plugin_initialize");

  mysql_mutex_assert_owner(&LOCK_plugin);
  uint state= plugin->state;
  DBUG_ASSERT(state == PLUGIN_IS_UNINITIALIZED);

  mysql_mutex_unlock(&LOCK_plugin);

  mysql_prlock_wrlock(&LOCK_system_variables_hash);
  if (test_plugin_options(tmp_root, plugin, argc, argv))
    state= PLUGIN_IS_DISABLED;
  mysql_prlock_unlock(&LOCK_system_variables_hash);

  if (options_only || state == PLUGIN_IS_DISABLED)
  {
    ret= !options_only && plugin_is_forced(plugin);
    state= PLUGIN_IS_DISABLED;
    goto err;
  }

  if (plugin_type_initialize[plugin->plugin->type])
  {
    if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
    {
      sql_print_error("Plugin '%s' registration as a %s failed.",
                      plugin->name.str, plugin_type_names[plugin->plugin->type].str);
      goto err;
    }
  }
  else if (plugin->plugin->init)
  {
    if (plugin->plugin->init(plugin))
    {
      sql_print_error("Plugin '%s' init function returned error.",
                      plugin->name.str);
      goto err;
    }
  }
  state= PLUGIN_IS_READY; // plugin->init() succeeded

  if (plugin->plugin->status_vars)
  {
    /*
      historical ndb behavior caused MySQL plugins to specify
      status var names in full, with the plugin name prefix.
      this was never fixed in MySQL.
      MariaDB fixes that but supports MySQL style too.
    */
    SHOW_VAR *show_vars= plugin->plugin->status_vars;
    SHOW_VAR tmp_array[2]= {
      {plugin->plugin->name, (char*)plugin->plugin->status_vars, SHOW_ARRAY},
      {0, 0, SHOW_UNDEF}
    };
    if (strncasecmp(show_vars->name, plugin->name.str, plugin->name.length))
      show_vars= tmp_array;

    if (add_status_vars(show_vars))
      goto err;
  }

  ret= 0;

err:
  if (ret)
    plugin_variables_deinit(plugin);

  mysql_mutex_lock(&LOCK_plugin);
  plugin->state= state;

  DBUG_RETURN(ret);
}

Project: server

bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name,
                            const LEX_STRING *dl_arg)
{
  TABLE *table;
  TABLE_LIST tables;
  LEX_STRING dl= *dl_arg;
  bool error= false;
  unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE] =
  { MYSQL_AUDIT_GENERAL_CLASSMASK };
  DBUG_ENTER("mysql_uninstall_plugin");

  tables.init_one_table("mysql", 5, "plugin", 6, "plugin", TL_WRITE);

  if (!opt_noacl && check_table_access(thd, DELETE_ACL, &tables, FALSE, 1, FALSE))
    DBUG_RETURN(TRUE);

  WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)

  /* need to open before acquiring LOCK_plugin or it will deadlock */
  if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
    DBUG_RETURN(TRUE);

  if (!table->key_info)
  {
    my_printf_error(ER_UNKNOWN_ERROR,
                    "The table %s.%s has no primary key. "
                    "Please check the table definition and "
                    "create the primary key accordingly.", MYF(0),
                    table->s->db.str, table->s->table_name.str);
    DBUG_RETURN(TRUE);
  }

  /*
    Pre-acquire audit plugins for events that may potentially occur
    during [UN]INSTALL PLUGIN.

    When audit event is triggered, audit subsystem acquires interested
    plugins by walking through plugin list. Evidently plugin list
    iterator protects plugin list by acquiring LOCK_plugin, see
    plugin_foreach_with_mask().

    On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
    rather for a long time.

    When audit event is triggered during [UN]INSTALL PLUGIN, plugin
    list iterator acquires the same lock (within the same thread)
    second time.

    This hack should be removed when LOCK_plugin is fixed so it
    protects only what it supposed to protect.

    See also mysql_install_plugin() and initialize_audit_plugin()
  */
  if (mysql_audit_general_enabled())
    mysql_audit_acquire_plugins(thd, event_class_mask);

  mysql_mutex_lock(&LOCK_plugin);

  if (name->str)
    error= do_uninstall(thd, table, name);
  else
  {
    fix_dl_name(thd->mem_root, &dl);
    st_plugin_dl *plugin_dl= plugin_dl_find(&dl);
    if (plugin_dl)
    {
      for (struct st_maria_plugin *plugin= plugin_dl->plugins;
           plugin->info; plugin++)
      {
        LEX_STRING str= { const_cast<char*>(plugin->name), strlen(plugin->name) };
        error|= do_uninstall(thd, table, &str);
      }
    }
    else
    {
      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SONAME", dl.str);
      error= true;
    }
  }
  reap_plugins();

  global_plugin_version++;
  mysql_mutex_unlock(&LOCK_plugin);
  DBUG_RETURN(error);

WSREP_ERROR_LABEL:
  DBUG_RETURN(TRUE);
}

Project: server

my_bool mark_changed(int, const struct my_option *opt, char *)
{
  if (opt->app_type)
  {
    sys_var *var= (sys_var*) opt->app_type;
    var->value_origin= sys_var::CONFIG;
  }
  return 0;
}

Project: server

sys_var *find_plugin_sysvar(st_plugin_int *plugin, st_mysql_sys_var *plugin_var)
{
  for (sys_var *var= plugin->system_vars; var; var= var->next)
  {
    sys_var_pluginvar *pvar=var->cast_pluginvar();
    if (pvar->plugin_var == plugin_var)
      return var;
  }
  return 0;
}

Project: server

static SHOW_COMP_OPTION plugin_status(const LEX_STRING *name, int type)
{
  SHOW_COMP_OPTION rc= SHOW_OPTION_NO;
  struct st_plugin_int *plugin;
  DBUG_ENTER("plugin_is_ready");
  mysql_mutex_lock(&LOCK_plugin);
  if ((plugin= plugin_find_internal(name, type)))
  {
    rc= SHOW_OPTION_DISABLED;
    if (plugin->state == PLUGIN_IS_READY)
      rc= SHOW_OPTION_YES;
  }
  mysql_mutex_unlock(&LOCK_plugin);
  DBUG_RETURN(rc);
}

Project: server

  virtual void session_save_default(THD *thd, set_var *var) {}

Project: server

bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
{
  DBUG_ASSERT(!is_readonly());
  mysql_mutex_assert_owner(&LOCK_global_system_variables);

  void *tgt= real_value_ptr(thd, OPT_GLOBAL);
  const void *src= &var->save_result;

  if (!var->value)
    src= var_def_ptr(plugin_var);

  plugin_var->update(thd, plugin_var, tgt, src);
  return false;
}

Project: server

  uchar *default_value_ptr(THD *thd)
  { return do_value_ptr(thd, OPT_DEFAULT, 0); }

Project: server

  uchar* global_value_ptr(THD *thd, const LEX_STRING *base)
  { return do_value_ptr(thd, OPT_GLOBAL, base); }

Project: server

static char **mysql_sys_var_str(THD* thd, int offset)
{
  return (char **) intern_sys_var_ptr(thd, offset, true);
}

Project: server

static double *mysql_sys_var_double(THD* thd, int offset)
{
  return (double *) intern_sys_var_ptr(thd, offset, true);
}

Project: server

int thd_setspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key, void *value)
{
  DBUG_ASSERT(key != INVALID_THD_KEY);
  if (key == INVALID_THD_KEY || (!thd && !(thd= current_thd)))
    return EINVAL;
  
  memcpy(intern_sys_var_ptr(thd, key, true), &value, sizeof(void*));
  return 0;
}

Project: server

bool plugin_is_ready(const LEX_STRING *name, int type)
{
  bool rc= FALSE;
  if (plugin_status(name, type) == SHOW_OPTION_YES)
    rc= TRUE;
  return rc;
}

Project: server

static unsigned long *mysql_sys_var_ulong(THD* thd, int offset)
{
  return (unsigned long *) intern_sys_var_ptr(thd, offset, true);
}

Project: server

static struct st_plugin_int *plugin_find_internal(const LEX_STRING *name, int type)
{
  uint i;
  DBUG_ENTER("plugin_find_internal");
  if (! initialized)
    DBUG_RETURN(0);

  mysql_mutex_assert_owner(&LOCK_plugin);

  if (type == MYSQL_ANY_PLUGIN)
  {
    for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
    {
      struct st_plugin_int *plugin= (st_plugin_int *)
        my_hash_search(&plugin_hash[i], (const uchar *)name->str, name->length);
      if (plugin)
        DBUG_RETURN(plugin);
    }
  }
  else
    DBUG_RETURN((st_plugin_int *)
        my_hash_search(&plugin_hash[type], (const uchar *)name->str,
                       name->length));
  DBUG_RETURN(0);
}

Project: server

static void free_plugin_mem(struct st_plugin_dl *p)
{
#ifdef HAVE_DLOPEN
  if (p->ptr_backup)
  {
    DBUG_ASSERT(p->nbackups);
    DBUG_ASSERT(p->handle);
    restore_ptr_backup(p->nbackups, p->ptr_backup);
    my_free(p->ptr_backup);
  }
  if (p->handle)
    dlclose(p->handle);
#endif
  my_free(p->dl.str);
  if (p->allocated)
    my_free(p->plugins);
}

Project: server

static const void *var_def_ptr(st_mysql_sys_var *pv)
{
    switch (pv->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
    case PLUGIN_VAR_INT:
      return &((sysvar_uint_t*) pv)->def_val;
    case PLUGIN_VAR_LONG:
      return &((sysvar_ulong_t*) pv)->def_val;
    case PLUGIN_VAR_LONGLONG:
      return &((sysvar_ulonglong_t*) pv)->def_val;
    case PLUGIN_VAR_ENUM:
      return &((sysvar_enum_t*) pv)->def_val;
    case PLUGIN_VAR_SET:
      return &((sysvar_set_t*) pv)->def_val;
    case PLUGIN_VAR_BOOL:
      return &((sysvar_bool_t*) pv)->def_val;
    case PLUGIN_VAR_STR:
      return &((sysvar_str_t*) pv)->def_val;
    case PLUGIN_VAR_DOUBLE:
      return &((sysvar_double_t*) pv)->def_val;
    case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_uint_t*) pv)->def_val;
    case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_ulong_t*) pv)->def_val;
    case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_ulonglong_t*) pv)->def_val;
    case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_enum_t*) pv)->def_val;
    case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_set_t*) pv)->def_val;
    case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_bool_t*) pv)->def_val;
    case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_str_t*) pv)->def_val;
    case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL:
      return &((thdvar_double_t*) pv)->def_val;
    default:
      DBUG_ASSERT(0);
      return NULL;
    }
}

Project: server

static SHOW_TYPE pluginvar_show_type(const st_mysql_sys_var *plugin_var)
{
  switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_UNSIGNED)) {
  case PLUGIN_VAR_BOOL:
    return SHOW_MY_BOOL;
  case PLUGIN_VAR_INT:
    return SHOW_SINT;
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
    return SHOW_UINT;
  case PLUGIN_VAR_LONG:
    return SHOW_SLONG;
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
    return SHOW_ULONG;
  case PLUGIN_VAR_LONGLONG:
    return SHOW_SLONGLONG;
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
    return SHOW_ULONGLONG;
  case PLUGIN_VAR_STR:
    return SHOW_CHAR_PTR;
  case PLUGIN_VAR_ENUM:
  case PLUGIN_VAR_SET:
    return SHOW_CHAR;
  case PLUGIN_VAR_DOUBLE:
    return SHOW_DOUBLE;
  default:
    DBUG_ASSERT(0);
    return SHOW_UNDEF;
  }
}

Project: server

static int item_value_type(struct st_mysql_value *value)
{
  switch (((st_item_value_holder*)value)->item->result_type()) {
  case INT_RESULT:
    return MYSQL_VALUE_TYPE_INT;
  case REAL_RESULT:
    return MYSQL_VALUE_TYPE_REAL;
  default:
    return MYSQL_VALUE_TYPE_STRING;
  }
}

Project: server

static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl,
                                      void *sym, char *dlpath,
                                      int report)
{
  DBUG_ENTER("read_maria_plugin_info");

  /* Determine interface version */
  if (!(sym))
  {
    /*
      Actually this branch impossible because in case of absence of maria
      version we try mysql version.
    */
    report_error(report, ER_CANT_FIND_DL_ENTRY,
                 maria_plugin_interface_version_sym);
    DBUG_RETURN(TRUE);
  }
  plugin_dl->mariaversion= *(int *)sym;
  plugin_dl->mysqlversion= 0;
  /* Versioning */
  if (plugin_dl->mariaversion < min_maria_plugin_interface_version ||
      (plugin_dl->mariaversion >> 8) > (MARIA_PLUGIN_INTERFACE_VERSION >> 8))
  {
    report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, ENOEXEC,
                 "plugin interface version mismatch");
    DBUG_RETURN(TRUE);
  }
  /* Find plugin declarations */
  if (!(sym= dlsym(plugin_dl->handle, maria_plugin_declarations_sym)))
  {
    report_error(report, ER_CANT_FIND_DL_ENTRY, maria_plugin_declarations_sym);
    DBUG_RETURN(TRUE);
  }
  if (plugin_dl->mariaversion != MARIA_PLUGIN_INTERFACE_VERSION)
  {
    uint sizeof_st_plugin;
    struct st_maria_plugin *old, *cur;
    char *ptr= (char *)sym;

    if ((sym= dlsym(plugin_dl->handle, maria_sizeof_st_plugin_sym)))
      sizeof_st_plugin= *(int *)sym;
    else
    {
      report_error(report, ER_CANT_FIND_DL_ENTRY, maria_sizeof_st_plugin_sym);
      DBUG_RETURN(TRUE);
    }

    if (sizeof_st_plugin != sizeof(st_mysql_plugin))
    {
      int i;
      for (i= 0;
           ((struct st_maria_plugin *)(ptr + i * sizeof_st_plugin))->info;
           i++)
        /* no op */;

      cur= (struct st_maria_plugin*)
        my_malloc((i + 1) * sizeof(struct st_maria_plugin),
                  MYF(MY_ZEROFILL|MY_WME));
      if (!cur)
      {
        report_error(report, ER_OUTOFMEMORY,
                     static_cast<int>(plugin_dl->dl.length));
        DBUG_RETURN(TRUE);
      }
      /*
        All st_plugin fields not initialized in the plugin explicitly, are
        set to 0. It matches C standard behaviour for struct initializers that
        have less values than the struct definition.
      */
      for (i=0;
           (old= (struct st_maria_plugin *)(ptr + i * sizeof_st_plugin))->info;
           i++)
        memcpy(cur + i, old, MY_MIN(sizeof(cur[i]), sizeof_st_plugin));

      sym= cur;
      plugin_dl->allocated= true;
    }
    else
      sym= ptr;
  }
  plugin_dl->plugins= (struct st_maria_plugin *)sym;

  DBUG_RETURN(FALSE);
}

Project: server

static int item_val_real(struct st_mysql_value *value, double *buf)
{
  Item *item= ((st_item_value_holder*)value)->item;
  *buf= item->val_real();
  if (item->is_null())
    return 1;
  return 0;
}

Project: server

int plugin_init(int *argc, char **argv, int flags)
{
  uint i;
  struct st_maria_plugin **builtins;
  struct st_maria_plugin *plugin;
  struct st_plugin_int tmp, *plugin_ptr, **reap;
  MEM_ROOT tmp_root;
  bool reaped_mandatory_plugin= false;
  bool mandatory= true;
  LEX_STRING MyISAM= { C_STRING_WITH_LEN("MyISAM") };
  DBUG_ENTER("plugin_init");

  if (initialized)
    DBUG_RETURN(0);

  dlopen_count =0;

  init_alloc_root(&plugin_mem_root, 4096, 4096, MYF(0));
  init_alloc_root(&plugin_vars_mem_root, 4096, 4096, MYF(0));
  init_alloc_root(&tmp_root, 4096, 4096, MYF(0));

  if (my_hash_init(&bookmark_hash, &my_charset_bin, 32, 0, 0,
                   get_bookmark_hash_key, NULL, HASH_UNIQUE))
      goto err;

  /*
    The 80 is from 2016-04-27 when we had 71 default plugins
    Big enough to avoid many mallocs even in future
  */
  if (my_init_dynamic_array(&plugin_dl_array,
                            sizeof(struct st_plugin_dl *), 16, 16, MYF(0)) ||
      my_init_dynamic_array(&plugin_array,
                            sizeof(struct st_plugin_int *), 80, 32, MYF(0)))
    goto err;

  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
  {
    if (my_hash_init(&plugin_hash[i], system_charset_info, 32, 0, 0,
                     get_plugin_hash_key, NULL, HASH_UNIQUE))
      goto err;
  }

  /* prepare debug_sync service */
  DBUG_ASSERT(strcmp(list_of_services[1].name, "debug_sync_service") == 0);
  list_of_services[1].service= *(void**)&debug_sync_C_callback_ptr;

  /* prepare encryption_keys service */
  finalize_encryption_plugin(0);

  mysql_mutex_lock(&LOCK_plugin);

  initialized= 1;

  /*
    First we register builtin plugins
  */
  if (global_system_variables.log_warnings >= 9)
    sql_print_information("Initializing built-in plugins");

  for (builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++)
  {
    if (!*builtins)
    {
      builtins= mysql_optional_plugins;
      mandatory= false;
      if (!*builtins)
        break;
    }
    for (plugin= *builtins; plugin->info; plugin++)
    {
      if (opt_ignore_builtin_innodb &&
          !my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name,
                        6, (const uchar*) "InnoDB", 6))
        continue;

      bzero(&tmp, sizeof(tmp));
      tmp.plugin= plugin;
      tmp.name.str= (char *)plugin->name;
      tmp.name.length= strlen(plugin->name);
      tmp.state= 0;
      tmp.load_option= mandatory ? PLUGIN_FORCE : PLUGIN_ON;

      for (i=0; i < array_elements(override_plugin_load_policy); i++)
      {
        if (!my_strcasecmp(&my_charset_latin1, plugin->name,
                           override_plugin_load_policy[i].plugin_name))
        {
          tmp.load_option= override_plugin_load_policy[i].override;
          break;
        }
      }

      free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
      tmp.state= PLUGIN_IS_UNINITIALIZED;
      if (register_builtin(plugin, &tmp, &plugin_ptr))
        goto err_unlock;
    }
  }

  /*
    First, we initialize only MyISAM - that should almost always succeed
    (almost always, because plugins can be loaded outside of the server, too).
  */
  plugin_ptr= plugin_find_internal(&MyISAM, MYSQL_STORAGE_ENGINE_PLUGIN);
  DBUG_ASSERT(plugin_ptr || !mysql_mandatory_plugins[0]);
  if (plugin_ptr)
  {
    DBUG_ASSERT(plugin_ptr->load_option == PLUGIN_FORCE);

    if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv, false))
      goto err_unlock;

    /*
      set the global default storage engine variable so that it will
      not be null in any child thread.
    */
    global_system_variables.table_plugin =
      intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr));
      DBUG_ASSERT(plugin_ptr->ref_count == 1);

  }
  mysql_mutex_unlock(&LOCK_plugin);

  /* Register (not initialize!) all dynamic plugins */
  if (!(flags & PLUGIN_INIT_SKIP_DYNAMIC_LOADING))
  {
    I_List_iterator<i_string> iter(opt_plugin_load_list);
    i_string *item;
    if (global_system_variables.log_warnings >= 9)
      sql_print_information("Initializing plugins specified on the command line");
    while (NULL != (item= iter++))
      plugin_load_list(&tmp_root, item->ptr);

    if (!(flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE))
    {
      char path[FN_REFLEN + 1];
      build_table_filename(path, sizeof(path) - 1, "mysql", "plugin", reg_ext, 0);
      char engine_name_buf[NAME_CHAR_LEN + 1];
      LEX_STRING maybe_myisam= { engine_name_buf, 0 };
      frm_type_enum frm_type= dd_frm_type(NULL, path, &maybe_myisam);
      /* if mysql.plugin table is MyISAM - load it right away */
      if (frm_type == FRMTYPE_TABLE && !strcasecmp(maybe_myisam.str, "MyISAM"))
      {
        plugin_load(&tmp_root);
        flags|= PLUGIN_INIT_SKIP_PLUGIN_TABLE;
      }
    }
  }

  /*
    Now we initialize all remaining plugins
  */

  mysql_mutex_lock(&LOCK_plugin);
  reap= (st_plugin_int **) my_alloca((plugin_array.elements+1) * sizeof(void*));
  *(reap++)= NULL;

  for(;;)
  {
    for (i=0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
    {
      HASH *hash= plugin_hash + plugin_type_initialization_order[i];
      for (uint idx= 0; idx < hash->records; idx++)
      {
        plugin_ptr= (struct st_plugin_int *) my_hash_element(hash, idx);
        if (plugin_ptr->state == PLUGIN_IS_UNINITIALIZED)
        {
          if (plugin_initialize(&tmp_root, plugin_ptr, argc, argv,
                                (flags & PLUGIN_INIT_SKIP_INITIALIZATION)))
          {
            plugin_ptr->state= PLUGIN_IS_DYING;
            *(reap++)= plugin_ptr;
          }
        }
      }
    }

    /* load and init plugins from the plugin table (unless done already) */
    if (flags & PLUGIN_INIT_SKIP_PLUGIN_TABLE)
      break;

    mysql_mutex_unlock(&LOCK_plugin);
    plugin_load(&tmp_root);
    flags|= PLUGIN_INIT_SKIP_PLUGIN_TABLE;
    mysql_mutex_lock(&LOCK_plugin);
  }

  /*
    Check if any plugins have to be reaped
  */
  while ((plugin_ptr= *(--reap)))
  {
    mysql_mutex_unlock(&LOCK_plugin);
    if (plugin_is_forced(plugin_ptr))
      reaped_mandatory_plugin= TRUE;
    plugin_deinitialize(plugin_ptr, true);
    mysql_mutex_lock(&LOCK_plugin);
    plugin_del(plugin_ptr);
  }

  mysql_mutex_unlock(&LOCK_plugin);
  my_afree(reap);
  if (reaped_mandatory_plugin)
    goto err;

  free_root(&tmp_root, MYF(0));

  DBUG_RETURN(0);

err_unlock:
  mysql_mutex_unlock(&LOCK_plugin);
err:
  free_root(&tmp_root, MYF(0));
  DBUG_RETURN(1);
}

Project: server

sys_var_pluginvar::sys_var_pluginvar(sys_var_chain *chain, const char *name_arg,
        st_plugin_int *p, st_mysql_sys_var *pv)
    : sys_var(chain, name_arg, pv->comment, pluginvar_sysvar_flags(pv),
              0, pv->flags & PLUGIN_VAR_NOCMDOPT ? -1 : 0, NO_ARG,
              pluginvar_show_type(pv), 0,
              NULL, VARIABLE_NOT_IN_BINLOG, NULL, NULL, NULL),
    plugin(p), plugin_var(pv)
{
  plugin_var->name= name_arg;
  plugin_opt_set_limits(&option, pv);
}

Project: server

static void intern_plugin_unlock(LEX *lex, plugin_ref plugin)
{
  int i;
  st_plugin_int *pi;
  DBUG_ENTER("intern_plugin_unlock");

  mysql_mutex_assert_owner(&LOCK_plugin);

  if (!plugin)
    DBUG_VOID_RETURN;

  pi= plugin_ref_to_int(plugin);

#ifdef DBUG_OFF
  if (!pi->plugin_dl)
    DBUG_VOID_RETURN;
#else
  my_free(plugin);
#endif

  if (lex)
  {
    /*
      Remove one instance of this plugin from the use list.
      We are searching backwards so that plugins locked last
      could be unlocked faster - optimizing for LIFO semantics.
    */
    for (i= lex->plugins.elements - 1; i >= 0; i--)
      if (plugin == *dynamic_element(&lex->plugins, i, plugin_ref*))
      {
        delete_dynamic_element(&lex->plugins, i);
        break;
      }
    DBUG_ASSERT(i >= 0);
  }

  DBUG_ASSERT(pi->ref_count);
  pi->ref_count--;

  DBUG_PRINT("lock",("thd: %p  plugin: \"%s\" UNLOCK ref_count: %d",
                     current_thd, pi->name.str, pi->ref_count));

  if (pi->state == PLUGIN_IS_DELETED && !pi->ref_count)
    reap_needed= true;

  DBUG_VOID_RETURN;
}

Project: server

static st_bookmark *find_bookmark(const char *plugin, const char *name,
                                  int flags)
{
  st_bookmark *result= NULL;
  uint namelen, length, pluginlen= 0;
  char *varname, *p;

  if (!(flags & PLUGIN_VAR_THDLOCAL))
    return NULL;

  namelen= strlen(name);
  if (plugin)
    pluginlen= strlen(plugin) + 1;
  length= namelen + pluginlen + 2;
  varname= (char*) my_alloca(length);

  if (plugin)
  {
    strxmov(varname + 1, plugin, "_", name, NullS);
    for (p= varname + 1; *p; p++)
      if (*p == '-')
        *p= '_';
  }
  else
    memcpy(varname + 1, name, namelen + 1);

  varname[0]= plugin_var_bookmark_key(flags);

  result= (st_bookmark*) my_hash_search(&bookmark_hash,
                                        (const uchar*) varname, length - 1);

  my_afree(varname);
  return result;
}

Project: server

static size_t var_storage_size(int flags)
{
  switch (flags & PLUGIN_VAR_TYPEMASK) {
  case PLUGIN_VAR_BOOL:         return sizeof(my_bool);
  case PLUGIN_VAR_INT:          return sizeof(int);
  case PLUGIN_VAR_LONG:         return sizeof(long);
  case PLUGIN_VAR_ENUM:         return sizeof(long);
  case PLUGIN_VAR_LONGLONG:     return sizeof(ulonglong);
  case PLUGIN_VAR_SET:          return sizeof(ulonglong);
  case PLUGIN_VAR_STR:          return sizeof(char*);
  case PLUGIN_VAR_DOUBLE:       return sizeof(double);
  default: DBUG_ASSERT(0);      return 0;
  }
}

Project: server

void plugin_opt_set_limits(struct my_option *options,
                           const struct st_mysql_sys_var *opt)
{
  options->sub_size= 0;

  switch (opt->flags & (PLUGIN_VAR_TYPEMASK |
                        PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL)) {
  /* global system variables */
  case PLUGIN_VAR_INT:
    OPTION_SET_LIMITS(GET_INT, options, (sysvar_int_t*) opt);
    break;
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED:
    OPTION_SET_LIMITS(GET_UINT, options, (sysvar_uint_t*) opt);
    break;
  case PLUGIN_VAR_LONG:
    OPTION_SET_LIMITS(GET_LONG, options, (sysvar_long_t*) opt);
    break;
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED:
    OPTION_SET_LIMITS(GET_ULONG, options, (sysvar_ulong_t*) opt);
    break;
  case PLUGIN_VAR_LONGLONG:
    OPTION_SET_LIMITS(GET_LL, options, (sysvar_longlong_t*) opt);
    break;
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED:
    OPTION_SET_LIMITS(GET_ULL, options, (sysvar_ulonglong_t*) opt);
    break;
  case PLUGIN_VAR_ENUM:
    options->var_type= GET_ENUM;
    options->typelib= ((sysvar_enum_t*) opt)->typelib;
    options->def_value= ((sysvar_enum_t*) opt)->def_val;
    options->min_value= options->block_size= 0;
    options->max_value= options->typelib->count - 1;
    break;
  case PLUGIN_VAR_SET:
    options->var_type= GET_SET;
    options->typelib= ((sysvar_set_t*) opt)->typelib;
    options->def_value= ((sysvar_set_t*) opt)->def_val;
    options->min_value= options->block_size= 0;
    options->max_value= (1ULL << options->typelib->count) - 1;
    break;
  case PLUGIN_VAR_BOOL:
    options->var_type= GET_BOOL;
    options->def_value= ((sysvar_bool_t*) opt)->def_val;
    options->typelib= &bool_typelib;
    break;
  case PLUGIN_VAR_STR:
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
                        GET_STR_ALLOC : GET_STR);
    options->def_value= (intptr) ((sysvar_str_t*) opt)->def_val;
    break;
  case PLUGIN_VAR_DOUBLE:
    OPTION_SET_LIMITS_DOUBLE(options, (sysvar_double_t*) opt);
    break;
  /* threadlocal variables */
  case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL:
    OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt);
    break;
  case PLUGIN_VAR_INT | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
    OPTION_SET_LIMITS(GET_UINT, options, (thdvar_uint_t*) opt);
    break;
  case PLUGIN_VAR_LONG | PLUGIN_VAR_THDLOCAL:
    OPTION_SET_LIMITS(GET_LONG, options, (thdvar_long_t*) opt);
    break;
  case PLUGIN_VAR_LONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
    OPTION_SET_LIMITS(GET_ULONG, options, (thdvar_ulong_t*) opt);
    break;
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_THDLOCAL:
    OPTION_SET_LIMITS(GET_LL, options, (thdvar_longlong_t*) opt);
    break;
  case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL:
    OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt);
    break;
  case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL:
    OPTION_SET_LIMITS_DOUBLE(options, (thdvar_double_t*) opt);
    break;
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
    options->var_type= GET_ENUM;
    options->typelib= ((thdvar_enum_t*) opt)->typelib;
    options->def_value= ((thdvar_enum_t*) opt)->def_val;
    options->min_value= options->block_size= 0;
    options->max_value= options->typelib->count - 1;
    break;
  case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
    options->var_type= GET_SET;
    options->typelib= ((thdvar_set_t*) opt)->typelib;
    options->def_value= ((thdvar_set_t*) opt)->def_val;
    options->min_value= options->block_size= 0;
    options->max_value= (1ULL << options->typelib->count) - 1;
    break;
  case PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL:
    options->var_type= GET_BOOL;
    options->def_value= ((thdvar_bool_t*) opt)->def_val;
    options->typelib= &bool_typelib;
    break;
  case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL:
    options->var_type= ((opt->flags & PLUGIN_VAR_MEMALLOC) ?
                        GET_STR_ALLOC : GET_STR);
    options->def_value= (intptr) ((thdvar_str_t*) opt)->def_val;
    break;
  default:
    DBUG_ASSERT(0);
  }
  options->arg_type= REQUIRED_ARG;
  if (opt->flags & PLUGIN_VAR_NOCMDARG)
    options->arg_type= NO_ARG;
  if (opt->flags & PLUGIN_VAR_OPCMDARG)
    options->arg_type= OPT_ARG;
}

Project: server

bool sys_var_pluginvar::do_check(THD *thd, set_var *var)
{
  st_item_value_holder value;
  DBUG_ASSERT(!is_readonly());
  DBUG_ASSERT(plugin_var->check);

  value.value_type= item_value_type;
  value.val_str= item_val_str;
  value.val_int= item_val_int;
  value.val_real= item_val_real;
  value.is_unsigned= item_is_unsigned;
  value.item= var->value;

  return plugin_var->check(thd, plugin_var, &var->save_result, &value);
}

Project: server

static void cleanup_variables(struct system_variables *vars)
{
  st_bookmark *v;
  uint idx;

  mysql_prlock_rdlock(&LOCK_system_variables_hash);
  for (idx= 0; idx < bookmark_hash.records; idx++)
  {
    v= (st_bookmark*) my_hash_element(&bookmark_hash, idx);

    if (v->version > vars->dynamic_variables_version)
      continue; /* not in vars */

    DBUG_ASSERT((uint)v->offset <= vars->dynamic_variables_head);

    /* free allocated strings (PLUGIN_VAR_STR | PLUGIN_VAR_MEMALLOC) */
    if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
         v->key[0] & BOOKMARK_MEMALLOC)
    {
      char **ptr= (char**)(vars->dynamic_variables_ptr + v->offset);
      my_free(*ptr);
      *ptr= NULL;
    }
  }
  mysql_prlock_unlock(&LOCK_system_variables_hash);

  DBUG_ASSERT(vars->table_plugin == NULL);
  DBUG_ASSERT(vars->tmp_table_plugin == NULL);
  DBUG_ASSERT(vars->enforced_table_plugin == NULL);

  my_free(vars->dynamic_variables_ptr);
  vars->dynamic_variables_ptr= NULL;
  vars->dynamic_variables_size= 0;
  vars->dynamic_variables_version= 0;
}

Project: server

static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
                               void *save, st_mysql_value *value)
{
  my_bool fixed1, fixed2;
  long long orig, val;
  struct my_option options;
  value->val_int(value, &orig);
  val= orig;
  plugin_opt_set_limits(&options, var);

  if (var->flags & PLUGIN_VAR_UNSIGNED)
  {
    if ((fixed1= (!value->is_unsigned(value) && val < 0)))
      val=0;
    *(ulonglong *)save= getopt_ull_limit_value((ulonglong) val, &options,
                                               &fixed2);
  }
  else
  {
    if ((fixed1= (value->is_unsigned(value) && val < 0)))
      val=LONGLONG_MAX;
    *(longlong *)save= getopt_ll_limit_value(val, &options, &fixed2);
  }

  return throw_bounds_warning(thd, var->name, fixed1 || fixed2,
                              value->is_unsigned(value), (longlong) orig);
}

Project: server

static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
                             my_option *options)
{
  const char *plugin_name= tmp->plugin->name;
  const LEX_STRING plugin_dash = { C_STRING_WITH_LEN("plugin-") };
  uint plugin_name_len= strlen(plugin_name);
  uint optnamelen;
  const int max_comment_len= 255;
  char *comment= (char *) alloc_root(mem_root, max_comment_len + 1);
  char *optname;

  int index= 0, UNINIT_VAR(offset);
  st_mysql_sys_var *opt, **plugin_option;
  st_bookmark *v;

  /** Used to circumvent the const attribute on my_option::name */
  char *plugin_name_ptr, *plugin_name_with_prefix_ptr;

  DBUG_ENTER("construct_options");

  plugin_name_ptr= (char*) alloc_root(mem_root, plugin_name_len + 1);
  strcpy(plugin_name_ptr, plugin_name);
  my_casedn_str(&my_charset_latin1, plugin_name_ptr);
  convert_underscore_to_dash(plugin_name_ptr, plugin_name_len);
  plugin_name_with_prefix_ptr= (char*) alloc_root(mem_root,
                                                  plugin_name_len +
                                                  plugin_dash.length + 1);
  strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, plugin_name_ptr, NullS);

  if (!plugin_is_forced(tmp))
  {
    /* support --skip-plugin-foo syntax */
    options[0].name= plugin_name_ptr;
    options[1].name= plugin_name_with_prefix_ptr;
    options[0].id= options[1].id= 0;
    options[0].var_type= options[1].var_type= GET_ENUM;
    options[0].arg_type= options[1].arg_type= OPT_ARG;
    options[0].def_value= options[1].def_value= 1; /* ON */
    options[0].typelib= options[1].typelib= &global_plugin_typelib;

    strxnmov(comment, max_comment_len, "Enable or disable ", plugin_name,
            " plugin. One of: ON, OFF, FORCE (don't start if the plugin"
            " fails to load), FORCE_PLUS_PERMANENT (like FORCE, but the"
            " plugin can not be uninstalled).", NullS);
    options[0].comment= comment;
    /*
      Allocate temporary space for the value of the tristate.
      This option will have a limited lifetime and is not used beyond
      server initialization.
      GET_ENUM value is an unsigned long integer.
    */
    options[0].value= options[1].value=
                      (uchar **)alloc_root(mem_root, sizeof(ulong));
    *((ulong*) options[0].value)= (ulong) options[0].def_value;

    options+= 2;
  }

  /*
    Two passes as the 2nd pass will take pointer addresses for use
    by my_getopt and register_var() in the first pass uses realloc
  */

  for (plugin_option= tmp->plugin->system_vars;
       plugin_option && *plugin_option; plugin_option++, index++)
  {
    opt= *plugin_option;

    if (!opt->name)
    {
      sql_print_error("Missing variable name in plugin '%s'.",
                      plugin_name);
      DBUG_RETURN(-1);
    }

    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
      continue;
    if (!(register_var(plugin_name_ptr, opt->name, opt->flags)))
      continue;
    switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
    case PLUGIN_VAR_BOOL:
      ((thdvar_bool_t *) opt)->resolve= mysql_sys_var_char;
      break;
    case PLUGIN_VAR_INT:
      ((thdvar_int_t *) opt)->resolve= mysql_sys_var_int;
      break;
    case PLUGIN_VAR_LONG:
      ((thdvar_long_t *) opt)->resolve= mysql_sys_var_long;
      break;
    case PLUGIN_VAR_LONGLONG:
      ((thdvar_longlong_t *) opt)->resolve= mysql_sys_var_longlong;
      break;
    case PLUGIN_VAR_STR:
      ((thdvar_str_t *) opt)->resolve= mysql_sys_var_str;
      break;
    case PLUGIN_VAR_ENUM:
      ((thdvar_enum_t *) opt)->resolve= mysql_sys_var_ulong;
      break;
    case PLUGIN_VAR_SET:
      ((thdvar_set_t *) opt)->resolve= mysql_sys_var_ulonglong;
      break;
    case PLUGIN_VAR_DOUBLE:
      ((thdvar_double_t *) opt)->resolve= mysql_sys_var_double;
      break;
    default:
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
                      opt->flags, plugin_name);
      DBUG_RETURN(-1);
    };
  }

  for (plugin_option= tmp->plugin->system_vars;
       plugin_option && *plugin_option; plugin_option++, index++)
  {
    switch ((opt= *plugin_option)->flags & PLUGIN_VAR_TYPEMASK) {
    case PLUGIN_VAR_BOOL:
      if (!opt->check)
        opt->check= check_func_bool;
      if (!opt->update)
        opt->update= update_func_bool;
      break;
    case PLUGIN_VAR_INT:
      if (!opt->check)
        opt->check= check_func_int;
      if (!opt->update)
        opt->update= update_func_int;
      break;
    case PLUGIN_VAR_LONG:
      if (!opt->check)
        opt->check= check_func_long;
      if (!opt->update)
        opt->update= update_func_long;
      break;
    case PLUGIN_VAR_LONGLONG:
      if (!opt->check)
        opt->check= check_func_longlong;
      if (!opt->update)
        opt->update= update_func_longlong;
      break;
    case PLUGIN_VAR_STR:
      if (!opt->check)
        opt->check= check_func_str;
      if (!opt->update)
      {
        opt->update= update_func_str;
        if (!(opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)))
        {
          opt->flags|= PLUGIN_VAR_READONLY;
          sql_print_warning("Server variable %s of plugin %s was forced "
                            "to be read-only: string variable without "
                            "update_func and PLUGIN_VAR_MEMALLOC flag",
                            opt->name, plugin_name);
        }
      }
      break;
    case PLUGIN_VAR_ENUM:
      if (!opt->check)
        opt->check= check_func_enum;
      if (!opt->update)
        opt->update= update_func_long;
      break;
    case PLUGIN_VAR_SET:
      if (!opt->check)
        opt->check= check_func_set;
      if (!opt->update)
        opt->update= update_func_longlong;
      break;
    case PLUGIN_VAR_DOUBLE:
      if (!opt->check)
        opt->check= check_func_double;
      if (!opt->update)
        opt->update= update_func_double;
      break;
    default:
      sql_print_error("Unknown variable type code 0x%x in plugin '%s'.",
                      opt->flags, plugin_name);
      DBUG_RETURN(-1);
    }

    if ((opt->flags & (PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_THDLOCAL))
                    == PLUGIN_VAR_NOCMDOPT)
      continue;

    if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
    {
      optnamelen= strlen(opt->name);
      optname= (char*) alloc_root(mem_root, plugin_name_len + optnamelen + 2);
      strxmov(optname, plugin_name_ptr, "-", opt->name, NullS);
      optnamelen= plugin_name_len + optnamelen + 1;
    }
    else
    {
      /* this should not fail because register_var should create entry */
      if (!(v= find_bookmark(plugin_name_ptr, opt->name, opt->flags)))
      {
        sql_print_error("Thread local variable '%s' not allocated "
                        "in plugin '%s'.", opt->name, plugin_name);
        DBUG_RETURN(-1);
      }

      *(int*)(opt + 1)= offset= v->offset;

      if (opt->flags & PLUGIN_VAR_NOCMDOPT)
      {
        char *val= global_system_variables.dynamic_variables_ptr + offset;
        if (((opt->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR) &&
             (opt->flags & PLUGIN_VAR_MEMALLOC))
        {
          char *def_val= *(char**)var_def_ptr(opt);
          *(char**)val= def_val ? my_strdup(def_val, MYF(0)) : NULL;
        }
        else
          memcpy(val, var_def_ptr(opt), var_storage_size(opt->flags));
        continue;
      }

      optname= (char*) memdup_root(mem_root, v->key + 1,
                                   (optnamelen= v->name_len) + 1);
    }

    convert_underscore_to_dash(optname, optnamelen);

    options->name= optname;
    options->comment= opt->comment;
    options->app_type= (opt->flags & PLUGIN_VAR_NOSYSVAR) ? NULL : opt;
    options->id= 0;

    plugin_opt_set_limits(options, opt);

    if (opt->flags & PLUGIN_VAR_THDLOCAL)
      options->value= options->u_max_value= (uchar**)
        (global_system_variables.dynamic_variables_ptr + offset);
    else
      options->value= options->u_max_value= *(uchar***) (opt + 1);

    char *option_name_ptr;
    options[1]= options[0];
    options[1].name= option_name_ptr= (char*) alloc_root(mem_root,
                                                        plugin_dash.length +
                                                        optnamelen + 1);
    options[1].comment= 0; /* Hidden from the help text */
    strxmov(option_name_ptr, plugin_dash.str, optname, NullS);

    options+= 2;
  }

  DBUG_RETURN(0);
}

Project: server

static int pluginvar_sysvar_flags(const st_mysql_sys_var *p)
{
  return (p->flags & PLUGIN_VAR_THDLOCAL ? sys_var::SESSION : sys_var::GLOBAL)
       | (p->flags & PLUGIN_VAR_READONLY ? sys_var::READONLY : 0);
}

Project: server

static char *mysql_sys_var_char(THD* thd, int offset)
{
  return (char *) intern_sys_var_ptr(thd, offset, true);
}

Project: server

static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report)
{
#ifdef HAVE_DLOPEN
  char dlpath[FN_REFLEN];
  uint plugin_dir_len, dummy_errors, i;
  struct st_plugin_dl *tmp= 0, plugin_dl;
  void *sym;
  st_ptr_backup tmp_backup[array_elements(list_of_services)];
  DBUG_ENTER("plugin_dl_add");
  DBUG_PRINT("enter", ("dl->str: '%s', dl->length: %d",
                       dl->str, (int) dl->length));
  mysql_mutex_assert_owner(&LOCK_plugin);
  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 (check_string_char_length((LEX_STRING *) dl, 0, NAME_CHAR_LEN,
                               system_charset_info, 1) ||
      check_valid_path(dl->str, dl->length) ||
      plugin_dir_len + dl->length + 1 >= FN_REFLEN)
  {
    report_error(report, 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);
  }
  bzero(&plugin_dl, sizeof(plugin_dl));
  /* Compile dll path */
  strxnmov(dlpath, sizeof(dlpath) - 1, opt_plugin_dir, "/", dl->str, NullS);
  (void) unpack_filename(dlpath, dlpath);
  plugin_dl.ref_count= 1;
  /* Open new dll handle */
  if (!(plugin_dl.handle= dlopen(dlpath, RTLD_NOW)))
  {
    report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, errno, my_dlerror(dlpath));
    goto ret;
  }
  dlopen_count++;

#ifdef HAVE_LINK_H
  if (global_system_variables.log_warnings > 2)
  {
    struct link_map *lm = (struct link_map*) plugin_dl.handle;
    sql_print_information("Loaded '%s' with offset 0x%zx", dl->str, (size_t)lm->l_addr);
  }
#endif

  /* Checks which plugin interface present and reads info */
  if (!(sym= dlsym(plugin_dl.handle, maria_plugin_interface_version_sym)))
  {
    if (read_mysql_plugin_info(&plugin_dl,
                               dlsym(plugin_dl.handle,
                                     plugin_interface_version_sym),
                               dlpath,
                               report))
      goto ret;
  }
  else
  {
    if (read_maria_plugin_info(&plugin_dl, sym, dlpath, report))
      goto ret;
  }

  /* link the services in */
  for (i= 0; i < array_elements(list_of_services); i++)
  {
    if ((sym= dlsym(plugin_dl.handle, list_of_services[i].name)))
    {
      void **ptr= (void **)sym;
      uint ver= (uint)(intptr)*ptr;
      if (ver > list_of_services[i].version ||
        (ver >> 8) < (list_of_services[i].version >> 8))
      {
        char buf[MYSQL_ERRMSG_SIZE];
        my_snprintf(buf, sizeof(buf),
                    "service '%s' interface version mismatch",
                    list_of_services[i].name);
        report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, ENOEXEC, buf);
        goto ret;
      }
      tmp_backup[plugin_dl.nbackups++].save(ptr);
      *ptr= list_of_services[i].service;
    }
  }

  if (plugin_dl.nbackups)
  {
    size_t bytes= plugin_dl.nbackups * sizeof(plugin_dl.ptr_backup[0]);
    plugin_dl.ptr_backup= (st_ptr_backup *)my_malloc(bytes, MYF(0));
    if (!plugin_dl.ptr_backup)
    {
      restore_ptr_backup(plugin_dl.nbackups, tmp_backup);
      report_error(report, ER_OUTOFMEMORY, bytes);
      goto ret;
    }
    memcpy(plugin_dl.ptr_backup, tmp_backup, bytes);
  }

  /* Duplicate and convert dll name */
  plugin_dl.dl.length= dl->length * files_charset_info->mbmaxlen + 1;
  if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0))))
  {
    report_error(report, ER_OUTOFMEMORY,
                 static_cast<int>(plugin_dl.dl.length));
    goto ret;
  }
  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 (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl)))
  {
    report_error(report, ER_OUTOFMEMORY,
                 static_cast<int>(sizeof(struct st_plugin_dl)));
    goto ret;
  }

ret:
  if (!tmp)
    free_plugin_mem(&plugin_dl);

  DBUG_RETURN(tmp);

#else
  DBUG_ENTER("plugin_dl_add");
  report_error(report, ER_FEATURE_DISABLED, "plugin", "HAVE_DLOPEN");
  DBUG_RETURN(0);
#endif
}

Project: server

static void reap_plugins(void)
{
  uint count;
  struct st_plugin_int *plugin, **reap, **list;

  mysql_mutex_assert_owner(&LOCK_plugin);

  if (!reap_needed)
    return;

  reap_needed= false;
  count= plugin_array.elements;
  reap= (struct st_plugin_int **)my_alloca(sizeof(plugin)*(count+1));
  *(reap++)= NULL;

  for (uint i=0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
  {
    HASH *hash= plugin_hash + plugin_type_initialization_order[i];
    for (uint j= 0; j < hash->records; j++)
    {
      plugin= (struct st_plugin_int *) my_hash_element(hash, j);
      if (plugin->state == PLUGIN_IS_DELETED && !plugin->ref_count)
      {
        /* change the status flag to prevent reaping by another thread */
        plugin->state= PLUGIN_IS_DYING;
        *(reap++)= plugin;
      }
    }
  }

  mysql_mutex_unlock(&LOCK_plugin);

  list= reap;
  while ((plugin= *(--list)))
      plugin_deinitialize(plugin, true);

  mysql_mutex_lock(&LOCK_plugin);

  while ((plugin= *(--reap)))
    plugin_del(plugin);

  my_afree(reap);
}

Project: server

static const char *item_val_str(struct st_mysql_value *value,
                                char *buffer, int *length)
{
  String str(buffer, *length, system_charset_info), *res;
  if (!(res= ((st_item_value_holder*)value)->item->val_str(&str)))
    return NULL;
  *length= res->length();
  if (res->c_ptr_quick() == buffer)
    return buffer;

  /*
    Lets be nice and create a temporary string since the
    buffer was too small
  */
  return current_thd->strmake(res->ptr(), res->length());
}

Project: server

TYPELIB* sys_var_pluginvar::plugin_var_typelib(void)
{
  switch (plugin_var->flags & (PLUGIN_VAR_TYPEMASK | PLUGIN_VAR_THDLOCAL)) {
  case PLUGIN_VAR_ENUM:
    return ((sysvar_enum_t *)plugin_var)->typelib;
  case PLUGIN_VAR_SET:
    return ((sysvar_set_t *)plugin_var)->typelib;
  case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
    return ((thdvar_enum_t *)plugin_var)->typelib;
  case PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL:
    return ((thdvar_set_t *)plugin_var)->typelib;
  default:
    return NULL;
  }
  return NULL;	/* Keep compiler happy */
}

Project: server

static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl,
                                      void *sym, char *dlpath,
                                      int report)
{
  DBUG_ENTER("read_maria_plugin_info");
  /* Determine interface version */
  if (!sym)
  {
    report_error(report, ER_CANT_FIND_DL_ENTRY, plugin_interface_version_sym);
    DBUG_RETURN(TRUE);
  }
  plugin_dl->mariaversion= 0;
  plugin_dl->mysqlversion= *(int *)sym;
  /* Versioning */
  if (plugin_dl->mysqlversion < min_plugin_interface_version ||
      (plugin_dl->mysqlversion >> 8) > (MYSQL_PLUGIN_INTERFACE_VERSION >> 8))
  {
    report_error(report, ER_CANT_OPEN_LIBRARY, dlpath, ENOEXEC,
                 "plugin interface version mismatch");
    DBUG_RETURN(TRUE);
  }
  /* Find plugin declarations */
  if (!(sym= dlsym(plugin_dl->handle, plugin_declarations_sym)))
  {
    report_error(report, ER_CANT_FIND_DL_ENTRY, plugin_declarations_sym);
    DBUG_RETURN(TRUE);
  }

  /* convert mysql declaration to maria one */
  {
    int i;
    uint sizeof_st_plugin;
    struct st_mysql_plugin *old;
    struct st_maria_plugin *cur;
    char *ptr= (char *)sym;

    if ((sym= dlsym(plugin_dl->handle, sizeof_st_plugin_sym)))
      sizeof_st_plugin= *(int *)sym;
    else
    {
      DBUG_ASSERT(min_plugin_interface_version == 0);
      sizeof_st_plugin= (int)offsetof(struct st_mysql_plugin, version);
    }

    for (i= 0;
         ((struct st_mysql_plugin *)(ptr + i * sizeof_st_plugin))->info;
         i++)
      /* no op */;

    cur= (struct st_maria_plugin*)
          my_malloc((i + 1) * sizeof(struct st_maria_plugin),
                    MYF(MY_ZEROFILL|MY_WME));
    if (!cur)
    {
      report_error(report, ER_OUTOFMEMORY,
                   static_cast<int>(plugin_dl->dl.length));
      DBUG_RETURN(TRUE);
    }
    /*
      All st_plugin fields not initialized in the plugin explicitly, are
      set to 0. It matches C standard behaviour for struct initializers that
      have less values than the struct definition.
    */
    for (i=0;
         (old= (struct st_mysql_plugin *)(ptr + i * sizeof_st_plugin))->info;
         i++)
    {

      cur[i].type= old->type;
      cur[i].info= old->info;
      cur[i].name= old->name;
      cur[i].author= old->author;
      cur[i].descr= old->descr;
      cur[i].license= old->license;
      cur[i].init= old->init;
      cur[i].deinit= old->deinit;
      cur[i].version= old->version;
      cur[i].status_vars= old->status_vars;
      cur[i].system_vars= old->system_vars;
      /*
        Something like this should be added to process
        new mysql plugin versions:
        if (plugin_dl->mysqlversion > 0x0101)
        {
           cur[i].newfield= CONSTANT_MEANS_UNKNOWN;
        }
        else
        {
           cur[i].newfield= old->newfield;
        }
      */
      /* Maria only fields */
      cur[i].version_info= "Unknown";
      cur[i].maturity= MariaDB_PLUGIN_MATURITY_UNKNOWN;
    }
    plugin_dl->allocated= true;
    plugin_dl->plugins= (struct st_maria_plugin *)cur;
  }

  DBUG_RETURN(FALSE);
}

Project: server

void plugin_thdvar_init(THD *thd)
{
  plugin_ref old_table_plugin= thd->variables.table_plugin;
  plugin_ref old_tmp_table_plugin= thd->variables.tmp_table_plugin;
  plugin_ref old_enforced_table_plugin= thd->variables.enforced_table_plugin;
  DBUG_ENTER("plugin_thdvar_init");

  // This function may be called many times per THD (e.g. on COM_CHANGE_USER)
  thd->variables.table_plugin= NULL;
  thd->variables.tmp_table_plugin= NULL;
  thd->variables.enforced_table_plugin= NULL;
  cleanup_variables(&thd->variables);

  thd->variables= global_system_variables;

  /* we are going to allocate these lazily */
  thd->variables.dynamic_variables_version= 0;
  thd->variables.dynamic_variables_size= 0;
  thd->variables.dynamic_variables_ptr= 0;

  mysql_mutex_lock(&LOCK_plugin);
  thd->variables.table_plugin=
      intern_plugin_lock(NULL, global_system_variables.table_plugin);
  if (global_system_variables.tmp_table_plugin)
    thd->variables.tmp_table_plugin=
          intern_plugin_lock(NULL, global_system_variables.tmp_table_plugin);
  if (global_system_variables.enforced_table_plugin)
    thd->variables.enforced_table_plugin=
          intern_plugin_lock(NULL, global_system_variables.enforced_table_plugin);
  intern_plugin_unlock(NULL, old_table_plugin);
  intern_plugin_unlock(NULL, old_tmp_table_plugin);
  intern_plugin_unlock(NULL, old_enforced_table_plugin);
  mysql_mutex_unlock(&LOCK_plugin);

  DBUG_VOID_RETURN;
}

Project: server

  virtual void global_save_default(THD *thd, set_var *var) {}

Project: server

static st_bookmark *register_var(const char *plugin, const char *name,
                                 int flags)
{
  uint length= strlen(plugin) + strlen(name) + 3, size, offset, new_size;
  st_bookmark *result;
  char *varname, *p;

  DBUG_ASSERT(flags & PLUGIN_VAR_THDLOCAL);

  size= var_storage_size(flags);
  varname= ((char*) my_alloca(length));
  strxmov(varname + 1, plugin, "_", name, NullS);
  for (p= varname + 1; *p; p++)
    if (*p == '-')
      *p= '_';

  if (!(result= find_bookmark(NULL, varname + 1, flags)))
  {
    result= (st_bookmark*) alloc_root(&plugin_vars_mem_root,
                                      sizeof(struct st_bookmark) + length-1);
    varname[0]= plugin_var_bookmark_key(flags);
    memcpy(result->key, varname, length);
    result->name_len= length - 2;
    result->offset= -1;

    DBUG_ASSERT(size && !(size & (size-1))); /* must be power of 2 */

    offset= global_system_variables.dynamic_variables_size;
    offset= (offset + size - 1) & ~(size - 1);
    result->offset= (int) offset;

    new_size= (offset + size + 63) & ~63;

    if (new_size > global_variables_dynamic_size)
    {
      global_system_variables.dynamic_variables_ptr= (char*)
        my_realloc(global_system_variables.dynamic_variables_ptr, new_size,
                   MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
      max_system_variables.dynamic_variables_ptr= (char*)
        my_realloc(max_system_variables.dynamic_variables_ptr, new_size,
                   MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));
      /*
        Clear the new variable value space. This is required for string
        variables. If their value is non-NULL, it must point to a valid
        string.
      */
      bzero(global_system_variables.dynamic_variables_ptr +
            global_variables_dynamic_size,
            new_size - global_variables_dynamic_size);
      bzero(max_system_variables.dynamic_variables_ptr +
            global_variables_dynamic_size,
            new_size - global_variables_dynamic_size);
      global_variables_dynamic_size= new_size;
    }

    global_system_variables.dynamic_variables_head= offset;
    max_system_variables.dynamic_variables_head= offset;
    global_system_variables.dynamic_variables_size= offset + size;
    max_system_variables.dynamic_variables_size= offset + size;
    global_system_variables.dynamic_variables_version++;
    max_system_variables.dynamic_variables_version++;

    result->version= global_system_variables.dynamic_variables_version;

    /* this should succeed because we have already checked if a dup exists */
    if (my_hash_insert(&bookmark_hash, (uchar*) result))
    {
      fprintf(stderr, "failed to add placeholder to hash");
      DBUG_ASSERT(0);
    }
  }
  my_afree(varname);
  return result;
}

Project: server

int thd_key_create(MYSQL_THD_KEY_T *key)
{
  int flags= PLUGIN_VAR_THDLOCAL | PLUGIN_VAR_STR |
             PLUGIN_VAR_NOSYSVAR | PLUGIN_VAR_NOCMDOPT;
  char namebuf[256];
  snprintf(namebuf, sizeof(namebuf), "%u", thd_key_no++);
  mysql_prlock_wrlock(&LOCK_system_variables_hash);
  // non-letters in the name as an extra safety
  st_bookmark *bookmark= register_var("\a\v\a\t\a\r", namebuf, flags);
  mysql_prlock_unlock(&LOCK_system_variables_hash);
  if (bookmark)
  {
    *key= bookmark->offset;
    return 0;
  }
  return ENOMEM;
}

Project: server

void plugin_unlock_list(THD *thd, plugin_ref *list, uint count)
{
  LEX *lex= thd ? thd->lex : 0;
  DBUG_ENTER("plugin_unlock_list");
  if (count == 0)
    DBUG_VOID_RETURN;

  DBUG_ASSERT(list);
  mysql_mutex_lock(&LOCK_plugin);
  while (count--)
    intern_plugin_unlock(lex, *list++);
  reap_plugins();
  mysql_mutex_unlock(&LOCK_plugin);
  DBUG_VOID_RETURN;
}

Project: server

bool plugin_is_forced(struct st_plugin_int *p)
{
  return p->load_option == PLUGIN_FORCE ||
         p->load_option == PLUGIN_FORCE_PLUS_PERMANENT;
}

Project: server

uchar *get_plugin_hash_key(const uchar *buff, size_t *length,
                           my_bool not_used __attribute__((unused)))
{
  struct st_plugin_int *plugin= (st_plugin_int *)buff;
  *length= (uint)plugin->name.length;
  return((uchar *)plugin->name.str);
}

Project: server

sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length,
                         bool throw_error, bool locked)
{
  sys_var *var;
  sys_var_pluginvar *pi= NULL;
  plugin_ref plugin;
  DBUG_ENTER("find_sys_var_ex");
  DBUG_PRINT("enter", ("var '%.*s'", (int)length, str));

  if (!locked)
    mysql_mutex_lock(&LOCK_plugin);
  mysql_prlock_rdlock(&LOCK_system_variables_hash);
  if ((var= intern_find_sys_var(str, length)) &&
      (pi= var->cast_pluginvar()))
  {
    mysql_prlock_unlock(&LOCK_system_variables_hash);
    LEX *lex= thd ? thd->lex : 0;
    if (!(plugin= intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin))))
      var= NULL; /* failed to lock it, it must be uninstalling */
    else
    if (!(plugin_state(plugin) & PLUGIN_IS_READY))
    {
      /* initialization not completed */
      var= NULL;
      intern_plugin_unlock(lex, plugin);
    }
  }
  else
    mysql_prlock_unlock(&LOCK_system_variables_hash);
  if (!locked)
    mysql_mutex_unlock(&LOCK_plugin);

  if (!throw_error && !var)
    my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), (int)length, (char*) str);
  DBUG_RETURN(var);
}

Project: server

uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
                             my_bool not_used __attribute__((unused)))
{
  struct st_bookmark *var= (st_bookmark *)buff;
  *length= var->name_len + 1;
  return (uchar*) var->key;
}

Project: server

plugin_ref plugin_lock_by_name(THD *thd, const LEX_STRING *name, int type)
{
  LEX *lex= thd ? thd->lex : 0;
  plugin_ref rc= NULL;
  st_plugin_int *plugin;
  DBUG_ENTER("plugin_lock_by_name");
  mysql_mutex_lock(&LOCK_plugin);
  if ((plugin= plugin_find_internal(name, type)))
    rc= intern_plugin_lock(lex, plugin_int_to_ref(plugin));
  mysql_mutex_unlock(&LOCK_plugin);
  DBUG_RETURN(rc);
}

Project: server

void wsrep_plugins_post_init()
{
  THD *thd;
  I_List_iterator<THD> it(threads);

  while ((thd= it++))
  {
    if (IF_WSREP(thd->wsrep_applier,1))
    {
      // Save options_bits as it will get overwritten in plugin_thdvar_init()
      ulonglong option_bits_saved= thd->variables.option_bits;

      plugin_thdvar_init(thd);

      // Restore option_bits
      thd->variables.option_bits= option_bits_saved;
    }
  }

  return;
}

Project: server

static bool finalize_install(THD *thd, TABLE *table, const LEX_STRING *name,
                             int *argc, char **argv)
{
  struct st_plugin_int *tmp= plugin_find_internal(name, MYSQL_ANY_PLUGIN);
  int error;
  DBUG_ASSERT(tmp);
  mysql_mutex_assert_owner(&LOCK_plugin); // because of tmp->state

  if (tmp->state != PLUGIN_IS_UNINITIALIZED)
  {
    /* already installed */
    return 0;
  }
  else
  {
    if (plugin_initialize(thd->mem_root, tmp, argc, argv, false))
    {
      report_error(REPORT_TO_USER, ER_CANT_INITIALIZE_UDF, name->str,
                   "Plugin initialization function failed.");
      tmp->state= PLUGIN_IS_DELETED;
      return 1;
    }
  }
  if (tmp->state == PLUGIN_IS_DISABLED)
  {
    if (global_system_variables.log_warnings)
      push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
                          ER_CANT_INITIALIZE_UDF,
                          ER_THD(thd, ER_CANT_INITIALIZE_UDF),
                          name->str, "Plugin is disabled");
  }

  /*
    We do not replicate the INSTALL PLUGIN statement. Disable binlogging
    of the insert into the plugin table, so that it is not replicated in
    row based mode.
  */
  tmp_disable_binlog(thd);
  table->use_all_columns();
  restore_record(table, s->default_values);
  table->field[0]->store(name->str, name->length, system_charset_info);
  table->field[1]->store(tmp->plugin_dl->dl.str, tmp->plugin_dl->dl.length,
                         files_charset_info);
  error= table->file->ha_write_row(table->record[0]);
  reenable_binlog(thd);
  if (error)
  {
    table->file->print_error(error, MYF(0));
    tmp->state= PLUGIN_IS_DELETED;
    return 1;
  }
  return 0;
}

Project: server

static bool plugin_add(MEM_ROOT *tmp_root,
                       const LEX_STRING *name, LEX_STRING *dl, int report)
{
  struct st_plugin_int tmp, *maybe_dupe;
  struct st_maria_plugin *plugin;
  uint oks= 0, errs= 0, dupes= 0;
  DBUG_ENTER("plugin_add");
  DBUG_PRINT("enter", ("name: %s  dl: %s", name->str, dl->str));

  if (name->str && plugin_find_internal(name, MYSQL_ANY_PLUGIN))
  {
    report_error(report, ER_PLUGIN_INSTALLED, name->str);
    DBUG_RETURN(TRUE);
  }
  /* Clear the whole struct to catch future extensions. */
  bzero((char*) &tmp, sizeof(tmp));
  fix_dl_name(tmp_root, dl);
  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++)
  {
    tmp.name.str= (char *)plugin->name;
    tmp.name.length= strlen(plugin->name);

    if (plugin->type < 0 || plugin->type >= MYSQL_MAX_PLUGIN_TYPE_NUM)
      continue; // invalid plugin type

    if (plugin->type == MYSQL_UDF_PLUGIN ||
        (plugin->type == MariaDB_PASSWORD_VALIDATION_PLUGIN &&
         tmp.plugin_dl->mariaversion == 0))
      continue; // unsupported plugin type

    if (name->str && my_strnncoll(system_charset_info,
                                  (const uchar *)name->str, name->length,
                                  (const uchar *)tmp.name.str, tmp.name.length))
      continue; // plugin name doesn't match

    if (!name->str &&
        (maybe_dupe= plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN)))
    {
      if (plugin->name != maybe_dupe->plugin->name)
      {
        report_error(report, ER_UDF_EXISTS, plugin->name);
        DBUG_RETURN(TRUE);
      }
      dupes++;
      continue; // already installed
    }
    struct st_plugin_int *tmp_plugin_ptr;
    if (*(int*)plugin->info <
        min_plugin_info_interface_version[plugin->type] ||
        ((*(int*)plugin->info) >> 8) >
        (cur_plugin_info_interface_version[plugin->type] >> 8))
    {
      char buf[256];
      strxnmov(buf, sizeof(buf) - 1, "API version for ",
               plugin_type_names[plugin->type].str,
               " plugin ", tmp.name.str,
               " not supported by this version of the server", NullS);
      report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, ENOEXEC, buf);
      goto err;
    }
    if (plugin_maturity_map[plugin->maturity] < plugin_maturity)
    {
      char buf[256];
      strxnmov(buf, sizeof(buf) - 1, "Loading of ",
               plugin_maturity_names[plugin->maturity],
               " plugin ", tmp.name.str,
               " is prohibited by --plugin-maturity=",
               plugin_maturity_names[plugin_maturity],
               NullS);
      report_error(report, ER_CANT_OPEN_LIBRARY, dl->str, EPERM, buf);
      goto err;
    }
    tmp.plugin= plugin;
    tmp.ref_count= 0;
    tmp.state= PLUGIN_IS_UNINITIALIZED;
    tmp.load_option= PLUGIN_ON;

    if (!(tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
      goto err;
    if (my_hash_insert(&plugin_hash[plugin->type], (uchar*)tmp_plugin_ptr))
      tmp_plugin_ptr->state= PLUGIN_IS_FREED;
    init_alloc_root(&tmp_plugin_ptr->mem_root, 4096, 4096, MYF(0));

    if (name->str)
      DBUG_RETURN(FALSE); // all done

    oks++;
    tmp.plugin_dl->ref_count++;
    continue; // otherwise - go on

err:
    errs++;
    if (name->str)
      break;
  }

  DBUG_ASSERT(!name->str || !dupes); // dupes is ONLY for name->str == 0

  if (errs == 0 && oks == 0 && !dupes) // no plugin was found
    report_error(report, ER_CANT_FIND_DL_ENTRY, name->str);

  plugin_dl_del(tmp.plugin_dl);
  DBUG_RETURN(errs > 0 || oks + dupes == 0);
}

Project: server

static int check_func_bool(THD *thd, struct st_mysql_sys_var *var,
                           void *save, st_mysql_value *value)
{
  char buff[STRING_BUFFER_USUAL_SIZE];
  const char *str;
  int result, length;
  long long tmp;

  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
  {
    length= sizeof(buff);
    if (!(str= value->val_str(value, buff, &length)) ||
        (result= find_type(&bool_typelib, str, length, 1)-1) < 0)
      goto err;
  }
  else
  {
    if (value->val_int(value, &tmp) < 0)
      goto err;
    if (tmp != 0 && tmp != 1)
      goto err;
    result= (int) tmp;
  }
  *(my_bool *) save= result ? 1 : 0;
  return 0;
err:
  return 1;
}

Project: server

static void fix_dl_name(MEM_ROOT *root, LEX_STRING *dl)
{
  const size_t so_ext_len= sizeof(SO_EXT) - 1;
  if (dl->length < so_ext_len ||
      my_strcasecmp(&my_charset_latin1, dl->str + dl->length - so_ext_len,
                    SO_EXT))
  {
    char *s= (char*)alloc_root(root, dl->length + so_ext_len + 1);
    memcpy(s, dl->str, dl->length);
    strcpy(s + dl->length, SO_EXT);
    dl->str= s;
    dl->length+= so_ext_len;
  }
}

Project: server

static uchar *intern_sys_var_ptr(THD* thd, int offset, bool global_lock)
{
  DBUG_ENTER("intern_sys_var_ptr");
  DBUG_ASSERT(offset >= 0);
  DBUG_ASSERT((uint)offset <= global_system_variables.dynamic_variables_head);

  if (!thd)
    DBUG_RETURN((uchar*) global_system_variables.dynamic_variables_ptr + offset);

  /*
    dynamic_variables_head points to the largest valid offset
  */
  if (!thd->variables.dynamic_variables_ptr ||
      (uint)offset > thd->variables.dynamic_variables_head)
  {
    mysql_prlock_rdlock(&LOCK_system_variables_hash);
    sync_dynamic_session_variables(thd, global_lock);
    mysql_prlock_unlock(&LOCK_system_variables_hash);
  }
  DBUG_RETURN((uchar*)thd->variables.dynamic_variables_ptr + offset);
}

Project: server

void sync_dynamic_session_variables(THD* thd, bool global_lock)
{
  uint idx;

  thd->variables.dynamic_variables_ptr= (char*)
    my_realloc(thd->variables.dynamic_variables_ptr,
               global_variables_dynamic_size,
               MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR));

  if (global_lock)
    mysql_mutex_lock(&LOCK_global_system_variables);

  mysql_mutex_assert_owner(&LOCK_global_system_variables);

  memcpy(thd->variables.dynamic_variables_ptr +
           thd->variables.dynamic_variables_size,
         global_system_variables.dynamic_variables_ptr +
           thd->variables.dynamic_variables_size,
         global_system_variables.dynamic_variables_size -
           thd->variables.dynamic_variables_size);

  /*
    now we need to iterate through any newly copied 'defaults'
    and if it is a string type with MEMALLOC flag, we need to strdup
  */
  for (idx= 0; idx < bookmark_hash.records; idx++)
  {
    st_bookmark *v= (st_bookmark*) my_hash_element(&bookmark_hash,idx);

    if (v->version <= thd->variables.dynamic_variables_version)
      continue; /* already in thd->variables */

    /* Here we do anything special that may be required of the data types */

    if ((v->key[0] & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_STR &&
         v->key[0] & BOOKMARK_MEMALLOC)
    {
      char **pp= (char**) (thd->variables.dynamic_variables_ptr + v->offset);
      if (*pp)
        *pp= my_strdup(*pp, MYF(MY_WME|MY_FAE));
    }
  }

  if (global_lock)
    mysql_mutex_unlock(&LOCK_global_system_variables);

  thd->variables.dynamic_variables_version=
         global_system_variables.dynamic_variables_version;
  thd->variables.dynamic_variables_head=
         global_system_variables.dynamic_variables_head;
  thd->variables.dynamic_variables_size=
         global_system_variables.dynamic_variables_size;
}

Project: server

static int item_val_int(struct st_mysql_value *value, long long *buf)
{
  Item *item= ((st_item_value_holder*)value)->item;
  *buf= item->val_int();
  if (item->is_null())
    return 1;
  return 0;
}

Project: server

static int item_is_unsigned(struct st_mysql_value *value)
{
  Item *item= ((st_item_value_holder*)value)->item;
  return item->unsigned_flag;
}

Project: server

static struct st_plugin_dl *plugin_dl_find(const LEX_STRING *dl)
{
  uint i;
  struct st_plugin_dl *tmp;
  DBUG_ENTER("plugin_dl_find");
  for (i= 0; i < plugin_dl_array.elements; i++)
  {
    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);
}

Project: server

static void plugin_variables_deinit(struct st_plugin_int *plugin)
{

  for (sys_var *var= plugin->system_vars; var; var= var->next)
    (*var->test_load)= FALSE;
  mysql_del_sys_var_chain(plugin->system_vars);
}

Project: server

static int check_func_enum(THD *thd, struct st_mysql_sys_var *var,
                           void *save, st_mysql_value *value)
{
  char buff[STRING_BUFFER_USUAL_SIZE];
  const char *str;
  TYPELIB *typelib;
  long long tmp;
  long result;
  int length;

  if (var->flags & PLUGIN_VAR_THDLOCAL)
    typelib= ((thdvar_enum_t*) var)->typelib;
  else
    typelib= ((sysvar_enum_t*) var)->typelib;

  if (value->value_type(value) == MYSQL_VALUE_TYPE_STRING)
  {
    length= sizeof(buff);
    if (!(str= value->val_str(value, buff, &length)))
      goto err;
    if ((result= (long)find_type(typelib, str, length, 0) - 1) < 0)
      goto err;
  }
  else
  {
    if (value->val_int(value, &tmp))
      goto err;
    if (tmp < 0 || tmp >= typelib->count)
      goto err;
    result= (long) tmp;
  }
  *(long*)save= result;
  return 0;
err:
  return 1;
}

Project: server

static int check_func_double(THD *thd, struct st_mysql_sys_var *var,
                             void *save, st_mysql_value *value)
{
  double v;
  my_bool fixed;
  struct my_option option;

  value->val_real(value, &v);
  plugin_opt_set_limits(&option, var);
  *(double *) save= getopt_double_limit_value(v, &option, &fixed);

  return throw_bounds_warning(thd, var->name, fixed, v);
}

Project: server

static st_plugin_dl *plugin_dl_insert_or_reuse(struct st_plugin_dl *plugin_dl)
{
  uint i;
  struct st_plugin_dl *tmp;
  DBUG_ENTER("plugin_dl_insert_or_reuse");
  for (i= 0; i < plugin_dl_array.elements; i++)
  {
    tmp= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
    if (! tmp->ref_count)
    {
      memcpy(tmp, plugin_dl, sizeof(struct st_plugin_dl));
      DBUG_RETURN(tmp);
    }
  }
  if (insert_dynamic(&plugin_dl_array, (uchar*)&plugin_dl))
    DBUG_RETURN(0);
  tmp= *dynamic_element(&plugin_dl_array, plugin_dl_array.elements - 1,
                        struct st_plugin_dl **)=
      (struct st_plugin_dl *) memdup_root(&plugin_mem_root, (uchar*)plugin_dl,
                                           sizeof(struct st_plugin_dl));
  DBUG_RETURN(tmp);
}

Project: server

static bool plugin_dl_foreach_internal(THD *thd, st_plugin_dl *plugin_dl,
                                       st_maria_plugin *plug,
                                       plugin_foreach_func *func, void *arg)
{
  for (; plug->name; plug++)
  {
    st_plugin_int tmp, *plugin;

    tmp.name.str= const_cast<char*>(plug->name);
    tmp.name.length= strlen(plug->name);
    tmp.plugin= plug;
    tmp.plugin_dl= plugin_dl;

    mysql_mutex_lock(&LOCK_plugin);
    if ((plugin= plugin_find_internal(&tmp.name, MYSQL_ANY_PLUGIN)) &&
        plugin->plugin == plug)

    {
      tmp.state= plugin->state;
      tmp.load_option= plugin->load_option;
    }
    else
    {
      tmp.state= PLUGIN_IS_FREED;
      tmp.load_option= PLUGIN_OFF;
    }
    mysql_mutex_unlock(&LOCK_plugin);

    plugin= &tmp;
    if (func(thd, plugin_int_to_ref(plugin), arg))
      return 1;
  }
  return 0;
}

Project: server

plugin_ref plugin_lock(THD *thd, plugin_ref ptr)
{
  LEX *lex= thd ? thd->lex : 0;
  plugin_ref rc;
  DBUG_ENTER("plugin_lock");

#ifdef DBUG_OFF
  /*
    In optimized builds we don't do reference counting for built-in
    (plugin->plugin_dl == 0) plugins.

    Note that we access plugin->plugin_dl outside of LOCK_plugin, and for
    dynamic plugins a 'plugin' could correspond to plugin that was unloaded
    meanwhile!  But because st_plugin_int is always allocated on
    plugin_mem_root, the pointer can never be invalid - the memory is never
    freed.
    Of course, the memory that 'plugin' points to can be overwritten by
    another plugin being loaded, but plugin->plugin_dl can never change
    from zero to non-zero or vice versa.
    That is, it's always safe to check for plugin->plugin_dl==0 even
    without a mutex.
  */
  if (! plugin_dlib(ptr))
  {
    plugin_ref_to_int(ptr)->locks_total++;
    DBUG_RETURN(ptr);
  }
#endif
  mysql_mutex_lock(&LOCK_plugin);
  plugin_ref_to_int(ptr)->locks_total++;
  rc= intern_plugin_lock(lex, ptr);
  mysql_mutex_unlock(&LOCK_plugin);
  DBUG_RETURN(rc);
}

Project: server

void plugin_thdvar_cleanup(THD *thd)
{
  uint idx;
  plugin_ref *list;
  DBUG_ENTER("plugin_thdvar_cleanup");

  mysql_mutex_lock(&LOCK_plugin);

  unlock_variables(thd, &thd->variables);
  cleanup_variables(&thd->variables);

  if ((idx= thd->lex->plugins.elements))
  {
    list= ((plugin_ref*) thd->lex->plugins.buffer) + idx - 1;
    DBUG_PRINT("info",("unlocking %d plugins", idx));
    while ((uchar*) list >= thd->lex->plugins.buffer)
      intern_plugin_unlock(NULL, *list--);
  }

  reap_plugins();
  mysql_mutex_unlock(&LOCK_plugin);

  reset_dynamic(&thd->lex->plugins);

  DBUG_VOID_RETURN;
}

Project: server

uchar* sys_var_pluginvar::do_value_ptr(THD *thd, enum_var_type type,
                                       const LEX_STRING *base)
{
  uchar* result;

  result= real_value_ptr(thd, type);

  if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_ENUM)
    result= (uchar*) get_type(plugin_var_typelib(), *(ulong*)result);
  else if ((plugin_var->flags & PLUGIN_VAR_TYPEMASK) == PLUGIN_VAR_SET)
    result= (uchar*) set_to_string(thd, 0, *(ulonglong*) result,
                                   plugin_var_typelib()->type_names);
  return result;
}

Project: server

sys_var *find_sys_var(THD *thd, const char *str, size_t length)
{
  return find_sys_var_ex(thd, str, length, false, false);
}

Project: server

bool check_valid_path(const char *path, size_t len)
{
  size_t prefix= my_strcspn(files_charset_info, path, path + len, FN_DIRSEP);
  return  prefix < len;
}

Project: server

static unsigned long long *mysql_sys_var_ulonglong(THD* thd, int offset)
{
  return (unsigned long long *) intern_sys_var_ptr(thd, offset, true);
}

Project: server

static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
                          void *save, st_mysql_value *value)
{
  my_bool fixed1, fixed2;
  long long orig, val;
  struct my_option options;
  value->val_int(value, &orig);
  val= orig;
  plugin_opt_set_limits(&options, var);

  if (var->flags & PLUGIN_VAR_UNSIGNED)
  {
    if ((fixed1= (!value->is_unsigned(value) && val < 0)))
      val=0;
    *(uint *)save= (uint) getopt_ull_limit_value((ulonglong) val, &options,
                                                   &fixed2);
  }
  else
  {
    if ((fixed1= (value->is_unsigned(value) && val < 0)))
      val=LONGLONG_MAX;
    *(int *)save= (int) getopt_ll_limit_value(val, &options, &fixed2);
  }

  return throw_bounds_warning(thd, var->name, fixed1 || fixed2,
                              value->is_unsigned(value), (longlong) orig);
}

Project: server

static void update_func_str(THD *thd, struct st_mysql_sys_var *var,
                             void *tgt, const void *save)
{
  char *value= *(char**) save;
  if (var->flags & PLUGIN_VAR_MEMALLOC)
  {
    char *old= *(char**) tgt;
    if (value)
      *(char**) tgt= my_strdup(value, MYF(0));
    else
      *(char**) tgt= 0;
    my_free(old);
  }
  else
    *(char**) tgt= value;
}

Project: server

bool sys_var_pluginvar::session_is_default(THD *thd)
{
  uchar *value= plugin_var->flags & PLUGIN_VAR_THDLOCAL
                ? intern_sys_var_ptr(thd, *(int*) (plugin_var+1), true)
                : *(uchar**) (plugin_var+1);

    real_value_ptr(thd, OPT_SESSION);

  switch (plugin_var->flags & PLUGIN_VAR_TYPEMASK) {
  case PLUGIN_VAR_BOOL:
    return option.def_value == *(my_bool*)value;
  case PLUGIN_VAR_INT:
    return option.def_value == *(int*)value;
  case PLUGIN_VAR_LONG:
  case PLUGIN_VAR_ENUM:
    return option.def_value == *(long*)value;
  case PLUGIN_VAR_LONGLONG:
  case PLUGIN_VAR_SET:
    return option.def_value == *(longlong*)value;
  case PLUGIN_VAR_STR:
    {
      const char *a=(char*)option.def_value;
      const char *b=(char*)value;
      return (!a && !b) || (a && b && strcmp(a,b));
    }
  case PLUGIN_VAR_DOUBLE:
    return getopt_ulonglong2double(option.def_value) == *(double*)value;
  }
  DBUG_ASSERT(0);
  return 0;
}

Project: server

bool sys_var_pluginvar::session_update(THD *thd, set_var *var)
{
  DBUG_ASSERT(!is_readonly());
  DBUG_ASSERT(plugin_var->flags & PLUGIN_VAR_THDLOCAL);
  DBUG_ASSERT(thd == current_thd);

  mysql_mutex_lock(&LOCK_global_system_variables);
  void *tgt= real_value_ptr(thd, OPT_SESSION);
  const void *src= var->value ? (void*)&var->save_result
                              : (void*)real_value_ptr(thd, OPT_GLOBAL);
  mysql_mutex_unlock(&LOCK_global_system_variables);

  plugin_var->update(thd, plugin_var, tgt, src);

  return false;
}

Project: server

SHOW_COMP_OPTION plugin_status(const char *name, size_t len, int type)
{
  LEX_STRING plugin_name= { (char *) name, len };
  return plugin_status(&plugin_name, type);
}

Project: server

static void update_func_bool(THD *thd, struct st_mysql_sys_var *var,
                             void *tgt, const void *save)
{
  *(my_bool *) tgt= *(my_bool *) save ? 1 : 0;
}

Project: server

void* thd_getspecific(MYSQL_THD thd, MYSQL_THD_KEY_T key)
{
  DBUG_ASSERT(key != INVALID_THD_KEY);
  if (key == INVALID_THD_KEY || (!thd && !(thd= current_thd)))
    return 0;

  return *(void**)(intern_sys_var_ptr(thd, key, true));
}

Project: server

  sys_var_pluginvar *cast_pluginvar() { return this; }

Project: server

static long *mysql_sys_var_long(THD* thd, int offset)
{
  return (long *) intern_sys_var_ptr(thd, offset, true);
}

Project: server

void plugin_shutdown(void)
{
  uint i, count= plugin_array.elements;
  struct st_plugin_int **plugins, *plugin;
  struct st_plugin_dl **dl;
  DBUG_ENTER("plugin_shutdown");

  if (initialized)
  {
    mysql_mutex_lock(&LOCK_plugin);

    reap_needed= true;

    /*
      We want to shut down plugins in a reasonable order, this will
      become important when we have plugins which depend upon each other.
      Circular references cannot be reaped so they are forced afterwards.
      TODO: Have an additional step here to notify all active plugins that
      shutdown is requested to allow plugins to deinitialize in parallel.
    */
    while (reap_needed && (count= plugin_array.elements))
    {
      reap_plugins();
      for (i= 0; i < count; i++)
      {
        plugin= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
        if (plugin->state == PLUGIN_IS_READY)
        {
          plugin->state= PLUGIN_IS_DELETED;
          reap_needed= true;
        }
      }
      if (!reap_needed)
      {
        /*
          release any plugin references held.
        */
        unlock_variables(NULL, &global_system_variables);
        unlock_variables(NULL, &max_system_variables);
      }
    }

    plugins= (struct st_plugin_int **) my_alloca(sizeof(void*) * (count+1));

    /*
      If we have any plugins which did not die cleanly, we force shutdown
    */
    for (i= 0; i < count; i++)
    {
      plugins[i]= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
      /* change the state to ensure no reaping races */
      if (plugins[i]->state == PLUGIN_IS_DELETED)
        plugins[i]->state= PLUGIN_IS_DYING;
    }
    mysql_mutex_unlock(&LOCK_plugin);

    /*
      We loop through all plugins and call deinit() if they have one.
    */
    for (i= 0; i < count; i++)
      if (!(plugins[i]->state & (PLUGIN_IS_UNINITIALIZED | PLUGIN_IS_FREED |
                                 PLUGIN_IS_DISABLED)))
      {
        /*
          We are forcing deinit on plugins so we don't want to do a ref_count
          check until we have processed all the plugins.
        */
        plugin_deinitialize(plugins[i], false);
      }

    /*
      It's perfectly safe not to lock LOCK_plugin, as there're no
      concurrent threads anymore. But some functions called from here
      use mysql_mutex_assert_owner(), so we lock the mutex to satisfy it
    */
    mysql_mutex_lock(&LOCK_plugin);

    /*
      We defer checking ref_counts until after all plugins are deinitialized
      as some may have worker threads holding on to plugin references.
    */
    for (i= 0; i < count; i++)
    {
      if (plugins[i]->ref_count)
        sql_print_error("Plugin '%s' has ref_count=%d after shutdown.",
                        plugins[i]->name.str, plugins[i]->ref_count);
      if (plugins[i]->state & PLUGIN_IS_UNINITIALIZED ||
          plugins[i]->state & PLUGIN_IS_DISABLED)
        plugin_del(plugins[i]);
    }

    /*
      Now we can deallocate all memory.
    */

    cleanup_variables(&global_system_variables);
    cleanup_variables(&max_system_variables);
    mysql_mutex_unlock(&LOCK_plugin);

    initialized= 0;
    mysql_mutex_destroy(&LOCK_plugin);

    my_afree(plugins);
  }

  /* Dispose of the memory */

  for (i= 0; i < MYSQL_MAX_PLUGIN_TYPE_NUM; i++)
    my_hash_free(&plugin_hash[i]);
  delete_dynamic(&plugin_array);

  count= plugin_dl_array.elements;
  dl= (struct st_plugin_dl **)my_alloca(sizeof(void*) * count);
  for (i= 0; i < count; i++)
    dl[i]= *dynamic_element(&plugin_dl_array, i, struct st_plugin_dl **);
  for (i= 0; i < plugin_dl_array.elements; i++)
    free_plugin_mem(dl[i]);
  my_afree(dl);
  delete_dynamic(&plugin_dl_array);

  my_hash_free(&bookmark_hash);
  free_root(&plugin_mem_root, MYF(0));
  free_root(&plugin_vars_mem_root, MYF(0));

  global_variables_dynamic_size= 0;

  DBUG_VOID_RETURN;
}

Project: server

static inline char plugin_var_bookmark_key(uint flags)
{
  return (flags & PLUGIN_VAR_TYPEMASK) |
         (flags & PLUGIN_VAR_MEMALLOC ? BOOKMARK_MEMALLOC : 0);
}

Project: server

static inline void convert_dash_to_underscore(char *str, int len)
{
  for (char *p= str; p <= str+len; p++)
    if (*p == '-')
      *p= '_';
}

Project: server

static void update_func_long(THD *thd, struct st_mysql_sys_var *var,
                             void *tgt, const void *save)
{
  *(long *)tgt= *(long *) save;
}

Project: server

static void init_plugin_psi_keys(void)
{
  const char* category= "sql";
  int count;

  if (PSI_server == NULL)
    return;

  count= array_elements(all_plugin_mutexes);
  PSI_server->register_mutex(category, all_plugin_mutexes, count);
}