summaryrefslogtreecommitdiff
path: root/sql/create_options.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/create_options.cc')
-rw-r--r--sql/create_options.cc255
1 files changed, 217 insertions, 38 deletions
diff --git a/sql/create_options.cc b/sql/create_options.cc
index c33de34f3ca..cd9f098eb07 100644
--- a/sql/create_options.cc
+++ b/sql/create_options.cc
@@ -21,6 +21,7 @@
#include "create_options.h"
#include <my_getopt.h>
+#include "set_var.h"
#define FRM_QUOTED_VALUE 0x8000
@@ -74,7 +75,7 @@ void engine_option_value::link(engine_option_value **start,
}
static bool report_wrong_value(THD *thd, const char *name, const char *val,
- my_bool suppress_warning)
+ bool suppress_warning)
{
if (suppress_warning)
return 0;
@@ -86,13 +87,13 @@ static bool report_wrong_value(THD *thd, const char *name, const char *val,
return 1;
}
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_OPTION_VALUE,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_BAD_OPTION_VALUE,
ER(ER_BAD_OPTION_VALUE), val, name);
return 0;
}
static bool report_unknown_option(THD *thd, engine_option_value *val,
- my_bool suppress_warning)
+ bool suppress_warning)
{
DBUG_ENTER("report_unknown_option");
@@ -109,14 +110,16 @@ static bool report_unknown_option(THD *thd, engine_option_value *val,
DBUG_RETURN(TRUE);
}
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_UNKNOWN_OPTION, ER(ER_UNKNOWN_OPTION), val->name.str);
DBUG_RETURN(FALSE);
}
+#define value_ptr(STRUCT,OPT) ((char*)(STRUCT) + (OPT)->offset)
+
static bool set_one_value(ha_create_table_option *opt,
- THD *thd, LEX_STRING *value, void *base,
- my_bool suppress_warning,
+ THD *thd, const LEX_STRING *value, void *base,
+ bool suppress_warning,
MEM_ROOT *root)
{
DBUG_ENTER("set_one_value");
@@ -126,9 +129,11 @@ static bool set_one_value(ha_create_table_option *opt,
(value->str ? value->str : "<DEFAULT>")));
switch (opt->type)
{
+ case HA_OPTION_TYPE_SYSVAR:
+ DBUG_ASSERT(0); // HA_OPTION_TYPE_SYSVAR's are replaced in resolve_sysvars()
case HA_OPTION_TYPE_ULL:
{
- ulonglong *val= (ulonglong*)((char*)base + opt->offset);
+ ulonglong *val= (ulonglong*)value_ptr(base, opt);
if (!value->str)
{
*val= opt->def_value;
@@ -152,7 +157,7 @@ static bool set_one_value(ha_create_table_option *opt,
}
case HA_OPTION_TYPE_STRING:
{
- char **val= (char **)((char *)base + opt->offset);
+ char **val= (char **)value_ptr(base, opt);
if (!value->str)
{
*val= 0;
@@ -165,7 +170,7 @@ static bool set_one_value(ha_create_table_option *opt,
}
case HA_OPTION_TYPE_ENUM:
{
- uint *val= (uint *)((char *)base + opt->offset), num;
+ uint *val= (uint *)value_ptr(base, opt), num;
*val= (uint) opt->def_value;
if (!value->str)
@@ -197,7 +202,7 @@ static bool set_one_value(ha_create_table_option *opt,
}
case HA_OPTION_TYPE_BOOL:
{
- bool *val= (bool *)((char *)base + opt->offset);
+ bool *val= (bool *)value_ptr(base, opt);
*val= opt->def_value;
if (!value->str)
@@ -257,52 +262,92 @@ static const size_t ha_option_type_sizeof[]=
@retval FALSE OK
*/
-my_bool parse_option_list(THD* thd, void *option_struct_arg,
- engine_option_value *option_list,
- ha_create_table_option *rules,
- my_bool suppress_warning,
- MEM_ROOT *root)
+bool parse_option_list(THD* thd, handlerton *hton, void *option_struct_arg,
+ engine_option_value **option_list,
+ ha_create_table_option *rules,
+ bool suppress_warning, MEM_ROOT *root)
{
ha_create_table_option *opt;
size_t option_struct_size= 0;
- engine_option_value *val= option_list;
+ engine_option_value *val, *last;
void **option_struct= (void**)option_struct_arg;
DBUG_ENTER("parse_option_list");
DBUG_PRINT("enter",
- ("struct: 0x%lx list: 0x%lx rules: 0x%lx suppres %u root 0x%lx",
- (ulong) *option_struct, (ulong)option_list, (ulong)rules,
- (uint) suppress_warning, (ulong) root));
+ ("struct: %p list: %p rules: %p suppress_warning: %u root: %p",
+ *option_struct, *option_list, rules,
+ (uint) suppress_warning, root));
if (rules)
{
- LEX_STRING default_val= {NULL, 0};
for (opt= rules; opt->name; opt++)
set_if_bigger(option_struct_size, opt->offset +
ha_option_type_sizeof[opt->type]);
*option_struct= alloc_root(root, option_struct_size);
-
- /* set all values to default */
- for (opt= rules; opt->name; opt++)
- set_one_value(opt, thd, &default_val, *option_struct,
- suppress_warning, root);
}
- for (; val; val= val->next)
+ for (opt= rules; rules && opt->name; opt++)
{
- for (opt= rules; opt && opt->name; opt++)
+ bool seen=false;
+ for (val= *option_list; val; val= val->next)
{
+ last= val;
if (my_strnncoll(system_charset_info,
(uchar*)opt->name, opt->name_length,
(uchar*)val->name.str, val->name.length))
continue;
+ seen=true;
+
+ if (val->parsed && !val->value.str)
+ continue;
+
if (set_one_value(opt, thd, &val->value,
*option_struct, suppress_warning || val->parsed, root))
DBUG_RETURN(TRUE);
val->parsed= true;
break;
}
+ if (!seen)
+ {
+ LEX_STRING default_val= null_lex_str;
+
+ /*
+ If it's CREATE/ALTER TABLE parsing mode (options are created in the
+ transient thd->mem_root, not in the long living TABLE_SHARE::mem_root),
+ and variable-backed option was not explicitly set.
+
+ If it's not create, but opening of the existing frm (that was,
+ probably, created with the older version of the storage engine and
+ does not have this option stored), we take the *default* value of the
+ sysvar, not the *current* value. Because we don't want to have
+ different option values for the same table if it's opened many times.
+ */
+ if (root == thd->mem_root && opt->var)
+ {
+ // take a value from the variable and add it to the list
+ sys_var *sysvar= find_hton_sysvar(hton, opt->var);
+ DBUG_ASSERT(sysvar);
+
+ char buf[256];
+ String sbuf(buf, sizeof(buf), system_charset_info), *str;
+ if ((str= sysvar->val_str(&sbuf, thd, OPT_SESSION, 0)))
+ {
+ LEX_STRING name= { const_cast<char*>(opt->name), opt->name_length };
+ default_val.str= strmake_root(root, str->ptr(), str->length());
+ default_val.length= str->length();
+ val= new (root) engine_option_value(name, default_val, true,
+ option_list, &last);
+ val->parsed= true;
+ }
+ }
+ set_one_value(opt, thd, &default_val, *option_struct,
+ suppress_warning, root);
+ }
+ }
+
+ for (val= *option_list; val; val= val->next)
+ {
if (report_unknown_option(thd, val, suppress_warning))
DBUG_RETURN(TRUE);
val->parsed= true;
@@ -313,6 +358,103 @@ my_bool parse_option_list(THD* thd, void *option_struct_arg,
/**
+ Resolves all HA_OPTION_TYPE_SYSVAR elements.
+
+ This is done when an engine is loaded.
+*/
+static bool resolve_sysvars(handlerton *hton, ha_create_table_option *rules)
+{
+ for (ha_create_table_option *opt= rules; rules && opt->name; opt++)
+ {
+ if (opt->type == HA_OPTION_TYPE_SYSVAR)
+ {
+ struct my_option optp;
+ plugin_opt_set_limits(&optp, opt->var);
+ switch(optp.var_type) {
+ case GET_ULL:
+ case GET_ULONG:
+ case GET_UINT:
+ opt->type= HA_OPTION_TYPE_ULL;
+ opt->def_value= (ulonglong)optp.def_value;
+ opt->min_value= (ulonglong)optp.min_value;
+ opt->max_value= (ulonglong)optp.max_value;
+ opt->block_size= (ulonglong)optp.block_size;
+ break;
+ case GET_STR:
+ case GET_STR_ALLOC:
+ opt->type= HA_OPTION_TYPE_STRING;
+ break;
+ case GET_BOOL:
+ opt->type= HA_OPTION_TYPE_BOOL;
+ opt->def_value= optp.def_value;
+ break;
+ case GET_ENUM:
+ {
+ opt->type= HA_OPTION_TYPE_ENUM;
+ opt->def_value= optp.def_value;
+
+ char buf[256];
+ String str(buf, sizeof(buf), system_charset_info);
+ str.length(0);
+ for (const char **s= optp.typelib->type_names; *s; s++)
+ {
+ if (str.append(*s) || str.append(','))
+ return 1;
+ }
+ DBUG_ASSERT(str.length());
+ opt->values= my_strndup(str.ptr(), str.length()-1, MYF(MY_WME));
+ if (!opt->values)
+ return 1;
+ break;
+ }
+ default:
+ DBUG_ASSERT(0);
+ }
+ }
+ }
+ return 0;
+}
+
+bool resolve_sysvar_table_options(handlerton *hton)
+{
+ return resolve_sysvars(hton, hton->table_options) ||
+ resolve_sysvars(hton, hton->field_options) ||
+ resolve_sysvars(hton, hton->index_options);
+}
+
+/*
+ Restore HA_OPTION_TYPE_SYSVAR options back as they were
+ before resolve_sysvars().
+
+ This is done when the engine is unloaded, so that we could
+ call resolve_sysvars() if the engine is installed again.
+*/
+static void free_sysvars(handlerton *hton, ha_create_table_option *rules)
+{
+ for (ha_create_table_option *opt= rules; rules && opt->name; opt++)
+ {
+ if (opt->var)
+ {
+ my_free(const_cast<char*>(opt->values));
+ opt->type= HA_OPTION_TYPE_SYSVAR;
+ opt->def_value= 0;
+ opt->min_value= 0;
+ opt->max_value= 0;
+ opt->block_size= 0;
+ opt->values= 0;
+ }
+ }
+}
+
+void free_sysvar_table_options(handlerton *hton)
+{
+ free_sysvars(hton, hton->table_options);
+ free_sysvars(hton, hton->field_options);
+ free_sysvars(hton, hton->index_options);
+}
+
+
+/**
Parses all table/fields/keys options
@param thd thread handler
@@ -323,27 +465,27 @@ my_bool parse_option_list(THD* thd, void *option_struct_arg,
@retval FALSE OK
*/
-my_bool parse_engine_table_options(THD *thd, handlerton *ht,
- TABLE_SHARE *share)
+bool parse_engine_table_options(THD *thd, handlerton *ht, TABLE_SHARE *share)
{
MEM_ROOT *root= &share->mem_root;
DBUG_ENTER("parse_engine_table_options");
- if (parse_option_list(thd, &share->option_struct, share->option_list,
+ if (parse_option_list(thd, ht, &share->option_struct, & share->option_list,
ht->table_options, TRUE, root))
DBUG_RETURN(TRUE);
for (Field **field= share->field; *field; field++)
{
- if (parse_option_list(thd, &(*field)->option_struct, (*field)->option_list,
+ if (parse_option_list(thd, ht, &(*field)->option_struct,
+ & (*field)->option_list,
ht->field_options, TRUE, root))
DBUG_RETURN(TRUE);
}
for (uint index= 0; index < share->keys; index ++)
{
- if (parse_option_list(thd, &share->key_info[index].option_struct,
- share->key_info[index].option_list,
+ if (parse_option_list(thd, ht, &share->key_info[index].option_struct,
+ & share->key_info[index].option_list,
ht->index_options, TRUE, root))
DBUG_RETURN(TRUE);
}
@@ -352,6 +494,26 @@ my_bool parse_engine_table_options(THD *thd, handlerton *ht,
}
+bool engine_options_differ(void *old_struct, void *new_struct,
+ ha_create_table_option *rules)
+{
+ ha_create_table_option *opt;
+ for (opt= rules; rules && opt->name; opt++)
+ {
+ char **old_val= (char**)value_ptr(old_struct, opt);
+ char **new_val= (char**)value_ptr(new_struct, opt);
+ int neq;
+ if (opt->type == HA_OPTION_TYPE_STRING)
+ neq= (*old_val && *new_val) ? strcmp(*old_val, *new_val) : *old_val != *new_val;
+ else
+ neq= memcmp(old_val, new_val, ha_option_type_sizeof[opt->type]);
+ if (neq)
+ return true;
+ }
+ return false;
+}
+
+
/**
Returns representation length of key and value in the frm file
*/
@@ -543,8 +705,8 @@ uchar *engine_option_value::frm_read(const uchar *buff, engine_option_value **st
@retval FALSE OK
*/
-my_bool engine_table_options_frm_read(const uchar *buff, uint length,
- TABLE_SHARE *share)
+bool engine_table_options_frm_read(const uchar *buff, uint length,
+ TABLE_SHARE *share)
{
const uchar *buff_end= buff + length;
engine_option_value *UNINIT_VAR(end);
@@ -604,12 +766,29 @@ engine_option_value *merge_engine_table_options(engine_option_value *first,
DBUG_ENTER("merge_engine_table_options");
LINT_INIT(end);
- /* find last element */
- if (first && second)
- for (end= first; end->next; end= end->next) /* no-op */;
+ /* Create copy of first list */
+ for (opt= first, first= 0; opt; opt= opt->next)
+ new (root) engine_option_value(opt, &first, &end);
for (opt= second; opt; opt= opt->next)
new (root) engine_option_value(opt->name, opt->value, opt->quoted_value,
&first, &end);
DBUG_RETURN(first);
}
+
+bool is_engine_option_known(engine_option_value *opt,
+ ha_create_table_option *rules)
+{
+ if (!rules)
+ return false;
+
+ for (; rules->name; rules++)
+ {
+ if (!my_strnncoll(system_charset_info,
+ (uchar*)rules->name, rules->name_length,
+ (uchar*)opt->name.str, opt->name.length))
+ return true;
+ }
+ return false;
+}
+