2014-01-06 06:22:35 +01:00
|
|
|
/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
|
2014-08-06 14:39:15 +02:00
|
|
|
Copyright (c) 2014, SkySQL Ab.
|
2018-11-06 07:41:48 +01:00
|
|
|
Copyright (c) 2016, 2018, MariaDB Corporation.
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
|
|
|
|
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 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
|
2019-05-11 20:29:06 +02:00
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
|
2010-08-16 14:53:30 +02:00
|
|
|
|
2017-06-18 05:42:16 +02:00
|
|
|
#include "mariadb.h"
|
2010-08-16 14:53:30 +02:00
|
|
|
#include "sql_parse.h" // check_one_table_access
|
2013-06-15 17:32:08 +02:00
|
|
|
// check_merge_table_access
|
|
|
|
// check_one_table_access
|
2010-08-16 14:53:30 +02:00
|
|
|
#include "sql_table.h" // mysql_alter_table, etc.
|
2013-06-15 17:32:08 +02:00
|
|
|
#include "sql_cmd.h" // Sql_cmd
|
|
|
|
#include "sql_alter.h" // Sql_cmd_alter_table
|
|
|
|
#include "sql_partition.h" // struct partition_info, etc.
|
|
|
|
#include "debug_sync.h" // DEBUG_SYNC
|
|
|
|
#include "sql_truncate.h" // mysql_truncate_table,
|
|
|
|
// Sql_cmd_truncate_table
|
2010-08-16 16:25:23 +02:00
|
|
|
#include "sql_admin.h" // Analyze/Check/.._table_statement
|
2010-08-16 14:53:30 +02:00
|
|
|
#include "sql_partition_admin.h" // Alter_table_*_partition
|
2010-10-28 12:08:09 +02:00
|
|
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
#include "ha_partition.h" // ha_partition
|
2010-10-28 12:08:09 +02:00
|
|
|
#endif
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
#include "sql_base.h" // open_and_lock_tables
|
2020-10-02 14:59:06 +02:00
|
|
|
#include "ddl_log.h"
|
2022-02-15 14:36:02 +01:00
|
|
|
#include "wsrep_mysqld.h"
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
#ifndef WITH_PARTITION_STORAGE_ENGINE
|
|
|
|
|
2013-08-15 10:47:18 +02:00
|
|
|
bool Sql_cmd_partition_unsupported::execute(THD *)
|
2010-08-16 14:53:30 +02:00
|
|
|
{
|
2013-08-15 10:47:18 +02:00
|
|
|
DBUG_ENTER("Sql_cmd_partition_unsupported::execute");
|
2010-08-16 14:53:30 +02:00
|
|
|
/* error, partitioning support not compiled in... */
|
|
|
|
my_error(ER_FEATURE_DISABLED, MYF(0), "partitioning",
|
|
|
|
"--with-plugin-partition");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2020-03-30 13:50:03 +02:00
|
|
|
static bool return_with_logging(THD *thd)
|
|
|
|
{
|
|
|
|
if (thd->slave_thread &&
|
|
|
|
write_bin_log_with_if_exists(thd, true, false, true))
|
|
|
|
return(true);
|
|
|
|
my_ok(thd);
|
|
|
|
return(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
bool Sql_cmd_alter_table_exchange_partition::execute(THD *thd)
|
|
|
|
{
|
|
|
|
/* Moved from mysql_execute_command */
|
|
|
|
LEX *lex= thd->lex;
|
|
|
|
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
|
2018-05-22 19:08:39 +02:00
|
|
|
SELECT_LEX *select_lex= lex->first_select_lex();
|
2013-06-15 17:32:08 +02:00
|
|
|
/* first table of first SELECT_LEX */
|
|
|
|
TABLE_LIST *first_table= (TABLE_LIST*) select_lex->table_list.first;
|
|
|
|
/*
|
|
|
|
Code in mysql_alter_table() may modify its HA_CREATE_INFO argument,
|
|
|
|
so we have to use a copy of this structure to make execution
|
|
|
|
prepared statement- safe. A shallow copy is enough as no memory
|
|
|
|
referenced from this structure will be modified.
|
|
|
|
@todo move these into constructor...
|
|
|
|
*/
|
2019-09-30 11:48:26 +02:00
|
|
|
IF_DBUG(HA_CREATE_INFO create_info(lex->create_info);,)
|
2013-06-15 17:32:08 +02:00
|
|
|
Alter_info alter_info(lex->alter_info, thd->mem_root);
|
2020-02-09 18:53:11 +01:00
|
|
|
privilege_t priv_needed(ALTER_ACL | DROP_ACL | INSERT_ACL | CREATE_ACL);
|
2013-06-15 17:32:08 +02:00
|
|
|
|
|
|
|
DBUG_ENTER("Sql_cmd_alter_table_exchange_partition::execute");
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(thd->is_fatal_error))
|
|
|
|
{
|
|
|
|
/* out of memory creating a copy of alter_info */
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
2018-04-04 11:16:12 +02:00
|
|
|
}
|
2013-06-15 17:32:08 +02:00
|
|
|
|
|
|
|
/* Must be set in the parser */
|
2018-01-07 17:03:44 +01:00
|
|
|
DBUG_ASSERT(select_lex->db.str);
|
2013-06-15 17:32:08 +02:00
|
|
|
/* also check the table to be exchanged with the partition */
|
2018-02-19 10:23:20 +01:00
|
|
|
DBUG_ASSERT(alter_info.partition_flags & ALTER_PARTITION_EXCHANGE);
|
2013-06-15 17:32:08 +02:00
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(check_access(thd, priv_needed, first_table->db.str,
|
|
|
|
&first_table->grant.privilege,
|
|
|
|
&first_table->grant.m_internal,
|
|
|
|
0, 0)) ||
|
|
|
|
unlikely(check_access(thd, priv_needed, first_table->next_local->db.str,
|
|
|
|
&first_table->next_local->grant.privilege,
|
|
|
|
&first_table->next_local->grant.m_internal,
|
|
|
|
0, 0)))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(check_grant(thd, priv_needed, first_table, FALSE, UINT_MAX,
|
|
|
|
FALSE)))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
/* Not allowed with EXCHANGE PARTITION */
|
|
|
|
DBUG_ASSERT(!create_info.data_file_name && !create_info.index_file_name);
|
2017-07-25 09:56:44 +02:00
|
|
|
WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
|
2013-06-15 17:32:08 +02:00
|
|
|
|
|
|
|
DBUG_RETURN(exchange_partition(thd, first_table, &alter_info));
|
2017-07-25 09:56:44 +02:00
|
|
|
#ifdef WITH_WSREP
|
2018-11-06 07:41:48 +01:00
|
|
|
wsrep_error_label:
|
2017-07-25 09:56:44 +02:00
|
|
|
/* handle errors in TO_ISOLATION here */
|
|
|
|
DBUG_RETURN(true);
|
|
|
|
#endif /* WITH_WSREP */
|
2013-06-15 17:32:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Checks that the tables will be able to be used for EXCHANGE PARTITION.
|
|
|
|
@param table Non partitioned table.
|
|
|
|
@param part_table Partitioned table.
|
|
|
|
|
|
|
|
@retval FALSE if OK, otherwise error is reported and TRUE is returned.
|
|
|
|
*/
|
2018-04-04 11:16:12 +02:00
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
static bool check_exchange_partition(TABLE *table, TABLE *part_table)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("check_exchange_partition");
|
|
|
|
|
|
|
|
/* Both tables must exist */
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(!part_table || !table))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The first table must be partitioned, and the second must not */
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(!part_table->part_info))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(table->part_info))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_EXCHANGE_PART_TABLE, MYF(0),
|
|
|
|
table->s->table_name.str);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(part_table->file->ht != partition_hton))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
Only allowed on partitioned tables throught the generic ha_partition
|
2014-08-21 18:11:46 +02:00
|
|
|
handler, i.e not yet for native partitioning.
|
2013-06-15 17:32:08 +02:00
|
|
|
*/
|
|
|
|
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(table->file->ht != part_table->part_info->default_engine_type))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
my_error(ER_MIX_HANDLER_ERROR, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Verify that table is not tmp table, partitioned tables cannot be tmp. */
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(table->s->tmp_table != NO_TMP_TABLE))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_EXCHANGE_TEMP_TABLE, MYF(0),
|
|
|
|
table->s->table_name.str);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The table cannot have foreign keys constraints or be referenced */
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(!table->file->can_switch_engines()))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_EXCHANGE_FOREIGN_KEY, MYF(0),
|
|
|
|
table->s->table_name.str);
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Compare table structure/options between a non partitioned table
|
|
|
|
and a specific partition of a partitioned table.
|
|
|
|
|
|
|
|
@param thd Thread object.
|
|
|
|
@param table Non partitioned table.
|
|
|
|
@param part_table Partitioned table.
|
|
|
|
@param part_elem Partition element to use for partition specific compare.
|
|
|
|
*/
|
|
|
|
static bool compare_table_with_partition(THD *thd, TABLE *table,
|
|
|
|
TABLE *part_table,
|
2017-09-17 20:01:38 +02:00
|
|
|
partition_element *part_elem,
|
|
|
|
uint part_id)
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
HA_CREATE_INFO table_create_info, part_create_info;
|
|
|
|
Alter_info part_alter_info;
|
|
|
|
Alter_table_ctx part_alter_ctx; // Not used
|
|
|
|
DBUG_ENTER("compare_table_with_partition");
|
|
|
|
|
|
|
|
bool metadata_equal= false;
|
2019-03-16 16:03:54 +01:00
|
|
|
part_create_info.init();
|
|
|
|
table_create_info.init();
|
2013-06-15 17:32:08 +02:00
|
|
|
|
|
|
|
update_create_info_from_table(&table_create_info, table);
|
|
|
|
/* get the current auto_increment value */
|
|
|
|
table->file->update_create_info(&table_create_info);
|
|
|
|
/* mark all columns used, since they are used when preparing the new table */
|
|
|
|
part_table->use_all_columns();
|
|
|
|
table->use_all_columns();
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(mysql_prepare_alter_table(thd, part_table, &part_create_info,
|
|
|
|
&part_alter_info, &part_alter_ctx)))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
my_error(ER_TABLES_DIFFERENT_METADATA, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
/* db_type is not set in prepare_alter_table */
|
|
|
|
part_create_info.db_type= part_table->part_info->default_engine_type;
|
2017-09-17 20:01:38 +02:00
|
|
|
((ha_partition*)(part_table->file))->update_part_create_info(&part_create_info, part_id);
|
2013-06-15 17:32:08 +02:00
|
|
|
/*
|
|
|
|
Since we exchange the partition with the table, allow exchanging
|
|
|
|
auto_increment value as well.
|
|
|
|
*/
|
|
|
|
part_create_info.auto_increment_value=
|
|
|
|
table_create_info.auto_increment_value;
|
|
|
|
|
|
|
|
/* Check compatible row_types and set create_info accordingly. */
|
|
|
|
{
|
|
|
|
enum row_type part_row_type= part_table->file->get_row_type();
|
|
|
|
enum row_type table_row_type= table->file->get_row_type();
|
|
|
|
if (part_row_type != table_row_type)
|
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
|
|
|
|
"ROW_FORMAT");
|
|
|
|
DBUG_RETURN(true);
|
|
|
|
}
|
|
|
|
part_create_info.row_type= table->s->row_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
NOTE: ha_blackhole does not support check_if_compatible_data,
|
|
|
|
so this always fail for blackhole tables.
|
|
|
|
ha_myisam compares pointers to verify that DATA/INDEX DIRECTORY is
|
|
|
|
the same, so any table using data/index_file_name will fail.
|
|
|
|
*/
|
|
|
|
if (mysql_compare_tables(table, &part_alter_info, &part_create_info,
|
|
|
|
&metadata_equal))
|
|
|
|
{
|
|
|
|
my_error(ER_TABLES_DIFFERENT_METADATA, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_SYNC(thd, "swap_partition_after_compare_tables");
|
|
|
|
if (!metadata_equal)
|
|
|
|
{
|
|
|
|
my_error(ER_TABLES_DIFFERENT_METADATA, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
2022-05-18 16:38:56 +02:00
|
|
|
|
|
|
|
if (table->s->db_create_options != part_table->s->db_create_options)
|
|
|
|
{
|
|
|
|
my_error(ER_TABLES_DIFFERENT_METADATA, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_ASSERT(table->s->db_options_in_use ==
|
|
|
|
part_table->s->db_options_in_use);
|
|
|
|
|
|
|
|
if (table_create_info.avg_row_length != part_create_info.avg_row_length)
|
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
|
|
|
|
"AVG_ROW_LENGTH");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (table_create_info.table_options != part_create_info.table_options)
|
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
|
|
|
|
"TABLE OPTION");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (table->s->table_charset != part_table->s->table_charset)
|
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
|
|
|
|
"CHARACTER SET");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
NOTE: We do not support update of frm-file, i.e. change
|
|
|
|
max/min_rows, data/index_file_name etc.
|
|
|
|
The workaround is to use REORGANIZE PARTITION to rewrite
|
|
|
|
the frm file and then use EXCHANGE PARTITION when they are the same.
|
|
|
|
*/
|
|
|
|
if (compare_partition_options(&table_create_info, part_elem))
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Exchange partition/table with ddl log.
|
|
|
|
|
|
|
|
@details How to handle a crash in the middle of the rename (break on error):
|
|
|
|
1) register in ddl_log that we are going to exchange swap_table with part.
|
|
|
|
2) do the first rename (swap_table -> tmp-name) and sync the ddl_log.
|
|
|
|
3) do the second rename (part -> swap_table) and sync the ddl_log.
|
|
|
|
4) do the last rename (tmp-name -> part).
|
|
|
|
5) mark the entry done.
|
|
|
|
|
|
|
|
Recover by:
|
|
|
|
5) is done, All completed. Nothing to recover.
|
|
|
|
4) is done see 3). (No mark or sync in the ddl_log...)
|
|
|
|
3) is done -> try rename part -> tmp-name (ignore failure) goto 2).
|
|
|
|
2) is done -> try rename swap_table -> part (ignore failure) goto 1).
|
|
|
|
1) is done -> try rename tmp-name -> swap_table (ignore failure).
|
|
|
|
before 1) Nothing to recover...
|
|
|
|
|
|
|
|
@param thd Thread handle
|
|
|
|
@param name name of table/partition 1 (to be exchanged with 2)
|
|
|
|
@param from_name name of table/partition 2 (to be exchanged with 1)
|
|
|
|
@param tmp_name temporary name to use while exchaning
|
|
|
|
@param ht handlerton of the table/partitions
|
|
|
|
|
|
|
|
@return Operation status
|
|
|
|
@retval TRUE Error
|
|
|
|
@retval FALSE Success
|
|
|
|
|
|
|
|
@note ha_heap always succeeds in rename (since it is created upon usage).
|
|
|
|
This is OK when to recover from a crash since all heap are empty and the
|
|
|
|
recover is done early in the startup of the server (right before
|
|
|
|
read_init_file which can populate the tables).
|
|
|
|
|
|
|
|
And if no crash we can trust the syncs in the ddl_log.
|
|
|
|
|
|
|
|
What about if the rename is put into a background thread? That will cause
|
|
|
|
corruption and is avoided by the exlusive metadata lock.
|
|
|
|
*/
|
|
|
|
static bool exchange_name_with_ddl_log(THD *thd,
|
|
|
|
const char *name,
|
|
|
|
const char *from_name,
|
|
|
|
const char *tmp_name,
|
|
|
|
handlerton *ht)
|
|
|
|
{
|
|
|
|
DDL_LOG_ENTRY exchange_entry;
|
|
|
|
DDL_LOG_MEMORY_ENTRY *log_entry= NULL;
|
|
|
|
DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
|
|
|
|
bool error= TRUE;
|
|
|
|
bool error_set= FALSE;
|
|
|
|
handler *file= NULL;
|
|
|
|
DBUG_ENTER("exchange_name_with_ddl_log");
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(!(file= get_new_handler(NULL, thd->mem_root, ht))))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
/* prepare the action entry */
|
2020-10-15 01:25:57 +02:00
|
|
|
bzero(&exchange_entry, sizeof(exchange_entry));
|
2013-06-15 17:32:08 +02:00
|
|
|
exchange_entry.entry_type= DDL_LOG_ENTRY_CODE;
|
|
|
|
exchange_entry.action_type= DDL_LOG_EXCHANGE_ACTION;
|
2020-10-15 01:25:57 +02:00
|
|
|
lex_string_set(&exchange_entry.name, name);
|
|
|
|
lex_string_set(&exchange_entry.from_name, from_name);
|
|
|
|
lex_string_set(&exchange_entry.tmp_name, tmp_name);
|
|
|
|
lex_string_set(&exchange_entry.handler_name,
|
|
|
|
ha_resolve_storage_engine_name(ht));
|
2013-06-15 17:32:08 +02:00
|
|
|
exchange_entry.phase= EXCH_PHASE_NAME_TO_TEMP;
|
|
|
|
|
|
|
|
mysql_mutex_lock(&LOCK_gdl);
|
|
|
|
/*
|
|
|
|
write to the ddl log what to do by:
|
|
|
|
1) write the action entry (i.e. which names to be exchanged)
|
|
|
|
2) write the execution entry with a link to the action entry
|
|
|
|
*/
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_1", goto err_no_action_written;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_1", DBUG_SUICIDE(););
|
2020-10-12 10:21:05 +02:00
|
|
|
if (unlikely(ddl_log_write_entry(&exchange_entry, &log_entry)))
|
2013-06-15 17:32:08 +02:00
|
|
|
goto err_no_action_written;
|
|
|
|
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_2", goto err_no_execute_written;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_2", DBUG_SUICIDE(););
|
2020-10-15 01:25:57 +02:00
|
|
|
if (unlikely(ddl_log_write_execute_entry(log_entry->entry_pos,
|
|
|
|
&exec_log_entry)))
|
2013-06-15 17:32:08 +02:00
|
|
|
goto err_no_execute_written;
|
|
|
|
/* ddl_log is written and synced */
|
|
|
|
|
|
|
|
mysql_mutex_unlock(&LOCK_gdl);
|
|
|
|
/*
|
|
|
|
Execute the name exchange.
|
|
|
|
Do one rename, increase the phase, update the action entry and sync.
|
|
|
|
In case of errors in the ddl_log we must fail and let the ddl_log try
|
|
|
|
to revert the changes, since otherwise it could revert the command after
|
|
|
|
we sent OK to the client.
|
|
|
|
*/
|
|
|
|
/* call rename table from table to tmp-name */
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_3",
|
2018-01-04 15:21:18 +01:00
|
|
|
my_error(ER_ERROR_ON_RENAME, MYF(0), name, tmp_name, 0);
|
2013-06-15 17:32:08 +02:00
|
|
|
error_set= TRUE;
|
|
|
|
goto err_rename;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_3", DBUG_SUICIDE(););
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(file->ha_rename_table(name, tmp_name)))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
2018-01-04 15:21:18 +01:00
|
|
|
my_error(ER_ERROR_ON_RENAME, MYF(0), name, tmp_name, my_errno);
|
2013-06-15 17:32:08 +02:00
|
|
|
error_set= TRUE;
|
|
|
|
goto err_rename;
|
|
|
|
}
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_4", goto err_rename;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_4", DBUG_SUICIDE(););
|
2020-10-12 10:21:05 +02:00
|
|
|
if (unlikely(ddl_log_increment_phase(log_entry->entry_pos)))
|
2013-06-15 17:32:08 +02:00
|
|
|
goto err_rename;
|
|
|
|
|
|
|
|
/* call rename table from partition to table */
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_5",
|
2018-01-04 15:21:18 +01:00
|
|
|
my_error(ER_ERROR_ON_RENAME, MYF(0), from_name, name, 0);
|
2013-06-15 17:32:08 +02:00
|
|
|
error_set= TRUE;
|
|
|
|
goto err_rename;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_5", DBUG_SUICIDE(););
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(file->ha_rename_table(from_name, name)))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
2017-04-23 18:39:57 +02:00
|
|
|
my_error(ER_ERROR_ON_RENAME, MYF(0), from_name, name, my_errno);
|
2013-06-15 17:32:08 +02:00
|
|
|
error_set= TRUE;
|
|
|
|
goto err_rename;
|
|
|
|
}
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_6", goto err_rename;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_6", DBUG_SUICIDE(););
|
2020-10-12 10:21:05 +02:00
|
|
|
if (unlikely(ddl_log_increment_phase(log_entry->entry_pos)))
|
2013-06-15 17:32:08 +02:00
|
|
|
goto err_rename;
|
|
|
|
|
|
|
|
/* call rename table from tmp-nam to partition */
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_7",
|
2018-01-04 15:21:18 +01:00
|
|
|
my_error(ER_ERROR_ON_RENAME, MYF(0), tmp_name, from_name, 0);
|
2013-06-15 17:32:08 +02:00
|
|
|
error_set= TRUE;
|
|
|
|
goto err_rename;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_7", DBUG_SUICIDE(););
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(file->ha_rename_table(tmp_name, from_name)))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
2017-04-23 18:39:57 +02:00
|
|
|
my_error(ER_ERROR_ON_RENAME, MYF(0), tmp_name, from_name, my_errno);
|
2013-06-15 17:32:08 +02:00
|
|
|
error_set= TRUE;
|
|
|
|
goto err_rename;
|
|
|
|
}
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_8", goto err_rename;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_8", DBUG_SUICIDE(););
|
2020-10-12 10:21:05 +02:00
|
|
|
if (unlikely(ddl_log_increment_phase(log_entry->entry_pos)))
|
2013-06-15 17:32:08 +02:00
|
|
|
goto err_rename;
|
|
|
|
|
|
|
|
/* The exchange is complete and ddl_log is deactivated */
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_fail_9", goto err_rename;);
|
|
|
|
DBUG_EXECUTE_IF("exchange_partition_abort_9", DBUG_SUICIDE(););
|
|
|
|
/* all OK */
|
|
|
|
error= FALSE;
|
|
|
|
delete file;
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
err_rename:
|
|
|
|
/*
|
|
|
|
Nothing to do if any of these commands fails :( the commands itselfs
|
|
|
|
will log to the error log about the failures...
|
|
|
|
*/
|
|
|
|
/* execute the ddl log entry to revert the renames */
|
2020-10-12 10:21:05 +02:00
|
|
|
(void) ddl_log_execute_entry(current_thd, log_entry->entry_pos);
|
2013-06-15 17:32:08 +02:00
|
|
|
mysql_mutex_lock(&LOCK_gdl);
|
|
|
|
/* mark the execute log entry done */
|
2020-10-15 01:25:57 +02:00
|
|
|
(void) ddl_log_disable_execute_entry(&exec_log_entry);
|
2013-06-15 17:32:08 +02:00
|
|
|
/* release the execute log entry */
|
2020-10-12 10:21:05 +02:00
|
|
|
(void) ddl_log_release_memory_entry(exec_log_entry);
|
2013-06-15 17:32:08 +02:00
|
|
|
err_no_execute_written:
|
|
|
|
/* release the action log entry */
|
2020-10-12 10:21:05 +02:00
|
|
|
(void) ddl_log_release_memory_entry(log_entry);
|
2013-06-15 17:32:08 +02:00
|
|
|
err_no_action_written:
|
|
|
|
mysql_mutex_unlock(&LOCK_gdl);
|
|
|
|
delete file;
|
|
|
|
if (!error_set)
|
|
|
|
my_error(ER_DDL_LOG_ERROR, MYF(0));
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@brief Swap places between a partition and a table.
|
|
|
|
|
|
|
|
@details Verify that the tables are compatible (same engine, definition etc),
|
|
|
|
verify that all rows in the table will fit in the partition,
|
|
|
|
if all OK, rename table to tmp name, rename partition to table
|
|
|
|
and finally rename tmp name to partition.
|
|
|
|
|
|
|
|
1) Take upgradable mdl, open tables and then lock them (inited in parse)
|
|
|
|
2) Verify that metadata matches
|
|
|
|
3) verify data
|
|
|
|
4) Upgrade to exclusive mdl for both tables
|
|
|
|
5) Rename table <-> partition
|
|
|
|
6) Rely on close_thread_tables to release mdl and table locks
|
|
|
|
|
|
|
|
@param thd Thread handle
|
|
|
|
@param table_list Table where the partition exists as first table,
|
|
|
|
Table to swap with the partition as second table
|
|
|
|
@param alter_info Contains partition name to swap
|
|
|
|
|
|
|
|
@note This is a DDL operation so triggers will not be used.
|
|
|
|
*/
|
|
|
|
bool Sql_cmd_alter_table_exchange_partition::
|
|
|
|
exchange_partition(THD *thd, TABLE_LIST *table_list, Alter_info *alter_info)
|
|
|
|
{
|
|
|
|
TABLE *part_table, *swap_table;
|
|
|
|
TABLE_LIST *swap_table_list;
|
|
|
|
handlerton *table_hton;
|
|
|
|
partition_element *part_elem;
|
2017-04-23 18:39:57 +02:00
|
|
|
const char *partition_name;
|
2013-06-15 17:32:08 +02:00
|
|
|
char temp_name[FN_REFLEN+1];
|
2017-07-06 23:47:33 +02:00
|
|
|
char part_file_name[2*FN_REFLEN+1];
|
2013-06-15 17:32:08 +02:00
|
|
|
char swap_file_name[FN_REFLEN+1];
|
|
|
|
char temp_file_name[FN_REFLEN+1];
|
2021-03-30 16:06:55 +02:00
|
|
|
char part_table_name[NAME_LEN + 1];
|
|
|
|
char part_db[NAME_LEN + 1];
|
|
|
|
char swap_table_name[NAME_LEN + 1];
|
|
|
|
char swap_db[NAME_LEN + 1];
|
|
|
|
uchar part_tabledef_version[MY_UUID_SIZE];
|
|
|
|
uchar swap_tabledef_version[MY_UUID_SIZE];
|
|
|
|
|
|
|
|
backup_log_info ddl_log;
|
|
|
|
bzero(&ddl_log, sizeof(ddl_log));
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
uint swap_part_id;
|
|
|
|
uint part_file_name_len;
|
|
|
|
Alter_table_prelocking_strategy alter_prelocking_strategy;
|
|
|
|
MDL_ticket *swap_table_mdl_ticket= NULL;
|
|
|
|
MDL_ticket *part_table_mdl_ticket= NULL;
|
|
|
|
uint table_counter;
|
2020-03-30 13:50:03 +02:00
|
|
|
bool error= TRUE, force_if_exists= 0;
|
|
|
|
ulonglong save_option_bits= thd->variables.option_bits;
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_ENTER("mysql_exchange_partition");
|
2018-02-19 10:23:20 +01:00
|
|
|
DBUG_ASSERT(alter_info->partition_flags & ALTER_PARTITION_EXCHANGE);
|
2013-06-15 17:32:08 +02:00
|
|
|
|
|
|
|
/* Don't allow to exchange with log table */
|
|
|
|
swap_table_list= table_list->next_local;
|
2014-01-29 14:37:17 +01:00
|
|
|
if (check_if_log_table(swap_table_list, FALSE, "ALTER PARTITION"))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Currently no MDL lock that allows both read and write and is upgradeable
|
|
|
|
to exclusive, so leave the lock type to TL_WRITE_ALLOW_READ also on the
|
|
|
|
partitioned table.
|
|
|
|
|
|
|
|
TODO: add MDL lock that allows both read and write and is upgradable to
|
|
|
|
exclusive lock. This would allow to continue using the partitioned table
|
|
|
|
also with update/insert/delete while the verification of the swap table
|
|
|
|
is running.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
NOTE: It is not possible to exchange a crashed partition/table since
|
|
|
|
we need some info from the engine, which we can only access after open,
|
|
|
|
to be able to verify the structure/metadata.
|
|
|
|
*/
|
|
|
|
table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE);
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(open_tables(thd, &table_list, &table_counter, 0,
|
|
|
|
&alter_prelocking_strategy)))
|
2020-03-30 13:50:03 +02:00
|
|
|
{
|
|
|
|
if (thd->lex->if_exists() &&
|
|
|
|
thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
ALTER TABLE IF EXISTS was used on not existing table
|
|
|
|
We have to log the query on a slave as the table may be a shared one
|
|
|
|
from the master and we need to ensure that the next slave can see
|
|
|
|
the statement as this slave may not have the table shared
|
|
|
|
*/
|
|
|
|
thd->clear_error();
|
|
|
|
if (thd->slave_thread &&
|
|
|
|
write_bin_log(thd, true, thd->query(), thd->query_length()))
|
|
|
|
DBUG_RETURN(true);
|
|
|
|
my_ok(thd);
|
|
|
|
DBUG_RETURN(false);
|
|
|
|
}
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(true);
|
2020-03-30 13:50:03 +02:00
|
|
|
}
|
2013-06-15 17:32:08 +02:00
|
|
|
|
|
|
|
part_table= table_list->table;
|
|
|
|
swap_table= swap_table_list->table;
|
|
|
|
|
2022-05-30 12:28:44 +02:00
|
|
|
/* Don't allow to exchange with a VIEW */
|
|
|
|
if (unlikely(swap_table_list->view))
|
|
|
|
{
|
|
|
|
my_error(ER_WRONG_OBJECT, MYF(0), table_list->db.str,
|
|
|
|
swap_table_list->table_name.str, "BASE TABLE");
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(check_exchange_partition(swap_table, part_table)))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
2020-07-31 17:11:17 +02:00
|
|
|
if (part_table->file->check_if_updates_are_ignored("ALTER"))
|
|
|
|
DBUG_RETURN(return_with_logging(thd));
|
|
|
|
|
2020-03-30 13:50:03 +02:00
|
|
|
/* Add IF EXISTS to binlog if shared table */
|
|
|
|
if (part_table->file->partition_ht()->flags &
|
|
|
|
HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
|
|
|
|
force_if_exists= 1;
|
|
|
|
|
2021-03-30 16:06:55 +02:00
|
|
|
ddl_log.org_table.str= part_table_name;
|
|
|
|
DBUG_ASSERT(part_table->s->table_name.length <= NAME_LEN);
|
|
|
|
ddl_log.org_table.length= part_table->s->table_name.length;
|
|
|
|
strmake(part_table_name, part_table->s->table_name.str, NAME_LEN);
|
|
|
|
|
|
|
|
ddl_log.org_database.str= part_db;
|
|
|
|
DBUG_ASSERT(part_table->s->db.length <= NAME_LEN);
|
|
|
|
ddl_log.org_database.length= part_table->s->db.length;
|
|
|
|
strmake(part_db, part_table->s->db.str, NAME_LEN);
|
|
|
|
|
|
|
|
ddl_log.new_table.str= swap_table_name;
|
|
|
|
DBUG_ASSERT(swap_table->s->table_name.length <= NAME_LEN);
|
|
|
|
ddl_log.new_table.length= swap_table->s->table_name.length;
|
|
|
|
strmake(swap_table_name, swap_table->s->table_name.str, NAME_LEN);
|
|
|
|
|
|
|
|
ddl_log.new_database.str= swap_db;
|
|
|
|
DBUG_ASSERT(swap_table->s->db.length <= NAME_LEN);
|
|
|
|
ddl_log.new_database.length= swap_table->s->db.length;
|
|
|
|
strmake(swap_db, swap_table->s->db.str, NAME_LEN);
|
|
|
|
|
|
|
|
memcpy(part_tabledef_version, part_table->s->tabledef_version.str,
|
|
|
|
MY_UUID_SIZE);
|
|
|
|
ddl_log.org_table_id.str= part_tabledef_version;
|
|
|
|
ddl_log.org_table_id.length= MY_UUID_SIZE;
|
|
|
|
memcpy(swap_tabledef_version, swap_table->s->tabledef_version.str,
|
|
|
|
MY_UUID_SIZE);
|
|
|
|
ddl_log.new_table_id.str= swap_tabledef_version;
|
|
|
|
ddl_log.new_table_id.length= MY_UUID_SIZE;
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
/* set lock pruning on first table */
|
|
|
|
partition_name= alter_info->partition_names.head();
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(table_list->table->part_info->
|
|
|
|
set_named_partition_bitmap(partition_name,
|
|
|
|
strlen(partition_name))))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(true);
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(lock_tables(thd, table_list, table_counter, 0)))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(true);
|
|
|
|
|
|
|
|
table_hton= swap_table->file->ht;
|
|
|
|
|
|
|
|
THD_STAGE_INFO(thd, stage_verifying_table);
|
|
|
|
|
|
|
|
/* Will append the partition name later in part_info->get_part_elem() */
|
|
|
|
part_file_name_len= build_table_filename(part_file_name,
|
|
|
|
sizeof(part_file_name),
|
2018-01-07 17:03:44 +01:00
|
|
|
table_list->db.str,
|
|
|
|
table_list->table_name.str,
|
2013-06-15 17:32:08 +02:00
|
|
|
"", 0);
|
|
|
|
build_table_filename(swap_file_name,
|
|
|
|
sizeof(swap_file_name),
|
2018-01-07 17:03:44 +01:00
|
|
|
swap_table_list->db.str,
|
|
|
|
swap_table_list->table_name.str,
|
2013-06-15 17:32:08 +02:00
|
|
|
"", 0);
|
2020-04-09 15:52:59 +02:00
|
|
|
/* create a unique temp name */
|
|
|
|
my_snprintf(temp_name, sizeof(temp_name), "%s-exchange-%lx-%llx",
|
2013-06-15 17:32:08 +02:00
|
|
|
tmp_file_prefix, current_pid, thd->thread_id);
|
|
|
|
if (lower_case_table_names)
|
|
|
|
my_casedn_str(files_charset_info, temp_name);
|
|
|
|
build_table_filename(temp_file_name, sizeof(temp_file_name),
|
2018-01-07 17:03:44 +01:00
|
|
|
table_list->next_local->db.str,
|
2013-06-15 17:32:08 +02:00
|
|
|
temp_name, "", FN_IS_TMP);
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(!(part_elem=
|
|
|
|
part_table->part_info->get_part_elem(partition_name,
|
|
|
|
part_file_name +
|
|
|
|
part_file_name_len,
|
|
|
|
sizeof(part_file_name) -
|
|
|
|
part_file_name_len,
|
|
|
|
&swap_part_id))))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(swap_part_id == NOT_A_PARTITION_ID))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
DBUG_ASSERT(part_table->part_info->is_sub_partitioned());
|
|
|
|
my_error(ER_PARTITION_INSTEAD_OF_SUBPARTITION, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(compare_table_with_partition(thd, swap_table, part_table,
|
|
|
|
part_elem,
|
|
|
|
swap_part_id)))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
/* Table and partition has same structure/options, OK to exchange */
|
|
|
|
|
2017-11-05 16:04:20 +01:00
|
|
|
thd_proc_info(thd, "Verifying data with partition");
|
2013-06-15 17:32:08 +02:00
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(verify_data_with_partition(swap_table, part_table,
|
|
|
|
swap_part_id)))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get exclusive mdl lock on both tables, alway the non partitioned table
|
|
|
|
first. Remember the tickets for downgrading locks later.
|
|
|
|
*/
|
|
|
|
swap_table_mdl_ticket= swap_table->mdl_ticket;
|
|
|
|
part_table_mdl_ticket= part_table->mdl_ticket;
|
|
|
|
|
|
|
|
/*
|
|
|
|
No need to set used_partitions to only propagate
|
|
|
|
HA_EXTRA_PREPARE_FOR_RENAME to one part since no built in engine uses
|
|
|
|
that flag. And the action would probably be to force close all other
|
|
|
|
instances which is what we are doing any way.
|
|
|
|
*/
|
|
|
|
if (wait_while_table_is_used(thd, swap_table, HA_EXTRA_PREPARE_FOR_RENAME) ||
|
|
|
|
wait_while_table_is_used(thd, part_table, HA_EXTRA_PREPARE_FOR_RENAME))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
DEBUG_SYNC(thd, "swap_partition_after_wait");
|
|
|
|
|
|
|
|
close_all_tables_for_name(thd, swap_table->s, HA_EXTRA_NOT_USED, NULL);
|
|
|
|
close_all_tables_for_name(thd, part_table->s, HA_EXTRA_NOT_USED, NULL);
|
|
|
|
|
|
|
|
DEBUG_SYNC(thd, "swap_partition_before_rename");
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(exchange_name_with_ddl_log(thd, swap_file_name, part_file_name,
|
|
|
|
temp_file_name, table_hton)))
|
2013-06-15 17:32:08 +02:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Reopen tables under LOCK TABLES. Ignore the return value for now. It's
|
|
|
|
better to keep master/slave in consistent state. Alternative would be to
|
|
|
|
try to revert the exchange operation and issue error.
|
|
|
|
*/
|
2018-04-20 10:10:33 +02:00
|
|
|
(void) thd->locked_tables_list.reopen_tables(thd, false);
|
2013-06-15 17:32:08 +02:00
|
|
|
|
2020-03-30 13:50:03 +02:00
|
|
|
if (force_if_exists)
|
|
|
|
thd->variables.option_bits|= OPTION_IF_EXISTS;
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely((error= write_bin_log(thd, TRUE, thd->query(),
|
|
|
|
thd->query_length()))))
|
2013-06-15 17:32:08 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
The error is reported in write_bin_log().
|
|
|
|
We try to revert to make it easier to keep the master/slave in sync.
|
|
|
|
*/
|
|
|
|
(void) exchange_name_with_ddl_log(thd, part_file_name, swap_file_name,
|
|
|
|
temp_file_name, table_hton);
|
|
|
|
}
|
2021-03-30 16:06:55 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ddl_log.query= { C_STRING_WITH_LEN("EXCHANGE_PARTITION") };
|
|
|
|
ddl_log.org_partitioned= true;
|
|
|
|
ddl_log.new_partitioned= false;
|
|
|
|
ddl_log.org_storage_engine_name= *hton_name(table_hton);
|
|
|
|
ddl_log.new_storage_engine_name= *hton_name(table_hton);
|
|
|
|
backup_log_ddl(&ddl_log);
|
|
|
|
}
|
2020-03-30 13:50:03 +02:00
|
|
|
thd->variables.option_bits= save_option_bits;
|
2013-06-15 17:32:08 +02:00
|
|
|
|
|
|
|
err:
|
|
|
|
if (thd->locked_tables_mode)
|
|
|
|
{
|
|
|
|
if (swap_table_mdl_ticket)
|
|
|
|
swap_table_mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
|
|
|
if (part_table_mdl_ticket)
|
|
|
|
part_table_mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
|
|
|
}
|
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(!error))
|
2013-06-15 17:32:08 +02:00
|
|
|
my_ok(thd);
|
|
|
|
|
|
|
|
// For query cache
|
|
|
|
table_list->table= NULL;
|
|
|
|
table_list->next_local->table= NULL;
|
|
|
|
query_cache_invalidate3(thd, table_list, FALSE);
|
|
|
|
|
|
|
|
DBUG_RETURN(error);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sql_cmd_alter_table_analyze_partition::execute(THD *thd)
|
2010-08-16 14:53:30 +02:00
|
|
|
{
|
|
|
|
bool res;
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_ENTER("Sql_cmd_alter_table_analyze_partition::execute");
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Flag that it is an ALTER command which administrates partitions, used
|
|
|
|
by ha_partition
|
|
|
|
*/
|
2018-02-19 10:23:20 +01:00
|
|
|
thd->lex->alter_info.partition_flags|= ALTER_PARTITION_ADMIN;
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
res= Sql_cmd_analyze_table::execute(thd);
|
|
|
|
|
2010-08-16 14:53:30 +02:00
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
bool Sql_cmd_alter_table_check_partition::execute(THD *thd)
|
2010-08-16 14:53:30 +02:00
|
|
|
{
|
|
|
|
bool res;
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_ENTER("Sql_cmd_alter_table_check_partition::execute");
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Flag that it is an ALTER command which administrates partitions, used
|
|
|
|
by ha_partition
|
|
|
|
*/
|
2018-02-19 10:23:20 +01:00
|
|
|
thd->lex->alter_info.partition_flags|= ALTER_PARTITION_ADMIN;
|
2010-08-16 14:53:30 +02:00
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
res= Sql_cmd_check_table::execute(thd);
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
bool Sql_cmd_alter_table_optimize_partition::execute(THD *thd)
|
2010-08-16 14:53:30 +02:00
|
|
|
{
|
|
|
|
bool res;
|
|
|
|
DBUG_ENTER("Alter_table_optimize_partition_statement::execute");
|
|
|
|
|
|
|
|
/*
|
|
|
|
Flag that it is an ALTER command which administrates partitions, used
|
|
|
|
by ha_partition
|
|
|
|
*/
|
2018-02-19 10:23:20 +01:00
|
|
|
thd->lex->alter_info.partition_flags|= ALTER_PARTITION_ADMIN;
|
2010-08-16 14:53:30 +02:00
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
res= Sql_cmd_optimize_table::execute(thd);
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
bool Sql_cmd_alter_table_repair_partition::execute(THD *thd)
|
2010-08-16 14:53:30 +02:00
|
|
|
{
|
|
|
|
bool res;
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_ENTER("Sql_cmd_alter_table_repair_partition::execute");
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Flag that it is an ALTER command which administrates partitions, used
|
|
|
|
by ha_partition
|
|
|
|
*/
|
2018-02-19 10:23:20 +01:00
|
|
|
thd->lex->alter_info.partition_flags|= ALTER_PARTITION_ADMIN;
|
2010-08-16 14:53:30 +02:00
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
res= Sql_cmd_repair_table::execute(thd);
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
bool Sql_cmd_alter_table_truncate_partition::execute(THD *thd)
|
2010-08-16 14:53:30 +02:00
|
|
|
{
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
int error;
|
|
|
|
ha_partition *partition;
|
|
|
|
ulong timeout= thd->variables.lock_wait_timeout;
|
2018-05-22 19:08:39 +02:00
|
|
|
TABLE_LIST *first_table= thd->lex->first_select_lex()->table_list.first;
|
2013-06-15 17:32:08 +02:00
|
|
|
Alter_info *alter_info= &thd->lex->alter_info;
|
|
|
|
uint table_counter, i;
|
|
|
|
List<String> partition_names_list;
|
2020-03-30 13:50:03 +02:00
|
|
|
bool binlog_stmt, force_if_exists= 0;
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_ENTER("Sql_cmd_alter_table_truncate_partition::execute");
|
2010-08-16 14:53:30 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Flag that it is an ALTER command which administrates partitions, used
|
|
|
|
by ha_partition.
|
|
|
|
*/
|
2018-02-19 10:23:20 +01:00
|
|
|
thd->lex->alter_info.partition_flags|= (ALTER_PARTITION_ADMIN |
|
|
|
|
ALTER_PARTITION_TRUNCATE);
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
|
|
|
|
/* Fix the lock types (not the same as ordinary ALTER TABLE). */
|
|
|
|
first_table->lock_type= TL_WRITE;
|
|
|
|
first_table->mdl_request.set_type(MDL_EXCLUSIVE);
|
|
|
|
|
2010-08-16 14:53:30 +02:00
|
|
|
/*
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
Check table permissions and open it with a exclusive lock.
|
|
|
|
Ensure it is a partitioned table and finally, upcast the
|
|
|
|
handler and invoke the partition truncate method. Lastly,
|
|
|
|
write the statement to the binary log if necessary.
|
2010-08-16 14:53:30 +02:00
|
|
|
*/
|
|
|
|
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
if (check_one_table_access(thd, DROP_ACL, first_table))
|
|
|
|
DBUG_RETURN(TRUE);
|
2010-08-16 14:53:30 +02:00
|
|
|
|
2014-08-06 14:39:15 +02:00
|
|
|
#ifdef WITH_WSREP
|
2016-06-10 22:19:59 +02:00
|
|
|
if (WSREP(thd) &&
|
|
|
|
(!thd->is_current_stmt_binlog_format_row() ||
|
|
|
|
!thd->find_temporary_table(first_table)) &&
|
2014-03-25 22:01:05 +01:00
|
|
|
wsrep_to_isolation_begin(
|
2018-01-07 17:03:44 +01:00
|
|
|
thd, first_table->db.str, first_table->table_name.str, NULL)
|
2014-03-25 22:01:05 +01:00
|
|
|
)
|
2014-08-06 14:39:15 +02:00
|
|
|
{
|
2015-08-06 06:36:40 +02:00
|
|
|
WSREP_WARN("ALTER TABLE TRUNCATE PARTITION isolation failure");
|
2014-03-25 22:01:05 +01:00
|
|
|
DBUG_RETURN(TRUE);
|
2014-08-06 14:39:15 +02:00
|
|
|
}
|
|
|
|
#endif /* WITH_WSREP */
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
if (open_tables(thd, &first_table, &table_counter, 0))
|
2020-03-30 13:50:03 +02:00
|
|
|
{
|
|
|
|
if (thd->lex->if_exists() &&
|
|
|
|
thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
ALTER TABLE IF EXISTS was used on not existing table
|
|
|
|
We have to log the query on a slave as the table may be a shared one
|
|
|
|
from the master and we need to ensure that the next slave can see
|
|
|
|
the statement as this slave may not have the table shared
|
|
|
|
*/
|
|
|
|
thd->clear_error();
|
|
|
|
DBUG_RETURN(return_with_logging(thd));
|
|
|
|
}
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
|
2020-03-30 13:50:03 +02:00
|
|
|
if (!first_table->table || first_table->view)
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
2020-03-30 13:50:03 +02:00
|
|
|
if (first_table->table->file->check_if_updates_are_ignored("ALTER"))
|
|
|
|
DBUG_RETURN(return_with_logging(thd));
|
|
|
|
|
|
|
|
if (first_table->table->s->db_type() != partition_hton)
|
|
|
|
{
|
|
|
|
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (first_table->table->file->partition_ht()->flags &
|
|
|
|
HTON_TABLE_MAY_NOT_EXIST_ON_SLAVE)
|
|
|
|
force_if_exists= 1;
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
/*
|
|
|
|
Prune all, but named partitions,
|
|
|
|
to avoid excessive calls to external_lock().
|
|
|
|
*/
|
2017-04-23 18:39:57 +02:00
|
|
|
List_iterator<const char> partition_names_it(alter_info->partition_names);
|
2013-06-15 17:32:08 +02:00
|
|
|
uint num_names= alter_info->partition_names.elements;
|
|
|
|
for (i= 0; i < num_names; i++)
|
|
|
|
{
|
2017-04-23 18:39:57 +02:00
|
|
|
const char *partition_name= partition_names_it++;
|
2013-06-15 17:32:08 +02:00
|
|
|
String *str_partition_name= new (thd->mem_root)
|
Reduce usage of strlen()
Changes:
- To detect automatic strlen() I removed the methods in String that
uses 'const char *' without a length:
- String::append(const char*)
- Binary_string(const char *str)
- String(const char *str, CHARSET_INFO *cs)
- append_for_single_quote(const char *)
All usage of append(const char*) is changed to either use
String::append(char), String::append(const char*, size_t length) or
String::append(LEX_CSTRING)
- Added STRING_WITH_LEN() around constant string arguments to
String::append()
- Added overflow argument to escape_string_for_mysql() and
escape_quotes_for_mysql() instead of returning (size_t) -1 on overflow.
This was needed as most usage of the above functions never tested the
result for -1 and would have given wrong results or crashes in case
of overflows.
- Added Item_func_or_sum::func_name_cstring(), which returns LEX_CSTRING.
Changed all Item_func::func_name()'s to func_name_cstring()'s.
The old Item_func_or_sum::func_name() is now an inline function that
returns func_name_cstring().str.
- Changed Item::mode_name() and Item::func_name_ext() to return
LEX_CSTRING.
- Changed for some functions the name argument from const char * to
to const LEX_CSTRING &:
- Item::Item_func_fix_attributes()
- Item::check_type_...()
- Type_std_attributes::agg_item_collations()
- Type_std_attributes::agg_item_set_converter()
- Type_std_attributes::agg_arg_charsets...()
- Type_handler_hybrid_field_type::aggregate_for_result()
- Type_handler_geometry::check_type_geom_or_binary()
- Type_handler::Item_func_or_sum_illegal_param()
- Predicant_to_list_comparator::add_value_skip_null()
- Predicant_to_list_comparator::add_value()
- cmp_item_row::prepare_comparators()
- cmp_item_row::aggregate_row_elements_for_comparison()
- Cursor_ref::print_func()
- Removes String_space() as it was only used in one cases and that
could be simplified to not use String_space(), thanks to the fixed
my_vsnprintf().
- Added some const LEX_CSTRING's for common strings:
- NULL_clex_str, DATA_clex_str, INDEX_clex_str.
- Changed primary_key_name to a LEX_CSTRING
- Renamed String::set_quick() to String::set_buffer_if_not_allocated() to
clarify what the function really does.
- Rename of protocol function:
bool store(const char *from, CHARSET_INFO *cs) to
bool store_string_or_null(const char *from, CHARSET_INFO *cs).
This was done to both clarify the difference between this 'store' function
and also to make it easier to find unoptimal usage of store() calls.
- Added Protocol::store(const LEX_CSTRING*, CHARSET_INFO*)
- Changed some 'const char*' arrays to instead be of type LEX_CSTRING.
- class Item_func_units now used LEX_CSTRING for name.
Other things:
- Fixed a bug in mysql.cc:construct_prompt() where a wrong escape character
in the prompt would cause some part of the prompt to be duplicated.
- Fixed a lot of instances where the length of the argument to
append is known or easily obtain but was not used.
- Removed some not needed 'virtual' definition for functions that was
inherited from the parent. I added override to these.
- Fixed Ordered_key::print() to preallocate needed buffer. Old code could
case memory overruns.
- Simplified some loops when adding char * to a String with delimiters.
2020-08-12 19:29:55 +02:00
|
|
|
String(partition_name, strlen(partition_name), system_charset_info);
|
2013-06-15 17:32:08 +02:00
|
|
|
if (!str_partition_name)
|
|
|
|
DBUG_RETURN(true);
|
2015-08-24 13:42:07 +02:00
|
|
|
partition_names_list.push_back(str_partition_name, thd->mem_root);
|
2013-06-15 17:32:08 +02:00
|
|
|
}
|
2018-01-29 08:01:14 +01:00
|
|
|
if (first_table->table->
|
|
|
|
part_info->set_partition_bitmaps(&partition_names_list))
|
2013-06-15 17:32:08 +02:00
|
|
|
DBUG_RETURN(true);
|
|
|
|
|
|
|
|
if (lock_tables(thd, first_table, table_counter, 0))
|
|
|
|
DBUG_RETURN(true);
|
|
|
|
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
/*
|
|
|
|
Under locked table modes this might still not be an exclusive
|
|
|
|
lock. Hence, upgrade the lock since the handler truncate method
|
|
|
|
mandates an exclusive metadata lock.
|
|
|
|
*/
|
|
|
|
MDL_ticket *ticket= first_table->table->mdl_ticket;
|
2013-06-15 17:32:08 +02:00
|
|
|
if (thd->mdl_context.upgrade_shared_lock(ticket, MDL_EXCLUSIVE, timeout))
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
|
2019-12-17 13:25:15 +01:00
|
|
|
first_table->table->s->tdc->flush(thd, true);
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
partition= (ha_partition*) first_table->table->file;
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
/* Invoke the handler method responsible for truncating the partition. */
|
2018-04-04 11:16:12 +02:00
|
|
|
if (unlikely(error= partition->truncate_partition(alter_info,
|
|
|
|
&binlog_stmt)))
|
2013-06-15 17:32:08 +02:00
|
|
|
partition->print_error(error, MYF(0));
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
All effects of a truncate operation are committed even if the
|
|
|
|
operation fails. Thus, the query must be written to the binary
|
2010-12-01 22:47:40 +01:00
|
|
|
log. The exception is a unimplemented truncate method or failure
|
|
|
|
before any call to handler::truncate() is done.
|
|
|
|
Also, it is logged in statement format, regardless of the binlog format.
|
2015-06-03 22:31:05 +02:00
|
|
|
|
|
|
|
Since we've changed data within the table, we also have to invalidate
|
|
|
|
the query cache for it.
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
*/
|
2018-04-04 11:16:12 +02:00
|
|
|
if (likely(error != HA_ERR_WRONG_COMMAND))
|
2015-06-03 22:31:05 +02:00
|
|
|
{
|
2020-03-30 13:50:03 +02:00
|
|
|
ulonglong save_option_bits= thd->variables.option_bits;
|
|
|
|
if (force_if_exists)
|
|
|
|
thd->variables.option_bits|= OPTION_IF_EXISTS;
|
|
|
|
|
2015-06-03 22:31:05 +02:00
|
|
|
query_cache_invalidate3(thd, first_table, FALSE);
|
|
|
|
if (binlog_stmt)
|
|
|
|
error|= write_bin_log(thd, !error, thd->query(), thd->query_length());
|
2020-03-30 13:50:03 +02:00
|
|
|
thd->variables.option_bits= save_option_bits;
|
2015-06-03 22:31:05 +02:00
|
|
|
}
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
A locked table ticket was upgraded to a exclusive lock. After the
|
|
|
|
the query has been written to the binary log, downgrade the lock
|
|
|
|
to a shared one.
|
|
|
|
*/
|
|
|
|
if (thd->locked_tables_mode)
|
2013-06-15 17:32:08 +02:00
|
|
|
ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE);
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
|
2018-04-04 11:16:12 +02:00
|
|
|
if (likely(!error))
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
my_ok(thd);
|
|
|
|
|
2013-06-15 17:32:08 +02:00
|
|
|
// Invalidate query cache
|
|
|
|
DBUG_ASSERT(!first_table->next_local);
|
|
|
|
query_cache_invalidate3(thd, first_table, FALSE);
|
|
|
|
|
Bug#49938: Failing assertion: inode or deadlock in fsp/fsp0fsp.c
Bug#54678: InnoDB, TRUNCATE, ALTER, I_S SELECT, crash or deadlock
- Incompatible change: truncate no longer resorts to a row by
row delete if the storage engine does not support the truncate
method. Consequently, the count of affected rows does not, in
any case, reflect the actual number of rows.
- Incompatible change: it is no longer possible to truncate a
table that participates as a parent in a foreign key constraint,
unless it is a self-referencing constraint (both parent and child
are in the same table). To work around this incompatible change
and still be able to truncate such tables, disable foreign checks
with SET foreign_key_checks=0 before truncate. Alternatively, if
foreign key checks are necessary, please use a DELETE statement
without a WHERE condition.
Problem description:
The problem was that for storage engines that do not support
truncate table via a external drop and recreate, such as InnoDB
which implements truncate via a internal drop and recreate, the
delete_all_rows method could be invoked with a shared metadata
lock, causing problems if the engine needed exclusive access
to some internal metadata. This problem originated with the
fact that there is no truncate specific handler method, which
ended up leading to a abuse of the delete_all_rows method that
is primarily used for delete operations without a condition.
Solution:
The solution is to introduce a truncate handler method that is
invoked when the engine does not support truncation via a table
drop and recreate. This method is invoked under a exclusive
metadata lock, so that there is only a single instance of the
table when the method is invoked.
Also, the method is not invoked and a error is thrown if
the table is a parent in a non-self-referencing foreign key
relationship. This was necessary to avoid inconsistency as
some integrity checks are bypassed. This is inline with the
fact that truncate is primarily a DDL operation that was
designed to quickly remove all data from a table.
mysql-test/suite/innodb/t/innodb-truncate.test:
Add test cases for truncate and foreign key checks.
Also test that InnoDB resets auto-increment on truncate.
mysql-test/suite/innodb/t/innodb.test:
FK is not necessary, test is related to auto-increment.
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/suite/innodb/t/innodb_mysql.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
Use delete instead of truncate, test is used to check
the interaction of FKs, triggers and delete.
mysql-test/suite/parts/inc/partition_check.inc:
Fix typo.
mysql-test/suite/sys_vars/t/foreign_key_checks_func.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
mysql-test/t/mdl_sync.test:
Modify test case to reflect and ensure that truncate takes
a exclusive metadata lock.
mysql-test/t/trigger-trans.test:
Update error number, truncate is no longer invoked if
table is parent in a FK relationship.
sql/ha_partition.cc:
Reorganize the various truncate methods. delete_all_rows is now
passed directly to the underlying engines, so as truncate. The
code responsible for truncating individual partitions is moved
to ha_partition::truncate_partition, which is invoked when a
ALTER TABLE t1 TRUNCATE PARTITION p statement is executed.
Since the partition truncate no longer can be invoked via
delete, the bitmap operations are not necessary anymore. The
explicit reset of the auto-increment value is also removed
as the underlying engines are now responsible for reseting
the value.
sql/handler.cc:
Wire up the handler truncate method.
sql/handler.h:
Introduce and document the truncate handler method. It assumes
certain use cases of delete_all_rows.
Add method to retrieve the list of foreign keys referencing a
table. Method is used to avoid truncating tables that are
parent in a foreign key relationship.
sql/share/errmsg-utf8.txt:
Add error message for truncate and FK.
sql/sql_lex.h:
Introduce a flag so that the partition engine can detect when
a partition is being truncated. Used to give a special error.
sql/sql_parse.cc:
Function mysql_truncate_table no longer exists.
sql/sql_partition_admin.cc:
Implement the TRUNCATE PARTITION statement.
sql/sql_truncate.cc:
Change the truncate table implementation to use the new truncate
handler method and to not rely on row-by-row delete anymore.
The truncate handler method is always invoked with a exclusive
metadata lock. Also, it is no longer possible to truncate a
table that is parent in some non-self-referencing foreign key.
storage/archive/ha_archive.cc:
Rename method as the description indicates that in the future
this could be a truncate operation.
storage/blackhole/ha_blackhole.cc:
Implement truncate as no operation for the blackhole engine in
order to remain compatible with older releases.
storage/federated/ha_federated.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/heap/ha_heap.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/ibmdb2i/ha_ibmdb2i.cc:
Introduce truncate method that invokes delete_all_rows.
This is required to support partition truncate as this
form of truncate does not implement the drop and recreate
protocol.
storage/innobase/handler/ha_innodb.cc:
Rename delete_all_rows to truncate. InnoDB now does truncate
under a exclusive metadata lock.
Introduce and reorganize methods used to retrieve the list
of foreign keys referenced by a or referencing a table.
storage/myisammrg/ha_myisammrg.cc:
Introduce truncate method that invokes delete_all_rows.
This is required in order to remain compatible with earlier
releases where truncate would resort to a row-by-row delete.
2010-10-06 16:34:28 +02:00
|
|
|
DBUG_RETURN(error);
|
2010-08-16 14:53:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|