summaryrefslogtreecommitdiff
path: root/sql/opt_range.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/opt_range.cc')
-rw-r--r--sql/opt_range.cc172
1 files changed, 112 insertions, 60 deletions
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index ad48f3050c0..eb6eefccf02 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -343,6 +343,7 @@ typedef struct st_qsel_param {
char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH],
max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH];
bool quick; // Don't calulate possible keys
+ COND *cond;
uint fields_bitmap_size;
MY_BITMAP needed_fields; /* bitmask of fields needed by the query */
@@ -363,10 +364,11 @@ class TABLE_READ_PLAN;
struct st_ror_scan_info;
-static SEL_TREE * get_mm_parts(PARAM *param,Field *field,
+static SEL_TREE * get_mm_parts(PARAM *param,COND *cond_func,Field *field,
Item_func::Functype type,Item *value,
Item_result cmp_type);
-static SEL_ARG *get_mm_leaf(PARAM *param,Field *field,KEY_PART *key_part,
+static SEL_ARG *get_mm_leaf(PARAM *param,COND *cond_func,Field *field,
+ KEY_PART *key_part,
Item_func::Functype type,Item *value);
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond);
@@ -688,14 +690,25 @@ SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0)
}
-SQL_SELECT::~SQL_SELECT()
+void SQL_SELECT::cleanup()
{
delete quick;
+ quick= 0;
if (free_cond)
+ {
+ free_cond=0;
delete cond;
+ cond= 0;
+ }
close_cached_file(&file);
}
+
+SQL_SELECT::~SQL_SELECT()
+{
+ cleanup();
+}
+
#undef index // Fix for Unixware 7
QUICK_SELECT_I::QUICK_SELECT_I()
@@ -1132,6 +1145,7 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
return 0; // OOM
}
increment_use_count(1);
+ tmp->color= color;
return tmp;
}
@@ -1426,7 +1440,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
param.needed_reg= &needed_reg;
param.imerge_cost_buff_size= 0;
-
thd->no_errors=1; // Don't warn about NULL
init_sql_alloc(&alloc, thd->variables.range_alloc_block_size, 0);
@@ -2890,6 +2903,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0); // Can't be calculated
+ param->cond= cond;
+
if (cond_func->functype() == Item_func::BETWEEN)
{
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
@@ -2897,10 +2912,10 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
Item_result cmp_type=field->cmp_type();
DBUG_RETURN(tree_and(param,
- get_mm_parts(param, field,
+ get_mm_parts(param, cond_func, field,
Item_func::GE_FUNC,
cond_func->arguments()[1], cmp_type),
- get_mm_parts(param, field,
+ get_mm_parts(param, cond_func, field,
Item_func::LE_FUNC,
cond_func->arguments()[2], cmp_type)));
}
@@ -2913,13 +2928,14 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
{
Field *field=((Item_field*) (func->key_item()))->field;
Item_result cmp_type=field->cmp_type();
- tree= get_mm_parts(param,field,Item_func::EQ_FUNC,
+ tree= get_mm_parts(param,cond_func,field,Item_func::EQ_FUNC,
func->arguments()[1],cmp_type);
if (!tree)
DBUG_RETURN(tree); // Not key field
for (uint i=2 ; i < func->argument_count(); i++)
{
- SEL_TREE *new_tree=get_mm_parts(param,field,Item_func::EQ_FUNC,
+ SEL_TREE *new_tree=get_mm_parts(param,cond_func,field,
+ Item_func::EQ_FUNC,
func->arguments()[i],cmp_type);
tree=tree_or(param,tree,new_tree);
}
@@ -2938,7 +2954,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
/* btw, ft_func's arguments()[0] isn't FIELD_ITEM. SerG*/
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
{
- tree= get_mm_parts(param,
+ tree= get_mm_parts(param, cond_func,
((Item_field*) (cond_func->arguments()[0]))->field,
cond_func->functype(),
cond_func->arg_count > 1 ? cond_func->arguments()[1] :
@@ -2951,7 +2967,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
cond_func->have_rev_func() &&
cond_func->arguments()[1]->type() == Item::FIELD_ITEM)
{
- DBUG_RETURN(get_mm_parts(param,
+ DBUG_RETURN(get_mm_parts(param, cond_func,
((Item_field*)
(cond_func->arguments()[1]))->field,
((Item_bool_func2*) cond_func)->rev_functype(),
@@ -2965,7 +2981,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
static SEL_TREE *
-get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
+get_mm_parts(PARAM *param, COND *cond_func, Field *field,
+ Item_func::Functype type,
Item *value, Item_result cmp_type)
{
bool ne_func= FALSE;
@@ -2994,7 +3011,8 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
DBUG_RETURN(0); // OOM
if (!value || !(value->used_tables() & ~param->read_tables))
{
- sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value);
+ sel_arg=get_mm_leaf(param,cond_func,
+ key_part->field,key_part,type,value);
if (!sel_arg)
continue;
if (sel_arg->type == SEL_ARG::IMPOSSIBLE)
@@ -3017,7 +3035,8 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
if (ne_func)
{
- SEL_TREE *tree2= get_mm_parts(param, field, Item_func::GT_FUNC,
+ SEL_TREE *tree2= get_mm_parts(param, cond_func,
+ field, Item_func::GT_FUNC,
value, cmp_type);
if (tree2)
tree= tree_or(param,tree,tree2);
@@ -3028,7 +3047,7 @@ get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
static SEL_ARG *
-get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
+get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part,
Item_func::Functype type,Item *value)
{
uint maybe_null=(uint) field->real_maybe_null(), copies;
@@ -3037,6 +3056,32 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
char *str, *str2;
DBUG_ENTER("get_mm_leaf");
+ if (!value) // IS NULL or IS NOT NULL
+ {
+ if (field->table->outer_join) // Can't use a key on this
+ DBUG_RETURN(0);
+ if (!maybe_null) // Not null field
+ DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
+ if (!(tree=new SEL_ARG(field,is_null_string,is_null_string)))
+ DBUG_RETURN(0); // out of memory
+ if (type == Item_func::ISNOTNULL_FUNC)
+ {
+ tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
+ tree->max_flag=NO_MAX_RANGE;
+ }
+ DBUG_RETURN(tree);
+ }
+
+ /*
+ We can't use an index when comparing strings of
+ different collations
+ */
+ if (field->result_type() == STRING_RESULT &&
+ value->result_type() == STRING_RESULT &&
+ key_part->image_type == Field::itRAW &&
+ ((Field_str*)field)->charset() != conf_func->compare_collation())
+ DBUG_RETURN(0);
+
if (type == Item_func::LIKE_FUNC)
{
bool like_error;
@@ -3084,14 +3129,15 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
max_str[0]= min_str[0]=0;
like_error= my_like_range(field->charset(),
- res->ptr(),res->length(),
- wild_prefix,wild_one,wild_many,
- field_length,
- min_str+offset, max_str+offset,
- &min_length,&max_length);
-
+ res->ptr(), res->length(),
+ ((Item_func_like*)(param->cond))->escape,
+ wild_one, wild_many,
+ field_length,
+ min_str+offset, max_str+offset,
+ &min_length, &max_length);
if (like_error) // Can't optimize with LIKE
DBUG_RETURN(0);
+
if (offset != maybe_null) // Blob
{
int2store(min_str+maybe_null,min_length);
@@ -3100,22 +3146,6 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(new SEL_ARG(field,min_str,max_str));
}
- if (!value) // IS NULL or IS NOT NULL
- {
- if (field->table->outer_join) // Can't use a key on this
- DBUG_RETURN(0);
- if (!maybe_null) // Not null field
- DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
- if (!(tree=new SEL_ARG(field,is_null_string,is_null_string)))
- DBUG_RETURN(0); // out of memory
- if (type == Item_func::ISNOTNULL_FUNC)
- {
- tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
- tree->max_flag=NO_MAX_RANGE;
- }
- DBUG_RETURN(tree);
- }
-
if (!field->optimize_range(param->real_keynr[key_part->key]) &&
type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC)
@@ -3129,8 +3159,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
value->result_type() != STRING_RESULT &&
field->cmp_type() != value->result_type())
DBUG_RETURN(0);
-
- if (value->save_in_field(field, 1) > 0)
+
+ if (value->save_in_field(field, 1) < 0)
{
/* This happens when we try to insert a NULL field in a not null column */
DBUG_RETURN(&null_element); // cmp with NULL is never true
@@ -3842,6 +3872,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
return 0; // OOM
tmp->copy_max_to_min(&key);
tmp->increment_use_count(key1->use_count+1);
+ /* Increment key count as it may be used for next loop */
+ key.increment_use_count(1);
new_arg->next_key_part=key_or(tmp->next_key_part,key.next_key_part);
key1=key1->insert(new_arg);
break;
@@ -4273,6 +4305,7 @@ static ulong count_key_part_usage(SEL_ARG *root, SEL_ARG *key)
void SEL_ARG::test_use_count(SEL_ARG *root)
{
+ uint e_count=0;
if (this == root && use_count != 1)
{
sql_print_error("Note: Use_count: Wrong count %lu for root",use_count);
@@ -4280,7 +4313,6 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
}
if (this->type != SEL_ARG::KEY_RANGE)
return;
- uint e_count=0;
for (SEL_ARG *pos=first(); pos ; pos=pos->next)
{
e_count++;
@@ -4297,8 +4329,8 @@ void SEL_ARG::test_use_count(SEL_ARG *root)
}
}
if (e_count != elements)
- sql_print_error("Warning: Wrong use count: %u for tree at %lx", e_count,
- (gptr) this);
+ sql_print_error("Warning: Wrong use count: %u (should be %u) for tree at %lx",
+ e_count, elements, (gptr) this);
}
#endif
@@ -4359,6 +4391,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
if (cpk_scan)
param->is_ror_scan= true;
}
+ DBUG_PRINT("exit", ("Records: %lu", (ulong) records));
DBUG_RETURN(records);
}
@@ -4671,9 +4704,9 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
}
/* Get range for retrieving rows in QUICK_SELECT::get_next */
- if (!(range= new QUICK_RANGE(param->min_key,
+ if (!(range= new QUICK_RANGE((const char *) param->min_key,
(uint) (tmp_min_key - param->min_key),
- param->max_key,
+ (const char *) param->max_key,
(uint) (tmp_max_key - param->max_key),
flag)))
return 1; // out of memory
@@ -4821,8 +4854,30 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
key_part->part_length+=HA_KEY_BLOB_LENGTH;
key_part->null_bit= key_info->key_part[part].null_bit;
}
- if (!insert_dynamic(&quick->ranges,(gptr)&range))
- return quick;
+ if (insert_dynamic(&quick->ranges,(gptr)&range))
+ goto err;
+
+ /*
+ Add a NULL range if REF_OR_NULL optimization is used.
+ For example:
+ if we have "WHERE A=2 OR A IS NULL" we created the (A=2) range above
+ and have ref->null_ref_key set. Will create a new NULL range here.
+ */
+ if (ref->null_ref_key)
+ {
+ QUICK_RANGE *null_range;
+
+ *ref->null_ref_key= 1; // Set null byte then create a range
+ if (!(null_range= new QUICK_RANGE((char*)ref->key_buff, ref->key_length,
+ (char*)ref->key_buff, ref->key_length,
+ EQ_RANGE)))
+ goto err;
+ *ref->null_ref_key= 0; // Clear null byte
+ if (insert_dynamic(&quick->ranges,(gptr)&null_range))
+ goto err;
+ }
+
+ return quick;
err:
delete quick;
@@ -5099,12 +5154,7 @@ int QUICK_RANGE_SELECT::get_next()
int result;
if (range)
{ // Already read through key
-/* result=((range->flag & EQ_RANGE) ?
- file->index_next_same(record, (byte*) range->min_key,
- range->min_length) :
- file->index_next(record));
-*/
- result=((range->flag & (EQ_RANGE | GEOM_FLAG) ) ?
+ result=((range->flag & (EQ_RANGE | GEOM_FLAG)) ?
file->index_next_same(record, (byte*) range->min_key,
range->min_length) :
file->index_next(record));
@@ -5360,15 +5410,17 @@ int QUICK_SELECT_DESC::get_next()
((range->flag & NEAR_MAX) ?
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV));
#else
- /* Heikki changed Sept 11, 2002: since InnoDB does not store the cursor
- position if READ_KEY_EXACT is used to a primary key with all
- key columns specified, we must use below HA_READ_KEY_OR_NEXT,
- so that InnoDB stores the cursor position and is able to move
- the cursor one step backward after the search. */
-
- /* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will
- * do the right thing - go past all keys which match the prefix */
-
+ /*
+ Heikki changed Sept 11, 2002: since InnoDB does not store the cursor
+ position if READ_KEY_EXACT is used to a primary key with all
+ key columns specified, we must use below HA_READ_KEY_OR_NEXT,
+ so that InnoDB stores the cursor position and is able to move
+ the cursor one step backward after the search.
+ */
+ /*
+ Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will
+ do the right thing - go past all keys which match the prefix
+ */
result=file->index_read(record, (byte*) range->max_key,
range->max_length,
((range->flag & NEAR_MAX) ?