[Commits] a1c4620: MDEV-6858: enforce_storage_engine option

Jan Lindström jan.lindstrom at mariadb.com
Sun Mar 8 17:24:36 EET 2015


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.

---
 mysql-test/r/enforce_storage_engine.result | 50 ++++++++++++++++++++++++++++++
 mysql-test/t/enforce_storage_engine.test   | 35 +++++++++++++++++++++
 sql/handler.cc                             | 28 +++++++++++++++++
 sql/handler.h                              |  1 +
 sql/mysqld.cc                              |  4 +--
 sql/sql_class.h                            |  1 +
 sql/sql_plugin.cc                          |  8 ++++-
 sql/sql_table.cc                           | 12 +++++++
 sql/sys_vars.cc                            | 22 +++++++++++++
 9 files changed, 158 insertions(+), 3 deletions(-)

diff --git a/mysql-test/r/enforce_storage_engine.result b/mysql-test/r/enforce_storage_engine.result
new file mode 100644
index 0000000..7e62de5
--- /dev/null
+++ b/mysql-test/r/enforce_storage_engine.result
@@ -0,0 +1,50 @@
+drop table if exists t1;
+SET SESSION enforce_storage_engine=InnoDB;
+select @@session.enforce_storage_engine;
+@@session.enforce_storage_engine
+InnoDB
+CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` varchar(10) DEFAULT NULL,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=MyISAM;
+Warnings:
+Note	1266	Using storage engine InnoDB for table 't1'
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` varchar(10) DEFAULT NULL,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+SET SESSION sql_mode='NO_ENGINE_SUBSTITUTION';
+CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `c1` int(11) NOT NULL AUTO_INCREMENT,
+  `c2` varchar(10) DEFAULT NULL,
+  PRIMARY KEY (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+INSERT INTO t1 values (1,'abba');
+CREATE TABLE t2 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=MyISAM;
+ERROR 42000: Unknown storage engine 'MyISAM'
+SET SESSION enforce_storage_engine=MyISAM;
+select @@session.enforce_storage_engine;
+@@session.enforce_storage_engine
+MyISAM
+select * from t1;
+c1	c2
+1	abba
+drop table t1;
+SET SESSION enforce_storage_engine=FooBar;
+ERROR 42000: Unknown storage engine 'FooBar'
+select @@session.enforce_storage_engine;
+@@session.enforce_storage_engine
+MyISAM
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 @@
+-- source include/have_innodb.inc
+-- source include/not_embedded.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+SET SESSION enforce_storage_engine=InnoDB;
+select @@session.enforce_storage_engine;
+CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=MyISAM;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+SET SESSION sql_mode='NO_ENGINE_SUBSTITUTION';
+CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB;
+SHOW CREATE TABLE t1;
+INSERT INTO t1 values (1,'abba');
+
+--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;
+
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/handler.h b/sql/handler.h
index 5ef9208..86c7c18 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1356,6 +1356,7 @@ static inline sys_var *find_hton_sysvar(handlerton *hton, st_mysql_sys_var *var)
 
 handlerton *ha_default_handlerton(THD *thd);
 handlerton *ha_default_tmp_handlerton(THD *thd);
+handlerton *ha_enforced_handlerton(THD *thd);
 
 /* Possible flags of a handlerton (there can be 32 of them) */
 #define HTON_NO_FLAGS                 0
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)
 {
   if (!engine_name)
   {
diff --git a/sql/sql_class.h b/sql/sql_class.h
index bd145bd..5930c6c 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -618,6 +618,7 @@ typedef struct system_variables
 
   plugin_ref table_plugin;
   plugin_ref tmp_table_plugin;
+  plugin_ref enforced_table_plugin;
 
   /* Only charset part of these variables is sensible */
   CHARSET_INFO  *character_set_filesystem;
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 2fe22ea..fe020d3 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -3089,11 +3089,13 @@ 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;
@@ -3113,12 +3115,14 @@ void plugin_thdvar_init(THD *thd)
             intern_plugin_lock(NULL, global_system_variables.tmp_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);
   }
   else
   {
     thd->variables.table_plugin= NULL;
     thd->variables.tmp_table_plugin= NULL;
+    thd->variables.enforced_table_plugin= NULL;
   }
 
   DBUG_VOID_RETURN;
@@ -3132,7 +3136,8 @@ 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);
-  vars->table_plugin= vars->tmp_table_plugin= NULL;
+  intern_plugin_unlock(NULL, vars->enforced_table_plugin);
+  vars->table_plugin= vars->tmp_table_plugin= vars->enforced_table_plugin= NULL;
 }
 
 
@@ -3170,6 +3175,7 @@ static void cleanup_variables(struct system_variables *vars)
 
   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;
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);
   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);
+
+
+static bool check_super_and_not_null(sys_var *self, THD*thd, set_var *var)
+{
+#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.


More information about the commits mailing list