summaryrefslogtreecommitdiff
path: root/sql/sql_alter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_alter.cc')
-rw-r--r--sql/sql_alter.cc287
1 files changed, 233 insertions, 54 deletions
diff --git a/sql/sql_alter.cc b/sql/sql_alter.cc
index 8716dde5727..59498d71bb1 100644
--- a/sql/sql_alter.cc
+++ b/sql/sql_alter.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
- Copyright (c) 2016, MariaDB Corporation
+ Copyright (c) 2016, 2020, MariaDB Corporation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,6 +14,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+#include "mariadb.h"
#include "sql_parse.h" // check_access
#include "sql_table.h" // mysql_alter_table,
// mysql_exchange_partition
@@ -26,7 +27,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
key_list(rhs.key_list, mem_root),
create_list(rhs.create_list, mem_root),
check_constraint_list(rhs.check_constraint_list, mem_root),
- flags(rhs.flags),
+ flags(rhs.flags), partition_flags(rhs.partition_flags),
keys_onoff(rhs.keys_onoff),
partition_names(rhs.partition_names, mem_root),
num_parts(rhs.num_parts),
@@ -50,61 +51,233 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
}
-bool Alter_info::set_requested_algorithm(const LEX_STRING *str)
+bool Alter_info::set_requested_algorithm(const LEX_CSTRING *str)
{
// To avoid adding new keywords to the grammar, we match strings here.
- if (!my_strcasecmp(system_charset_info, str->str, "INPLACE"))
+ if (lex_string_eq(str, STRING_WITH_LEN("INPLACE")))
requested_algorithm= ALTER_TABLE_ALGORITHM_INPLACE;
- else if (!my_strcasecmp(system_charset_info, str->str, "COPY"))
+ else if (lex_string_eq(str, STRING_WITH_LEN("COPY")))
requested_algorithm= ALTER_TABLE_ALGORITHM_COPY;
- else if (!my_strcasecmp(system_charset_info, str->str, "DEFAULT"))
+ else if (lex_string_eq(str, STRING_WITH_LEN("DEFAULT")))
requested_algorithm= ALTER_TABLE_ALGORITHM_DEFAULT;
+ else if (lex_string_eq(str, STRING_WITH_LEN("NOCOPY")))
+ requested_algorithm= ALTER_TABLE_ALGORITHM_NOCOPY;
+ else if (lex_string_eq(str, STRING_WITH_LEN("INSTANT")))
+ requested_algorithm= ALTER_TABLE_ALGORITHM_INSTANT;
else
return true;
return false;
}
+void Alter_info::set_requested_algorithm(enum_alter_table_algorithm algo_val)
+{
+ requested_algorithm= algo_val;
+}
-bool Alter_info::set_requested_lock(const LEX_STRING *str)
+bool Alter_info::set_requested_lock(const LEX_CSTRING *str)
{
// To avoid adding new keywords to the grammar, we match strings here.
- if (!my_strcasecmp(system_charset_info, str->str, "NONE"))
+ if (lex_string_eq(str, STRING_WITH_LEN("NONE")))
requested_lock= ALTER_TABLE_LOCK_NONE;
- else if (!my_strcasecmp(system_charset_info, str->str, "SHARED"))
+ else if (lex_string_eq(str, STRING_WITH_LEN("SHARED")))
requested_lock= ALTER_TABLE_LOCK_SHARED;
- else if (!my_strcasecmp(system_charset_info, str->str, "EXCLUSIVE"))
+ else if (lex_string_eq(str, STRING_WITH_LEN("EXCLUSIVE")))
requested_lock= ALTER_TABLE_LOCK_EXCLUSIVE;
- else if (!my_strcasecmp(system_charset_info, str->str, "DEFAULT"))
+ else if (lex_string_eq(str, STRING_WITH_LEN("DEFAULT")))
requested_lock= ALTER_TABLE_LOCK_DEFAULT;
else
return true;
return false;
}
+const char* Alter_info::algorithm_clause(THD *thd) const
+{
+ switch (algorithm(thd)) {
+ case ALTER_TABLE_ALGORITHM_INPLACE:
+ return "ALGORITHM=INPLACE";
+ case ALTER_TABLE_ALGORITHM_COPY:
+ return "ALGORITHM=COPY";
+ case ALTER_TABLE_ALGORITHM_NONE:
+ DBUG_ASSERT(0);
+ /* Fall through */
+ case ALTER_TABLE_ALGORITHM_DEFAULT:
+ return "ALGORITHM=DEFAULT";
+ case ALTER_TABLE_ALGORITHM_NOCOPY:
+ return "ALGORITHM=NOCOPY";
+ case ALTER_TABLE_ALGORITHM_INSTANT:
+ return "ALGORITHM=INSTANT";
+ }
+
+ return NULL; /* purecov: begin deadcode */
+}
+
+const char* Alter_info::lock() const
+{
+ switch (requested_lock) {
+ case ALTER_TABLE_LOCK_SHARED:
+ return "LOCK=SHARED";
+ case ALTER_TABLE_LOCK_NONE:
+ return "LOCK=NONE";
+ case ALTER_TABLE_LOCK_DEFAULT:
+ return "LOCK=DEFAULT";
+ case ALTER_TABLE_LOCK_EXCLUSIVE:
+ return "LOCK=EXCLUSIVE";
+ }
+ return NULL; /* purecov: begin deadcode */
+}
+
+
+bool Alter_info::supports_algorithm(THD *thd,
+ const Alter_inplace_info *ha_alter_info)
+{
+ switch (ha_alter_info->inplace_supported) {
+ case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
+ case HA_ALTER_INPLACE_SHARED_LOCK:
+ case HA_ALTER_INPLACE_NO_LOCK:
+ case HA_ALTER_INPLACE_INSTANT:
+ return false;
+ case HA_ALTER_INPLACE_COPY_NO_LOCK:
+ case HA_ALTER_INPLACE_COPY_LOCK:
+ if (algorithm(thd) >= Alter_info::ALTER_TABLE_ALGORITHM_NOCOPY)
+ {
+ ha_alter_info->report_unsupported_error(algorithm_clause(thd),
+ "ALGORITHM=INPLACE");
+ return true;
+ }
+ return false;
+ case HA_ALTER_INPLACE_NOCOPY_NO_LOCK:
+ case HA_ALTER_INPLACE_NOCOPY_LOCK:
+ if (algorithm(thd) == Alter_info::ALTER_TABLE_ALGORITHM_INSTANT)
+ {
+ ha_alter_info->report_unsupported_error("ALGORITHM=INSTANT",
+ "ALGORITHM=NOCOPY");
+ return true;
+ }
+ return false;
+ case HA_ALTER_INPLACE_NOT_SUPPORTED:
+ if (algorithm(thd) >= Alter_info::ALTER_TABLE_ALGORITHM_INPLACE)
+ {
+ ha_alter_info->report_unsupported_error(algorithm_clause(thd),
+ "ALGORITHM=COPY");
+ return true;
+ }
+ return false;
+ case HA_ALTER_ERROR:
+ return true;
+ }
+ /* purecov: begin deadcode */
+ DBUG_ASSERT(0);
+ return false;
+}
+
+
+bool Alter_info::supports_lock(THD *thd,
+ const Alter_inplace_info *ha_alter_info)
+{
+ switch (ha_alter_info->inplace_supported) {
+ case HA_ALTER_INPLACE_EXCLUSIVE_LOCK:
+ // If SHARED lock and no particular algorithm was requested, use COPY.
+ if (requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED &&
+ algorithm(thd) == Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT &&
+ thd->variables.alter_algorithm ==
+ Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT)
+ return false;
+
+ if (requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED ||
+ requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE)
+ {
+ ha_alter_info->report_unsupported_error(lock(), "LOCK=EXCLUSIVE");
+ return true;
+ }
+ return false;
+ case HA_ALTER_INPLACE_NO_LOCK:
+ case HA_ALTER_INPLACE_INSTANT:
+ case HA_ALTER_INPLACE_COPY_NO_LOCK:
+ case HA_ALTER_INPLACE_NOCOPY_NO_LOCK:
+ return false;
+ case HA_ALTER_INPLACE_COPY_LOCK:
+ case HA_ALTER_INPLACE_NOCOPY_LOCK:
+ case HA_ALTER_INPLACE_NOT_SUPPORTED:
+ case HA_ALTER_INPLACE_SHARED_LOCK:
+ if (requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE)
+ {
+ ha_alter_info->report_unsupported_error("LOCK=NONE", "LOCK=SHARED");
+ return true;
+ }
+ return false;
+ case HA_ALTER_ERROR:
+ return true;
+ }
+ /* purecov: begin deadcode */
+ DBUG_ASSERT(0);
+ return false;
+}
+
+bool Alter_info::vers_prohibited(THD *thd) const
+{
+ if (thd->slave_thread ||
+ thd->variables.vers_alter_history != VERS_ALTER_HISTORY_ERROR)
+ {
+ return false;
+ }
+ if (flags & (
+ ALTER_PARSER_ADD_COLUMN |
+ ALTER_PARSER_DROP_COLUMN |
+ ALTER_CHANGE_COLUMN |
+ ALTER_COLUMN_ORDER))
+ {
+ return true;
+ }
+ if (flags & ALTER_ADD_INDEX)
+ {
+ List_iterator_fast<Key> key_it(const_cast<List<Key> &>(key_list));
+ Key *key;
+ while ((key= key_it++))
+ {
+ if (key->type == Key::PRIMARY || key->type == Key::UNIQUE)
+ return true;
+ }
+ }
+ return false;
+}
+
+Alter_info::enum_alter_table_algorithm
+Alter_info::algorithm(const THD *thd) const
+{
+ if (requested_algorithm == ALTER_TABLE_ALGORITHM_NONE)
+ return (Alter_info::enum_alter_table_algorithm) thd->variables.alter_algorithm;
+ return requested_algorithm;
+}
+
Alter_table_ctx::Alter_table_ctx()
: datetime_field(NULL), error_if_not_empty(false),
tables_opened(0),
- db(NULL), table_name(NULL), alias(NULL),
- new_db(NULL), new_name(NULL), new_alias(NULL),
+ db(null_clex_str), table_name(null_clex_str), alias(null_clex_str),
+ new_db(null_clex_str), new_name(null_clex_str), new_alias(null_clex_str),
fk_error_if_delete_row(false), fk_error_id(NULL),
- fk_error_table(NULL)
-#ifndef DBUG_OFF
+ fk_error_table(NULL), modified_primary_key(false)
+#ifdef DBUG_ASSERT_EXISTS
, tmp_table(false)
#endif
{
}
+/*
+ TODO: new_name_arg changes if lower case table names.
+ Should be copied or converted before call
+*/
Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
uint tables_opened_arg,
- char *new_db_arg, char *new_name_arg)
+ const LEX_CSTRING *new_db_arg,
+ const LEX_CSTRING *new_name_arg)
: datetime_field(NULL), error_if_not_empty(false),
tables_opened(tables_opened_arg),
- new_db(new_db_arg), new_name(new_name_arg),
+ new_db(*new_db_arg), new_name(*new_name_arg),
fk_error_if_delete_row(false), fk_error_id(NULL),
- fk_error_table(NULL)
-#ifndef DBUG_OFF
+ fk_error_table(NULL), modified_primary_key(false)
+#ifdef DBUG_ASSERT_EXISTS
, tmp_table(false)
#endif
{
@@ -117,28 +290,31 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
table_name= table_list->table_name;
alias= (lower_case_table_names == 2) ? table_list->alias : table_name;
- if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
+ if (!new_db.str || !my_strcasecmp(table_alias_charset, new_db.str, db.str))
new_db= db;
- if (new_name)
+ if (new_name.str)
{
- DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db, new_name));
+ DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db.str, new_name.str));
- if (lower_case_table_names == 1) // Convert new_name/new_alias to lower case
+ if (lower_case_table_names == 1) // Convert new_name/new_alias to lower
{
- my_casedn_str(files_charset_info, new_name);
+ new_name.length= my_casedn_str(files_charset_info, (char*) new_name.str);
new_alias= new_name;
}
else if (lower_case_table_names == 2) // Convert new_name to lower case
{
- strmov(new_alias= new_alias_buff, new_name);
- my_casedn_str(files_charset_info, new_name);
+ new_alias.str= new_alias_buff;
+ new_alias.length= new_name.length;
+ strmov(new_alias_buff, new_name.str);
+ new_name.length= my_casedn_str(files_charset_info, (char*) new_name.str);
+
}
else
new_alias= new_name; // LCTN=0 => case sensitive + case preserving
if (!is_database_changed() &&
- !my_strcasecmp(table_alias_charset, new_name, table_name))
+ !my_strcasecmp(table_alias_charset, new_name.str, table_name.str))
{
/*
Source and destination table names are equal:
@@ -154,22 +330,23 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
new_name= table_name;
}
- my_snprintf(tmp_name, sizeof(tmp_name), "%s-%lx_%lx", tmp_file_prefix,
- current_pid, thd->thread_id);
+ tmp_name.str= tmp_name_buff;
+ tmp_name.length= my_snprintf(tmp_name_buff, sizeof(tmp_name_buff), "%s-%lx_%llx",
+ tmp_file_prefix, current_pid, thd->thread_id);
/* Safety fix for InnoDB */
if (lower_case_table_names)
- my_casedn_str(files_charset_info, tmp_name);
+ tmp_name.length= my_casedn_str(files_charset_info, tmp_name_buff);
if (table_list->table->s->tmp_table == NO_TMP_TABLE)
{
- build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
+ build_table_filename(path, sizeof(path) - 1, db.str, table_name.str, "", 0);
- build_table_filename(new_path, sizeof(new_path) - 1, new_db, new_name, "", 0);
+ build_table_filename(new_path, sizeof(new_path) - 1, new_db.str, new_name.str, "", 0);
build_table_filename(new_filename, sizeof(new_filename) - 1,
- new_db, new_name, reg_ext, 0);
+ new_db.str, new_name.str, reg_ext, 0);
- build_table_filename(tmp_path, sizeof(tmp_path) - 1, new_db, tmp_name, "",
+ build_table_filename(tmp_path, sizeof(tmp_path) - 1, new_db.str, tmp_name.str, "",
FN_IS_TMP);
}
else
@@ -180,7 +357,7 @@ Alter_table_ctx::Alter_table_ctx(THD *thd, TABLE_LIST *table_list,
this case. This fact is enforced with assert.
*/
build_tmptable_filename(thd, tmp_path, sizeof(tmp_path));
-#ifndef DBUG_OFF
+#ifdef DBUG_ASSERT_EXISTS
tmp_table= true;
#endif
}
@@ -221,25 +398,28 @@ bool Sql_cmd_alter_table::execute(THD *thd)
DBUG_ENTER("Sql_cmd_alter_table::execute");
- if (thd->is_fatal_error) /* out of memory creating a copy of alter_info */
+ if (unlikely(thd->is_fatal_error))
+ {
+ /* out of memory creating a copy of alter_info */
DBUG_RETURN(TRUE);
+ }
/*
We also require DROP priv for ALTER TABLE ... DROP PARTITION, as well
as for RENAME TO, as being done by SQLCOM_RENAME_TABLE
*/
- if (alter_info.flags & (Alter_info::ALTER_DROP_PARTITION |
- Alter_info::ALTER_RENAME))
+ if ((alter_info.partition_flags & ALTER_PARTITION_DROP) ||
+ (alter_info.flags & ALTER_RENAME))
priv_needed|= DROP_ACL;
/* Must be set in the parser */
- DBUG_ASSERT(select_lex->db);
- DBUG_ASSERT(!(alter_info.flags & Alter_info::ALTER_EXCHANGE_PARTITION));
- DBUG_ASSERT(!(alter_info.flags & Alter_info::ALTER_ADMIN_PARTITION));
- if (check_access(thd, priv_needed, first_table->db,
+ DBUG_ASSERT(select_lex->db.str);
+ DBUG_ASSERT(!(alter_info.partition_flags & ALTER_PARTITION_EXCHANGE));
+ DBUG_ASSERT(!(alter_info.partition_flags & ALTER_PARTITION_ADMIN));
+ if (check_access(thd, priv_needed, first_table->db.str,
&first_table->grant.privilege,
&first_table->grant.m_internal,
0, 0) ||
- check_access(thd, INSERT_ACL | CREATE_ACL, select_lex->db,
+ check_access(thd, INSERT_ACL | CREATE_ACL, select_lex->db.str,
&priv,
NULL, /* Don't use first_tab->grant with sel_lex->db */
0, 0))
@@ -295,9 +475,7 @@ bool Sql_cmd_alter_table::execute(THD *thd)
{
// Rename of table
TABLE_LIST tmp_table;
- tmp_table.init_one_table(select_lex->db, strlen(select_lex->db),
- lex->name.str, lex->name.length,
- lex->name.str, TL_IGNORE);
+ tmp_table.init_one_table(&select_lex->db, &lex->name, 0, TL_IGNORE);
tmp_table.grant.privilege= priv;
if (check_grant(thd, INSERT_ACL | CREATE_ACL, &tmp_table, FALSE,
UINT_MAX, FALSE))
@@ -315,22 +493,23 @@ bool Sql_cmd_alter_table::execute(THD *thd)
"INDEX DIRECTORY");
create_info.data_file_name= create_info.index_file_name= NULL;
-#ifdef WITH_WSREP
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ thd->work_part_info= 0;
+#endif
+
if (WSREP(thd) &&
(!thd->is_current_stmt_binlog_format_row() ||
!thd->find_temporary_table(first_table)))
{
- WSREP_TO_ISOLATION_BEGIN_ALTER(((lex->name.str) ? select_lex->db : NULL),
- ((lex->name.str) ? lex->name.str : NULL),
- first_table,
- &alter_info);
+ WSREP_TO_ISOLATION_BEGIN_ALTER((lex->name.str ? select_lex->db.str : NULL),
+ (lex->name.str ? lex->name.str : NULL),
+ first_table, &alter_info);
thd->variables.auto_increment_offset = 1;
thd->variables.auto_increment_increment = 1;
}
-#endif /* WITH_WSREP */
- result= mysql_alter_table(thd, select_lex->db, lex->name.str,
+ result= mysql_alter_table(thd, &select_lex->db, &lex->name,
&create_info,
first_table,
&alter_info,
@@ -352,7 +531,7 @@ bool Sql_cmd_discard_import_tablespace::execute(THD *thd)
/* first table of first SELECT_LEX */
TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
- if (check_access(thd, ALTER_ACL, table_list->db,
+ if (check_access(thd, ALTER_ACL, table_list->db.str,
&table_list->grant.privilege,
&table_list->grant.m_internal,
0, 0))