mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
merged 5.1-bugteam -> bug 34773 tree
This commit is contained in:
171
sql/opt_range.cc
171
sql/opt_range.cc
@ -574,6 +574,7 @@ public:
|
||||
keys_map.clear_all();
|
||||
bzero((char*) keys,sizeof(keys));
|
||||
}
|
||||
SEL_TREE(SEL_TREE *arg, RANGE_OPT_PARAM *param);
|
||||
/*
|
||||
Note: there may exist SEL_TREE objects with sel_tree->type=KEY and
|
||||
keys[i]=0 for all i. (SergeyP: it is not clear whether there is any
|
||||
@ -767,6 +768,7 @@ public:
|
||||
trees_next(trees),
|
||||
trees_end(trees + PREALLOCED_TREES)
|
||||
{}
|
||||
SEL_IMERGE (SEL_IMERGE *arg, RANGE_OPT_PARAM *param);
|
||||
int or_sel_tree(RANGE_OPT_PARAM *param, SEL_TREE *tree);
|
||||
int or_sel_tree_with_checks(RANGE_OPT_PARAM *param, SEL_TREE *new_tree);
|
||||
int or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* imerge);
|
||||
@ -883,6 +885,61 @@ int SEL_IMERGE::or_sel_imerge_with_checks(RANGE_OPT_PARAM *param, SEL_IMERGE* im
|
||||
}
|
||||
|
||||
|
||||
SEL_TREE::SEL_TREE(SEL_TREE *arg, RANGE_OPT_PARAM *param): Sql_alloc()
|
||||
{
|
||||
keys_map= arg->keys_map;
|
||||
type= arg->type;
|
||||
for (int idx= 0; idx < MAX_KEY; idx++)
|
||||
{
|
||||
if ((keys[idx]= arg->keys[idx]))
|
||||
keys[idx]->increment_use_count(1);
|
||||
}
|
||||
|
||||
List_iterator<SEL_IMERGE> it(arg->merges);
|
||||
for (SEL_IMERGE *el= it++; el; el= it++)
|
||||
{
|
||||
SEL_IMERGE *merge= new SEL_IMERGE(el, param);
|
||||
if (!merge || merge->trees == merge->trees_next)
|
||||
{
|
||||
merges.empty();
|
||||
return;
|
||||
}
|
||||
merges.push_back (merge);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SEL_IMERGE::SEL_IMERGE (SEL_IMERGE *arg, RANGE_OPT_PARAM *param) : Sql_alloc()
|
||||
{
|
||||
uint elements= (arg->trees_end - arg->trees);
|
||||
if (elements > PREALLOCED_TREES)
|
||||
{
|
||||
uint size= elements * sizeof (SEL_TREE **);
|
||||
if (!(trees= (SEL_TREE **)alloc_root(param->mem_root, size)))
|
||||
goto mem_err;
|
||||
}
|
||||
else
|
||||
trees= &trees_prealloced[0];
|
||||
|
||||
trees_next= trees;
|
||||
trees_end= trees + elements;
|
||||
|
||||
for (SEL_TREE **tree = trees, **arg_tree= arg->trees; tree < trees_end;
|
||||
tree++, arg_tree++)
|
||||
{
|
||||
if (!(*tree= new SEL_TREE(*arg_tree, param)))
|
||||
goto mem_err;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
mem_err:
|
||||
trees= &trees_prealloced[0];
|
||||
trees_next= trees;
|
||||
trees_end= trees;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Perform AND operation on two index_merge lists and store result in *im1.
|
||||
*/
|
||||
@ -942,10 +999,23 @@ int imerge_list_or_tree(RANGE_OPT_PARAM *param,
|
||||
{
|
||||
SEL_IMERGE *imerge;
|
||||
List_iterator<SEL_IMERGE> it(*im1);
|
||||
bool tree_used= FALSE;
|
||||
while ((imerge= it++))
|
||||
{
|
||||
if (imerge->or_sel_tree_with_checks(param, tree))
|
||||
SEL_TREE *or_tree;
|
||||
if (tree_used)
|
||||
{
|
||||
or_tree= new SEL_TREE (tree, param);
|
||||
if (!or_tree ||
|
||||
(or_tree->keys_map.is_clear_all() && or_tree->merges.is_empty()))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
or_tree= tree;
|
||||
|
||||
if (imerge->or_sel_tree_with_checks(param, or_tree))
|
||||
it.remove();
|
||||
tree_used= TRUE;
|
||||
}
|
||||
return im1->is_empty();
|
||||
}
|
||||
@ -1081,7 +1151,7 @@ int QUICK_RANGE_SELECT::init()
|
||||
|
||||
if (file->inited != handler::NONE)
|
||||
file->ha_index_or_rnd_end();
|
||||
DBUG_RETURN(error= file->ha_index_init(index, 1));
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
@ -3145,10 +3215,12 @@ int find_used_partitions(PART_PRUNE_PARAM *ppar, SEL_ARG *key_tree)
|
||||
ppar->subpart_fields););
|
||||
/* Find the subpartition (it's HASH/KEY so we always have one) */
|
||||
partition_info *part_info= ppar->part_info;
|
||||
uint32 subpart_id= part_info->get_subpartition_id(part_info);
|
||||
|
||||
uint32 part_id, subpart_id;
|
||||
|
||||
if (part_info->get_subpartition_id(part_info, &subpart_id))
|
||||
return 0;
|
||||
|
||||
/* Mark this partition as used in each subpartition. */
|
||||
uint32 part_id;
|
||||
while ((part_id= ppar->part_iter.get_next(&ppar->part_iter)) !=
|
||||
NOT_A_PARTITION_ID)
|
||||
{
|
||||
@ -5547,7 +5619,9 @@ get_mm_parts(RANGE_OPT_PARAM *param, COND *cond_func, Field *field,
|
||||
tree->keys_map.set_bit(key_part->key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (tree && tree->merges.is_empty() && tree->keys_map.is_clear_all())
|
||||
tree= NULL;
|
||||
DBUG_RETURN(tree);
|
||||
}
|
||||
|
||||
@ -7936,6 +8010,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
|
||||
handler *file= head->file;
|
||||
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::read_keys_and_merge");
|
||||
|
||||
/* We're going to just read rowids. */
|
||||
file->extra(HA_EXTRA_KEYREAD);
|
||||
head->prepare_for_position();
|
||||
|
||||
@ -7994,15 +8069,17 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
|
||||
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", ("ok"));
|
||||
/* ok, all row ids are in Unique */
|
||||
/*
|
||||
Ok all rowids are in the Unique now. The next call will initialize
|
||||
head->sort structure so it can be used to iterate through the rowids
|
||||
sequence.
|
||||
*/
|
||||
result= unique->get(head);
|
||||
delete unique;
|
||||
doing_pk_scan= FALSE;
|
||||
/* index_merge currently doesn't support "using index" at all */
|
||||
file->extra(HA_EXTRA_NO_KEYREAD);
|
||||
/* start table scan */
|
||||
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1);
|
||||
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1 , 1, TRUE);
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
@ -8028,6 +8105,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
|
||||
{
|
||||
result= HA_ERR_END_OF_FILE;
|
||||
end_read_record(&read_record);
|
||||
free_io_cache(head);
|
||||
/* All rows from Unique have been retrieved, do a clustered PK scan */
|
||||
if (pk_quick_select)
|
||||
{
|
||||
@ -8556,9 +8634,17 @@ bool QUICK_RANGE_SELECT::row_in_ranges()
|
||||
|
||||
QUICK_SELECT_DESC::QUICK_SELECT_DESC(QUICK_RANGE_SELECT *q,
|
||||
uint used_key_parts_arg)
|
||||
:QUICK_RANGE_SELECT(*q), rev_it(rev_ranges)
|
||||
:QUICK_RANGE_SELECT(*q), rev_it(rev_ranges),
|
||||
used_key_parts (used_key_parts_arg)
|
||||
{
|
||||
QUICK_RANGE *r;
|
||||
/*
|
||||
Use default MRR implementation for reverse scans. No table engine
|
||||
currently can do an MRR scan with output in reverse index order.
|
||||
*/
|
||||
multi_range_length= 0;
|
||||
multi_range= NULL;
|
||||
multi_range_buff= NULL;
|
||||
|
||||
QUICK_RANGE **pr= (QUICK_RANGE**)ranges.buffer;
|
||||
QUICK_RANGE **end_range= pr + ranges.elements;
|
||||
@ -8598,10 +8684,11 @@ int QUICK_SELECT_DESC::get_next()
|
||||
int result;
|
||||
if (last_range)
|
||||
{ // Already read through key
|
||||
result = ((last_range->flag & EQ_RANGE)
|
||||
? file->index_next_same(record, last_range->min_key,
|
||||
last_range->min_length) :
|
||||
file->index_prev(record));
|
||||
result = ((last_range->flag & EQ_RANGE &&
|
||||
used_key_parts <= head->key_info[index].key_parts) ?
|
||||
file->index_next_same(record, last_range->min_key,
|
||||
last_range->min_length) :
|
||||
file->index_prev(record));
|
||||
if (!result)
|
||||
{
|
||||
if (cmp_prev(*rev_it.ref()) == 0)
|
||||
@ -8625,7 +8712,9 @@ int QUICK_SELECT_DESC::get_next()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (last_range->flag & EQ_RANGE)
|
||||
if (last_range->flag & EQ_RANGE &&
|
||||
used_key_parts <= head->key_info[index].key_parts)
|
||||
|
||||
{
|
||||
result = file->index_read_map(record, last_range->max_key,
|
||||
last_range->max_keypart_map,
|
||||
@ -8634,6 +8723,8 @@ int QUICK_SELECT_DESC::get_next()
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(last_range->flag & NEAR_MAX ||
|
||||
(last_range->flag & EQ_RANGE &&
|
||||
used_key_parts > head->key_info[index].key_parts) ||
|
||||
range_reads_after_key(last_range));
|
||||
result=file->index_read_map(record, last_range->max_key,
|
||||
last_range->max_keypart_map,
|
||||
@ -8731,54 +8822,6 @@ bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg)
|
||||
}
|
||||
|
||||
|
||||
/* TRUE if we are reading over a key that may have a NULL value */
|
||||
|
||||
#ifdef NOT_USED
|
||||
bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg,
|
||||
uint used_key_parts)
|
||||
{
|
||||
uint offset, end;
|
||||
KEY_PART *key_part = key_parts,
|
||||
*key_part_end= key_part+used_key_parts;
|
||||
|
||||
for (offset= 0, end = min(range_arg->min_length, range_arg->max_length) ;
|
||||
offset < end && key_part != key_part_end ;
|
||||
offset+= key_part++->store_length)
|
||||
{
|
||||
if (!memcmp((char*) range_arg->min_key+offset,
|
||||
(char*) range_arg->max_key+offset,
|
||||
key_part->store_length))
|
||||
continue;
|
||||
|
||||
if (key_part->null_bit && range_arg->min_key[offset])
|
||||
return 1; // min_key is null and max_key isn't
|
||||
// Range doesn't cover NULL. This is ok if there is no more null parts
|
||||
break;
|
||||
}
|
||||
/*
|
||||
If the next min_range is > NULL, then we can use this, even if
|
||||
it's a NULL key
|
||||
Example: SELECT * FROM t1 WHERE a = 2 AND b >0 ORDER BY a DESC,b DESC;
|
||||
|
||||
*/
|
||||
if (key_part != key_part_end && key_part->null_bit)
|
||||
{
|
||||
if (offset >= range_arg->min_length || range_arg->min_key[offset])
|
||||
return 1; // Could be null
|
||||
key_part++;
|
||||
}
|
||||
/*
|
||||
If any of the key parts used in the ORDER BY could be NULL, we can't
|
||||
use the key to sort the data.
|
||||
*/
|
||||
for (; key_part != key_part_end ; key_part++)
|
||||
if (key_part->null_bit)
|
||||
return 1; // Covers null part
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void QUICK_RANGE_SELECT::add_info_string(String *str)
|
||||
{
|
||||
KEY *key_info= head->key_info + index;
|
||||
|
Reference in New Issue
Block a user