summaryrefslogtreecommitdiff
path: root/sql/opt_range.cc
diff options
context:
space:
mode:
authorunknown <sergefp@mysql.com>2006-01-18 14:09:08 +0300
committerunknown <sergefp@mysql.com>2006-01-18 14:09:08 +0300
commit18a1e69ebaa46722c49c493f23ee45c4cf847c3c (patch)
tree125d1e6899817ba566c75f28a00bfcef1f98a7a4 /sql/opt_range.cc
parentb58c076c1898ec5f994660063df20ace2f1924e9 (diff)
parent0f1fa93af8708ea34326039f844ddd6ac053687c (diff)
downloadmariadb-git-18a1e69ebaa46722c49c493f23ee45c4cf847c3c.tar.gz
Manual merge
mysql-test/r/partition.result: Auto merged sql/handler.h: Auto merged sql/item.h: Auto merged sql/sql_class.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_select.cc: Auto merged
Diffstat (limited to 'sql/opt_range.cc')
-rw-r--r--sql/opt_range.cc508
1 files changed, 279 insertions, 229 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 7942edd935d..96e73dc465a 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -313,11 +313,46 @@ public:
}
SEL_ARG *clone_tree();
- /* Return TRUE if this represents "keypartK = const" or "keypartK IS NULL" */
+
+ /*
+ Check if this SEL_ARG object represents a single-point interval
+
+ SYNOPSIS
+ is_singlepoint()
+
+ DESCRIPTION
+ Check if this SEL_ARG object (not tree) represents a single-point
+ interval, i.e. if it represents a "keypart = const" or
+ "keypart IS NULL".
+
+ RETURN
+ TRUE This SEL_ARG object represents a singlepoint interval
+ FALSE Otherwise
+ */
+
bool is_singlepoint()
{
- return !min_flag && !max_flag &&
- !field->key_cmp((byte*) min_value, (byte*)max_value);
+ /*
+ Check for NEAR_MIN ("strictly less") and NO_MIN_RANGE (-inf < field)
+ flags, and the same for right edge.
+ */
+ if (min_flag || max_flag)
+ return FALSE;
+ byte *min_val= min_value;
+ byte *max_val= min_value;
+
+ if (maybe_null)
+ {
+ /* First byte is a NULL value indicator */
+ if (*min_val != *max_val)
+ return FALSE;
+
+ if (*min_val)
+ return TRUE; /* This "x IS NULL" */
+ min_val++;
+ max_val++;
+ }
+ return !field->key_cmp(min_val, max_val);
}
};
@@ -2035,7 +2070,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
}
/****************************************************************************
- * Partition pruning starts
+ * Partition pruning module
****************************************************************************/
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -2080,7 +2115,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
The list of intervals we'll obtain will look like this:
((t1.a, t1.b) = (1,'foo')),
((t1.a, t1.b) = (2,'bar')),
- ((t1,a, t1.b) > (10,'zz')) (**)
+ ((t1,a, t1.b) > (10,'zz'))
2. for each interval I
{
@@ -2110,7 +2145,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
Putting it all together, partitioning module works as follows:
prune_partitions() {
- call create_partition_index_descrition();
+ call create_partition_index_description();
call get_mm_tree(); // invoke the RangeAnalysisModule
@@ -2124,10 +2159,6 @@ struct st_part_prune_param;
struct st_part_opt_info;
typedef void (*mark_full_part_func)(partition_info*, uint32);
-typedef uint32 (*part_num_to_partition_id_func)(struct st_part_prune_param*,
- uint32);
-typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
- bool include_endpoint);
/*
Partition pruning operation context
@@ -2135,7 +2166,7 @@ typedef uint32 (*get_endpoint_func)(partition_info*, bool left_endpoint,
typedef struct st_part_prune_param
{
RANGE_OPT_PARAM range_param; /* Range analyzer parameters */
-
+
/***************************************************************
Following fields are filled in based solely on partitioning
definition and not modified after that:
@@ -2165,32 +2196,6 @@ typedef struct st_part_prune_param
int last_subpart_partno; /* Same as above for supartitioning */
/*
- Function to be used to analyze non-singlepoint intervals (Can be pointer
- to one of two functions - for RANGE and for LIST types). NULL means
- partitioning type and/or expression doesn't allow non-singlepoint interval
- analysis.
- See get_list_array_idx_for_endpoint (or get_range_...) for description of
- what the function does.
- */
- get_endpoint_func get_endpoint;
-
- /* Maximum possible value that can be returned by get_endpoint function */
- uint32 max_endpoint_val;
-
- /*
- For RANGE partitioning, part_num_to_part_id_range, for LIST partitioning,
- part_num_to_part_id_list. Just to avoid the if-else clutter.
- */
- part_num_to_partition_id_func endpoints_walk_func;
-
- /*
- If true, process "key < const" as "part_func(key) < part_func(const)",
- otherwise as "part_func(key) <= part_func(const)". Same for '>' and '>='.
- This is defined iff get_endpoint != NULL.
- */
- bool force_include_bounds;
-
- /*
is_part_keypart[i] == test(keypart #i in partitioning index is a member
used in partitioning)
Used to maintain current values of cur_part_fields and cur_subpart_fields
@@ -2208,28 +2213,15 @@ typedef struct st_part_prune_param
uint cur_part_fields;
/* Same as cur_part_fields, but for subpartitioning */
uint cur_subpart_fields;
-
- /***************************************************************
- Following fields are used to store an 'iterator' that can be
- used to obtain a set of used artitions.
- **************************************************************/
- /*
- Start and end+1 partition "numbers". They can have two meanings depending
- depending of the value of part_num_to_part_id:
- part_num_to_part_id_range - numbers are partition ids
- part_num_to_part_id_list - numbers are indexes in part_info->list_array
- */
- uint32 start_part_num;
- uint32 end_part_num;
- /*
- A function that should be used to convert two above "partition numbers"
- to partition_ids.
- */
- part_num_to_partition_id_func part_num_to_part_id;
+ /* Iterator to be used to obtain the "current" set of used partitions */
+ PARTITION_ITERATOR part_iter;
+
+ /* Initialized bitmap of no_subparts size */
+ MY_BITMAP subparts_bitmap;
} PART_PRUNE_PARAM;
-static bool create_partition_index_descrition(PART_PRUNE_PARAM *prune_par);
+static bool create_partition_index_description(PART_PRUNE_PARAM *prune_par);
static int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree);
static int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar,
SEL_IMERGE *imerge);
@@ -2243,7 +2235,7 @@ static uint32 part_num_to_part_id_range(PART_PRUNE_PARAM* prune_par,
static void print_partitioning_index(KEY_PART *parts, KEY_PART *parts_end);
static void dbug_print_field(Field *field);
static void dbug_print_segment_range(SEL_ARG *arg, KEY_PART *part);
-static void dbug_print_onepoint_range(SEL_ARG **start, uint num);
+static void dbug_print_singlepoint_range(SEL_ARG **start, uint num);
#endif
@@ -2297,7 +2289,7 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
range_par->mem_root= &alloc;
range_par->old_root= thd->mem_root;
- if (create_partition_index_descrition(&prune_param))
+ if (create_partition_index_description(&prune_param))
{
mark_all_partitions_as_used(part_info);
free_root(&alloc,MYF(0)); // Return memory & allocator
@@ -2335,15 +2327,14 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER)
goto all_used;
-
+
if (tree->merges.is_empty())
{
+ /* Range analysis has produced a single list of intervals. */
prune_param.arg_stack_end= prune_param.arg_stack;
prune_param.cur_part_fields= 0;
prune_param.cur_subpart_fields= 0;
- prune_param.part_num_to_part_id= part_num_to_part_id_range;
- prune_param.start_part_num= 0;
- prune_param.end_part_num= prune_param.part_info->no_parts;
+ init_all_partitions_iterator(part_info, &prune_param.part_iter);
if (!tree->keys[0] || (-1 == (res= find_used_partitions(&prune_param,
tree->keys[0]))))
goto all_used;
@@ -2352,14 +2343,30 @@ bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond)
{
if (tree->merges.elements == 1)
{
- if (-1 == (res |= find_used_partitions_imerge(&prune_param,
- tree->merges.head())))
+ /*
+ Range analysis has produced a "merge" of several intervals lists, a
+ SEL_TREE that represents an expression in form
+ sel_imerge = (tree1 OR tree2 OR ... OR treeN)
+ that cannot be reduced to one tree. This can only happen when
+ partitioning index has several keyparts and the condition is OR of
+ conditions that refer to different key parts. For example, we'll get
+ here for "partitioning_field=const1 OR subpartitioning_field=const2"
+ */
+ if (-1 == (res= find_used_partitions_imerge(&prune_param,
+ tree->merges.head())))
goto all_used;
}
else
{
- if (-1 == (res |= find_used_partitions_imerge_list(&prune_param,
- tree->merges)))
+ /*
+ Range analysis has produced a list of several imerges, i.e. a
+ structure that represents a condition in form
+ imerge_list= (sel_imerge1 AND sel_imerge2 AND ... AND sel_imergeN)
+ This is produced for complicated WHERE clauses that range analyzer
+ can't really analyze properly.
+ */
+ if (-1 == (res= find_used_partitions_imerge_list(&prune_param,
+ tree->merges)))
goto all_used;
}
}
@@ -2384,15 +2391,22 @@ end:
/*
- Store key image to table record
+ Store field key image to table record
SYNOPSIS
- field Field which key image should be stored.
- ptr Field value in key format.
- len Length of the value, in bytes.
+ store_key_image_to_rec()
+ field Field which key image should be stored
+ ptr Field value in key format
+ len Length of the value, in bytes
+
+ DESCRIPTION
+ Copy the field value from its key image to the table record. The source
+ is the value in key image format, occupying len bytes in buffer pointed
+ by ptr. The destination is table record, in "field value in table record"
+ format.
*/
-static void store_key_image_to_rec(Field *field, char *ptr, uint len)
+void store_key_image_to_rec(Field *field, char *ptr, uint len)
{
/* Do the same as print_key() does */
if (field->real_maybe_null())
@@ -2414,8 +2428,12 @@ static void store_key_image_to_rec(Field *field, char *ptr, uint len)
SYNOPSIS
store_selargs_to_rec()
ppar Partition pruning context
- start Array SEL_ARG* for which the minimum values should be stored
+ start Array of SEL_ARG* for which the minimum values should be stored
num Number of elements in the array
+
+ DESCRIPTION
+ For each SEL_ARG* interval in the specified array, store the left edge
+ field value (sel_arg->min, key image format) into the table record.
*/
static void store_selargs_to_rec(PART_PRUNE_PARAM *ppar, SEL_ARG **start,
@@ -2449,19 +2467,6 @@ static void mark_full_partition_used_with_parts(partition_info *part_info,
bitmap_set_bit(&part_info->used_partitions, start);
}
-/* See comment in PART_PRUNE_PARAM::part_num_to_part_id about what this is */
-static uint32 part_num_to_part_id_range(PART_PRUNE_PARAM* ppar, uint32 num)
-{
- return num;
-}
-
-/* See comment in PART_PRUNE_PARAM::part_num_to_part_id about what this is */
-static uint32 part_num_to_part_id_list(PART_PRUNE_PARAM* ppar, uint32 num)
-{
- return ppar->part_info->list_array[num].partition_id;
-}
-
-
/*
Find the set of used partitions for List<SEL_IMERGE>
SYNOPSIS
@@ -2473,7 +2478,7 @@ static uint32 part_num_to_part_id_list(PART_PRUNE_PARAM* ppar, uint32 num)
List<SEL_IMERGE> represents "imerge1 AND imerge2 AND ...".
The set of used partitions is an intersection of used partitions sets
for imerge_{i}.
- We accumulate this intersection a separate bitmap.
+ We accumulate this intersection in a separate bitmap.
RETURN
See find_used_partitions()
@@ -2491,7 +2496,7 @@ static int find_used_partitions_imerge_list(PART_PRUNE_PARAM *ppar,
bitmap_bytes)))
{
/*
- Fallback, process just first SEL_IMERGE. This can leave us with more
+ Fallback, process just the first SEL_IMERGE. This can leave us with more
partitions marked as used then actually needed.
*/
return find_used_partitions_imerge(ppar, merges.head());
@@ -2549,9 +2554,7 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge)
ppar->arg_stack_end= ppar->arg_stack;
ppar->cur_part_fields= 0;
ppar->cur_subpart_fields= 0;
- ppar->part_num_to_part_id= part_num_to_part_id_range;
- ppar->start_part_num= 0;
- ppar->end_part_num= ppar->part_info->no_parts;
+ init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
if (-1 == (res |= find_used_partitions(ppar, (*ptree)->keys[0])))
return -1;
}
@@ -2560,41 +2563,106 @@ int find_used_partitions_imerge(PART_PRUNE_PARAM *ppar, SEL_IMERGE *imerge)
/*
- Recursively walk the SEL_ARG tree, find/mark partitions that need to be used
+ Collect partitioning ranges for the SEL_ARG tree and mark partitions as used
SYNOPSIS
find_used_partitions()
ppar Partition pruning context.
- key_tree Intervals tree to perform pruning for.
+ key_tree SEL_ARG range tree to perform pruning for
DESCRIPTION
This function
- * recursively walks the SEL_ARG* tree, collecting partitioning
- "intervals";
- * finds the partitions one needs to use to get rows in these intervals;
+ * recursively walks the SEL_ARG* tree collecting partitioning "intervals"
+ * finds the partitions one needs to use to get rows in these intervals
* marks these partitions as used.
-
- WHAT IS CONSIDERED TO BE "INTERVALS"
- A partition pruning "interval" is equivalent to condition in one of the
- forms:
+ The next session desribes the process in greater detail.
+
+ IMPLEMENTATION
+ TYPES OF RESTRICTIONS THAT WE CAN OBTAIN PARTITIONS FOR
+ We can find out which [sub]partitions to use if we obtain restrictions on
+ [sub]partitioning fields in the following form:
+ 1. "partition_field1=const1 AND ... AND partition_fieldN=constN"
+ 1.1 Same as (1) but for subpartition fields
+
+ If partitioning supports interval analysis (i.e. partitioning is a
+ function of a single table field, and partition_info::
+ get_part_iter_for_interval != NULL), then we can also use condition in
+ this form:
+ 2. "const1 <=? partition_field <=? const2"
+ 2.1 Same as (2) but for subpartition_field
+
+ INFERRING THE RESTRICTIONS FROM SEL_ARG TREE
- "partition_field1=const1 AND ... partition_fieldN=constN" (1)
- "subpartition_field1=const1 AND ... subpartition_fieldN=constN" (2)
- "(1) AND (2)" (3)
+ The below is an example of what SEL_ARG tree may represent:
- In (1) and (2) all [sub]partitioning fields must be used, and "x=const"
- includes "x IS NULL".
+ (start)
+ | $
+ | Partitioning keyparts $ subpartitioning keyparts
+ | $
+ | ... ... $
+ | | | $
+ | +---------+ +---------+ $ +-----------+ +-----------+
+ \-| par1=c1 |--| par2=c2 |-----| subpar1=c3|--| subpar2=c5|
+ +---------+ +---------+ $ +-----------+ +-----------+
+ | $ | |
+ | $ | +-----------+
+ | $ | | subpar2=c6|
+ | $ | +-----------+
+ | $ |
+ | $ +-----------+ +-----------+
+ | $ | subpar1=c4|--| subpar2=c8|
+ | $ +-----------+ +-----------+
+ | $
+ | $
+ +---------+ $ +------------+ +------------+
+ | par1=c2 |------------------| subpar1=c10|--| subpar2=c12|
+ +---------+ $ +------------+ +------------+
+ | $
+ ... $
+
+ The up-down connections are connections via SEL_ARG::left and
+ SEL_ARG::right. A horizontal connection to the right is the
+ SEL_ARG::next_key_part connection.
- If partitioning is performed using
-
- PARTITION BY RANGE(unary_monotonic_func(single_partition_field)),
-
- then the following is also an interval:
+ find_used_partitions() traverses the entire tree via recursion on
+ * SEL_ARG::next_key_part (from left to right on the picture)
+ * SEL_ARG::left|right (up/down on the pic). Left-right recursion is
+ performed for each depth level.
+
+ Recursion descent on SEL_ARG::next_key_part is used to accumulate (in
+ ppar->arg_stack) constraints on partitioning and subpartitioning fields.
+ For the example in the above picture, one of stack states is:
+ in find_used_partitions(key_tree = "subpar2=c5") (***)
+ in find_used_partitions(key_tree = "subpar1=c3")
+ in find_used_partitions(key_tree = "par2=c2") (**)
+ in find_used_partitions(key_tree = "par1=c1")
+ in prune_partitions(...)
+ We apply partitioning limits as soon as possible, e.g. when we reach the
+ depth (**), we find which partition(s) correspond to "par1=c1 AND par2=c2",
+ and save them in ppar->part_iter.
+ When we reach the depth (***), we find which subpartition(s) correspond to
+ "subpar1=c3 AND subpar2=c5", and then mark appropriate subpartitions in
+ appropriate subpartitions as used.
+
+ It is possible that constraints on some partitioning fields are missing.
+ For the above example, consider this stack state:
+ in find_used_partitions(key_tree = "subpar2=c12") (***)
+ in find_used_partitions(key_tree = "subpar1=c10")
+ in find_used_partitions(key_tree = "par1=c2")
+ in prune_partitions(...)
+ Here we don't have constraints for all partitioning fields. Since we've
+ never set the ppar->part_iter to contain used set of partitions, we use
+ its default "all partitions" value. We get subpartition id for
+ "subpar1=c3 AND subpar2=c5", and mark that subpartition as used in every
+ partition.
+
+ The inverse is also possible: we may get constraints on partitioning
+ fields, but not constraints on subpartitioning fields. In that case,
+ calls to find_used_partitions() with depth below (**) will return -1,
+ and we will mark entire partition as used.
- " const1 OP1 single_partition_field OR const2" (4)
-
- where OP1 and OP2 are '<' OR '<=', and const_i can be +/- inf.
- Everything else is not a partition pruning "interval".
+ TODO
+ Replace recursion on SEL_ARG::left and SEL_ARG::right with a loop
RETURN
1 OK, one or more [sub]partitions are marked as used.
@@ -2620,58 +2688,29 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
if (key_tree->type == SEL_ARG::KEY_RANGE)
{
- if (partno == 0 && (NULL != ppar->get_endpoint))
+ if (partno == 0 && (NULL != ppar->part_info->get_part_iter_for_interval))
{
/*
Partitioning is done by RANGE|INTERVAL(monotonic_expr(fieldX)), and
- we got "const1 < fieldX < const2" interval.
+ we got "const1 CMP fieldX CMP const2" interval <-- psergey-todo: change
*/
DBUG_EXECUTE("info", dbug_print_segment_range(key_tree,
ppar->range_param.
key_parts););
- /* Find minimum */
- if (key_tree->min_flag & NO_MIN_RANGE)
- ppar->start_part_num= 0;
- else
- {
- /*
- Store the interval edge in the record buffer, and call the
- function that maps the edge in table-field space to an edge
- in ordered-set-of-partitions (for RANGE partitioning) or
- indexes-in-ordered-array-of-list-constants (for LIST) space.
- */
- store_key_image_to_rec(key_tree->field, key_tree->min_value,
- ppar->range_param.key_parts[0].length);
- bool include_endp= ppar->force_include_bounds ||
- !test(key_tree->min_flag & NEAR_MIN);
- ppar->start_part_num= ppar->get_endpoint(ppar->part_info, 1,
- include_endp);
- if (ppar->start_part_num == ppar->max_endpoint_val)
- {
- res= 0; /* No satisfying partitions */
- goto pop_and_go_right;
- }
- }
-
- /* Find maximum, do the same as above but for right interval bound */
- if (key_tree->max_flag & NO_MAX_RANGE)
- ppar->end_part_num= ppar->max_endpoint_val;
- else
+ res= ppar->part_info->
+ get_part_iter_for_interval(ppar->part_info,
+ FALSE,
+ key_tree->min_value,
+ key_tree->max_value,
+ key_tree->min_flag | key_tree->max_flag,
+ &ppar->part_iter);
+ if (!res)
+ goto go_right; /* res=0 --> no satisfying partitions */
+ if (res == -1)
{
- store_key_image_to_rec(key_tree->field, key_tree->max_value,
- ppar->range_param.key_parts[0].length);
- bool include_endp= ppar->force_include_bounds ||
- !test(key_tree->max_flag & NEAR_MAX);
- ppar->end_part_num= ppar->get_endpoint(ppar->part_info, 0,
- include_endp);
- if (ppar->start_part_num == ppar->end_part_num)
- {
- res= 0; /* No satisfying partitions */
- goto pop_and_go_right;
- }
+ //get a full range iterator
+ init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
}
- ppar->part_num_to_part_id= ppar->endpoints_walk_func;
-
/*
Save our intent to mark full partition as used if we will not be able
to obtain further limits on subpartitions
@@ -2680,6 +2719,42 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
goto process_next_key_part;
}
+ if (partno == ppar->last_subpart_partno &&
+ (NULL != ppar->part_info->get_subpart_iter_for_interval))
+ {
+ PARTITION_ITERATOR subpart_iter;
+ DBUG_EXECUTE("info", dbug_print_segment_range(key_tree,
+ ppar->range_param.
+ key_parts););
+ res= ppar->part_info->
+ get_subpart_iter_for_interval(ppar->part_info,
+ TRUE,
+ key_tree->min_value,
+ key_tree->max_value,
+ key_tree->min_flag | key_tree->max_flag,
+ &subpart_iter);
+ DBUG_ASSERT(res); /* We can't get "no satisfying subpartitions" */
+ if (res == -1)
+ return -1; /* all subpartitions satisfy */
+
+ uint32 subpart_id;
+ bitmap_clear_all(&ppar->subparts_bitmap);
+ while ((subpart_id= subpart_iter.get_next(&subpart_iter)) != NOT_A_PARTITION_ID)
+ bitmap_set_bit(&ppar->subparts_bitmap, subpart_id);
+
+ /* Mark each partition as used in each subpartition. */
+ uint32 part_id;
+ while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) !=
+ NOT_A_PARTITION_ID)
+ {
+ for (uint i= 0; i < ppar->part_info->no_subparts; i++)
+ if (bitmap_is_set(&ppar->subparts_bitmap, i))
+ bitmap_set_bit(&ppar->part_info->used_partitions,
+ part_id * ppar->part_info->no_subparts + i);
+ }
+ goto go_right;
+ }
+
if (key_tree->is_singlepoint())
{
pushed= TRUE;
@@ -2695,11 +2770,11 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
fields. Save all constN constants into table record buffer.
*/
store_selargs_to_rec(ppar, ppar->arg_stack, ppar->part_fields);
- DBUG_EXECUTE("info", dbug_print_onepoint_range(ppar->arg_stack,
+ DBUG_EXECUTE("info", dbug_print_singlepoint_range(ppar->arg_stack,
ppar->part_fields););
uint32 part_id;
longlong func_value;
- /* then find in which partition the {const1, ...,constN} tuple goes */
+ /* Find in which partition the {const1, ...,constN} tuple goes */
if (ppar->get_top_partition_id_func(ppar->part_info, &part_id,
&func_value))
{
@@ -2707,9 +2782,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
goto pop_and_go_right;
}
/* Rembember the limit we got - single partition #part_id */
- ppar->part_num_to_part_id= part_num_to_part_id_range;
- ppar->start_part_num= part_id;
- ppar->end_part_num= part_id + 1;
+ init_single_partition_iterator(part_id, &ppar->part_iter);
/*
If there are no subpartitions/we fail to get any limit for them,
@@ -2719,7 +2792,8 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
goto process_next_key_part;
}
- if (partno == ppar->last_subpart_partno)
+ if (partno == ppar->last_subpart_partno &&
+ ppar->cur_subpart_fields == ppar->subpart_fields)
{
/*
Ok, we've got "fieldN<=>constN"-type SEL_ARGs for all subpartitioning
@@ -2727,7 +2801,7 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
*/
store_selargs_to_rec(ppar, ppar->arg_stack_end - ppar->subpart_fields,
ppar->subpart_fields);
- DBUG_EXECUTE("info", dbug_print_onepoint_range(ppar->arg_stack_end -
+ DBUG_EXECUTE("info", dbug_print_singlepoint_range(ppar->arg_stack_end-
ppar->subpart_fields,
ppar->subpart_fields););
/* Find the subpartition (it's HASH/KEY so we always have one) */
@@ -2735,12 +2809,12 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
uint32 subpart_id= part_info->get_subpartition_id(part_info);
/* Mark this partition as used in each subpartition. */
- for (uint32 num= ppar->start_part_num; num != ppar->end_part_num;
- num++)
+ uint32 part_id;
+ while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) !=
+ NOT_A_PARTITION_ID)
{
bitmap_set_bit(&part_info->used_partitions,
- ppar->part_num_to_part_id(ppar, num) *
- part_info->no_subparts + subpart_id);
+ part_id * part_info->no_subparts + subpart_id);
}
res= 1; /* Some partitions were marked as used */
goto pop_and_go_right;
@@ -2761,31 +2835,28 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
process_next_key_part:
if (key_tree->next_key_part)
res= find_used_partitions(ppar, key_tree->next_key_part);
- else
+ else
res= -1;
-
- if (res == -1) /* Got "full range" for key_tree->next_key_part call */
+
+ if (set_full_part_if_bad_ret)
{
- if (set_full_part_if_bad_ret)
+ if (res == -1)
{
- for (uint32 num= ppar->start_part_num; num != ppar->end_part_num;
- num++)
+ /* Got "full range" for subpartitioning fields */
+ uint32 part_id;
+ bool found= FALSE;
+ while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) != NOT_A_PARTITION_ID)
{
- ppar->mark_full_partition_used(ppar->part_info,
- ppar->part_num_to_part_id(ppar, num));
+ ppar->mark_full_partition_used(ppar->part_info, part_id);
+ found= TRUE;
}
- res= 1;
+ res= test(found);
}
- else
- return -1;
- }
-
- if (set_full_part_if_bad_ret)
- {
- /* Restore the "used partition iterator" to its default */
- ppar->part_num_to_part_id= part_num_to_part_id_range;
- ppar->start_part_num= 0;
- ppar->end_part_num= ppar->part_info->no_parts;
+ /*
+ Restore the "used partitions iterator" to the default setting that
+ specifies iteration over all partitions.
+ */
+ init_all_partitions_iterator(ppar->part_info, &ppar->part_iter);
}
if (pushed)
@@ -2796,7 +2867,10 @@ pop_and_go_right:
ppar->cur_part_fields-= ppar->is_part_keypart[partno];
ppar->cur_subpart_fields-= ppar->is_subpart_keypart[partno];
}
-
+
+ if (res == -1)
+ return -1;
+go_right:
if (key_tree->right != &null_element)
{
if (-1 == (right_res= find_used_partitions(ppar,key_tree->right)))
@@ -2854,7 +2928,7 @@ static bool fields_ok_for_partition_index(Field **pfield)
struct
SYNOPSIS
- create_partition_index_descrition()
+ create_partition_index_description()
prune_par INOUT Partition pruning context
DESCRIPTION
@@ -2871,7 +2945,7 @@ static bool fields_ok_for_partition_index(Field **pfield)
FALSE OK
*/
-static bool create_partition_index_descrition(PART_PRUNE_PARAM *ppar)
+static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
{
RANGE_OPT_PARAM *range_par= &(ppar->range_param);
partition_info *part_info= ppar->part_info;
@@ -2903,38 +2977,6 @@ static bool create_partition_index_descrition(PART_PRUNE_PARAM *ppar)
ppar->get_top_partition_id_func= part_info->get_partition_id;
}
- enum_monotonicity_info minfo;
- ppar->get_endpoint= NULL;
- if (part_info->part_expr &&
- (minfo= part_info->part_expr->get_monotonicity_info()) != NON_MONOTONIC)
- {
- /*
- ppar->force_include_bounds 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)".
- */
- ppar->force_include_bounds= test(minfo == MONOTONIC_INCREASING);
- if (part_info->part_type == RANGE_PARTITION)
- {
- ppar->get_endpoint= get_partition_id_range_for_endpoint;
- ppar->endpoints_walk_func= part_num_to_part_id_range;
- ppar->max_endpoint_val= part_info->no_parts;
- }
- else if (part_info->part_type == LIST_PARTITION)
- {
- ppar->get_endpoint= get_list_array_idx_for_endpoint;
- ppar->endpoints_walk_func= part_num_to_part_id_list;
- ppar->max_endpoint_val= part_info->no_list_values;
- }
- }
-
KEY_PART *key_part;
MEM_ROOT *alloc= range_par->mem_root;
if (!total_parts ||
@@ -2947,11 +2989,19 @@ static bool create_partition_index_descrition(PART_PRUNE_PARAM *ppar)
!(ppar->is_subpart_keypart= (my_bool*)alloc_root(alloc, sizeof(my_bool)*
total_parts)))
return TRUE;
-
+
+ if (ppar->subpart_fields)
+ {
+ uint32 *buf;
+ uint32 bufsize= bitmap_buffer_size(ppar->part_info->no_subparts);
+ if (!(buf= (uint32*)alloc_root(alloc, bufsize)))
+ return TRUE;
+ bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->no_subparts, FALSE);
+ }
range_par->key_parts= key_part;
Field **field= (ppar->part_fields)? part_info->part_field_array :
part_info->subpart_field_array;
- bool subpart_fields= FALSE;
+ bool in_subpart_fields= FALSE;
for (uint part= 0; part < total_parts; part++, key_part++)
{
key_part->key= 0;
@@ -2972,13 +3022,13 @@ static bool create_partition_index_descrition(PART_PRUNE_PARAM *ppar)
key_part->image_type = Field::itRAW;
/* We don't set key_parts->null_bit as it will not be used */
- ppar->is_part_keypart[part]= !subpart_fields;
- ppar->is_subpart_keypart[part]= subpart_fields;
+ ppar->is_part_keypart[part]= !in_subpart_fields;
+ ppar->is_subpart_keypart[part]= in_subpart_fields;
if (!*(++field))
{
field= part_info->subpart_field_array;
- subpart_fields= TRUE;
+ in_subpart_fields= TRUE;
}
}
range_par->key_parts_end= key_part;
@@ -3058,7 +3108,7 @@ static void dbug_print_segment_range(SEL_ARG *arg, KEY_PART *part)
Print a singlepoint multi-keypart range interval to debug trace
SYNOPSIS
- dbug_print_onepoint_range()
+ dbug_print_singlepoint_range()
start Array of SEL_ARG* ptrs representing conditions on key parts
num Number of elements in the array.
@@ -3067,9 +3117,9 @@ static void dbug_print_segment_range(SEL_ARG *arg, KEY_PART *part)
interval to debug trace.
*/
-static void dbug_print_onepoint_range(SEL_ARG **start, uint num)
+static void dbug_print_singlepoint_range(SEL_ARG **start, uint num)
{
- DBUG_ENTER("dbug_print_onepoint_range");
+ DBUG_ENTER("dbug_print_singlepoint_range");
DBUG_LOCK_FILE;
SEL_ARG **end= start + num;