Hi, Jan!
On Mar 08, Jan Lindström wrote:
revision-id: a1c4620646d43eaff979c132a57ee2101070fa5e
parent(s): 1b74f32b1d94465f6d6e14e4aa7ba1f94c32e39e
committer: Jan Lindström
branch nick: 10.1-innodb
timestamp: 2015-03-08 17:23:05 +0200
message:
MDEV-6858: enforce_storage_engine option
Merge from Percona Server enforced use of a specific storage engine
authored by Stewart Smith.
Modified to be session variable and modifiable only by SUPER. Use
similar implementation as default_storage_engine.
diff --git a/mysql-test/t/enforce_storage_engine.test b/mysql-test/t/enforce_storage_engine.test
new file mode 100644
index 0000000..36231e6
--- /dev/null
+++ b/mysql-test/t/enforce_storage_engine.test
@@ -0,0 +1,35 @@
...
+--error ER_UNKNOWN_STORAGE_ENGINE
+CREATE TABLE t2 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=MyISAM;
+
+SET SESSION enforce_storage_engine=MyISAM;
+select @@session.enforce_storage_engine;
+select * from t1;
+drop table t1;
+
+--error 1286
+SET SESSION enforce_storage_engine=FooBar;
+
+select @@session.enforce_storage_engine;
Consider adding tests for "only modifiable by SUPER"
(create a new user, connect with it, see that enforce_storage_engine
cannot be changed), and for modified enforce_storage_engine
(you tested that it can be changed, but didn't do any CREATE TABLE with
the new value).
diff --git a/sql/handler.cc b/sql/handler.cc
index 12d7ffb..5d5ac30 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -117,6 +117,15 @@ static plugin_ref ha_default_tmp_plugin(THD *thd)
return ha_default_plugin(thd);
}
+
+static plugin_ref ha_enforced_plugin(THD *thd)
+{
+ if (thd->variables.enforced_table_plugin)
+ return thd->variables.enforced_table_plugin;
+ return NULL;
+}
+
+
/** @brief
Return the default storage engine handlerton for thread
@@ -148,6 +157,25 @@ handlerton *ha_default_tmp_handlerton(THD *thd)
/** @brief
+ Return the enforced storage engine handlerton for thread
+
+ SYNOPSIS
+ ha_enforce_handlerton(thd)
+ thd current thread
+
+ RETURN
+ pointer to handlerton OR NULL
+
+*/
+handlerton *ha_enforced_handlerton(THD *thd)
+{
+ plugin_ref plugin= ha_enforced_plugin(thd);
+ if (plugin)
+ return plugin_hton(plugin);
+ return NULL;
+}
+
+/** @brief
Return the storage engine handlerton for the supplied name
SYNOPSIS
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index b97742d..6966fd9 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4738,8 +4738,8 @@ static void add_file_to_crash_report(char *file)
#define init_default_storage_engine(X,Y) \
init_default_storage_engine_impl(#X, X, &global_system_variables.Y)
-static int init_default_storage_engine_impl(const char *opt_name,
- char *engine_name, plugin_ref *res)
+int init_default_storage_engine_impl(const char *opt_name,
+ char *engine_name, plugin_ref *res)
You've made init_default_storage_engine_impl() extern, but you never
use it anywhere.
And you've forgot to create a command line option for
enforced_table_plugin.
{
if (!engine_name)
{
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index e9a1ae9..184c073 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -9745,12 +9745,24 @@ static bool check_engine(THD *thd, const char *db_name,
DBUG_ENTER("check_engine");
handlerton **new_engine= &create_info->db_type;
handlerton *req_engine= *new_engine;
+ handlerton *enf_engine= ha_enforced_handlerton(thd);
I'd write it directly as
thd->variables.enforced_table_plugin ? plugin_hton(thd->variables.enforced_table_plugin) : NULL;
Or as an inlined function here, in sql_table.cc.
Not as two small but non-inlined functions in handler.cc, that are only
used once here.
bool no_substitution= thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION;
*new_engine= ha_checktype(thd, req_engine, no_substitution);
DBUG_ASSERT(*new_engine);
if (!*new_engine)
DBUG_RETURN(true);
+ if (enf_engine)
+ {
+ if (enf_engine != *new_engine && no_substitution)
+ {
+ const char *engine_name= ha_resolve_storage_engine_name(req_engine);
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), engine_name, engine_name);
+ DBUG_RETURN(TRUE);
+ }
+ *new_engine= enf_engine;
+ }
+
if (req_engine && req_engine != *new_engine)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 8371df0..cd53714 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3437,6 +3437,28 @@ static Sys_var_plugin Sys_default_tmp_storage_engine(
SESSION_VAR(tmp_table_plugin), NO_CMD_LINE,
MYSQL_STORAGE_ENGINE_PLUGIN, DEFAULT(&default_tmp_storage_engine));
+extern int init_default_storage_engine_impl(const char* opt_name, char *engine_name, plugin_ref *plugin);
Not used below.
+
+
+static bool check_super_and_not_null(sys_var *self, THD*thd, set_var *var)
I think that NULL value should be allowed, it means "don't enforce a
storage engine".
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ return true;
+ }
+#endif
+ return var->value && var->value->is_null();
+}
+
+static Sys_var_plugin Sys_enforce_storage_engine(
+ "enforce_storage_engine", "Force the use of a storage engine for new "
+ "tables",
+ SESSION_VAR(enforced_table_plugin),
+ NO_CMD_LINE, MYSQL_STORAGE_ENGINE_PLUGIN,
+ DEFAULT(0), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_super_and_not_null));
+
#if defined(ENABLED_DEBUG_SYNC)
/*
Variable can be set for the session only.
Regards,
Sergei