BUG#15408: Partitions: subpartition names are not unique
Also, moved some of the code out of handler.h and into partition specific files for better separation. Also, moved some of the C funcs into partition_info as formal C++ methods mysql-test/r/partition_mgm_err.result: result block for test of bug # 15408 mysql-test/t/partition_mgm_err.test: test for duplicate subpartition names sql/Makefile.am: adding sql_partition.h, partition_info.cpp, partition_info.h, and partition_element.h to the makefile sql/ha_partition.cc: using the new members of partition_info sql/ha_partition.h: using the new members of partition_info sql/handler.h: moved this code into sql_partition.h sql/mysql_priv.h: including sql_partition.h also now sql/opt_range.cc: using the new members of partition_info sql/sql_partition.cc: moved some of the functions out and into the partition_info class using the new members of partition_info sql/sql_show.cc: using the new members of partition_info win/cmakefiles/sql: added partition_info.cpp to the sql cmake file sql/partition_element.h: New BitKeeper file ``sql/partition_element.h'' sql/partition_info.h: New BitKeeper file ``sql/partition_info.h'' sql/sql_partition.h: New BitKeeper file ``sql/sql_partition.h''
This commit is contained in:
parent
99526f2efb
commit
d047fe77b7
@ -142,3 +142,8 @@ t1 CREATE TABLE `t1` (
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
CREATE TABLE t1 (a INT) PARTITION BY HASH(a);
|
CREATE TABLE t1 (a INT) PARTITION BY HASH(a);
|
||||||
ALTER TABLE t1 ADD PARTITION PARTITIONS 4;
|
ALTER TABLE t1 ADD PARTITION PARTITIONS 4;
|
||||||
|
CREATE TABLE t1 (s1 int, s2 int) PARTITION BY LIST (s1) (
|
||||||
|
PARTITION p1 VALUES IN (0) (SUBPARTITION p1b),
|
||||||
|
PARTITION p2 VALUES IN (2) (SUBPARTITION p1b)
|
||||||
|
);
|
||||||
|
ERROR HY000: Duplicate partition name p1b
|
||||||
|
@ -216,3 +216,12 @@ DROP TABLE t1;
|
|||||||
#
|
#
|
||||||
CREATE TABLE t1 (a INT) PARTITION BY HASH(a);
|
CREATE TABLE t1 (a INT) PARTITION BY HASH(a);
|
||||||
ALTER TABLE t1 ADD PARTITION PARTITIONS 4;
|
ALTER TABLE t1 ADD PARTITION PARTITIONS 4;
|
||||||
|
|
||||||
|
#
|
||||||
|
#BUG 15408: Partitions: subpartition names are not unique
|
||||||
|
#
|
||||||
|
--error ER_SAME_NAME_PARTITION
|
||||||
|
CREATE TABLE t1 (s1 int, s2 int) PARTITION BY LIST (s1) (
|
||||||
|
PARTITION p1 VALUES IN (0) (SUBPARTITION p1b),
|
||||||
|
PARTITION p2 VALUES IN (2) (SUBPARTITION p1b)
|
||||||
|
);
|
||||||
|
@ -65,7 +65,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||||||
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
|
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
|
||||||
parse_file.h sql_view.h sql_trigger.h \
|
parse_file.h sql_view.h sql_trigger.h \
|
||||||
sql_array.h sql_cursor.h event.h event_priv.h \
|
sql_array.h sql_cursor.h event.h event_priv.h \
|
||||||
sql_plugin.h authors.h
|
sql_plugin.h authors.h sql_partition.h partition_info.h partition_element.h
|
||||||
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
||||||
item.cc item_sum.cc item_buff.cc item_func.cc \
|
item.cc item_sum.cc item_buff.cc item_func.cc \
|
||||||
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
|
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
|
||||||
@ -101,7 +101,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
|||||||
sp_cache.cc parse_file.cc sql_trigger.cc \
|
sp_cache.cc parse_file.cc sql_trigger.cc \
|
||||||
event_executor.cc event.cc event_timed.cc \
|
event_executor.cc event.cc event_timed.cc \
|
||||||
sql_plugin.cc sql_binlog.cc \
|
sql_plugin.cc sql_binlog.cc \
|
||||||
handlerton.cc sql_tablespace.cc
|
handlerton.cc sql_tablespace.cc partition_info.cpp
|
||||||
EXTRA_mysqld_SOURCES = ha_innodb.cc ha_berkeley.cc ha_archive.cc \
|
EXTRA_mysqld_SOURCES = ha_innodb.cc ha_berkeley.cc ha_archive.cc \
|
||||||
ha_innodb.h ha_berkeley.h ha_archive.h \
|
ha_innodb.h ha_berkeley.h ha_archive.h \
|
||||||
ha_blackhole.cc ha_federated.cc ha_ndbcluster.cc \
|
ha_blackhole.cc ha_federated.cc ha_ndbcluster.cc \
|
||||||
|
@ -186,7 +186,7 @@ ha_partition::ha_partition(TABLE_SHARE *share)
|
|||||||
ha_partition::ha_partition(partition_info *part_info)
|
ha_partition::ha_partition(partition_info *part_info)
|
||||||
:handler(&partition_hton, NULL), m_part_info(part_info),
|
:handler(&partition_hton, NULL), m_part_info(part_info),
|
||||||
m_create_handler(TRUE),
|
m_create_handler(TRUE),
|
||||||
m_is_sub_partitioned(is_sub_partitioned(m_part_info))
|
m_is_sub_partitioned(m_part_info->is_sub_partitioned())
|
||||||
|
|
||||||
{
|
{
|
||||||
DBUG_ENTER("ha_partition::ha_partition(part_info)");
|
DBUG_ENTER("ha_partition::ha_partition(part_info)");
|
||||||
@ -331,7 +331,7 @@ int ha_partition::ha_initialise()
|
|||||||
|
|
||||||
if (m_create_handler)
|
if (m_create_handler)
|
||||||
{
|
{
|
||||||
m_tot_parts= get_tot_partitions(m_part_info);
|
m_tot_parts= m_part_info->get_tot_partitions();
|
||||||
DBUG_ASSERT(m_tot_parts > 0);
|
DBUG_ASSERT(m_tot_parts > 0);
|
||||||
if (new_handlers_from_part_info())
|
if (new_handlers_from_part_info())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
@ -1290,7 +1290,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
|
|||||||
DBUG_ENTER("ha_partition::change_partitions");
|
DBUG_ENTER("ha_partition::change_partitions");
|
||||||
|
|
||||||
m_reorged_parts= 0;
|
m_reorged_parts= 0;
|
||||||
if (!is_sub_partitioned(m_part_info))
|
if (!m_part_info->is_sub_partitioned())
|
||||||
no_subparts= 1;
|
no_subparts= 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1453,7 +1453,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
|
|||||||
if (part_elem->part_state == PART_CHANGED ||
|
if (part_elem->part_state == PART_CHANGED ||
|
||||||
(part_elem->part_state == PART_TO_BE_ADDED && temp_partitions))
|
(part_elem->part_state == PART_TO_BE_ADDED && temp_partitions))
|
||||||
name_variant= TEMP_PART_NAME;
|
name_variant= TEMP_PART_NAME;
|
||||||
if (is_sub_partitioned(m_part_info))
|
if (m_part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
List_iterator<partition_element> sub_it(part_elem->subpartitions);
|
List_iterator<partition_element> sub_it(part_elem->subpartitions);
|
||||||
uint j= 0, part;
|
uint j= 0, part;
|
||||||
|
@ -135,7 +135,7 @@ public:
|
|||||||
virtual void set_part_info(partition_info *part_info)
|
virtual void set_part_info(partition_info *part_info)
|
||||||
{
|
{
|
||||||
m_part_info= part_info;
|
m_part_info= part_info;
|
||||||
m_is_sub_partitioned= is_sub_partitioned(part_info);
|
m_is_sub_partitioned= part_info->is_sub_partitioned();
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
-------------------------------------------------------------------------
|
-------------------------------------------------------------------------
|
||||||
|
496
sql/handler.h
496
sql/handler.h
@ -95,13 +95,6 @@
|
|||||||
#define HA_ANY_INDEX_MAY_BE_UNIQUE (1 << 30)
|
#define HA_ANY_INDEX_MAY_BE_UNIQUE (1 << 30)
|
||||||
#define HA_NO_COPY_ON_ALTER (1 << 31)
|
#define HA_NO_COPY_ON_ALTER (1 << 31)
|
||||||
|
|
||||||
/* Flags for partition handlers */
|
|
||||||
#define HA_CAN_PARTITION (1 << 0) /* Partition support */
|
|
||||||
#define HA_CAN_UPDATE_PARTITION_KEY (1 << 1)
|
|
||||||
#define HA_CAN_PARTITION_UNIQUE (1 << 2)
|
|
||||||
#define HA_USE_AUTO_PARTITION (1 << 3)
|
|
||||||
|
|
||||||
|
|
||||||
/* bits in index_flags(index_number) for what you can do with index */
|
/* bits in index_flags(index_number) for what you can do with index */
|
||||||
#define HA_READ_NEXT 1 /* TODO really use this flag */
|
#define HA_READ_NEXT 1 /* TODO really use this flag */
|
||||||
#define HA_READ_PREV 2 /* supports ::index_prev */
|
#define HA_READ_PREV 2 /* supports ::index_prev */
|
||||||
@ -134,34 +127,6 @@
|
|||||||
#define HA_ONLINE_DROP_UNIQUE_INDEX (1L << 9) /*drop uniq. online*/
|
#define HA_ONLINE_DROP_UNIQUE_INDEX (1L << 9) /*drop uniq. online*/
|
||||||
#define HA_ONLINE_ADD_PK_INDEX (1L << 10)/*add prim. online*/
|
#define HA_ONLINE_ADD_PK_INDEX (1L << 10)/*add prim. online*/
|
||||||
#define HA_ONLINE_DROP_PK_INDEX (1L << 11)/*drop prim. online*/
|
#define HA_ONLINE_DROP_PK_INDEX (1L << 11)/*drop prim. online*/
|
||||||
/*
|
|
||||||
HA_PARTITION_FUNCTION_SUPPORTED indicates that the function is
|
|
||||||
supported at all.
|
|
||||||
HA_FAST_CHANGE_PARTITION means that optimised variants of the changes
|
|
||||||
exists but they are not necessarily done online.
|
|
||||||
|
|
||||||
HA_ONLINE_DOUBLE_WRITE means that the handler supports writing to both
|
|
||||||
the new partition and to the old partitions when updating through the
|
|
||||||
old partitioning schema while performing a change of the partitioning.
|
|
||||||
This means that we can support updating of the table while performing
|
|
||||||
the copy phase of the change. For no lock at all also a double write
|
|
||||||
from new to old must exist and this is not required when this flag is
|
|
||||||
set.
|
|
||||||
This is actually removed even before it was introduced the first time.
|
|
||||||
The new idea is that handlers will handle the lock level already in
|
|
||||||
store_lock for ALTER TABLE partitions.
|
|
||||||
|
|
||||||
HA_PARTITION_ONE_PHASE is a flag that can be set by handlers that take
|
|
||||||
care of changing the partitions online and in one phase. Thus all phases
|
|
||||||
needed to handle the change are implemented inside the storage engine.
|
|
||||||
The storage engine must also support auto-discovery since the frm file
|
|
||||||
is changed as part of the change and this change must be controlled by
|
|
||||||
the storage engine. A typical engine to support this is NDB (through
|
|
||||||
WL #2498).
|
|
||||||
*/
|
|
||||||
#define HA_PARTITION_FUNCTION_SUPPORTED (1L << 12)
|
|
||||||
#define HA_FAST_CHANGE_PARTITION (1L << 13)
|
|
||||||
#define HA_PARTITION_ONE_PHASE (1L << 14)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Index scan will not return records in rowid order. Not guaranteed to be
|
Index scan will not return records in rowid order. Not guaranteed to be
|
||||||
@ -618,33 +583,6 @@ enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
|
|||||||
|
|
||||||
enum ndb_distribution { ND_KEYHASH= 0, ND_LINHASH= 1 };
|
enum ndb_distribution { ND_KEYHASH= 0, ND_LINHASH= 1 };
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32 start_part;
|
|
||||||
uint32 end_part;
|
|
||||||
} part_id_range;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An enum and a struct to handle partitioning and subpartitioning.
|
|
||||||
*/
|
|
||||||
enum partition_type {
|
|
||||||
NOT_A_PARTITION= 0,
|
|
||||||
RANGE_PARTITION,
|
|
||||||
HASH_PARTITION,
|
|
||||||
LIST_PARTITION
|
|
||||||
};
|
|
||||||
|
|
||||||
enum partition_state {
|
|
||||||
PART_NORMAL= 0,
|
|
||||||
PART_IS_DROPPED= 1,
|
|
||||||
PART_TO_BE_DROPPED= 2,
|
|
||||||
PART_TO_BE_ADDED= 3,
|
|
||||||
PART_TO_BE_REORGED= 4,
|
|
||||||
PART_REORGED_DROPPED= 5,
|
|
||||||
PART_CHANGED= 6,
|
|
||||||
PART_IS_CHANGED= 7,
|
|
||||||
PART_IS_ADDED= 8
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ulonglong data_file_length;
|
ulonglong data_file_length;
|
||||||
@ -662,400 +600,12 @@ typedef struct {
|
|||||||
#define UNDEF_NODEGROUP 65535
|
#define UNDEF_NODEGROUP 65535
|
||||||
class Item;
|
class Item;
|
||||||
|
|
||||||
class partition_element :public Sql_alloc {
|
|
||||||
public:
|
|
||||||
List<partition_element> subpartitions;
|
|
||||||
List<longlong> list_val_list;
|
|
||||||
ulonglong part_max_rows;
|
|
||||||
ulonglong part_min_rows;
|
|
||||||
char *partition_name;
|
|
||||||
char *tablespace_name;
|
|
||||||
longlong range_value;
|
|
||||||
char* part_comment;
|
|
||||||
char* data_file_name;
|
|
||||||
char* index_file_name;
|
|
||||||
handlerton *engine_type;
|
|
||||||
enum partition_state part_state;
|
|
||||||
uint16 nodegroup_id;
|
|
||||||
|
|
||||||
partition_element()
|
|
||||||
: part_max_rows(0), part_min_rows(0), partition_name(NULL),
|
|
||||||
tablespace_name(NULL), range_value(0), part_comment(NULL),
|
|
||||||
data_file_name(NULL), index_file_name(NULL),
|
|
||||||
engine_type(NULL),part_state(PART_NORMAL),
|
|
||||||
nodegroup_id(UNDEF_NODEGROUP)
|
|
||||||
{
|
|
||||||
subpartitions.empty();
|
|
||||||
list_val_list.empty();
|
|
||||||
}
|
|
||||||
~partition_element() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
longlong list_value;
|
|
||||||
uint32 partition_id;
|
|
||||||
} LIST_PART_ENTRY;
|
|
||||||
|
|
||||||
class partition_info;
|
class partition_info;
|
||||||
|
|
||||||
typedef int (*get_part_id_func)(partition_info *part_info,
|
|
||||||
uint32 *part_id,
|
|
||||||
longlong *func_value);
|
|
||||||
typedef uint32 (*get_subpart_id_func)(partition_info *part_info);
|
|
||||||
|
|
||||||
|
|
||||||
struct st_partition_iter;
|
struct st_partition_iter;
|
||||||
#define NOT_A_PARTITION_ID ((uint32)-1)
|
#define NOT_A_PARTITION_ID ((uint32)-1)
|
||||||
|
|
||||||
/*
|
|
||||||
A "Get next" function for partition iterator.
|
|
||||||
SYNOPSIS
|
|
||||||
partition_iter_func()
|
|
||||||
part_iter Partition iterator, you call only "iter.get_next(&iter)"
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
NOT_A_PARTITION_ID if there are no more partitions.
|
|
||||||
[sub]partition_id of the next partition
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef uint32 (*partition_iter_func)(st_partition_iter* part_iter);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Partition set iterator. Used to enumerate a set of [sub]partitions
|
|
||||||
obtained in partition interval analysis (see get_partitions_in_range_iter).
|
|
||||||
|
|
||||||
For the user, the only meaningful field is get_next, which may be used as
|
|
||||||
follows:
|
|
||||||
part_iterator.get_next(&part_iterator);
|
|
||||||
|
|
||||||
Initialization is done by any of the following calls:
|
|
||||||
- get_partitions_in_range_iter-type function call
|
|
||||||
- init_single_partition_iterator()
|
|
||||||
- init_all_partitions_iterator()
|
|
||||||
Cleanup is not needed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct st_partition_iter
|
|
||||||
{
|
|
||||||
partition_iter_func get_next;
|
|
||||||
|
|
||||||
struct st_part_num_range
|
|
||||||
{
|
|
||||||
uint32 start;
|
|
||||||
uint32 end;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct st_field_value_range
|
|
||||||
{
|
|
||||||
longlong start;
|
|
||||||
longlong end;
|
|
||||||
};
|
|
||||||
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct st_part_num_range part_nums;
|
|
||||||
struct st_field_value_range field_vals;
|
|
||||||
};
|
|
||||||
partition_info *part_info;
|
|
||||||
} PARTITION_ITERATOR;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get an iterator for set of partitions that match given field-space interval
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
get_partitions_in_range_iter()
|
|
||||||
part_info Partitioning info
|
|
||||||
is_subpart
|
|
||||||
min_val Left edge, field value in opt_range_key format.
|
|
||||||
max_val Right edge, field value in opt_range_key format.
|
|
||||||
flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
|
|
||||||
NO_MAX_RANGE.
|
|
||||||
part_iter Iterator structure to be initialized
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Functions with this signature are used to perform "Partitioning Interval
|
|
||||||
Analysis". This analysis is applicable for any type of [sub]partitioning
|
|
||||||
by some function of a single fieldX. The idea is as follows:
|
|
||||||
Given an interval "const1 <=? fieldX <=? const2", find a set of partitions
|
|
||||||
that may contain records with value of fieldX within the given interval.
|
|
||||||
|
|
||||||
The min_val, max_val and flags parameters specify the interval.
|
|
||||||
The set of partitions is returned by initializing an iterator in *part_iter
|
|
||||||
|
|
||||||
NOTES
|
|
||||||
There are currently two functions of this type:
|
|
||||||
- get_part_iter_for_interval_via_walking
|
|
||||||
- get_part_iter_for_interval_via_mapping
|
|
||||||
|
|
||||||
RETURN
|
|
||||||
0 - No matching partitions, iterator not initialized
|
|
||||||
1 - Some partitions would match, iterator intialized for traversing them
|
|
||||||
-1 - All partitions would match, iterator not initialized
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
|
|
||||||
bool is_subpart,
|
|
||||||
char *min_val, char *max_val,
|
|
||||||
uint flags,
|
|
||||||
PARTITION_ITERATOR *part_iter);
|
|
||||||
|
|
||||||
|
|
||||||
class partition_info : public Sql_alloc
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/*
|
|
||||||
* Here comes a set of definitions needed for partitioned table handlers.
|
|
||||||
*/
|
|
||||||
List<partition_element> partitions;
|
|
||||||
List<partition_element> temp_partitions;
|
|
||||||
|
|
||||||
List<char> part_field_list;
|
|
||||||
List<char> subpart_field_list;
|
|
||||||
|
|
||||||
/*
|
|
||||||
If there is no subpartitioning, use only this func to get partition ids.
|
|
||||||
If there is subpartitioning, use the this func to get partition id when
|
|
||||||
you have both partition and subpartition fields.
|
|
||||||
*/
|
|
||||||
get_part_id_func get_partition_id;
|
|
||||||
|
|
||||||
/* Get partition id when we don't have subpartition fields */
|
|
||||||
get_part_id_func get_part_partition_id;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get subpartition id when we have don't have partition fields by we do
|
|
||||||
have subpartition ids.
|
|
||||||
Mikael said that for given constant tuple
|
|
||||||
{subpart_field1, ..., subpart_fieldN} the subpartition id will be the
|
|
||||||
same in all subpartitions
|
|
||||||
*/
|
|
||||||
get_subpart_id_func get_subpartition_id;
|
|
||||||
|
|
||||||
/* NULL-terminated array of fields used in partitioned expression */
|
|
||||||
Field **part_field_array;
|
|
||||||
/* NULL-terminated array of fields used in subpartitioned expression */
|
|
||||||
Field **subpart_field_array;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Array of all fields used in partition and subpartition expression,
|
|
||||||
without duplicates, NULL-terminated.
|
|
||||||
*/
|
|
||||||
Field **full_part_field_array;
|
|
||||||
|
|
||||||
Item *part_expr;
|
|
||||||
Item *subpart_expr;
|
|
||||||
|
|
||||||
Item *item_free_list;
|
|
||||||
|
|
||||||
/*
|
|
||||||
A bitmap of partitions used by the current query.
|
|
||||||
Usage pattern:
|
|
||||||
* The handler->extra(HA_EXTRA_RESET) call at query start/end sets all
|
|
||||||
partitions to be unused.
|
|
||||||
* Before index/rnd_init(), partition pruning code sets the bits for used
|
|
||||||
partitions.
|
|
||||||
*/
|
|
||||||
MY_BITMAP used_partitions;
|
|
||||||
|
|
||||||
union {
|
|
||||||
longlong *range_int_array;
|
|
||||||
LIST_PART_ENTRY *list_array;
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************************************
|
|
||||||
* INTERVAL ANALYSIS
|
|
||||||
********************************************/
|
|
||||||
/*
|
|
||||||
Partitioning interval analysis function for partitioning, or NULL if
|
|
||||||
interval analysis is not supported for this kind of partitioning.
|
|
||||||
*/
|
|
||||||
get_partitions_in_range_iter get_part_iter_for_interval;
|
|
||||||
/*
|
|
||||||
Partitioning interval analysis function for subpartitioning, or NULL if
|
|
||||||
interval analysis is not supported for this kind of partitioning.
|
|
||||||
*/
|
|
||||||
get_partitions_in_range_iter get_subpart_iter_for_interval;
|
|
||||||
|
|
||||||
/*
|
|
||||||
Valid iff
|
|
||||||
get_part_iter_for_interval=get_part_iter_for_interval_via_walking:
|
|
||||||
controls how we'll process "field < C" and "field > C" intervals.
|
|
||||||
If the partitioning function F is strictly increasing, then for any x, y
|
|
||||||
"x < y" => "F(x) < F(y)" (*), i.e. when we get interval "field < C"
|
|
||||||
we can perform partition pruning on the equivalent "F(field) < F(C)".
|
|
||||||
|
|
||||||
If the partitioning function not strictly increasing (it is simply
|
|
||||||
increasing), then instead of (*) we get "x < y" => "F(x) <= F(y)"
|
|
||||||
i.e. for interval "field < C" we can perform partition pruning for
|
|
||||||
"F(field) <= F(C)".
|
|
||||||
*/
|
|
||||||
bool range_analysis_include_bounds;
|
|
||||||
/********************************************
|
|
||||||
* INTERVAL ANALYSIS ENDS
|
|
||||||
********************************************/
|
|
||||||
|
|
||||||
char* part_info_string;
|
|
||||||
|
|
||||||
char *part_func_string;
|
|
||||||
char *subpart_func_string;
|
|
||||||
|
|
||||||
uchar *part_state;
|
|
||||||
|
|
||||||
partition_element *curr_part_elem;
|
|
||||||
partition_element *current_partition;
|
|
||||||
/*
|
|
||||||
These key_map's are used for Partitioning to enable quick decisions
|
|
||||||
on whether we can derive more information about which partition to
|
|
||||||
scan just by looking at what index is used.
|
|
||||||
*/
|
|
||||||
key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF;
|
|
||||||
key_map some_fields_in_PF;
|
|
||||||
|
|
||||||
handlerton *default_engine_type;
|
|
||||||
Item_result part_result_type;
|
|
||||||
partition_type part_type;
|
|
||||||
partition_type subpart_type;
|
|
||||||
|
|
||||||
uint part_info_len;
|
|
||||||
uint part_state_len;
|
|
||||||
uint part_func_len;
|
|
||||||
uint subpart_func_len;
|
|
||||||
|
|
||||||
uint no_parts;
|
|
||||||
uint no_subparts;
|
|
||||||
uint count_curr_subparts;
|
|
||||||
|
|
||||||
uint part_error_code;
|
|
||||||
|
|
||||||
uint no_list_values;
|
|
||||||
|
|
||||||
uint no_part_fields;
|
|
||||||
uint no_subpart_fields;
|
|
||||||
uint no_full_part_fields;
|
|
||||||
|
|
||||||
/*
|
|
||||||
This variable is used to calculate the partition id when using
|
|
||||||
LINEAR KEY/HASH. This functionality is kept in the MySQL Server
|
|
||||||
but mainly of use to handlers supporting partitioning.
|
|
||||||
*/
|
|
||||||
uint16 linear_hash_mask;
|
|
||||||
|
|
||||||
bool use_default_partitions;
|
|
||||||
bool use_default_no_partitions;
|
|
||||||
bool use_default_subpartitions;
|
|
||||||
bool use_default_no_subpartitions;
|
|
||||||
bool default_partitions_setup;
|
|
||||||
bool defined_max_value;
|
|
||||||
bool list_of_part_fields;
|
|
||||||
bool list_of_subpart_fields;
|
|
||||||
bool linear_hash_ind;
|
|
||||||
bool fixed;
|
|
||||||
bool from_openfrm;
|
|
||||||
|
|
||||||
partition_info()
|
|
||||||
: get_partition_id(NULL), get_part_partition_id(NULL),
|
|
||||||
get_subpartition_id(NULL),
|
|
||||||
part_field_array(NULL), subpart_field_array(NULL),
|
|
||||||
full_part_field_array(NULL),
|
|
||||||
part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
|
|
||||||
list_array(NULL),
|
|
||||||
part_info_string(NULL),
|
|
||||||
part_func_string(NULL), subpart_func_string(NULL),
|
|
||||||
part_state(NULL),
|
|
||||||
curr_part_elem(NULL), current_partition(NULL),
|
|
||||||
default_engine_type(NULL),
|
|
||||||
part_result_type(INT_RESULT),
|
|
||||||
part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION),
|
|
||||||
part_info_len(0), part_state_len(0),
|
|
||||||
part_func_len(0), subpart_func_len(0),
|
|
||||||
no_parts(0), no_subparts(0),
|
|
||||||
count_curr_subparts(0), part_error_code(0),
|
|
||||||
no_list_values(0), no_part_fields(0), no_subpart_fields(0),
|
|
||||||
no_full_part_fields(0), linear_hash_mask(0),
|
|
||||||
use_default_partitions(TRUE),
|
|
||||||
use_default_no_partitions(TRUE),
|
|
||||||
use_default_subpartitions(TRUE),
|
|
||||||
use_default_no_subpartitions(TRUE),
|
|
||||||
default_partitions_setup(FALSE),
|
|
||||||
defined_max_value(FALSE),
|
|
||||||
list_of_part_fields(FALSE), list_of_subpart_fields(FALSE),
|
|
||||||
linear_hash_ind(FALSE),
|
|
||||||
fixed(FALSE),
|
|
||||||
from_openfrm(FALSE)
|
|
||||||
{
|
|
||||||
all_fields_in_PF.clear_all();
|
|
||||||
all_fields_in_PPF.clear_all();
|
|
||||||
all_fields_in_SPF.clear_all();
|
|
||||||
some_fields_in_PF.clear_all();
|
|
||||||
partitions.empty();
|
|
||||||
temp_partitions.empty();
|
|
||||||
part_field_list.empty();
|
|
||||||
subpart_field_list.empty();
|
|
||||||
}
|
|
||||||
~partition_info() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
||||||
uint32 get_next_partition_id_range(struct st_partition_iter* part_iter);
|
|
||||||
|
|
||||||
/* Initialize the iterator to return a single partition with given part_id */
|
|
||||||
|
|
||||||
static inline void init_single_partition_iterator(uint32 part_id,
|
|
||||||
PARTITION_ITERATOR *part_iter)
|
|
||||||
{
|
|
||||||
part_iter->part_nums.start= part_id;
|
|
||||||
part_iter->part_nums.end= part_id+1;
|
|
||||||
part_iter->get_next= get_next_partition_id_range;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the iterator to enumerate all partitions */
|
|
||||||
static inline
|
|
||||||
void init_all_partitions_iterator(partition_info *part_info,
|
|
||||||
PARTITION_ITERATOR *part_iter)
|
|
||||||
{
|
|
||||||
part_iter->part_nums.start= 0;
|
|
||||||
part_iter->part_nums.end= part_info->no_parts;
|
|
||||||
part_iter->get_next= get_next_partition_id_range;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Answers the question if subpartitioning is used for a certain table
|
|
||||||
SYNOPSIS
|
|
||||||
is_sub_partitioned()
|
|
||||||
part_info A reference to the partition_info struct
|
|
||||||
RETURN VALUE
|
|
||||||
Returns true if subpartitioning used and false otherwise
|
|
||||||
DESCRIPTION
|
|
||||||
A routine to check for subpartitioning for improved readability of code
|
|
||||||
*/
|
|
||||||
static inline
|
|
||||||
bool is_sub_partitioned(partition_info *part_info)
|
|
||||||
{ return (part_info->subpart_type == NOT_A_PARTITION ? FALSE : TRUE); }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Returns the total number of partitions on the leaf level.
|
|
||||||
SYNOPSIS
|
|
||||||
get_tot_partitions()
|
|
||||||
part_info A reference to the partition_info struct
|
|
||||||
RETURN VALUE
|
|
||||||
Returns the number of partitions
|
|
||||||
DESCRIPTION
|
|
||||||
A routine to check for number of partitions for improved readability
|
|
||||||
of code
|
|
||||||
*/
|
|
||||||
static inline
|
|
||||||
uint get_tot_partitions(partition_info *part_info)
|
|
||||||
{
|
|
||||||
return part_info->no_parts *
|
|
||||||
(is_sub_partitioned(part_info) ? part_info->no_subparts : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct st_ha_create_information
|
typedef struct st_ha_create_information
|
||||||
{
|
{
|
||||||
@ -1100,52 +650,6 @@ typedef struct st_ha_check_opt
|
|||||||
} HA_CHECK_OPT;
|
} HA_CHECK_OPT;
|
||||||
|
|
||||||
|
|
||||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
|
||||||
bool is_partition_in_list(char *part_name, List<char> list_part_names);
|
|
||||||
char *are_partitions_in_table(partition_info *new_part_info,
|
|
||||||
partition_info *old_part_info);
|
|
||||||
bool check_reorganise_list(partition_info *new_part_info,
|
|
||||||
partition_info *old_part_info,
|
|
||||||
List<char> list_part_names);
|
|
||||||
bool set_up_defaults_for_partitioning(partition_info *part_info,
|
|
||||||
handler *file,
|
|
||||||
ulonglong max_rows,
|
|
||||||
uint start_no);
|
|
||||||
handler *get_ha_partition(partition_info *part_info);
|
|
||||||
int get_parts_for_update(const byte *old_data, byte *new_data,
|
|
||||||
const byte *rec0, partition_info *part_info,
|
|
||||||
uint32 *old_part_id, uint32 *new_part_id,
|
|
||||||
longlong *func_value);
|
|
||||||
int get_part_for_delete(const byte *buf, const byte *rec0,
|
|
||||||
partition_info *part_info, uint32 *part_id);
|
|
||||||
bool check_partition_info(partition_info *part_info,handlerton **eng_type,
|
|
||||||
handler *file, ulonglong max_rows);
|
|
||||||
bool fix_partition_func(THD *thd, const char *name, TABLE *table,
|
|
||||||
bool create_table_ind);
|
|
||||||
char *generate_partition_syntax(partition_info *part_info,
|
|
||||||
uint *buf_length, bool use_sql_alloc,
|
|
||||||
bool write_all);
|
|
||||||
bool partition_key_modified(TABLE *table, List<Item> &fields);
|
|
||||||
void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
|
||||||
const key_range *key_spec,
|
|
||||||
part_id_range *part_spec);
|
|
||||||
void get_full_part_id_from_key(const TABLE *table, byte *buf,
|
|
||||||
KEY *key_info,
|
|
||||||
const key_range *key_spec,
|
|
||||||
part_id_range *part_spec);
|
|
||||||
bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
|
|
||||||
uint part_info_len,
|
|
||||||
uchar *part_state, uint part_state_len,
|
|
||||||
TABLE *table, bool is_create_table_ind,
|
|
||||||
handlerton *default_db_type);
|
|
||||||
void make_used_partitions_str(partition_info *part_info, String *parts_str);
|
|
||||||
uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
|
|
||||||
bool left_endpoint,
|
|
||||||
bool include_endpoint);
|
|
||||||
uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
|
|
||||||
bool left_endpoint,
|
|
||||||
bool include_endpoint);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -503,6 +503,8 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
|
|||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "sql_plugin.h"
|
#include "sql_plugin.h"
|
||||||
#include "sql_udf.h"
|
#include "sql_udf.h"
|
||||||
|
#include "sql_partition.h"
|
||||||
|
|
||||||
class user_var_entry;
|
class user_var_entry;
|
||||||
class Security_context;
|
class Security_context;
|
||||||
enum enum_var_type
|
enum enum_var_type
|
||||||
|
@ -2976,7 +2976,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
|
|||||||
ppar->last_subpart_partno=
|
ppar->last_subpart_partno=
|
||||||
used_subpart_fields?(int)(used_part_fields + used_subpart_fields - 1): -1;
|
used_subpart_fields?(int)(used_part_fields + used_subpart_fields - 1): -1;
|
||||||
|
|
||||||
if (is_sub_partitioned(part_info))
|
if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
ppar->mark_full_partition_used= mark_full_partition_used_with_parts;
|
ppar->mark_full_partition_used= mark_full_partition_used_with_parts;
|
||||||
ppar->get_top_partition_id_func= part_info->get_part_partition_id;
|
ppar->get_top_partition_id_func= part_info->get_part_partition_id;
|
||||||
|
70
sql/partition_element.h
Normal file
70
sql/partition_element.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/* Copyright (C) 2000,2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||||
|
|
||||||
|
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; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
#ifdef USE_PRAGMA_INTERFACE
|
||||||
|
#pragma interface /* gcc class implementation */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An enum and a struct to handle partitioning and subpartitioning.
|
||||||
|
*/
|
||||||
|
enum partition_type {
|
||||||
|
NOT_A_PARTITION= 0,
|
||||||
|
RANGE_PARTITION,
|
||||||
|
HASH_PARTITION,
|
||||||
|
LIST_PARTITION
|
||||||
|
};
|
||||||
|
|
||||||
|
enum partition_state {
|
||||||
|
PART_NORMAL= 0,
|
||||||
|
PART_IS_DROPPED= 1,
|
||||||
|
PART_TO_BE_DROPPED= 2,
|
||||||
|
PART_TO_BE_ADDED= 3,
|
||||||
|
PART_TO_BE_REORGED= 4,
|
||||||
|
PART_REORGED_DROPPED= 5,
|
||||||
|
PART_CHANGED= 6,
|
||||||
|
PART_IS_CHANGED= 7,
|
||||||
|
PART_IS_ADDED= 8
|
||||||
|
};
|
||||||
|
|
||||||
|
class partition_element :public Sql_alloc {
|
||||||
|
public:
|
||||||
|
List<partition_element> subpartitions;
|
||||||
|
List<longlong> list_val_list;
|
||||||
|
ulonglong part_max_rows;
|
||||||
|
ulonglong part_min_rows;
|
||||||
|
char *partition_name;
|
||||||
|
char *tablespace_name;
|
||||||
|
longlong range_value;
|
||||||
|
char* part_comment;
|
||||||
|
char* data_file_name;
|
||||||
|
char* index_file_name;
|
||||||
|
handlerton *engine_type;
|
||||||
|
enum partition_state part_state;
|
||||||
|
uint16 nodegroup_id;
|
||||||
|
|
||||||
|
partition_element()
|
||||||
|
: part_max_rows(0), part_min_rows(0), partition_name(NULL),
|
||||||
|
tablespace_name(NULL), range_value(0), part_comment(NULL),
|
||||||
|
data_file_name(NULL), index_file_name(NULL),
|
||||||
|
engine_type(NULL),part_state(PART_NORMAL),
|
||||||
|
nodegroup_id(UNDEF_NODEGROUP)
|
||||||
|
{
|
||||||
|
subpartitions.empty();
|
||||||
|
list_val_list.empty();
|
||||||
|
}
|
||||||
|
~partition_element() {}
|
||||||
|
};
|
347
sql/partition_info.cpp
Normal file
347
sql/partition_info.cpp
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
/* Copyright (C) 2005 MySQL AB
|
||||||
|
|
||||||
|
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; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
/*
|
||||||
|
This file was introduced as a container for general functionality related
|
||||||
|
to partitioning introduced in MySQL version 5.1. It contains functionality
|
||||||
|
used by all handlers that support partitioning, which in the first version
|
||||||
|
is the partitioning handler itself and the NDB handler.
|
||||||
|
|
||||||
|
The first version was written by Mikael Ronstrom.
|
||||||
|
|
||||||
|
This version supports RANGE partitioning, LIST partitioning, HASH
|
||||||
|
partitioning and composite partitioning (hereafter called subpartitioning)
|
||||||
|
where each RANGE/LIST partitioning is HASH partitioned. The hash function
|
||||||
|
can either be supplied by the user or by only a list of fields (also
|
||||||
|
called KEY partitioning, where the MySQL server will use an internal
|
||||||
|
hash function.
|
||||||
|
There are quite a few defaults that can be used as well.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Some general useful functions */
|
||||||
|
|
||||||
|
#include "mysql_priv.h"
|
||||||
|
#include "ha_partition.h"
|
||||||
|
|
||||||
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a memory area where default partition names are stored and fill it
|
||||||
|
up with the names.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
create_default_partition_names()
|
||||||
|
part_no Partition number for subparts
|
||||||
|
no_parts Number of partitions
|
||||||
|
start_no Starting partition number
|
||||||
|
subpart Is it subpartitions
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
A pointer to the memory area of the default partition names
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
A support routine for the partition code where default values are
|
||||||
|
generated.
|
||||||
|
The external routine needing this code is check_partition_info
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_PART_NAME_SIZE 16
|
||||||
|
|
||||||
|
char *partition_info::create_default_partition_names(uint part_no, uint no_parts,
|
||||||
|
uint start_no, bool is_subpart)
|
||||||
|
{
|
||||||
|
char *ptr= sql_calloc(no_parts*MAX_PART_NAME_SIZE);
|
||||||
|
char *move_ptr= ptr;
|
||||||
|
uint i= 0;
|
||||||
|
DBUG_ENTER("create_default_partition_names");
|
||||||
|
|
||||||
|
if (likely(ptr != 0))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (is_subpart)
|
||||||
|
my_sprintf(move_ptr, (move_ptr,"p%usp%u", part_no, (start_no + i)));
|
||||||
|
else
|
||||||
|
my_sprintf(move_ptr, (move_ptr,"p%u", (start_no + i)));
|
||||||
|
move_ptr+=MAX_PART_NAME_SIZE;
|
||||||
|
} while (++i < no_parts);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mem_alloc_error(no_parts*MAX_PART_NAME_SIZE);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set up all the default partitions not set-up by the user in the SQL
|
||||||
|
statement. Also perform a number of checks that the user hasn't tried
|
||||||
|
to use default values where no defaults exists.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
set_up_default_partitions()
|
||||||
|
part_info The reference to all partition information
|
||||||
|
file A reference to a handler of the table
|
||||||
|
max_rows Maximum number of rows stored in the table
|
||||||
|
start_no Starting partition number
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
TRUE Error, attempted default values not possible
|
||||||
|
FALSE Ok, default partitions set-up
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The routine uses the underlying handler of the partitioning to define
|
||||||
|
the default number of partitions. For some handlers this requires
|
||||||
|
knowledge of the maximum number of rows to be stored in the table.
|
||||||
|
This routine only accepts HASH and KEY partitioning and thus there is
|
||||||
|
no subpartitioning if this routine is successful.
|
||||||
|
The external routine needing this code is check_partition_info
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool partition_info::set_up_default_partitions(handler *file, ulonglong max_rows,
|
||||||
|
uint start_no)
|
||||||
|
{
|
||||||
|
uint i;
|
||||||
|
char *default_name;
|
||||||
|
bool result= TRUE;
|
||||||
|
DBUG_ENTER("partition_info::set_up_default_partitions");
|
||||||
|
|
||||||
|
if (part_type != HASH_PARTITION)
|
||||||
|
{
|
||||||
|
const char *error_string;
|
||||||
|
if (part_type == RANGE_PARTITION)
|
||||||
|
error_string= partition_keywords[PKW_RANGE].str;
|
||||||
|
else
|
||||||
|
error_string= partition_keywords[PKW_LIST].str;
|
||||||
|
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (no_parts == 0)
|
||||||
|
no_parts= file->get_default_no_partitions(max_rows);
|
||||||
|
if (unlikely(no_parts > MAX_PARTITIONS))
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (unlikely((!(default_name= create_default_partition_names(0, no_parts,
|
||||||
|
start_no,
|
||||||
|
FALSE)))))
|
||||||
|
goto end;
|
||||||
|
i= 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
partition_element *part_elem= new partition_element();
|
||||||
|
if (likely(part_elem != 0 &&
|
||||||
|
(!partitions.push_back(part_elem))))
|
||||||
|
{
|
||||||
|
part_elem->engine_type= default_engine_type;
|
||||||
|
part_elem->partition_name= default_name;
|
||||||
|
default_name+=MAX_PART_NAME_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mem_alloc_error(sizeof(partition_element));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} while (++i < no_parts);
|
||||||
|
result= FALSE;
|
||||||
|
end:
|
||||||
|
DBUG_RETURN(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Set up all the default subpartitions not set-up by the user in the SQL
|
||||||
|
statement. Also perform a number of checks that the default partitioning
|
||||||
|
becomes an allowed partitioning scheme.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
set_up_default_subpartitions()
|
||||||
|
part_info The reference to all partition information
|
||||||
|
file A reference to a handler of the table
|
||||||
|
max_rows Maximum number of rows stored in the table
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
TRUE Error, attempted default values not possible
|
||||||
|
FALSE Ok, default partitions set-up
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
The routine uses the underlying handler of the partitioning to define
|
||||||
|
the default number of partitions. For some handlers this requires
|
||||||
|
knowledge of the maximum number of rows to be stored in the table.
|
||||||
|
This routine is only called for RANGE or LIST partitioning and those
|
||||||
|
need to be specified so only subpartitions are specified.
|
||||||
|
The external routine needing this code is check_partition_info
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool partition_info::set_up_default_subpartitions(handler *file,
|
||||||
|
ulonglong max_rows)
|
||||||
|
{
|
||||||
|
uint i, j; //, no_parts, no_subparts;
|
||||||
|
char *default_name, *name_ptr;
|
||||||
|
bool result= TRUE;
|
||||||
|
partition_element *part_elem;
|
||||||
|
List_iterator<partition_element> part_it(partitions);
|
||||||
|
DBUG_ENTER("partition_info::set_up_default_subpartitions");
|
||||||
|
|
||||||
|
if (no_subparts == 0)
|
||||||
|
no_subparts= file->get_default_no_partitions(max_rows);
|
||||||
|
// no_parts= part_info->no_parts;
|
||||||
|
//no_subparts= part_info->no_subparts;
|
||||||
|
if (unlikely((no_parts * no_subparts) > MAX_PARTITIONS))
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
// if (unlikely((!(default_name=
|
||||||
|
// create_default_partition_names(no_subparts, (uint)0, TRUE)))))
|
||||||
|
//goto end;
|
||||||
|
i= 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
part_elem= part_it++;
|
||||||
|
j= 0;
|
||||||
|
name_ptr= create_default_partition_names(i, no_subparts, (uint)0, TRUE);
|
||||||
|
if (unlikely(!name_ptr))
|
||||||
|
goto end;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
partition_element *subpart_elem= new partition_element();
|
||||||
|
if (likely(subpart_elem != 0 &&
|
||||||
|
(!part_elem->subpartitions.push_back(subpart_elem))))
|
||||||
|
{
|
||||||
|
subpart_elem->engine_type= default_engine_type;
|
||||||
|
subpart_elem->partition_name= name_ptr;
|
||||||
|
name_ptr+= MAX_PART_NAME_SIZE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mem_alloc_error(sizeof(partition_element));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
} while (++j < no_subparts);
|
||||||
|
} while (++i < no_parts);
|
||||||
|
result= FALSE;
|
||||||
|
end:
|
||||||
|
DBUG_RETURN(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Support routine for check_partition_info
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
set_up_defaults_for_partitioning()
|
||||||
|
part_info The reference to all partition information
|
||||||
|
file A reference to a handler of the table
|
||||||
|
max_rows Maximum number of rows stored in the table
|
||||||
|
start_no Starting partition number
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
TRUE Error, attempted default values not possible
|
||||||
|
FALSE Ok, default partitions set-up
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Set up defaults for partition or subpartition (cannot set-up for both,
|
||||||
|
this will return an error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool partition_info::set_up_defaults_for_partitioning(handler *file,
|
||||||
|
ulonglong max_rows,
|
||||||
|
uint start_no)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("partition_info::set_up_defaults_for_partitioning");
|
||||||
|
|
||||||
|
if (!default_partitions_setup)
|
||||||
|
{
|
||||||
|
default_partitions_setup= TRUE;
|
||||||
|
if (use_default_partitions)
|
||||||
|
DBUG_RETURN(set_up_default_partitions(file, max_rows, start_no));
|
||||||
|
if (is_sub_partitioned() &&
|
||||||
|
use_default_subpartitions)
|
||||||
|
DBUG_RETURN(set_up_default_subpartitions(file, max_rows));
|
||||||
|
}
|
||||||
|
DBUG_RETURN(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool partition_info::has_unique_name(partition_element *element)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("partition_info::has_unique_name");
|
||||||
|
|
||||||
|
const char *name_to_check= element->partition_name;
|
||||||
|
List_iterator<partition_element> parts_it(partitions);
|
||||||
|
|
||||||
|
partition_element *el;
|
||||||
|
while (el= (parts_it++))
|
||||||
|
{
|
||||||
|
if (!(my_strcasecmp(system_charset_info, el->partition_name,
|
||||||
|
name_to_check)) && el != element)
|
||||||
|
DBUG_RETURN(FALSE);
|
||||||
|
|
||||||
|
if (el->subpartitions.is_empty()) continue;
|
||||||
|
List_iterator<partition_element> subparts_it(el->subpartitions);
|
||||||
|
partition_element *sub_el;
|
||||||
|
while (sub_el= (subparts_it++))
|
||||||
|
{
|
||||||
|
if (!(my_strcasecmp(system_charset_info, sub_el->partition_name,
|
||||||
|
name_to_check)) && sub_el != element)
|
||||||
|
DBUG_RETURN(FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
A support function to check partition names for duplication in a
|
||||||
|
partitioned table
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
has_unique_names()
|
||||||
|
|
||||||
|
RETURN VALUES
|
||||||
|
TRUE Has unique part and subpart names
|
||||||
|
FALSE Doesn't
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Checks that the list of names in the partitions doesn't contain any
|
||||||
|
duplicated names.
|
||||||
|
*/
|
||||||
|
char *partition_info::has_unique_names()
|
||||||
|
{
|
||||||
|
DBUG_ENTER("partition_info::has_unique_names");
|
||||||
|
|
||||||
|
List_iterator<partition_element> parts_it(partitions);
|
||||||
|
|
||||||
|
partition_element *el;
|
||||||
|
while (el= (parts_it++))
|
||||||
|
{
|
||||||
|
if (! has_unique_name(el))
|
||||||
|
DBUG_RETURN(el->partition_name);
|
||||||
|
|
||||||
|
if (el->subpartitions.is_empty()) continue;
|
||||||
|
List_iterator<partition_element> subparts_it(el->subpartitions);
|
||||||
|
partition_element *subel;
|
||||||
|
while (subel= (subparts_it++))
|
||||||
|
{
|
||||||
|
if (! has_unique_name(subel))
|
||||||
|
DBUG_RETURN(subel->partition_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBUG_RETURN(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WITH_PARTITION_STORAGE_ENGINE */
|
295
sql/partition_info.h
Normal file
295
sql/partition_info.h
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
/* Copyright (C) 2000,2004 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||||
|
|
||||||
|
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; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
#ifdef USE_PRAGMA_INTERFACE
|
||||||
|
#pragma interface /* gcc class implementation */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "partition_element.h"
|
||||||
|
|
||||||
|
class partition_info;
|
||||||
|
|
||||||
|
/* Some function typedefs */
|
||||||
|
typedef int (*get_part_id_func)(partition_info *part_info,
|
||||||
|
uint32 *part_id,
|
||||||
|
longlong *func_value);
|
||||||
|
typedef uint32 (*get_subpart_id_func)(partition_info *part_info);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class partition_info : public Sql_alloc
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
* Here comes a set of definitions needed for partitioned table handlers.
|
||||||
|
*/
|
||||||
|
List<partition_element> partitions;
|
||||||
|
List<partition_element> temp_partitions;
|
||||||
|
|
||||||
|
List<char> part_field_list;
|
||||||
|
List<char> subpart_field_list;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If there is no subpartitioning, use only this func to get partition ids.
|
||||||
|
If there is subpartitioning, use the this func to get partition id when
|
||||||
|
you have both partition and subpartition fields.
|
||||||
|
*/
|
||||||
|
get_part_id_func get_partition_id;
|
||||||
|
|
||||||
|
/* Get partition id when we don't have subpartition fields */
|
||||||
|
get_part_id_func get_part_partition_id;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get subpartition id when we have don't have partition fields by we do
|
||||||
|
have subpartition ids.
|
||||||
|
Mikael said that for given constant tuple
|
||||||
|
{subpart_field1, ..., subpart_fieldN} the subpartition id will be the
|
||||||
|
same in all subpartitions
|
||||||
|
*/
|
||||||
|
get_subpart_id_func get_subpartition_id;
|
||||||
|
|
||||||
|
/* NULL-terminated array of fields used in partitioned expression */
|
||||||
|
Field **part_field_array;
|
||||||
|
/* NULL-terminated array of fields used in subpartitioned expression */
|
||||||
|
Field **subpart_field_array;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Array of all fields used in partition and subpartition expression,
|
||||||
|
without duplicates, NULL-terminated.
|
||||||
|
*/
|
||||||
|
Field **full_part_field_array;
|
||||||
|
|
||||||
|
Item *part_expr;
|
||||||
|
Item *subpart_expr;
|
||||||
|
|
||||||
|
Item *item_free_list;
|
||||||
|
|
||||||
|
/*
|
||||||
|
A bitmap of partitions used by the current query.
|
||||||
|
Usage pattern:
|
||||||
|
* The handler->extra(HA_EXTRA_RESET) call at query start/end sets all
|
||||||
|
partitions to be unused.
|
||||||
|
* Before index/rnd_init(), partition pruning code sets the bits for used
|
||||||
|
partitions.
|
||||||
|
*/
|
||||||
|
MY_BITMAP used_partitions;
|
||||||
|
|
||||||
|
union {
|
||||||
|
longlong *range_int_array;
|
||||||
|
LIST_PART_ENTRY *list_array;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************************************
|
||||||
|
* INTERVAL ANALYSIS
|
||||||
|
********************************************/
|
||||||
|
/*
|
||||||
|
Partitioning interval analysis function for partitioning, or NULL if
|
||||||
|
interval analysis is not supported for this kind of partitioning.
|
||||||
|
*/
|
||||||
|
get_partitions_in_range_iter get_part_iter_for_interval;
|
||||||
|
/*
|
||||||
|
Partitioning interval analysis function for subpartitioning, or NULL if
|
||||||
|
interval analysis is not supported for this kind of partitioning.
|
||||||
|
*/
|
||||||
|
get_partitions_in_range_iter get_subpart_iter_for_interval;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Valid iff
|
||||||
|
get_part_iter_for_interval=get_part_iter_for_interval_via_walking:
|
||||||
|
controls how we'll process "field < C" and "field > C" intervals.
|
||||||
|
If the partitioning function F is strictly increasing, then for any x, y
|
||||||
|
"x < y" => "F(x) < F(y)" (*), i.e. when we get interval "field < C"
|
||||||
|
we can perform partition pruning on the equivalent "F(field) < F(C)".
|
||||||
|
|
||||||
|
If the partitioning function not strictly increasing (it is simply
|
||||||
|
increasing), then instead of (*) we get "x < y" => "F(x) <= F(y)"
|
||||||
|
i.e. for interval "field < C" we can perform partition pruning for
|
||||||
|
"F(field) <= F(C)".
|
||||||
|
*/
|
||||||
|
bool range_analysis_include_bounds;
|
||||||
|
/********************************************
|
||||||
|
* INTERVAL ANALYSIS ENDS
|
||||||
|
********************************************/
|
||||||
|
|
||||||
|
char* part_info_string;
|
||||||
|
|
||||||
|
char *part_func_string;
|
||||||
|
char *subpart_func_string;
|
||||||
|
|
||||||
|
uchar *part_state;
|
||||||
|
|
||||||
|
partition_element *curr_part_elem;
|
||||||
|
partition_element *current_partition;
|
||||||
|
/*
|
||||||
|
These key_map's are used for Partitioning to enable quick decisions
|
||||||
|
on whether we can derive more information about which partition to
|
||||||
|
scan just by looking at what index is used.
|
||||||
|
*/
|
||||||
|
key_map all_fields_in_PF, all_fields_in_PPF, all_fields_in_SPF;
|
||||||
|
key_map some_fields_in_PF;
|
||||||
|
|
||||||
|
handlerton *default_engine_type;
|
||||||
|
Item_result part_result_type;
|
||||||
|
partition_type part_type;
|
||||||
|
partition_type subpart_type;
|
||||||
|
|
||||||
|
uint part_info_len;
|
||||||
|
uint part_state_len;
|
||||||
|
uint part_func_len;
|
||||||
|
uint subpart_func_len;
|
||||||
|
|
||||||
|
uint no_parts;
|
||||||
|
uint no_subparts;
|
||||||
|
uint count_curr_subparts;
|
||||||
|
|
||||||
|
uint part_error_code;
|
||||||
|
|
||||||
|
uint no_list_values;
|
||||||
|
|
||||||
|
uint no_part_fields;
|
||||||
|
uint no_subpart_fields;
|
||||||
|
uint no_full_part_fields;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This variable is used to calculate the partition id when using
|
||||||
|
LINEAR KEY/HASH. This functionality is kept in the MySQL Server
|
||||||
|
but mainly of use to handlers supporting partitioning.
|
||||||
|
*/
|
||||||
|
uint16 linear_hash_mask;
|
||||||
|
|
||||||
|
bool use_default_partitions;
|
||||||
|
bool use_default_no_partitions;
|
||||||
|
bool use_default_subpartitions;
|
||||||
|
bool use_default_no_subpartitions;
|
||||||
|
bool default_partitions_setup;
|
||||||
|
bool defined_max_value;
|
||||||
|
bool list_of_part_fields;
|
||||||
|
bool list_of_subpart_fields;
|
||||||
|
bool linear_hash_ind;
|
||||||
|
bool fixed;
|
||||||
|
bool from_openfrm;
|
||||||
|
|
||||||
|
partition_info()
|
||||||
|
: get_partition_id(NULL), get_part_partition_id(NULL),
|
||||||
|
get_subpartition_id(NULL),
|
||||||
|
part_field_array(NULL), subpart_field_array(NULL),
|
||||||
|
full_part_field_array(NULL),
|
||||||
|
part_expr(NULL), subpart_expr(NULL), item_free_list(NULL),
|
||||||
|
list_array(NULL),
|
||||||
|
part_info_string(NULL),
|
||||||
|
part_func_string(NULL), subpart_func_string(NULL),
|
||||||
|
part_state(NULL),
|
||||||
|
curr_part_elem(NULL), current_partition(NULL),
|
||||||
|
default_engine_type(NULL),
|
||||||
|
part_result_type(INT_RESULT),
|
||||||
|
part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION),
|
||||||
|
part_info_len(0), part_state_len(0),
|
||||||
|
part_func_len(0), subpart_func_len(0),
|
||||||
|
no_parts(0), no_subparts(0),
|
||||||
|
count_curr_subparts(0), part_error_code(0),
|
||||||
|
no_list_values(0), no_part_fields(0), no_subpart_fields(0),
|
||||||
|
no_full_part_fields(0), linear_hash_mask(0),
|
||||||
|
use_default_partitions(TRUE),
|
||||||
|
use_default_no_partitions(TRUE),
|
||||||
|
use_default_subpartitions(TRUE),
|
||||||
|
use_default_no_subpartitions(TRUE),
|
||||||
|
default_partitions_setup(FALSE),
|
||||||
|
defined_max_value(FALSE),
|
||||||
|
list_of_part_fields(FALSE), list_of_subpart_fields(FALSE),
|
||||||
|
linear_hash_ind(FALSE),
|
||||||
|
fixed(FALSE),
|
||||||
|
from_openfrm(FALSE)
|
||||||
|
{
|
||||||
|
all_fields_in_PF.clear_all();
|
||||||
|
all_fields_in_PPF.clear_all();
|
||||||
|
all_fields_in_SPF.clear_all();
|
||||||
|
some_fields_in_PF.clear_all();
|
||||||
|
partitions.empty();
|
||||||
|
temp_partitions.empty();
|
||||||
|
part_field_list.empty();
|
||||||
|
subpart_field_list.empty();
|
||||||
|
}
|
||||||
|
~partition_info() {}
|
||||||
|
|
||||||
|
bool is_sub_partitioned();
|
||||||
|
uint get_tot_partitions();
|
||||||
|
bool set_up_defaults_for_partitioning(handler *file, ulonglong max_rows,
|
||||||
|
uint start_no);
|
||||||
|
char *has_unique_names();
|
||||||
|
private:
|
||||||
|
bool set_up_default_partitions(handler *file, ulonglong max_rows,
|
||||||
|
uint start_no);
|
||||||
|
bool set_up_default_subpartitions(handler *file, ulonglong max_rows);
|
||||||
|
char *create_default_partition_names(uint part_no, uint no_parts,
|
||||||
|
uint start_no, bool is_subpart);
|
||||||
|
bool has_unique_name(partition_element *element);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Answers the question if subpartitioning is used for a certain table
|
||||||
|
SYNOPSIS
|
||||||
|
is_sub_partitioned()
|
||||||
|
part_info A reference to the partition_info struct
|
||||||
|
RETURN VALUE
|
||||||
|
Returns true if subpartitioning used and false otherwise
|
||||||
|
DESCRIPTION
|
||||||
|
A routine to check for subpartitioning for improved readability of code
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
bool partition_info::is_sub_partitioned()
|
||||||
|
{
|
||||||
|
return (subpart_type == NOT_A_PARTITION ? FALSE : TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns the total number of partitions on the leaf level.
|
||||||
|
SYNOPSIS
|
||||||
|
get_tot_partitions()
|
||||||
|
part_info A reference to the partition_info struct
|
||||||
|
RETURN VALUE
|
||||||
|
Returns the number of partitions
|
||||||
|
DESCRIPTION
|
||||||
|
A routine to check for number of partitions for improved readability
|
||||||
|
of code
|
||||||
|
*/
|
||||||
|
inline
|
||||||
|
uint partition_info::get_tot_partitions()
|
||||||
|
{
|
||||||
|
return no_parts * (is_sub_partitioned() ? no_subparts : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 get_next_partition_id_range(struct st_partition_iter* part_iter);
|
||||||
|
|
||||||
|
/* Initialize the iterator to return a single partition with given part_id */
|
||||||
|
|
||||||
|
static inline void init_single_partition_iterator(uint32 part_id,
|
||||||
|
PARTITION_ITERATOR *part_iter)
|
||||||
|
{
|
||||||
|
part_iter->part_nums.start= part_id;
|
||||||
|
part_iter->part_nums.end= part_id+1;
|
||||||
|
part_iter->get_next= get_next_partition_id_range;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize the iterator to enumerate all partitions */
|
||||||
|
static inline
|
||||||
|
void init_all_partitions_iterator(partition_info *part_info,
|
||||||
|
PARTITION_ITERATOR *part_iter)
|
||||||
|
{
|
||||||
|
part_iter->part_nums.start= 0;
|
||||||
|
part_iter->part_nums.end= part_info->no_parts;
|
||||||
|
part_iter->get_next= get_next_partition_id_range;
|
||||||
|
}
|
@ -181,59 +181,6 @@ bool is_name_in_list(char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
A support function to check partition names for duplication in a
|
|
||||||
partitioned table
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
are_partitions_in_table()
|
|
||||||
new_part_info New partition info
|
|
||||||
old_part_info Old partition info
|
|
||||||
|
|
||||||
RETURN VALUES
|
|
||||||
TRUE Duplicate names found
|
|
||||||
FALSE Duplicate names not found
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Can handle that the new and old parts are the same in which case it
|
|
||||||
checks that the list of names in the partitions doesn't contain any
|
|
||||||
duplicated names.
|
|
||||||
*/
|
|
||||||
|
|
||||||
char *are_partitions_in_table(partition_info *new_part_info,
|
|
||||||
partition_info *old_part_info)
|
|
||||||
{
|
|
||||||
uint no_new_parts= new_part_info->partitions.elements;
|
|
||||||
uint no_old_parts= old_part_info->partitions.elements;
|
|
||||||
uint new_count, old_count;
|
|
||||||
List_iterator<partition_element> new_parts_it(new_part_info->partitions);
|
|
||||||
bool is_same_part_info= (new_part_info == old_part_info);
|
|
||||||
DBUG_ENTER("are_partitions_in_table");
|
|
||||||
DBUG_PRINT("enter", ("%u", no_new_parts));
|
|
||||||
|
|
||||||
new_count= 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
List_iterator<partition_element> old_parts_it(old_part_info->partitions);
|
|
||||||
char *new_name= (new_parts_it++)->partition_name;
|
|
||||||
DBUG_PRINT("info", ("%s", new_name));
|
|
||||||
new_count++;
|
|
||||||
old_count= 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
char *old_name= (old_parts_it++)->partition_name;
|
|
||||||
old_count++;
|
|
||||||
if (is_same_part_info && old_count == new_count)
|
|
||||||
break;
|
|
||||||
if (!(my_strcasecmp(system_charset_info, old_name, new_name)))
|
|
||||||
{
|
|
||||||
DBUG_PRINT("info", ("old_name = %s, not ok", old_name));
|
|
||||||
DBUG_RETURN(old_name);
|
|
||||||
}
|
|
||||||
} while (old_count < no_old_parts);
|
|
||||||
} while (new_count < no_new_parts);
|
|
||||||
DBUG_RETURN(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set-up defaults for partitions.
|
Set-up defaults for partitions.
|
||||||
@ -262,7 +209,7 @@ bool partition_default_handling(TABLE *table, partition_info *part_info,
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_sub_partitioned(part_info) &&
|
else if (part_info->is_sub_partitioned() &&
|
||||||
part_info->use_default_no_subpartitions)
|
part_info->use_default_no_subpartitions)
|
||||||
{
|
{
|
||||||
uint no_parts;
|
uint no_parts;
|
||||||
@ -274,8 +221,8 @@ bool partition_default_handling(TABLE *table, partition_info *part_info,
|
|||||||
part_info->no_subparts= no_parts / part_info->no_parts;
|
part_info->no_subparts= no_parts / part_info->no_parts;
|
||||||
DBUG_ASSERT((no_parts % part_info->no_parts) == 0);
|
DBUG_ASSERT((no_parts % part_info->no_parts) == 0);
|
||||||
}
|
}
|
||||||
set_up_defaults_for_partitioning(part_info, table->file,
|
part_info->set_up_defaults_for_partitioning(table->file,
|
||||||
(ulonglong)0, (uint)0);
|
(ulonglong)0, (uint)0);
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,244 +607,9 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create a memory area where default partition names are stored and fill it
|
|
||||||
up with the names.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
create_default_partition_names()
|
|
||||||
no_parts Number of partitions
|
|
||||||
start_no Starting partition number
|
|
||||||
subpart Is it subpartitions
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
A pointer to the memory area of the default partition names
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
A support routine for the partition code where default values are
|
|
||||||
generated.
|
|
||||||
The external routine needing this code is check_partition_info
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MAX_PART_NAME_SIZE 8
|
|
||||||
|
|
||||||
static char *create_default_partition_names(uint no_parts, uint start_no,
|
|
||||||
bool is_subpart)
|
|
||||||
{
|
|
||||||
char *ptr= sql_calloc(no_parts*MAX_PART_NAME_SIZE);
|
|
||||||
char *move_ptr= ptr;
|
|
||||||
uint i= 0;
|
|
||||||
DBUG_ENTER("create_default_partition_names");
|
|
||||||
|
|
||||||
if (likely(ptr != 0))
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (is_subpart)
|
|
||||||
my_sprintf(move_ptr, (move_ptr,"sp%u", (start_no + i)));
|
|
||||||
else
|
|
||||||
my_sprintf(move_ptr, (move_ptr,"p%u", (start_no + i)));
|
|
||||||
move_ptr+=MAX_PART_NAME_SIZE;
|
|
||||||
} while (++i < no_parts);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mem_alloc_error(no_parts*MAX_PART_NAME_SIZE);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set up all the default partitions not set-up by the user in the SQL
|
|
||||||
statement. Also perform a number of checks that the user hasn't tried
|
|
||||||
to use default values where no defaults exists.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
set_up_default_partitions()
|
|
||||||
part_info The reference to all partition information
|
|
||||||
file A reference to a handler of the table
|
|
||||||
max_rows Maximum number of rows stored in the table
|
|
||||||
start_no Starting partition number
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
TRUE Error, attempted default values not possible
|
|
||||||
FALSE Ok, default partitions set-up
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
The routine uses the underlying handler of the partitioning to define
|
|
||||||
the default number of partitions. For some handlers this requires
|
|
||||||
knowledge of the maximum number of rows to be stored in the table.
|
|
||||||
This routine only accepts HASH and KEY partitioning and thus there is
|
|
||||||
no subpartitioning if this routine is successful.
|
|
||||||
The external routine needing this code is check_partition_info
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool set_up_default_partitions(partition_info *part_info,
|
|
||||||
handler *file, ulonglong max_rows,
|
|
||||||
uint start_no)
|
|
||||||
{
|
|
||||||
uint no_parts, i;
|
|
||||||
char *default_name;
|
|
||||||
bool result= TRUE;
|
|
||||||
DBUG_ENTER("set_up_default_partitions");
|
|
||||||
|
|
||||||
if (part_info->part_type != HASH_PARTITION)
|
|
||||||
{
|
|
||||||
const char *error_string;
|
|
||||||
if (part_info->part_type == RANGE_PARTITION)
|
|
||||||
error_string= partition_keywords[PKW_RANGE].str;
|
|
||||||
else
|
|
||||||
error_string= partition_keywords[PKW_LIST].str;
|
|
||||||
my_error(ER_PARTITIONS_MUST_BE_DEFINED_ERROR, MYF(0), error_string);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
if (part_info->no_parts == 0)
|
|
||||||
part_info->no_parts= file->get_default_no_partitions(max_rows);
|
|
||||||
no_parts= part_info->no_parts;
|
|
||||||
if (unlikely(no_parts > MAX_PARTITIONS))
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
if (unlikely((!(default_name= create_default_partition_names(no_parts,
|
|
||||||
start_no,
|
|
||||||
FALSE)))))
|
|
||||||
goto end;
|
|
||||||
i= 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
partition_element *part_elem= new partition_element();
|
|
||||||
if (likely(part_elem != 0 &&
|
|
||||||
(!part_info->partitions.push_back(part_elem))))
|
|
||||||
{
|
|
||||||
part_elem->engine_type= part_info->default_engine_type;
|
|
||||||
part_elem->partition_name= default_name;
|
|
||||||
default_name+=MAX_PART_NAME_SIZE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mem_alloc_error(sizeof(partition_element));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
} while (++i < no_parts);
|
|
||||||
result= FALSE;
|
|
||||||
end:
|
|
||||||
DBUG_RETURN(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Set up all the default subpartitions not set-up by the user in the SQL
|
|
||||||
statement. Also perform a number of checks that the default partitioning
|
|
||||||
becomes an allowed partitioning scheme.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
set_up_default_subpartitions()
|
|
||||||
part_info The reference to all partition information
|
|
||||||
file A reference to a handler of the table
|
|
||||||
max_rows Maximum number of rows stored in the table
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
TRUE Error, attempted default values not possible
|
|
||||||
FALSE Ok, default partitions set-up
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
The routine uses the underlying handler of the partitioning to define
|
|
||||||
the default number of partitions. For some handlers this requires
|
|
||||||
knowledge of the maximum number of rows to be stored in the table.
|
|
||||||
This routine is only called for RANGE or LIST partitioning and those
|
|
||||||
need to be specified so only subpartitions are specified.
|
|
||||||
The external routine needing this code is check_partition_info
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool set_up_default_subpartitions(partition_info *part_info,
|
|
||||||
handler *file, ulonglong max_rows)
|
|
||||||
{
|
|
||||||
uint i, j, no_parts, no_subparts;
|
|
||||||
char *default_name, *name_ptr;
|
|
||||||
bool result= TRUE;
|
|
||||||
partition_element *part_elem;
|
|
||||||
List_iterator<partition_element> part_it(part_info->partitions);
|
|
||||||
DBUG_ENTER("set_up_default_subpartitions");
|
|
||||||
|
|
||||||
if (part_info->no_subparts == 0)
|
|
||||||
part_info->no_subparts= file->get_default_no_partitions(max_rows);
|
|
||||||
no_parts= part_info->no_parts;
|
|
||||||
no_subparts= part_info->no_subparts;
|
|
||||||
if (unlikely((no_parts * no_subparts) > MAX_PARTITIONS))
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
if (unlikely((!(default_name=
|
|
||||||
create_default_partition_names(no_subparts, (uint)0, TRUE)))))
|
|
||||||
goto end;
|
|
||||||
i= 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
part_elem= part_it++;
|
|
||||||
j= 0;
|
|
||||||
name_ptr= default_name;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
partition_element *subpart_elem= new partition_element();
|
|
||||||
if (likely(subpart_elem != 0 &&
|
|
||||||
(!part_elem->subpartitions.push_back(subpart_elem))))
|
|
||||||
{
|
|
||||||
subpart_elem->engine_type= part_info->default_engine_type;
|
|
||||||
subpart_elem->partition_name= name_ptr;
|
|
||||||
name_ptr+= MAX_PART_NAME_SIZE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mem_alloc_error(sizeof(partition_element));
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
} while (++j < no_subparts);
|
|
||||||
} while (++i < no_parts);
|
|
||||||
result= FALSE;
|
|
||||||
end:
|
|
||||||
DBUG_RETURN(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Support routine for check_partition_info
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
set_up_defaults_for_partitioning()
|
|
||||||
part_info The reference to all partition information
|
|
||||||
file A reference to a handler of the table
|
|
||||||
max_rows Maximum number of rows stored in the table
|
|
||||||
start_no Starting partition number
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
TRUE Error, attempted default values not possible
|
|
||||||
FALSE Ok, default partitions set-up
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Set up defaults for partition or subpartition (cannot set-up for both,
|
|
||||||
this will return an error.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool set_up_defaults_for_partitioning(partition_info *part_info,
|
|
||||||
handler *file,
|
|
||||||
ulonglong max_rows, uint start_no)
|
|
||||||
{
|
|
||||||
DBUG_ENTER("set_up_defaults_for_partitioning");
|
|
||||||
|
|
||||||
if (!part_info->default_partitions_setup)
|
|
||||||
{
|
|
||||||
part_info->default_partitions_setup= TRUE;
|
|
||||||
if (part_info->use_default_partitions)
|
|
||||||
DBUG_RETURN(set_up_default_partitions(part_info, file, max_rows,
|
|
||||||
start_no));
|
|
||||||
if (is_sub_partitioned(part_info) && part_info->use_default_subpartitions)
|
|
||||||
DBUG_RETURN(set_up_default_subpartitions(part_info, file, max_rows));
|
|
||||||
}
|
|
||||||
DBUG_RETURN(FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -967,7 +679,7 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type,
|
|||||||
char *same_name;
|
char *same_name;
|
||||||
DBUG_ENTER("check_partition_info");
|
DBUG_ENTER("check_partition_info");
|
||||||
|
|
||||||
if (unlikely(is_sub_partitioned(part_info) &&
|
if (unlikely(part_info->is_sub_partitioned() &&
|
||||||
(!(part_info->part_type == RANGE_PARTITION ||
|
(!(part_info->part_type == RANGE_PARTITION ||
|
||||||
part_info->part_type == LIST_PARTITION))))
|
part_info->part_type == LIST_PARTITION))))
|
||||||
{
|
{
|
||||||
@ -975,17 +687,17 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type,
|
|||||||
my_error(ER_SUBPARTITION_ERROR, MYF(0));
|
my_error(ER_SUBPARTITION_ERROR, MYF(0));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (unlikely(set_up_defaults_for_partitioning(part_info, file,
|
if (unlikely(part_info->set_up_defaults_for_partitioning(file,
|
||||||
max_rows, (uint)0)))
|
max_rows,
|
||||||
|
(uint)0)))
|
||||||
goto end;
|
goto end;
|
||||||
tot_partitions= get_tot_partitions(part_info);
|
tot_partitions= part_info->get_tot_partitions();
|
||||||
if (unlikely(tot_partitions > MAX_PARTITIONS))
|
if (unlikely(tot_partitions > MAX_PARTITIONS))
|
||||||
{
|
{
|
||||||
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
if (((same_name= are_partitions_in_table(part_info,
|
if (same_name= part_info->has_unique_names())
|
||||||
part_info))))
|
|
||||||
{
|
{
|
||||||
my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
|
my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
|
||||||
goto end;
|
goto end;
|
||||||
@ -1001,7 +713,7 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type,
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
partition_element *part_elem= part_it++;
|
partition_element *part_elem= part_it++;
|
||||||
if (!is_sub_partitioned(part_info))
|
if (!part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
if (part_elem->engine_type == NULL)
|
if (part_elem->engine_type == NULL)
|
||||||
part_elem->engine_type= part_info->default_engine_type;
|
part_elem->engine_type= part_info->default_engine_type;
|
||||||
@ -1194,7 +906,7 @@ static bool create_full_part_field_array(TABLE *table,
|
|||||||
bool result= FALSE;
|
bool result= FALSE;
|
||||||
DBUG_ENTER("create_full_part_field_array");
|
DBUG_ENTER("create_full_part_field_array");
|
||||||
|
|
||||||
if (!is_sub_partitioned(part_info))
|
if (!part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
part_info->full_part_field_array= part_info->part_field_array;
|
part_info->full_part_field_array= part_info->part_field_array;
|
||||||
part_info->no_full_part_fields= part_info->no_part_fields;
|
part_info->no_full_part_fields= part_info->no_part_fields;
|
||||||
@ -1751,7 +1463,7 @@ static void set_up_partition_key_maps(TABLE *table,
|
|||||||
part_info->all_fields_in_PF.set_bit(i);
|
part_info->all_fields_in_PF.set_bit(i);
|
||||||
if (some_fields)
|
if (some_fields)
|
||||||
part_info->some_fields_in_PF.set_bit(i);
|
part_info->some_fields_in_PF.set_bit(i);
|
||||||
if (is_sub_partitioned(part_info))
|
if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
check_fields_in_PF(part_info->part_field_array,
|
check_fields_in_PF(part_info->part_field_array,
|
||||||
&all_fields, &some_fields);
|
&all_fields, &some_fields);
|
||||||
@ -1789,7 +1501,7 @@ static void set_up_partition_func_pointers(partition_info *part_info)
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("set_up_partition_func_pointers");
|
DBUG_ENTER("set_up_partition_func_pointers");
|
||||||
|
|
||||||
if (is_sub_partitioned(part_info))
|
if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
if (part_info->part_type == RANGE_PARTITION)
|
if (part_info->part_type == RANGE_PARTITION)
|
||||||
{
|
{
|
||||||
@ -2011,7 +1723,7 @@ bool fix_partition_func(THD *thd, const char* name, TABLE *table,
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_sub_partitioned(part_info))
|
if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(part_info->subpart_type == HASH_PARTITION);
|
DBUG_ASSERT(part_info->subpart_type == HASH_PARTITION);
|
||||||
/*
|
/*
|
||||||
@ -2442,7 +2154,7 @@ char *generate_partition_syntax(partition_info *part_info,
|
|||||||
err+= add_int(fptr, part_info->no_parts);
|
err+= add_int(fptr, part_info->no_parts);
|
||||||
err+= add_space(fptr);
|
err+= add_space(fptr);
|
||||||
}
|
}
|
||||||
if (is_sub_partitioned(part_info))
|
if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
err+= add_subpartition_by(fptr);
|
err+= add_subpartition_by(fptr);
|
||||||
/* Must be hash partitioning for subpartitioning */
|
/* Must be hash partitioning for subpartitioning */
|
||||||
@ -2528,9 +2240,9 @@ char *generate_partition_syntax(partition_info *part_info,
|
|||||||
err+= add_string(fptr, part_elem->partition_name);
|
err+= add_string(fptr, part_elem->partition_name);
|
||||||
err+= add_space(fptr);
|
err+= add_space(fptr);
|
||||||
err+= add_partition_values(fptr, part_info, part_elem);
|
err+= add_partition_values(fptr, part_info, part_elem);
|
||||||
if (!is_sub_partitioned(part_info))
|
if (!part_info->is_sub_partitioned())
|
||||||
err+= add_partition_options(fptr, part_elem);
|
err+= add_partition_options(fptr, part_elem);
|
||||||
if (is_sub_partitioned(part_info) &&
|
if (part_info->is_sub_partitioned() &&
|
||||||
(write_all || (!part_info->use_default_subpartitions)))
|
(write_all || (!part_info->use_default_subpartitions)))
|
||||||
{
|
{
|
||||||
err+= add_space(fptr);
|
err+= add_space(fptr);
|
||||||
@ -3635,7 +3347,7 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
|||||||
const key_range *key_spec, part_id_range *part_spec)
|
const key_range *key_spec, part_id_range *part_spec)
|
||||||
{
|
{
|
||||||
partition_info *part_info= table->part_info;
|
partition_info *part_info= table->part_info;
|
||||||
uint no_parts= get_tot_partitions(part_info);
|
uint no_parts= part_info->get_tot_partitions();
|
||||||
uint i, part_id;
|
uint i, part_id;
|
||||||
uint sub_part= no_parts;
|
uint sub_part= no_parts;
|
||||||
uint32 part_part= no_parts;
|
uint32 part_part= no_parts;
|
||||||
@ -3671,7 +3383,7 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
|||||||
get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec);
|
get_full_part_id_from_key(table,buf,key_info,key_spec,part_spec);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
else if (is_sub_partitioned(part_info))
|
else if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
if (part_info->all_fields_in_SPF.is_set(index))
|
if (part_info->all_fields_in_SPF.is_set(index))
|
||||||
sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
|
sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
|
||||||
@ -3713,7 +3425,7 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
|||||||
clear_indicator_in_key_fields(key_info);
|
clear_indicator_in_key_fields(key_info);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
else if (is_sub_partitioned(part_info))
|
else if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
if (check_part_func_bound(part_info->subpart_field_array))
|
if (check_part_func_bound(part_info->subpart_field_array))
|
||||||
sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
|
sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
|
||||||
@ -4131,7 +3843,7 @@ static bool check_native_partitioned(HA_CREATE_INFO *create_info,bool *ret_val,
|
|||||||
do
|
do
|
||||||
{
|
{
|
||||||
partition_element *part_elem= part_it++;
|
partition_element *part_elem= part_it++;
|
||||||
if (is_sub_partitioned(part_info) &&
|
if (part_info->is_sub_partitioned() &&
|
||||||
part_elem->subpartitions.elements)
|
part_elem->subpartitions.elements)
|
||||||
{
|
{
|
||||||
uint no_subparts= part_elem->subpartitions.elements;
|
uint no_subparts= part_elem->subpartitions.elements;
|
||||||
@ -4321,7 +4033,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
|
|||||||
my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
|
my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
if (is_sub_partitioned(tab_part_info))
|
if (tab_part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
if (alt_part_info->no_subparts == 0)
|
if (alt_part_info->no_subparts == 0)
|
||||||
alt_part_info->no_subparts= tab_part_info->no_subparts;
|
alt_part_info->no_subparts= tab_part_info->no_subparts;
|
||||||
@ -4339,10 +4051,9 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
alt_part_info->part_type= tab_part_info->part_type;
|
alt_part_info->part_type= tab_part_info->part_type;
|
||||||
if (set_up_defaults_for_partitioning(alt_part_info,
|
if (alt_part_info->set_up_defaults_for_partitioning(table->file,
|
||||||
table->file,
|
ULL(0),
|
||||||
ULL(0),
|
tab_part_info->no_parts))
|
||||||
tab_part_info->no_parts))
|
|
||||||
{
|
{
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
@ -5550,7 +5261,7 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str)
|
|||||||
uint partition_id= 0;
|
uint partition_id= 0;
|
||||||
List_iterator<partition_element> it(part_info->partitions);
|
List_iterator<partition_element> it(part_info->partitions);
|
||||||
|
|
||||||
if (is_sub_partitioned(part_info))
|
if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
partition_element *head_pe;
|
partition_element *head_pe;
|
||||||
while ((head_pe= it++))
|
while ((head_pe= it++))
|
||||||
|
218
sql/sql_partition.h
Normal file
218
sql/sql_partition.h
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
/* Copyright (C) 2005 MySQL AB
|
||||||
|
|
||||||
|
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; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
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
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma interface /* gcc class implementation */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Flags for partition handlers */
|
||||||
|
#define HA_CAN_PARTITION (1 << 0) /* Partition support */
|
||||||
|
#define HA_CAN_UPDATE_PARTITION_KEY (1 << 1)
|
||||||
|
#define HA_CAN_PARTITION_UNIQUE (1 << 2)
|
||||||
|
#define HA_USE_AUTO_PARTITION (1 << 3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
HA_PARTITION_FUNCTION_SUPPORTED indicates that the function is
|
||||||
|
supported at all.
|
||||||
|
HA_FAST_CHANGE_PARTITION means that optimised variants of the changes
|
||||||
|
exists but they are not necessarily done online.
|
||||||
|
|
||||||
|
HA_ONLINE_DOUBLE_WRITE means that the handler supports writing to both
|
||||||
|
the new partition and to the old partitions when updating through the
|
||||||
|
old partitioning schema while performing a change of the partitioning.
|
||||||
|
This means that we can support updating of the table while performing
|
||||||
|
the copy phase of the change. For no lock at all also a double write
|
||||||
|
from new to old must exist and this is not required when this flag is
|
||||||
|
set.
|
||||||
|
This is actually removed even before it was introduced the first time.
|
||||||
|
The new idea is that handlers will handle the lock level already in
|
||||||
|
store_lock for ALTER TABLE partitions.
|
||||||
|
|
||||||
|
HA_PARTITION_ONE_PHASE is a flag that can be set by handlers that take
|
||||||
|
care of changing the partitions online and in one phase. Thus all phases
|
||||||
|
needed to handle the change are implemented inside the storage engine.
|
||||||
|
The storage engine must also support auto-discovery since the frm file
|
||||||
|
is changed as part of the change and this change must be controlled by
|
||||||
|
the storage engine. A typical engine to support this is NDB (through
|
||||||
|
WL #2498).
|
||||||
|
*/
|
||||||
|
#define HA_PARTITION_FUNCTION_SUPPORTED (1L << 12)
|
||||||
|
#define HA_FAST_CHANGE_PARTITION (1L << 13)
|
||||||
|
#define HA_PARTITION_ONE_PHASE (1L << 14)
|
||||||
|
|
||||||
|
/*typedef struct {
|
||||||
|
ulonglong data_file_length;
|
||||||
|
ulonglong max_data_file_length;
|
||||||
|
ulonglong index_file_length;
|
||||||
|
ulonglong delete_length;
|
||||||
|
ha_rows records;
|
||||||
|
ulong mean_rec_length;
|
||||||
|
time_t create_time;
|
||||||
|
time_t check_time;
|
||||||
|
time_t update_time;
|
||||||
|
ulonglong check_sum;
|
||||||
|
} PARTITION_INFO;
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
longlong list_value;
|
||||||
|
uint32 partition_id;
|
||||||
|
} LIST_PART_ENTRY;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32 start_part;
|
||||||
|
uint32 end_part;
|
||||||
|
} part_id_range;
|
||||||
|
|
||||||
|
struct st_partition_iter;
|
||||||
|
#define NOT_A_PARTITION_ID ((uint32)-1)
|
||||||
|
|
||||||
|
bool is_partition_in_list(char *part_name, List<char> list_part_names);
|
||||||
|
char *are_partitions_in_table(partition_info *new_part_info,
|
||||||
|
partition_info *old_part_info);
|
||||||
|
bool check_reorganise_list(partition_info *new_part_info,
|
||||||
|
partition_info *old_part_info,
|
||||||
|
List<char> list_part_names);
|
||||||
|
handler *get_ha_partition(partition_info *part_info);
|
||||||
|
int get_parts_for_update(const byte *old_data, byte *new_data,
|
||||||
|
const byte *rec0, partition_info *part_info,
|
||||||
|
uint32 *old_part_id, uint32 *new_part_id,
|
||||||
|
longlong *func_value);
|
||||||
|
int get_part_for_delete(const byte *buf, const byte *rec0,
|
||||||
|
partition_info *part_info, uint32 *part_id);
|
||||||
|
bool check_partition_info(partition_info *part_info,handlerton **eng_type,
|
||||||
|
handler *file, ulonglong max_rows);
|
||||||
|
bool fix_partition_func(THD *thd, const char *name, TABLE *table,
|
||||||
|
bool create_table_ind);
|
||||||
|
char *generate_partition_syntax(partition_info *part_info,
|
||||||
|
uint *buf_length, bool use_sql_alloc,
|
||||||
|
bool write_all);
|
||||||
|
bool partition_key_modified(TABLE *table, List<Item> &fields);
|
||||||
|
void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
||||||
|
const key_range *key_spec,
|
||||||
|
part_id_range *part_spec);
|
||||||
|
void get_full_part_id_from_key(const TABLE *table, byte *buf,
|
||||||
|
KEY *key_info,
|
||||||
|
const key_range *key_spec,
|
||||||
|
part_id_range *part_spec);
|
||||||
|
bool mysql_unpack_partition(THD *thd, const uchar *part_buf,
|
||||||
|
uint part_info_len,
|
||||||
|
uchar *part_state, uint part_state_len,
|
||||||
|
TABLE *table, bool is_create_table_ind,
|
||||||
|
handlerton *default_db_type);
|
||||||
|
void make_used_partitions_str(partition_info *part_info, String *parts_str);
|
||||||
|
uint32 get_list_array_idx_for_endpoint(partition_info *part_info,
|
||||||
|
bool left_endpoint,
|
||||||
|
bool include_endpoint);
|
||||||
|
uint32 get_partition_id_range_for_endpoint(partition_info *part_info,
|
||||||
|
bool left_endpoint,
|
||||||
|
bool include_endpoint);
|
||||||
|
|
||||||
|
/*
|
||||||
|
A "Get next" function for partition iterator.
|
||||||
|
SYNOPSIS
|
||||||
|
partition_iter_func()
|
||||||
|
part_iter Partition iterator, you call only "iter.get_next(&iter)"
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
NOT_A_PARTITION_ID if there are no more partitions.
|
||||||
|
[sub]partition_id of the next partition
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uint32 (*partition_iter_func)(st_partition_iter* part_iter);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Partition set iterator. Used to enumerate a set of [sub]partitions
|
||||||
|
obtained in partition interval analysis (see get_partitions_in_range_iter).
|
||||||
|
|
||||||
|
For the user, the only meaningful field is get_next, which may be used as
|
||||||
|
follows:
|
||||||
|
part_iterator.get_next(&part_iterator);
|
||||||
|
|
||||||
|
Initialization is done by any of the following calls:
|
||||||
|
- get_partitions_in_range_iter-type function call
|
||||||
|
- init_single_partition_iterator()
|
||||||
|
- init_all_partitions_iterator()
|
||||||
|
Cleanup is not needed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct st_partition_iter
|
||||||
|
{
|
||||||
|
partition_iter_func get_next;
|
||||||
|
|
||||||
|
struct st_part_num_range
|
||||||
|
{
|
||||||
|
uint32 start;
|
||||||
|
uint32 end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct st_field_value_range
|
||||||
|
{
|
||||||
|
longlong start;
|
||||||
|
longlong end;
|
||||||
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct st_part_num_range part_nums;
|
||||||
|
struct st_field_value_range field_vals;
|
||||||
|
};
|
||||||
|
partition_info *part_info;
|
||||||
|
} PARTITION_ITERATOR;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get an iterator for set of partitions that match given field-space interval
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
get_partitions_in_range_iter()
|
||||||
|
part_info Partitioning info
|
||||||
|
is_subpart
|
||||||
|
min_val Left edge, field value in opt_range_key format.
|
||||||
|
max_val Right edge, field value in opt_range_key format.
|
||||||
|
flags Some combination of NEAR_MIN, NEAR_MAX, NO_MIN_RANGE,
|
||||||
|
NO_MAX_RANGE.
|
||||||
|
part_iter Iterator structure to be initialized
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Functions with this signature are used to perform "Partitioning Interval
|
||||||
|
Analysis". This analysis is applicable for any type of [sub]partitioning
|
||||||
|
by some function of a single fieldX. The idea is as follows:
|
||||||
|
Given an interval "const1 <=? fieldX <=? const2", find a set of partitions
|
||||||
|
that may contain records with value of fieldX within the given interval.
|
||||||
|
|
||||||
|
The min_val, max_val and flags parameters specify the interval.
|
||||||
|
The set of partitions is returned by initializing an iterator in *part_iter
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
There are currently two functions of this type:
|
||||||
|
- get_part_iter_for_interval_via_walking
|
||||||
|
- get_part_iter_for_interval_via_mapping
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 - No matching partitions, iterator not initialized
|
||||||
|
1 - Some partitions would match, iterator intialized for traversing them
|
||||||
|
-1 - All partitions would match, iterator not initialized
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int (*get_partitions_in_range_iter)(partition_info *part_info,
|
||||||
|
bool is_subpart,
|
||||||
|
char *min_val, char *max_val,
|
||||||
|
uint flags,
|
||||||
|
PARTITION_ITERATOR *part_iter);
|
||||||
|
|
||||||
|
#include "partition_info.h"
|
||||||
|
|
@ -3657,7 +3657,7 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
|
|||||||
table->field[9]->set_notnull();
|
table->field[9]->set_notnull();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_sub_partitioned(part_info))
|
if (part_info->is_sub_partitioned())
|
||||||
{
|
{
|
||||||
/* Subpartition method */
|
/* Subpartition method */
|
||||||
if (part_info->list_of_subpart_fields)
|
if (part_info->list_of_subpart_fields)
|
||||||
|
@ -40,7 +40,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc discover.
|
|||||||
sql_state.c sql_string.cc sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
|
sql_state.c sql_string.cc sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
|
||||||
sql_update.cc sql_view.cc sql_yacc.h sql_yacc.cc strfunc.cc table.cc thr_malloc.cc time.cc tztime.cc
|
sql_update.cc sql_view.cc sql_yacc.h sql_yacc.cc strfunc.cc table.cc thr_malloc.cc time.cc tztime.cc
|
||||||
uniques.cc unireg.cc item_xmlfunc.cc rpl_tblmap.cc sql_binlog.cc event_executor.cc
|
uniques.cc unireg.cc item_xmlfunc.cc rpl_tblmap.cc sql_binlog.cc event_executor.cc
|
||||||
event_timed.cc sql_tablespace.cc event.cc ../sql-common/my_user.c
|
event_timed.cc sql_tablespace.cc event.cc ../sql-common/my_user.c partition_info.cpp
|
||||||
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
|
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
|
||||||
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
|
${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
|
||||||
${PROJECT_SOURCE_DIR}/include/mysqld_error.h
|
${PROJECT_SOURCE_DIR}/include/mysqld_error.h
|
||||||
|
Loading…
x
Reference in New Issue
Block a user