mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
Merge reggie@192.168.0.9:/home/reggie/work/mysql-5.1-bug15408
into big_geek.:C:/Work/mysql/mysql-5.1-bug15408 sql/ha_partition.cc: Auto merged sql/opt_range.cc: Auto merged sql/sql_partition.cc: Auto merged sql/sql_show.cc: Auto merged sql/handler.h: merging changes into my partition code reorg
This commit is contained in:
commit
8270eb50e4
15 changed files with 982 additions and 823 deletions
|
@ -142,3 +142,8 @@ t1 CREATE TABLE `t1` (
|
|||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a INT) PARTITION BY HASH(a);
|
||||
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);
|
||||
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 \
|
||||
parse_file.h sql_view.h sql_trigger.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 \
|
||||
item.cc item_sum.cc item_buff.cc item_func.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 \
|
||||
event_executor.cc event.cc event_timed.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 \
|
||||
ha_innodb.h ha_berkeley.h ha_archive.h \
|
||||
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)
|
||||
:handler(&partition_hton, NULL), m_part_info(part_info),
|
||||
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)");
|
||||
|
@ -331,7 +331,7 @@ int ha_partition::ha_initialise()
|
|||
|
||||
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);
|
||||
if (new_handlers_from_part_info())
|
||||
DBUG_RETURN(1);
|
||||
|
@ -1290,7 +1290,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
|
|||
DBUG_ENTER("ha_partition::change_partitions");
|
||||
|
||||
m_reorged_parts= 0;
|
||||
if (!is_sub_partitioned(m_part_info))
|
||||
if (!m_part_info->is_sub_partitioned())
|
||||
no_subparts= 1;
|
||||
|
||||
/*
|
||||
|
@ -1453,7 +1453,7 @@ int ha_partition::change_partitions(HA_CREATE_INFO *create_info,
|
|||
if (part_elem->part_state == PART_CHANGED ||
|
||||
(part_elem->part_state == PART_TO_BE_ADDED && temp_partitions))
|
||||
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);
|
||||
uint j= 0, part;
|
||||
|
|
|
@ -135,7 +135,7 @@ public:
|
|||
virtual void set_part_info(partition_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();
|
||||
}
|
||||
/*
|
||||
-------------------------------------------------------------------------
|
||||
|
|
498
sql/handler.h
498
sql/handler.h
|
@ -95,13 +95,6 @@
|
|||
#define HA_ANY_INDEX_MAY_BE_UNIQUE (1 << 30)
|
||||
#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 */
|
||||
#define HA_READ_NEXT 1 /* TODO really use this flag */
|
||||
#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_ADD_PK_INDEX (1L << 10)/*add 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
|
||||
|
@ -618,33 +583,6 @@ enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
|
|||
|
||||
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 {
|
||||
ulonglong data_file_length;
|
||||
|
@ -662,400 +600,12 @@ typedef struct {
|
|||
#define UNDEF_NODEGROUP 65535
|
||||
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;
|
||||
|
||||
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;
|
||||
#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
|
||||
{
|
||||
|
@ -1100,54 +650,6 @@ typedef struct st_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 prune_partition_set(const TABLE *table, part_id_range *part_spec);
|
||||
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
|
||||
|
||||
|
||||
/*
|
||||
This is a buffer area that the handler can use to store rows.
|
||||
|
|
|
@ -503,6 +503,8 @@ typedef my_bool (*qc_engine_callback)(THD *thd, char *table_key,
|
|||
#include "protocol.h"
|
||||
#include "sql_plugin.h"
|
||||
#include "sql_udf.h"
|
||||
#include "sql_partition.h"
|
||||
|
||||
class user_var_entry;
|
||||
class Security_context;
|
||||
enum enum_var_type
|
||||
|
|
|
@ -2976,7 +2976,7 @@ static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
|
|||
ppar->last_subpart_partno=
|
||||
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->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.
|
||||
|
@ -262,7 +209,7 @@ bool partition_default_handling(TABLE *table, partition_info *part_info,
|
|||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
else if (is_sub_partitioned(part_info) &&
|
||||
else if (part_info->is_sub_partitioned() &&
|
||||
part_info->use_default_no_subpartitions)
|
||||
{
|
||||
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;
|
||||
DBUG_ASSERT((no_parts % part_info->no_parts) == 0);
|
||||
}
|
||||
set_up_defaults_for_partitioning(part_info, table->file,
|
||||
(ulonglong)0, (uint)0);
|
||||
part_info->set_up_defaults_for_partitioning(table->file,
|
||||
(ulonglong)0, (uint)0);
|
||||
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;
|
||||
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 == LIST_PARTITION))))
|
||||
{
|
||||
|
@ -975,17 +687,17 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type,
|
|||
my_error(ER_SUBPARTITION_ERROR, MYF(0));
|
||||
goto end;
|
||||
}
|
||||
if (unlikely(set_up_defaults_for_partitioning(part_info, file,
|
||||
max_rows, (uint)0)))
|
||||
if (unlikely(part_info->set_up_defaults_for_partitioning(file,
|
||||
max_rows,
|
||||
(uint)0)))
|
||||
goto end;
|
||||
tot_partitions= get_tot_partitions(part_info);
|
||||
tot_partitions= part_info->get_tot_partitions();
|
||||
if (unlikely(tot_partitions > MAX_PARTITIONS))
|
||||
{
|
||||
my_error(ER_TOO_MANY_PARTITIONS_ERROR, MYF(0));
|
||||
goto end;
|
||||
}
|
||||
if (((same_name= are_partitions_in_table(part_info,
|
||||
part_info))))
|
||||
if (same_name= part_info->has_unique_names())
|
||||
{
|
||||
my_error(ER_SAME_NAME_PARTITION, MYF(0), same_name);
|
||||
goto end;
|
||||
|
@ -1001,7 +713,7 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type,
|
|||
do
|
||||
{
|
||||
partition_element *part_elem= part_it++;
|
||||
if (!is_sub_partitioned(part_info))
|
||||
if (!part_info->is_sub_partitioned())
|
||||
{
|
||||
if (part_elem->engine_type == NULL)
|
||||
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;
|
||||
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->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);
|
||||
if (some_fields)
|
||||
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,
|
||||
&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");
|
||||
|
||||
if (is_sub_partitioned(part_info))
|
||||
if (part_info->is_sub_partitioned())
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (is_sub_partitioned(part_info))
|
||||
if (part_info->is_sub_partitioned())
|
||||
{
|
||||
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_space(fptr);
|
||||
}
|
||||
if (is_sub_partitioned(part_info))
|
||||
if (part_info->is_sub_partitioned())
|
||||
{
|
||||
err+= add_subpartition_by(fptr);
|
||||
/* 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_space(fptr);
|
||||
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);
|
||||
if (is_sub_partitioned(part_info) &&
|
||||
if (part_info->is_sub_partitioned() &&
|
||||
(write_all || (!part_info->use_default_subpartitions)))
|
||||
{
|
||||
err+= add_space(fptr);
|
||||
|
@ -3680,7 +3392,7 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
|||
const key_range *key_spec, part_id_range *part_spec)
|
||||
{
|
||||
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 sub_part= no_parts;
|
||||
uint32 part_part= no_parts;
|
||||
|
@ -3720,7 +3432,7 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
|||
prune_partition_set(table, part_spec);
|
||||
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))
|
||||
sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
|
||||
|
@ -3766,7 +3478,7 @@ void get_partition_set(const TABLE *table, byte *buf, const uint index,
|
|||
prune_partition_set(table, part_spec);
|
||||
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))
|
||||
sub_part= get_sub_part_id_from_key(table, buf, key_info, key_spec);
|
||||
|
@ -4187,7 +3899,7 @@ static bool check_native_partitioned(HA_CREATE_INFO *create_info,bool *ret_val,
|
|||
do
|
||||
{
|
||||
partition_element *part_elem= part_it++;
|
||||
if (is_sub_partitioned(part_info) &&
|
||||
if (part_info->is_sub_partitioned() &&
|
||||
part_elem->subpartitions.elements)
|
||||
{
|
||||
uint no_subparts= part_elem->subpartitions.elements;
|
||||
|
@ -4377,7 +4089,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
|
|||
my_error(ER_ADD_PARTITION_NO_NEW_PARTITION, MYF(0));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (is_sub_partitioned(tab_part_info))
|
||||
if (tab_part_info->is_sub_partitioned())
|
||||
{
|
||||
if (alt_part_info->no_subparts == 0)
|
||||
alt_part_info->no_subparts= tab_part_info->no_subparts;
|
||||
|
@ -4395,10 +4107,9 @@ uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
|
|||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
alt_part_info->part_type= tab_part_info->part_type;
|
||||
if (set_up_defaults_for_partitioning(alt_part_info,
|
||||
table->file,
|
||||
ULL(0),
|
||||
tab_part_info->no_parts))
|
||||
if (alt_part_info->set_up_defaults_for_partitioning(table->file,
|
||||
ULL(0),
|
||||
tab_part_info->no_parts))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
@ -5606,7 +5317,7 @@ void make_used_partitions_str(partition_info *part_info, String *parts_str)
|
|||
uint partition_id= 0;
|
||||
List_iterator<partition_element> it(part_info->partitions);
|
||||
|
||||
if (is_sub_partitioned(part_info))
|
||||
if (part_info->is_sub_partitioned())
|
||||
{
|
||||
partition_element *head_pe;
|
||||
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"
|
||||
|
|
@ -3770,7 +3770,7 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables,
|
|||
table->field[9]->set_notnull();
|
||||
}
|
||||
|
||||
if (is_sub_partitioned(part_info))
|
||||
if (part_info->is_sub_partitioned())
|
||||
{
|
||||
/* Subpartition method */
|
||||
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_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
|
||||
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.h
|
||||
${PROJECT_SOURCE_DIR}/include/mysqld_error.h
|
||||
|
|
Loading…
Reference in a new issue