mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
Added new syntax for partition management mysql-test/t/partition_error.test: New line sql/ha_partition.cc: Added support for DROP PARTITION on-line sql/ha_partition.h: Added support for DROP PARTITION on-line sql/handler.h: Introduced state of partition Introduced extra list of temporary partitions Removed no_full_parts A couple of methods to check for duplicate names of partitions Adaptions of default checks to be useful from ALTER TABLE partition management New method on handler to drop partitions New method to check for foreign keys on table sql/lex.h: COALESCE and REORGANISE used by ALTER TABLE x COALESCE/REORGANISE PARTITION sql/mysql_priv.h: Parser needs method to check if partition management command is ongoing sql/share/errmsg.txt: A number of new error messages for partition management sql/sql_lex.h: Adapted the ALTER_INFO data structure for partition management sql/sql_partition.cc: Couple of new routines + adaption of existing for new partition management functionality sql/sql_table.cc: bin log writing into separate subroutine to minimise code duplication. Lots of new code to handle partition management sql/sql_yacc.yy: New syntax for partition management Fixed a few errors in the parser part for partitioning
This commit is contained in:
671
sql/sql_table.cc
671
sql/sql_table.cc
@@ -45,6 +45,64 @@ static bool prepare_blob_field(THD *thd, create_field *sql_field);
|
||||
static bool check_engine(THD *thd, const char *table_name,
|
||||
enum db_type *new_engine);
|
||||
|
||||
/*
|
||||
SYNOPSIS
|
||||
write_bin_log()
|
||||
thd Thread object
|
||||
clear_error is clear_error to be called
|
||||
RETURN VALUES
|
||||
NONE
|
||||
DESCRIPTION
|
||||
Write the binlog if open, routine used in multiple places in this
|
||||
file
|
||||
*/
|
||||
|
||||
static void write_bin_log(THD *thd, bool clear_error)
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
if (clear_error)
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SYNOPSIS
|
||||
abort_and_upgrade_lock()
|
||||
thd Thread object
|
||||
table Table object
|
||||
db Database name
|
||||
table_name Table name
|
||||
old_lock_level Old lock level
|
||||
RETURN VALUES
|
||||
TRUE Failure
|
||||
FALSE Success
|
||||
DESCRIPTION
|
||||
Remember old lock level (for possible downgrade later on), abort all
|
||||
waiting threads and ensure that all keeping locks currently are
|
||||
completed such that we own the lock exclusively and no other interaction
|
||||
is ongoing.
|
||||
*/
|
||||
|
||||
static bool abort_and_upgrade_lock(THD *thd, TABLE *table, const char *db,
|
||||
const char *table_name,
|
||||
uint *old_lock_level)
|
||||
{
|
||||
uint flags= RTFC_WAIT_OTHER_THREAD_FLAG | RTFC_CHECK_KILLED_FLAG;
|
||||
DBUG_ENTER("abort_and_upgrade_locks");
|
||||
|
||||
*old_lock_level= table->reginfo.lock_type;
|
||||
mysql_lock_abort(thd, table);
|
||||
VOID(remove_table_from_cache(thd, db, table_name, flags));
|
||||
if (thd->killed)
|
||||
{
|
||||
thd->no_warnings_for_error= 0;
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
Build the path to a file for a table (or the base path that can
|
||||
@@ -317,13 +375,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
if (some_tables_deleted || tmp_table_deleted || !error)
|
||||
{
|
||||
query_cache_invalidate3(thd, tables, 0);
|
||||
if (!dont_log_query && mysql_bin_log.is_open())
|
||||
{
|
||||
if (!error)
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
if (!dont_log_query)
|
||||
write_bin_log(thd, !error);
|
||||
}
|
||||
|
||||
unlock_table_names(thd, tables, (TABLE_LIST*) 0);
|
||||
@@ -1709,12 +1762,8 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
}
|
||||
thd->tmp_table_used= 1;
|
||||
}
|
||||
if (!internal_tmp_table && mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
if (!internal_tmp_table)
|
||||
write_bin_log(thd, TRUE);
|
||||
error= FALSE;
|
||||
|
||||
end:
|
||||
@@ -2784,12 +2833,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
}
|
||||
|
||||
// Must be written before unlock
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
write_bin_log(thd, TRUE);
|
||||
res= FALSE;
|
||||
goto err;
|
||||
|
||||
@@ -2895,11 +2939,7 @@ mysql_discard_or_import_tablespace(THD *thd,
|
||||
error=1;
|
||||
if (error)
|
||||
goto err;
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
write_bin_log(thd, FALSE);
|
||||
err:
|
||||
close_thread_tables(thd);
|
||||
thd->tablespace_op=FALSE;
|
||||
@@ -3301,7 +3341,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
enum db_type old_db_type,new_db_type;
|
||||
uint need_copy_table= 0;
|
||||
#ifdef HAVE_PARTITION_DB
|
||||
bool online_add_empty_partition= FALSE;
|
||||
bool online_drop_partition= FALSE;
|
||||
bool partition_changed= FALSE;
|
||||
enum db_type default_engine_type;
|
||||
#endif
|
||||
DBUG_ENTER("mysql_alter_table");
|
||||
|
||||
@@ -3378,66 +3421,421 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
old_db_type= table->s->db_type;
|
||||
if (create_info->db_type == DB_TYPE_DEFAULT)
|
||||
create_info->db_type= old_db_type;
|
||||
|
||||
#ifdef HAVE_PARTITION_DB
|
||||
/*
|
||||
When thd->lex->part_info has a reference to a partition_info the
|
||||
ALTER TABLE contained a definition of a partitioning.
|
||||
|
||||
Case I:
|
||||
If there was a partition before and there is a new one defined.
|
||||
We use the new partitioning. The new partitioning is already
|
||||
defined in the correct variable so no work is needed to
|
||||
accomplish this.
|
||||
We do however need to update partition_changed to ensure that not
|
||||
only the frm file is changed in the ALTER TABLE command.
|
||||
|
||||
Case IIa:
|
||||
There was a partitioning before and there is no new one defined.
|
||||
Also the user has not specified an explicit engine to use.
|
||||
|
||||
We use the old partitioning also for the new table. We do this
|
||||
by assigning the partition_info from the table loaded in
|
||||
open_ltable to the partition_info struct used by mysql_create_table
|
||||
later in this method.
|
||||
|
||||
Case IIb:
|
||||
There was a partitioning before and there is no new one defined.
|
||||
The user has specified an explicit engine to use.
|
||||
|
||||
Since the user has specified an explicit engine to use we override
|
||||
the old partitioning info and create a new table using the specified
|
||||
engine. This is the reason for the extra check if old and new engine
|
||||
is equal.
|
||||
In this case the partition also is changed.
|
||||
|
||||
Case III:
|
||||
There was no partitioning before altering the table, there is
|
||||
partitioning defined in the altered table. Use the new partitioning.
|
||||
No work needed since the partitioning info is already in the
|
||||
correct variable.
|
||||
Also here partition has changed and thus a new table must be
|
||||
created.
|
||||
|
||||
Case IV:
|
||||
There was no partitioning before and no partitioning defined. Obviously
|
||||
no work needed.
|
||||
*/
|
||||
if (table->s->part_info)
|
||||
We need to handle both partition management command such as Add Partition
|
||||
and others here as well as an ALTER TABLE that completely changes the
|
||||
partitioning and yet others that don't change anything at all. We start
|
||||
by checking the partition management variants and then check the general
|
||||
change patterns.
|
||||
*/
|
||||
if (alter_info->flags & (ALTER_ADD_PARTITION +
|
||||
ALTER_DROP_PARTITION + ALTER_COALESCE_PARTITION +
|
||||
ALTER_REORGANISE_PARTITION))
|
||||
{
|
||||
if (!thd->lex->part_info &&
|
||||
create_info->db_type == old_db_type)
|
||||
thd->lex->part_info= table->s->part_info;
|
||||
partition_info *tab_part_info= table->s->part_info;
|
||||
if (!tab_part_info)
|
||||
{
|
||||
my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
{
|
||||
List_iterator<partition_element> t_it(tab_part_info->partitions);
|
||||
partition_element *t_part_elem= t_it++;
|
||||
if (is_sub_partitioned(tab_part_info))
|
||||
{
|
||||
List_iterator<partition_element> s_it(t_part_elem->subpartitions);
|
||||
t_part_elem= s_it++;
|
||||
}
|
||||
default_engine_type= t_part_elem->engine_type;
|
||||
}
|
||||
/*
|
||||
We are going to manipulate the partition info on the table object
|
||||
so we need to ensure that the data structure of the table object
|
||||
is freed by setting version to 0.
|
||||
*/
|
||||
table->s->version= 0L;
|
||||
if (alter_info->flags == ALTER_ADD_PARTITION)
|
||||
{
|
||||
/*
|
||||
We start by moving the new partitions to the list of temporary
|
||||
partitions. We will then check that the new partitions fit in the
|
||||
partitioning scheme as currently set-up.
|
||||
Partitions are always added at the end in ADD PARTITION.
|
||||
*/
|
||||
partition_info *alt_part_info= thd->lex->part_info;
|
||||
uint no_new_partitions= alt_part_info->no_parts;
|
||||
uint no_orig_partitions= tab_part_info->no_parts;
|
||||
uint check_total_partitions= no_new_partitions + no_orig_partitions;
|
||||
uint new_total_partitions= check_total_partitions;
|
||||
/*
|
||||
We allow quite a lot of values to be supplied by defaults, however we
|
||||
must know the number of new partitions in this case.
|
||||
*/
|
||||
if (no_new_partitions == 0)
|
||||
{
|
||||
my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (is_sub_partitioned(tab_part_info))
|
||||
{
|
||||
if (alt_part_info->no_subparts == 0)
|
||||
alt_part_info->no_subparts= tab_part_info->no_subparts;
|
||||
else if (alt_part_info->no_subparts != tab_part_info->no_subparts)
|
||||
{
|
||||
my_error(ER_ADD_PARTITION_SUBPART_ERROR, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
check_total_partitions= new_total_partitions*
|
||||
alt_part_info->no_subparts;
|
||||
}
|
||||
if (check_total_partitions > MAX_PARTITIONS)
|
||||
{
|
||||
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
alt_part_info->part_type= tab_part_info->part_type;
|
||||
if (set_up_defaults_for_partitioning(alt_part_info,
|
||||
table->file,
|
||||
(ulonglong)0ULL,
|
||||
tab_part_info->no_parts))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
/*
|
||||
Need to concatenate the lists here to make it possible to check the
|
||||
partition info for correctness using check_partition_info
|
||||
*/
|
||||
{
|
||||
List_iterator<partition_element> alt_it(alt_part_info->partitions);
|
||||
uint part_count= 0;
|
||||
do
|
||||
{
|
||||
partition_element *part_elem= alt_it++;
|
||||
tab_part_info->partitions.push_back(part_elem);
|
||||
tab_part_info->temp_partitions.push_back(part_elem);
|
||||
} while (++part_count < no_new_partitions);
|
||||
tab_part_info->no_parts+= no_new_partitions;
|
||||
}
|
||||
{
|
||||
List_iterator<partition_element> tab_it(tab_part_info->partitions);
|
||||
partition_element *part_elem= tab_it++;
|
||||
if (is_sub_partitioned(tab_part_info))
|
||||
{
|
||||
List_iterator<partition_element> sub_it(part_elem->subpartitions);
|
||||
part_elem= sub_it++;
|
||||
}
|
||||
if (check_partition_info(tab_part_info, part_elem->engine_type,
|
||||
table->file, (ulonglong)0ULL))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
create_info->db_type= DB_TYPE_PARTITION_DB;
|
||||
thd->lex->part_info= tab_part_info;
|
||||
if (table->file->alter_table_flags() & HA_ONLINE_ADD_EMPTY_PARTITION &&
|
||||
(tab_part_info->part_type == RANGE_PARTITION ||
|
||||
tab_part_info->part_type == LIST_PARTITION))
|
||||
{
|
||||
/*
|
||||
For range and list partitions add partition is simply adding a new
|
||||
empty partition to the table. If the handler support this we will
|
||||
use the simple method of doing this. In this case we need to break
|
||||
out the new partitions from the list again and only keep them in the
|
||||
temporary list. Added partitions are always added at the end.
|
||||
*/
|
||||
{
|
||||
List_iterator<partition_element> tab_it(tab_part_info->partitions);
|
||||
uint part_count= 0;
|
||||
do
|
||||
{
|
||||
tab_it++;
|
||||
} while (++part_count < no_orig_partitions);
|
||||
do
|
||||
{
|
||||
tab_it++;
|
||||
tab_it.remove();
|
||||
} while (++part_count < new_total_partitions);
|
||||
}
|
||||
tab_part_info->no_parts-= no_new_partitions;
|
||||
online_add_empty_partition= TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
tab_part_info->temp_partitions.empty();
|
||||
}
|
||||
}
|
||||
else if (alter_info->flags == ALTER_DROP_PARTITION)
|
||||
{
|
||||
/*
|
||||
Drop a partition from a range partition and list partitioning is
|
||||
always safe and can be made more or less immediate. It is necessary
|
||||
however to ensure that the partition to be removed is safely removed
|
||||
and that REPAIR TABLE can remove the partition if for some reason the
|
||||
command to drop the partition failed in the middle.
|
||||
*/
|
||||
uint part_count= 0;
|
||||
uint no_parts_dropped= alter_info->partition_names.elements;
|
||||
uint no_parts_found= 0;
|
||||
List_iterator<partition_element> part_it(tab_part_info->partitions);
|
||||
if (!(tab_part_info->part_type == RANGE_PARTITION ||
|
||||
tab_part_info->part_type == LIST_PARTITION))
|
||||
{
|
||||
my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "DROP");
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (no_parts_dropped >= tab_part_info->no_parts)
|
||||
{
|
||||
my_error(ER_DROP_LAST_PARTITION, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
do
|
||||
{
|
||||
partition_element *part_elem= part_it++;
|
||||
if (is_partition_in_list(part_elem->partition_name,
|
||||
alter_info->partition_names))
|
||||
{
|
||||
/*
|
||||
Remove the partition from the list and put it instead in the
|
||||
list of temporary partitions with a new state.
|
||||
*/
|
||||
no_parts_found++;
|
||||
part_elem->part_state= PART_IS_DROPPED;
|
||||
}
|
||||
} while (++part_count < tab_part_info->no_parts);
|
||||
if (no_parts_found != no_parts_dropped)
|
||||
{
|
||||
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (!(table->file->alter_table_flags() & HA_ONLINE_DROP_PARTITION))
|
||||
{
|
||||
my_error(ER_DROP_PARTITION_FAILURE, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (table->file->is_fk_defined_on_table_or_index(MAX_KEY))
|
||||
{
|
||||
my_error(ER_DROP_PARTITION_WHEN_FK_DEFINED, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
/*
|
||||
This code needs set-up of structures needed by mysql_create_table
|
||||
before it is called and thus we only set a boolean variable to be
|
||||
checked later down in the code when all needed data structures are
|
||||
prepared.
|
||||
*/
|
||||
online_drop_partition= TRUE;
|
||||
}
|
||||
else if (alter_info->flags == ALTER_COALESCE_PARTITION)
|
||||
{
|
||||
/*
|
||||
In this version COALESCE PARTITION is implemented by simply removing
|
||||
a partition from the table and using the normal ALTER TABLE code
|
||||
and ensuring that copy to a new table occurs. Later on we can optimise
|
||||
this function for Linear Hash partitions. In that case we can avoid
|
||||
reorganising the entire table. For normal hash partitions it will
|
||||
be a complete reorganise anyways so that can only be made on-line
|
||||
if it still uses a copy table.
|
||||
*/
|
||||
uint part_count= 0;
|
||||
uint no_parts_coalesced= alter_info->no_parts;
|
||||
uint no_parts_remain= tab_part_info->no_parts - no_parts_coalesced;
|
||||
List_iterator<partition_element> part_it(tab_part_info->partitions);
|
||||
if (tab_part_info->part_type != HASH_PARTITION)
|
||||
{
|
||||
my_error(ER_COALESCE_ONLY_ON_HASH_PARTITION, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (no_parts_coalesced == 0)
|
||||
{
|
||||
my_error(ER_COALESCE_PARTITION_NO_PARTITION, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (no_parts_coalesced >= tab_part_info->no_parts)
|
||||
{
|
||||
my_error(ER_DROP_LAST_PARTITION, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
do
|
||||
{
|
||||
part_it++;
|
||||
if (++part_count > no_parts_remain)
|
||||
part_it.remove();
|
||||
} while (part_count < tab_part_info->no_parts);
|
||||
tab_part_info->no_parts= no_parts_remain;
|
||||
}
|
||||
else if (alter_info->flags == ALTER_REORGANISE_PARTITION)
|
||||
{
|
||||
/*
|
||||
Reorganise partitions takes a number of partitions that are next
|
||||
to each other (at least for RANGE PARTITIONS) and then uses those
|
||||
to create a set of new partitions. So data is copied from those
|
||||
partitions into the new set of partitions. Those new partitions
|
||||
can have more values in the LIST value specifications or less both
|
||||
are allowed. The ranges can be different but since they are
|
||||
changing a set of consecutive partitions they must cover the same
|
||||
range as those changed from.
|
||||
This command can be used on RANGE and LIST partitions.
|
||||
*/
|
||||
uint no_parts_reorged= alter_info->partition_names.elements;
|
||||
uint no_parts_new= thd->lex->part_info->partitions.elements;
|
||||
partition_info *alt_part_info= thd->lex->part_info;
|
||||
uint check_total_partitions;
|
||||
if (no_parts_reorged > tab_part_info->no_parts)
|
||||
{
|
||||
my_error(ER_REORG_PARTITION_NOT_EXIST, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (!(tab_part_info->part_type == RANGE_PARTITION ||
|
||||
tab_part_info->part_type == LIST_PARTITION))
|
||||
{
|
||||
my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "REORGANISE");
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (is_partitions_in_table(alt_part_info, tab_part_info))
|
||||
{
|
||||
my_error(ER_SAME_NAME_PARTITION, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
check_total_partitions= tab_part_info->no_parts + no_parts_new;
|
||||
check_total_partitions-= no_parts_reorged;
|
||||
if (check_total_partitions > MAX_PARTITIONS)
|
||||
{
|
||||
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
{
|
||||
List_iterator<partition_element> tab_it(tab_part_info->partitions);
|
||||
uint part_count= 0;
|
||||
bool found_first= FALSE, found_last= FALSE;
|
||||
uint drop_count= 0;
|
||||
longlong tab_max_range, alt_max_range;
|
||||
do
|
||||
{
|
||||
partition_element *part_elem= tab_it++;
|
||||
if (is_partition_in_list(part_elem->partition_name,
|
||||
alter_info->partition_names))
|
||||
{
|
||||
drop_count++;
|
||||
tab_max_range= part_elem->range_value;
|
||||
if (!found_first)
|
||||
{
|
||||
uint alt_part_count= 0;
|
||||
found_first= TRUE;
|
||||
List_iterator<partition_element> alt_it(alt_part_info->partitions);
|
||||
do
|
||||
{
|
||||
partition_element *alt_part_elem= alt_it++;
|
||||
alt_max_range= alt_part_elem->range_value;
|
||||
if (alt_part_count == 0)
|
||||
tab_it.replace(alt_part_elem);
|
||||
else
|
||||
tab_it.after(alt_part_elem);
|
||||
} while (++alt_part_count < no_parts_new);
|
||||
}
|
||||
else if (found_last)
|
||||
{
|
||||
my_error(ER_CONSECUTIVE_REORG_PARTITIONS, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
else
|
||||
tab_it.remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found_first)
|
||||
found_last= TRUE;
|
||||
}
|
||||
} while (++part_count < tab_part_info->no_parts);
|
||||
if (drop_count != no_parts_reorged)
|
||||
{
|
||||
my_error(ER_DROP_PARTITION_NON_EXISTENT, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (tab_part_info->part_type == RANGE_PARTITION &&
|
||||
alt_max_range > tab_max_range)
|
||||
{
|
||||
my_error(ER_REORG_OUTSIDE_RANGE, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
partition_changed= TRUE;
|
||||
create_info->db_type= DB_TYPE_PARTITION_DB;
|
||||
thd->lex->part_info= tab_part_info;
|
||||
if (alter_info->flags == ALTER_ADD_PARTITION ||
|
||||
alter_info->flags == ALTER_REORGANISE_PARTITION)
|
||||
{
|
||||
if (check_partition_info(tab_part_info, default_engine_type,
|
||||
table->file, (ulonglong)0ULL))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (thd->lex->part_info)
|
||||
else
|
||||
{
|
||||
/*
|
||||
Need to cater for engine types that can handle partition without
|
||||
using the partition handler.
|
||||
When thd->lex->part_info has a reference to a partition_info the
|
||||
ALTER TABLE contained a definition of a partitioning.
|
||||
|
||||
Case I:
|
||||
If there was a partition before and there is a new one defined.
|
||||
We use the new partitioning. The new partitioning is already
|
||||
defined in the correct variable so no work is needed to
|
||||
accomplish this.
|
||||
We do however need to update partition_changed to ensure that not
|
||||
only the frm file is changed in the ALTER TABLE command.
|
||||
|
||||
Case IIa:
|
||||
There was a partitioning before and there is no new one defined.
|
||||
Also the user has not specified an explicit engine to use.
|
||||
|
||||
We use the old partitioning also for the new table. We do this
|
||||
by assigning the partition_info from the table loaded in
|
||||
open_ltable to the partition_info struct used by mysql_create_table
|
||||
later in this method.
|
||||
|
||||
Case IIb:
|
||||
There was a partitioning before and there is no new one defined.
|
||||
The user has specified an explicit engine to use.
|
||||
|
||||
Since the user has specified an explicit engine to use we override
|
||||
the old partitioning info and create a new table using the specified
|
||||
engine. This is the reason for the extra check if old and new engine
|
||||
is equal.
|
||||
In this case the partition also is changed.
|
||||
|
||||
Case III:
|
||||
There was no partitioning before altering the table, there is
|
||||
partitioning defined in the altered table. Use the new partitioning.
|
||||
No work needed since the partitioning info is already in the
|
||||
correct variable.
|
||||
Also here partition has changed and thus a new table must be
|
||||
created.
|
||||
|
||||
Case IV:
|
||||
There was no partitioning before and no partitioning defined.
|
||||
Obviously no work needed.
|
||||
*/
|
||||
if (thd->lex->part_info != table->s->part_info)
|
||||
partition_changed= TRUE;
|
||||
thd->lex->part_info->default_engine_type= create_info->db_type;
|
||||
create_info->db_type= DB_TYPE_PARTITION_DB;
|
||||
if (table->s->part_info)
|
||||
{
|
||||
if (!thd->lex->part_info &&
|
||||
create_info->db_type == old_db_type)
|
||||
thd->lex->part_info= table->s->part_info;
|
||||
}
|
||||
if (thd->lex->part_info)
|
||||
{
|
||||
/*
|
||||
Need to cater for engine types that can handle partition without
|
||||
using the partition handler.
|
||||
*/
|
||||
if (thd->lex->part_info != table->s->part_info)
|
||||
partition_changed= TRUE;
|
||||
thd->lex->part_info->default_engine_type= create_info->db_type;
|
||||
create_info->db_type= DB_TYPE_PARTITION_DB;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (check_engine(thd, new_name, &create_info->db_type))
|
||||
@@ -3503,12 +3901,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
}
|
||||
if (!error)
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
write_bin_log(thd, TRUE);
|
||||
if (do_send_ok)
|
||||
send_ok(thd);
|
||||
}
|
||||
@@ -3824,6 +4217,100 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
if (!need_copy_table)
|
||||
create_info->frm_only= 1;
|
||||
|
||||
if (partition_changed)
|
||||
{
|
||||
if (online_drop_partition)
|
||||
{
|
||||
/*
|
||||
Now after all checks and setting state on dropped partitions we can
|
||||
start the actual dropping of the partitions.
|
||||
1) Lock table in TL_WRITE_ONLY to ensure all other accesses on table
|
||||
are completed and no new ones are started until we have changed
|
||||
the frm file.
|
||||
2) Write the new frm file where state of dropped partitions is
|
||||
changed to PART_IS_DROPPED
|
||||
3) Perform the actual drop of the partition using the handler of the
|
||||
table.
|
||||
4) Write a new frm file of the table where the partitions are dropped
|
||||
from the table.
|
||||
|
||||
*/
|
||||
uint old_lock_type;
|
||||
partition_info *part_info= table->s->part_info;
|
||||
char path[FN_REFLEN+1];
|
||||
uint db_options= 0, key_count, syntax_len;
|
||||
KEY *key_info_buffer;
|
||||
char *part_syntax_buf;
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (abort_and_upgrade_lock(thd, table, db, table_name, &old_lock_type))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
mysql_prepare_table(thd, create_info, &create_list,
|
||||
&key_list, /*tmp_table*/ 0, &db_options,
|
||||
table->file, &key_info_buffer, &key_count,
|
||||
/*select_field_count*/ 0);
|
||||
if (!(part_syntax_buf= generate_partition_syntax(part_info,
|
||||
&syntax_len,
|
||||
TRUE)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
part_info->part_info_string= part_syntax_buf;
|
||||
part_info->part_info_len= syntax_len;
|
||||
build_table_path(path, sizeof(path), db, table_name, reg_ext);
|
||||
if (mysql_create_frm(thd, path, db, table_name, create_info,
|
||||
create_list, key_count, key_info_buffer,
|
||||
table->file))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
thd->lex->part_info= part_info;
|
||||
build_table_path(path, sizeof(path), db, table_name, "");
|
||||
if (table->file->drop_partitions(path))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
{
|
||||
List_iterator<partition_element> part_it(part_info->partitions);
|
||||
uint i= 0, remove_count= 0;
|
||||
do
|
||||
{
|
||||
partition_element *part_elem= part_it++;
|
||||
if (is_partition_in_list(part_elem->partition_name,
|
||||
alter_info->partition_names))
|
||||
{
|
||||
part_it.remove();
|
||||
remove_count++;
|
||||
}
|
||||
} while (++i < part_info->no_parts);
|
||||
part_info->no_parts-= remove_count;
|
||||
}
|
||||
if (!(part_syntax_buf= generate_partition_syntax(part_info,
|
||||
&syntax_len,
|
||||
TRUE)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
part_info->part_info_string= part_syntax_buf;
|
||||
part_info->part_info_len= syntax_len;
|
||||
build_table_path(path, sizeof(path), db, table_name, reg_ext);
|
||||
if (mysql_create_frm(thd, path, db, table_name, create_info,
|
||||
create_list, key_count, key_info_buffer,
|
||||
table->file) ||
|
||||
table->file->create_handler_files(path))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
thd->proc_info="end";
|
||||
write_bin_log(thd, FALSE);
|
||||
send_ok(thd);
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Handling of symlinked tables:
|
||||
If no rename:
|
||||
@@ -3949,12 +4436,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
my_free((gptr) new_table,MYF(0));
|
||||
goto err;
|
||||
}
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
write_bin_log(thd, TRUE);
|
||||
goto end_temporary;
|
||||
}
|
||||
|
||||
@@ -4085,15 +4567,14 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
goto err;
|
||||
}
|
||||
thd->proc_info="end";
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, FALSE, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
write_bin_log(thd, TRUE);
|
||||
VOID(pthread_cond_broadcast(&COND_refresh));
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
#ifdef HAVE_BERKELEY_DB
|
||||
/*
|
||||
TODO RONM: This problem needs to handled for Berkeley DB partitions
|
||||
as well
|
||||
*/
|
||||
if (old_db_type == DB_TYPE_BERKELEY_DB)
|
||||
{
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user