polardbxengine/sql/dd/impl/dictionary_impl.cc

700 lines
26 KiB
C++

/* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is also distributed with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have included with MySQL.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql/dd/impl/dictionary_impl.h"
#include <string.h>
#include <memory>
#include "m_ctype.h"
#include "m_string.h"
#include "my_dbug.h"
#include "my_inttypes.h"
#include "my_sys.h"
#include "mysql/thread_type.h"
#include "mysql/udf_registration_types.h"
#include "mysql_com.h"
#include "mysqld_error.h"
#include "sql/auth/auth_common.h" // acl_init
#include "sql/auth/sql_security_ctx.h"
#include "sql/auto_thd.h" // Auto_thd
#include "sql/bootstrap.h" // bootstrap::bootstrap_functor
#include "sql/dd/cache/dictionary_client.h" // dd::Dictionary_client
#include "sql/dd/dd.h" // enum_dd_init_type
#include "sql/dd/dd_schema.h" // dd::Schema_MDL_locker
#include "sql/dd/dd_version.h" // dd::DD_VERSION
#include "sql/dd/impl/bootstrap/bootstrapper.h" // dd::Bootstrapper
#include "sql/dd/impl/cache/shared_dictionary_cache.h" // Shared_dictionary_cache
#include "sql/dd/impl/system_registry.h" // dd::System_tables
#include "sql/dd/impl/tables/columns.h" // dd::tables::Columns
#include "sql/dd/impl/tables/dd_properties.h" // get_actual_dd_version()
#include "sql/dd/impl/tables/indexes.h" // dd::tables::Indexes
#include "sql/dd/impl/tables/table_partitions.h" // dd::tables::Table_partitions
#include "sql/dd/impl/tables/tables.h" // dd::tables::Tables
#include "sql/dd/impl/tables/tablespaces.h" // dd::tables::Tablespaces
#include "sql/dd/impl/utils.h" // dd::tables::Tablespaces
#include "sql/dd/info_schema/metadata.h" // dd::info_schema::store_dynamic...
#include "sql/dd/types/abstract_table.h" // dd::Abstract_table::DD_table
#include "sql/dd/types/column.h" // dd::Column::DD_table
#include "sql/dd/types/index.h" // dd::Index::DD_table
#include "sql/dd/types/object_table_definition.h"
#include "sql/dd/types/partition.h" // dd::Partition::DD_table
#include "sql/dd/types/system_view.h"
#include "sql/dd/types/table.h" // dd::Table::DD_table
#include "sql/dd/types/tablespace.h" // dd::Tablespace::DD_table
#include "sql/dd/upgrade_57/upgrade.h" // dd::upgrade
#include "sql/derror.h"
#include "sql/handler.h"
#include "sql/mdl.h"
#include "sql/opt_costconstantcache.h" // init_optimizer_cost_module
#include "sql/plugin_table.h"
#include "sql/sql_base.h" // close_cached_tables
#include "sql/sql_class.h" // THD
#include "sql/system_variables.h"
#include "sql/thd_raii.h" // Disable_autocommit_guard
#include "sql/transaction.h" // trans_commit()
#include "storage/perfschema/pfs_dd_version.h" // PFS_DD_VERSION
///////////////////////////////////////////////////////////////////////////
namespace dd {
///////////////////////////////////////////////////////////////////////////
// Implementation details.
///////////////////////////////////////////////////////////////////////////
class Object_table;
class Table;
Dictionary_impl *Dictionary_impl::s_instance = NULL;
Dictionary_impl *Dictionary_impl::instance() { return s_instance; }
Object_id Dictionary_impl::DEFAULT_CATALOG_ID = 1;
Object_id Dictionary_impl::DD_TABLESPACE_ID = 1;
const String_type Dictionary_impl::DEFAULT_CATALOG_NAME("def");
///////////////////////////////////////////////////////////////////////////
bool Dictionary_impl::init(enum_dd_init_type dd_init) {
if (dd_init == enum_dd_init_type::DD_INITIALIZE ||
dd_init == enum_dd_init_type::DD_RESTART_OR_UPGRADE) {
DBUG_ASSERT(!Dictionary_impl::s_instance);
if (Dictionary_impl::s_instance) return false; /* purecov: inspected */
std::unique_ptr<Dictionary_impl> d(new Dictionary_impl());
Dictionary_impl::s_instance = d.release();
}
/*
Initialize the cost model, but delete it after the dd is initialized.
This is because the cost model is needed for the dd initialization, but
it must be re-initialized later after the plugins have been initialized.
Upgrade process needs heap engine initialized, hence parameter 'true'
is passed to the function.
*/
init_optimizer_cost_module(true);
// Disable table encryption privilege checks for system threads.
bool saved_table_encryption_privilege_check =
opt_table_encryption_privilege_check;
opt_table_encryption_privilege_check = false;
/*
Install or start or upgrade the dictionary
depending on bootstrapping option.
*/
bool result = false;
// Creation of Data Dictionary through current server
if (dd_init == enum_dd_init_type::DD_INITIALIZE)
result = ::bootstrap::run_bootstrap_thread(
nullptr, nullptr, &bootstrap::initialize, SYSTEM_THREAD_DD_INITIALIZE);
// Creation of INFORMATION_SCHEMA system views.
else if (dd_init == enum_dd_init_type::DD_INITIALIZE_SYSTEM_VIEWS)
result = ::bootstrap::run_bootstrap_thread(nullptr, nullptr,
&dd::info_schema::initialize,
SYSTEM_THREAD_DD_INITIALIZE);
/*
Creation of Dictionary Tables in old Data Directory
This function also takes care of normal server restart.
*/
else if (dd_init == enum_dd_init_type::DD_RESTART_OR_UPGRADE)
result = ::bootstrap::run_bootstrap_thread(
nullptr, nullptr, &upgrade_57::do_pre_checks_and_initialize_dd,
SYSTEM_THREAD_DD_INITIALIZE);
// Populate metadata in DD tables from old data directory and do cleanup.
else if (dd_init == enum_dd_init_type::DD_POPULATE_UPGRADE)
result = ::bootstrap::run_bootstrap_thread(
nullptr, nullptr, &upgrade_57::fill_dd_and_finalize,
SYSTEM_THREAD_DD_INITIALIZE);
// Delete DD tables and do cleanup in case of error in upgrade
else if (dd_init == enum_dd_init_type::DD_DELETE)
result = ::bootstrap::run_bootstrap_thread(
nullptr, nullptr, &upgrade_57::terminate, SYSTEM_THREAD_DD_INITIALIZE);
// Update server and plugin I_S table metadata into DD tables.
else if (dd_init == enum_dd_init_type::DD_UPDATE_I_S_METADATA)
result = ::bootstrap::run_bootstrap_thread(
nullptr, nullptr, &dd::info_schema::update_I_S_metadata,
SYSTEM_THREAD_DD_INITIALIZE);
// Restore the table_encryption_privilege_check.
opt_table_encryption_privilege_check = saved_table_encryption_privilege_check;
/* Now that the dd is initialized, delete the cost model. */
delete_optimizer_cost_module();
return result;
}
///////////////////////////////////////////////////////////////////////////
bool Dictionary_impl::shutdown() {
if (!Dictionary_impl::s_instance) return true;
delete Dictionary_impl::s_instance;
Dictionary_impl::s_instance = NULL;
return false;
}
///////////////////////////////////////////////////////////////////////////
// Implementation details.
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::get_target_dd_version() { return dd::DD_VERSION; }
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::get_actual_dd_version(THD *thd) {
bool exists = false;
uint version = 0;
bool error MY_ATTRIBUTE((unused)) = tables::DD_properties::instance().get(
thd, "DD_VERSION", &version, &exists);
DBUG_ASSERT(!error);
DBUG_ASSERT(exists);
return version;
}
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::get_target_I_S_version() {
return dd::info_schema::IS_DD_VERSION;
}
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::get_actual_I_S_version(THD *thd) {
bool exists = false;
uint version = 0;
bool error MY_ATTRIBUTE((unused)) = tables::DD_properties::instance().get(
thd, "IS_VERSION", &version, &exists);
DBUG_ASSERT(!error);
DBUG_ASSERT(exists);
return version;
}
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::set_I_S_version(THD *thd, uint version) {
return tables::DD_properties::instance().set(thd, "IS_VERSION", version);
}
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::get_target_P_S_version() { return PFS_DD_VERSION; }
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::get_actual_P_S_version(THD *thd) {
bool exists = false;
uint version = 0;
bool error MY_ATTRIBUTE((unused)) = tables::DD_properties::instance().get(
thd, "PS_VERSION", &version, &exists);
DBUG_ASSERT(!error);
DBUG_ASSERT(exists);
return version;
}
///////////////////////////////////////////////////////////////////////////
uint Dictionary_impl::set_P_S_version(THD *thd, uint version) {
return tables::DD_properties::instance().set(thd, "PS_VERSION", version);
}
///////////////////////////////////////////////////////////////////////////
const Object_table *Dictionary_impl::get_dd_table(
const String_type &schema_name, const String_type &table_name) const {
if (!is_dd_schema_name(schema_name)) return NULL;
return System_tables::instance()->find_table(schema_name, table_name);
}
///////////////////////////////////////////////////////////////////////////
bool Dictionary_impl::is_dd_table_name(const String_type &schema_name,
const String_type &table_name) const {
if (!is_dd_schema_name(schema_name)) return false;
const System_tables::Types *table_type =
System_tables::instance()->find_type(schema_name, table_name);
return (table_type != nullptr &&
(*table_type == System_tables::Types::CORE ||
*table_type == System_tables::Types::INERT ||
*table_type == System_tables::Types::SECOND ||
*table_type == System_tables::Types::DDSE_PRIVATE ||
*table_type == System_tables::Types::DDSE_PROTECTED));
}
///////////////////////////////////////////////////////////////////////////
bool Dictionary_impl::is_system_table_name(
const String_type &schema_name, const String_type &table_name) const {
if (!is_dd_schema_name(schema_name)) return false;
const System_tables::Types *table_type =
System_tables::instance()->find_type(schema_name, table_name);
return (table_type != nullptr &&
(*table_type == System_tables::Types::SYSTEM));
}
///////////////////////////////////////////////////////////////////////////
int Dictionary_impl::table_type_error_code(
const String_type &schema_name, const String_type &table_name) const {
const System_tables::Types *type =
System_tables::instance()->find_type(schema_name, table_name);
if (type != nullptr) return System_tables::type_name_error_code(*type);
return ER_NO_SYSTEM_TABLE_ACCESS_FOR_TABLE;
}
///////////////////////////////////////////////////////////////////////////
bool Dictionary_impl::is_dd_table_access_allowed(bool is_dd_internal_thread,
bool is_ddl_statement,
const char *schema_name,
size_t schema_length,
const char *table_name) const {
/*
From WL#6391, we have the following matrix describing access:
---------+---------------------+
| Dictionary internal |
---------+----------+----------+
| DDL | DML |
---------+-----+----+-----+----+
| IN | EX | IN | EX |
---------+-----+----+-----+----+
Inert | X X |
Core | X X |
Second | X X |
DDSE_priv| X X |
DDSE_prot| X X X |
SYSTEM | X X X X |
---------+---------------------+
For performance reasons, we first check the schema
name to shortcut the evaluation. If the table is not in
the 'mysql' schema, we don't need any further checks. Same for
checking for internal threads - an internal thread has full
access. We also allow access if the appropriate debug flag
is set.
*/
if (schema_length != MYSQL_SCHEMA_NAME.length ||
strncmp(schema_name, MYSQL_SCHEMA_NAME.str, MYSQL_SCHEMA_NAME.length) ||
is_dd_internal_thread ||
DBUG_EVALUATE_IF("skip_dd_table_access_check", true, false))
return true;
// Now we need to get the table type.
const String_type schema_str(schema_name);
const String_type table_str(table_name);
const System_tables::Types *table_type =
System_tables::instance()->find_type(schema_str, table_str);
/*
Access allowed for external DD tables, for DML on protected DDSE tables,
and for any operation on SYSTEM tables.
*/
return (table_type == nullptr ||
(*table_type == System_tables::Types::DDSE_PROTECTED &&
!is_ddl_statement) ||
*table_type == System_tables::Types::SYSTEM);
}
///////////////////////////////////////////////////////////////////////////
bool Dictionary_impl::is_system_view_name(const char *schema_name,
const char *table_name,
bool *hidden) const {
/*
TODO One possible improvement here could be to try and use the variant
of is_infoschema_db() that takes length as a parameter. Then, if the
schema name length is different, this can quickly be used to conclude
that this is indeed not a system view, without having to do a strcmp at
all.
*/
if (schema_name == nullptr || table_name == nullptr ||
is_infoschema_db(schema_name) == false)
return false;
// The System_views registry stores the view name in uppercase.
// So convert the input to uppercase before search.
char tab_name_buf[NAME_LEN + 1];
my_stpcpy(tab_name_buf, table_name);
my_caseup_str(system_charset_info, tab_name_buf);
const system_views::System_view *s =
System_views::instance()->find(INFORMATION_SCHEMA_NAME.str, tab_name_buf);
if (s)
*hidden = s->hidden();
else
*hidden = false;
return s != nullptr;
}
///////////////////////////////////////////////////////////////////////////
/*
Global interface methods at 'dd' namespace.
Following are couple of API's that InnoDB needs to acquire MDL locks.
*/
static bool acquire_mdl(THD *thd, MDL_key::enum_mdl_namespace lock_namespace,
const char *schema_name, const char *table_name,
bool no_wait, ulong lock_wait_timeout,
enum_mdl_type lock_type,
enum_mdl_duration lock_duration,
MDL_ticket **out_mdl_ticket) {
DBUG_TRACE;
MDL_request mdl_request;
MDL_REQUEST_INIT(&mdl_request, lock_namespace, schema_name, table_name,
lock_type, lock_duration);
/*
If there is a request for an exclusive lock, we also need to acquire
a transactional intention exclusive backup lock and global read lock
(this is not done to get a lock, but rather to protect against others
setting the backup- or global read lock).
*/
MDL_request_list mdl_requests;
mdl_requests.push_front(&mdl_request);
MDL_request *grl_request = nullptr;
MDL_request *bl_request = nullptr;
if (lock_type == MDL_EXCLUSIVE) {
// If we cannot acquire protection against GRL, err out.
if (thd->global_read_lock.can_acquire_protection()) return true;
grl_request = new (thd->mem_root) MDL_request;
MDL_REQUEST_INIT(grl_request, MDL_key::GLOBAL, "", "",
MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(grl_request);
bl_request = new (thd->mem_root) MDL_request;
MDL_REQUEST_INIT(bl_request, MDL_key::BACKUP_LOCK, "", "",
MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION);
mdl_requests.push_front(bl_request);
}
/*
With no_wait, we acquire the locks one by one. When waiting,
we use the lock request list to get either all or none in
the same acquisition.
*/
if (no_wait) {
if (thd->mdl_context.try_acquire_lock(&mdl_request) ||
(grl_request != nullptr &&
thd->mdl_context.try_acquire_lock(bl_request)) ||
(bl_request != nullptr &&
thd->mdl_context.try_acquire_lock(grl_request))) {
return true;
}
} else if (thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout))
return true;
if (out_mdl_ticket) *out_mdl_ticket = mdl_request.ticket;
return false;
}
bool acquire_shared_table_mdl(THD *thd, const char *schema_name,
const char *table_name, bool no_wait,
MDL_ticket **out_mdl_ticket) {
return acquire_mdl(thd, MDL_key::TABLE, schema_name, table_name, no_wait,
thd->variables.lock_wait_timeout, MDL_SHARED, MDL_EXPLICIT,
out_mdl_ticket);
}
bool has_shared_table_mdl(THD *thd, const char *schema_name,
const char *table_name) {
return thd->mdl_context.owns_equal_or_stronger_lock(
MDL_key::TABLE, schema_name, table_name, MDL_SHARED);
}
bool has_exclusive_table_mdl(THD *thd, const char *schema_name,
const char *table_name) {
return thd->mdl_context.owns_equal_or_stronger_lock(
MDL_key::TABLE, schema_name, table_name, MDL_EXCLUSIVE);
}
bool acquire_exclusive_tablespace_mdl(THD *thd, const char *tablespace_name,
bool no_wait, MDL_ticket **ticket,
bool for_trx) {
enum_mdl_duration duration = (for_trx ? MDL_TRANSACTION : MDL_EXPLICIT);
return acquire_mdl(thd, MDL_key::TABLESPACE, "", tablespace_name, no_wait,
thd->variables.lock_wait_timeout, MDL_EXCLUSIVE, duration,
ticket);
}
bool acquire_shared_tablespace_mdl(THD *thd, const char *tablespace_name,
bool no_wait, MDL_ticket **ticket,
bool for_trx) {
// When requesting a tablespace name lock, we leave the schema name empty.
enum_mdl_duration duration = (for_trx ? MDL_TRANSACTION : MDL_EXPLICIT);
return acquire_mdl(thd, MDL_key::TABLESPACE, "", tablespace_name, no_wait,
thd->variables.lock_wait_timeout, MDL_SHARED, duration,
ticket);
}
bool has_shared_tablespace_mdl(THD *thd, const char *tablespace_name) {
// When checking a tablespace name lock, we leave the schema name empty.
return thd->mdl_context.owns_equal_or_stronger_lock(
MDL_key::TABLESPACE, "", tablespace_name, MDL_SHARED);
}
bool has_exclusive_tablespace_mdl(THD *thd, const char *tablespace_name) {
// When checking a tablespace name lock, we leave the schema name empty.
return thd->mdl_context.owns_equal_or_stronger_lock(
MDL_key::TABLESPACE, "", tablespace_name, MDL_EXCLUSIVE);
}
bool acquire_exclusive_table_mdl(THD *thd, const char *schema_name,
const char *table_name, bool no_wait,
MDL_ticket **out_mdl_ticket) {
return acquire_mdl(thd, MDL_key::TABLE, schema_name, table_name, no_wait,
thd->variables.lock_wait_timeout, MDL_EXCLUSIVE,
MDL_TRANSACTION, out_mdl_ticket);
}
bool acquire_exclusive_table_mdl(THD *thd, const char *schema_name,
const char *table_name,
unsigned long int lock_wait_timeout,
MDL_ticket **out_mdl_ticket) {
return acquire_mdl(thd, MDL_key::TABLE, schema_name, table_name, false,
lock_wait_timeout, MDL_EXCLUSIVE, MDL_TRANSACTION,
out_mdl_ticket);
}
bool acquire_exclusive_schema_mdl(THD *thd, const char *schema_name,
bool no_wait, MDL_ticket **out_mdl_ticket) {
return acquire_mdl(thd, MDL_key::SCHEMA, schema_name, "", no_wait,
thd->variables.lock_wait_timeout, MDL_EXCLUSIVE,
MDL_EXPLICIT, out_mdl_ticket);
}
void release_mdl(THD *thd, MDL_ticket *mdl_ticket) {
DBUG_TRACE;
thd->mdl_context.release_lock(mdl_ticket);
}
/* purecov: begin deadcode */
cache::Dictionary_client *get_dd_client(THD *thd) { return thd->dd_client(); }
/* purecov: end */
bool create_native_table(THD *thd, const Plugin_table *pt) {
if (dd::get_dictionary()->is_dd_table_name(pt->get_schema_name(),
pt->get_name())) {
my_error(ER_NO_SYSTEM_TABLE_ACCESS, MYF(0),
ER_THD_NONCONST(thd, dd::get_dictionary()->table_type_error_code(
pt->get_schema_name(), pt->get_name())),
pt->get_schema_name(), pt->get_name());
return true;
}
// Acquire MDL on new native table that we would create.
bool error = false;
MDL_request mdl_request;
MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, pt->get_schema_name(),
pt->get_name(), MDL_EXCLUSIVE, MDL_TRANSACTION);
dd::Schema_MDL_locker mdl_locker(thd);
if (mdl_locker.ensure_locked(pt->get_schema_name()) ||
thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
return true;
/*
1. Mark that we are executing a special DDL during
plugin initialization. This will enable DDL to not be
committed or binlogged. The called of this API would commit
the transaction.
2. Remove metadata of native table if already exists. This could
happen if server was crashed and restarted.
3. Create native table.
4. Undo 1.
*/
dd::cache::Dictionary_client *client = thd->dd_client();
const dd::Table *table_def = NULL;
if (client->acquire(pt->get_schema_name(), pt->get_name(), &table_def))
return true;
thd->mark_plugin_fake_ddl(true);
ulong master_access = thd->security_context()->master_access();
thd->security_context()->set_master_access(~(ulong)0);
{
Disable_binlog_guard guard(thd);
// Drop the table and related dynamic statistics too.
if (table_def) {
error =
client->drop(table_def) || client->remove_table_dynamic_statistics(
pt->get_schema_name(), pt->get_name());
}
if (!error) error = dd::execute_query(thd, pt->get_ddl());
}
thd->security_context()->set_master_access(master_access);
thd->mark_plugin_fake_ddl(false);
return error;
}
// Remove metadata of native table from DD tables.
bool drop_native_table(THD *thd, const char *schema_name,
const char *table_name) {
if (dd::get_dictionary()->is_dd_table_name(schema_name, table_name)) {
my_error(ER_NO_SYSTEM_TABLE_ACCESS, MYF(0),
ER_THD_NONCONST(thd, dd::get_dictionary()->table_type_error_code(
schema_name, table_name)),
schema_name, table_name);
return true;
}
// Acquire MDL on schema and table.
MDL_request mdl_request;
MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, schema_name, table_name,
MDL_EXCLUSIVE, MDL_TRANSACTION);
dd::Schema_MDL_locker mdl_locker(thd);
if (mdl_locker.ensure_locked(schema_name) ||
thd->mdl_context.acquire_lock(&mdl_request,
thd->variables.lock_wait_timeout))
return true;
dd::cache::Dictionary_client *client = thd->dd_client();
const dd::Table *table_def = NULL;
if (client->acquire(schema_name, table_name, &table_def)) {
// Error is reported by the dictionary subsystem.
return true;
}
// Not error is reported if table is not present.
if (!table_def) return false;
// Drop the table and related dynamic statistics too.
return client->drop(table_def) ||
client->remove_table_dynamic_statistics(schema_name, table_name);
}
bool reset_tables_and_tablespaces() {
Auto_THD thd;
handlerton *ddse = ha_resolve_by_legacy_type(thd.thd, DB_TYPE_INNODB);
// Acquire transactional metadata locks and evict all cached objects.
if (dd::cache::Shared_dictionary_cache::reset_tables_and_tablespaces(thd.thd))
return true;
// Evict all cached objects in the DD cache in the DDSE.
if (ddse->dict_cache_reset_tables_and_tablespaces != nullptr)
ddse->dict_cache_reset_tables_and_tablespaces();
bool ret = close_cached_tables(nullptr, nullptr, false, LONG_TIMEOUT);
// Release transactional metadata locks.
thd.thd->mdl_context.release_transactional_locks();
return ret;
}
bool commit_or_rollback_tablespace_change(THD *thd, dd::Tablespace *space,
bool error,
bool release_mdl_on_commit_only) {
dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
Disable_autocommit_guard autocommit_guard(thd);
if (!error && space != nullptr) {
error = thd->dd_client()->update(space);
}
if (error) {
trans_rollback_stmt(thd);
trans_rollback(thd);
} else {
error = trans_commit_stmt(thd) || trans_commit(thd);
}
if (!error || !release_mdl_on_commit_only) {
thd->mdl_context.release_transactional_locks();
}
return error;
}
template <typename Entity_object_type>
const Object_table &get_dd_table() {
return Entity_object_type::DD_table::instance();
}
template const Object_table &get_dd_table<dd::Column>();
template const Object_table &get_dd_table<dd::Index>();
template const Object_table &get_dd_table<dd::Partition>();
template const Object_table &get_dd_table<dd::Table>();
template const Object_table &get_dd_table<dd::Tablespace>();
void rename_tablespace_mdl_hook(THD *thd, MDL_ticket *src, MDL_ticket *dst) {
if (!thd->locked_tables_mode) {
return;
}
thd->locked_tables_list.add_rename_tablespace_mdls(src, dst);
}
} // namespace dd