summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sergefp@mysql.com>2006-04-26 00:30:54 +0400
committerunknown <sergefp@mysql.com>2006-04-26 00:30:54 +0400
commit7c018c39bbd11a343a99a548db4b0bdfcb904739 (patch)
tree1aff809dffefd3380e838ef241933451d794acfa /sql
parent9f5cec76223311e12715936163b92d756ccf80a8 (diff)
parent15e00f1f3dc8ed6220e69bd20ba5d9335da070d2 (diff)
downloadmariadb-git-7c018c39bbd11a343a99a548db4b0bdfcb904739.tar.gz
Merge spetrunia@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/psergey/mysql-5.0-bug15827-r2
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc10
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_cmpfunc.h77
-rw-r--r--sql/opt_range.cc93
4 files changed, 169 insertions, 12 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 8cf6fde1dbd..9410fa65408 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1991,6 +1991,16 @@ bool Item_decimal::eq(const Item *item, bool binary_cmp) const
}
+void Item_decimal::set_decimal_value(my_decimal *value_par)
+{
+ my_decimal2decimal(value_par, &decimal_value);
+ decimals= (uint8) decimal_value.frac;
+ unsigned_flag= !decimal_value.sign();
+ max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
+ decimals, unsigned_flag);
+}
+
+
String *Item_float::val_str(String *str)
{
// following assert is redundant, because fixed=1 assigned in constructor
diff --git a/sql/item.h b/sql/item.h
index d33e0ae34be..8b09bc14221 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1442,6 +1442,7 @@ public:
}
uint decimal_precision() const { return decimal_value.precision(); }
bool eq(const Item *, bool binary_cmp) const;
+ void set_decimal_value(my_decimal *value_par);
};
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 67f0a5f5e2e..1837603d78f 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -623,15 +623,17 @@ public:
/* Functions to handle the optimized IN */
+
+/* A vector of values of some type */
+
class in_vector :public Sql_alloc
{
- protected:
+public:
char *base;
uint size;
qsort2_cmp compare;
CHARSET_INFO *collation;
uint count;
-public:
uint used_count;
in_vector() {}
in_vector(uint elements,uint element_length,qsort2_cmp cmp_func,
@@ -647,6 +649,32 @@ public:
qsort2(base,used_count,size,compare,collation);
}
int find(Item *item);
+
+ /*
+ Create an instance of Item_{type} (e.g. Item_decimal) constant object
+ which type allows it to hold an element of this vector without any
+ conversions.
+ The purpose of this function is to be able to get elements of this
+ vector in form of Item_xxx constants without creating Item_xxx object
+ for every array element you get (i.e. this implements "FlyWeight" pattern)
+ */
+ virtual Item* create_item() { return NULL; }
+
+ /*
+ Store the value at position #pos into provided item object
+ SYNOPSIS
+ value_to_item()
+ pos Index of value to store
+ item Constant item to store value into. The item must be of the same
+ type that create_item() returns.
+ */
+ virtual void value_to_item(uint pos, Item *item) { }
+
+ /* Compare values number pos1 and pos2 for equality */
+ bool compare_elems(uint pos1, uint pos2)
+ {
+ return test(compare(collation, base + pos1*size, base + pos2*size));
+ }
};
class in_string :public in_vector
@@ -658,6 +686,16 @@ public:
~in_string();
void set(uint pos,Item *item);
byte *get_value(Item *item);
+ Item* create_item()
+ {
+ return new Item_string(collation);
+ }
+ void value_to_item(uint pos, Item *item)
+ {
+ String *str=((String*) base)+pos;
+ Item_string *to= (Item_string*)item;
+ to->str_value= *str;
+ }
};
class in_longlong :public in_vector
@@ -667,6 +705,19 @@ public:
in_longlong(uint elements);
void set(uint pos,Item *item);
byte *get_value(Item *item);
+
+ Item* create_item()
+ {
+ /*
+ We're created a signed INT, this may not be correct in
+ general case (see BUG#19342).
+ */
+ return new Item_int(0);
+ }
+ void value_to_item(uint pos, Item *item)
+ {
+ ((Item_int*)item)->value= ((longlong*)base)[pos];
+ }
};
class in_double :public in_vector
@@ -676,6 +727,15 @@ public:
in_double(uint elements);
void set(uint pos,Item *item);
byte *get_value(Item *item);
+ Item *create_item()
+ {
+ return new Item_float(0.0);
+ }
+ void value_to_item(uint pos, Item *item)
+ {
+ ((Item_float*)item)->value= ((double*) base)[pos];
+ }
+
};
class in_decimal :public in_vector
@@ -685,6 +745,16 @@ public:
in_decimal(uint elements);
void set(uint pos, Item *item);
byte *get_value(Item *item);
+ Item *create_item()
+ {
+ return new Item_decimal(0, FALSE);
+ }
+ void value_to_item(uint pos, Item *item)
+ {
+ my_decimal *dec= ((my_decimal *)base) + pos;
+ Item_decimal *item_dec= (Item_decimal*)item;
+ item_dec->set_decimal_value(dec);
+ }
};
@@ -864,12 +934,13 @@ public:
class Item_func_in :public Item_func_opt_neg
{
+public:
Item_result cmp_type;
in_vector *array;
cmp_item *in_item;
bool have_null;
DTCollation cmp_collation;
- public:
+
Item_func_in(List<Item> &list)
:Item_func_opt_neg(list), array(0), in_item(0), have_null(0)
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index ae02bb8934c..2610e4fc1c8 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3501,17 +3501,92 @@ static SEL_TREE *get_func_mm_tree(PARAM *param, Item_func *cond_func,
if (inv)
{
- tree= get_ne_mm_tree(param, cond_func, field,
- func->arguments()[1], func->arguments()[1],
- cmp_type);
- if (tree)
+ /*
+ We get here for conditions like "t.keypart NOT IN (....)".
+
+ If the IN-list contains only constants (and func->array is an ordered
+ array of them), we construct the appropriate SEL_ARG tree manually,
+ because constructing it using the range analyzer (as
+ AND_i( t.keypart != c_i)) will cause lots of memory to be consumed
+ (see BUG#15872).
+ */
+ if (func->array && func->cmp_type != ROW_RESULT)
{
- Item **arg, **end;
- for (arg= func->arguments()+2, end= arg+func->argument_count()-2;
- arg < end ; arg++)
+ /*
+ Create one Item_type constant object. We'll need it as
+ get_mm_parts only accepts constant values wrapped in Item_Type
+ objects.
+ We create the Item on param->mem_root which points to
+ per-statement mem_root (while thd->mem_root is currently pointing
+ to mem_root local to range optimizer).
+ */
+ MEM_ROOT *tmp_root= param->mem_root;
+ param->thd->mem_root= param->old_root;
+ Item *value_item= func->array->create_item();
+ param->thd->mem_root= tmp_root;
+
+ if (!value_item)
+ break;
+
+ /* Get a SEL_TREE for "-inf < X < c_0" interval */
+ func->array->value_to_item(0, value_item);
+ tree= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
+ value_item, cmp_type);
+ if (!tree)
+ break;
+#define NOT_IN_IGNORE_THRESHOLD 1000
+ SEL_TREE *tree2;
+ if (func->array->count < NOT_IN_IGNORE_THRESHOLD)
+ {
+ for (uint i=1; i < func->array->count; i++)
+ {
+ if (func->array->compare_elems(i, i-1))
+ {
+ /* Get a SEL_TREE for "-inf < X < c_i" interval */
+ func->array->value_to_item(i, value_item);
+ tree2= get_mm_parts(param, cond_func, field, Item_func::LT_FUNC,
+ value_item, cmp_type);
+
+ /* Change all intervals to be "c_{i-1} < X < c_i" */
+ for (uint idx= 0; idx < param->keys; idx++)
+ {
+ SEL_ARG *new_interval;
+ if ((new_interval= tree2->keys[idx]))
+ {
+ SEL_ARG *last_val= tree->keys[idx]->last();
+ new_interval->min_value= last_val->max_value;
+ new_interval->min_flag= NEAR_MIN;
+ }
+ }
+ tree= tree_or(param, tree, tree2);
+ }
+ }
+ }
+ else
+ func->array->value_to_item(func->array->count - 1, value_item);
+
+ /*
+ Get the SEL_TREE for the last "c_last < X < +inf" interval
+ (value_item cotains c_last already)
+ */
+ tree2= get_mm_parts(param, cond_func, field, Item_func::GT_FUNC,
+ value_item, cmp_type);
+ tree= tree_or(param, tree, tree2);
+ }
+ else
+ {
+ tree= get_ne_mm_tree(param, cond_func, field,
+ func->arguments()[1], func->arguments()[1],
+ cmp_type);
+ if (tree)
{
- tree= tree_and(param, tree, get_ne_mm_tree(param, cond_func, field,
- *arg, *arg, cmp_type));
+ Item **arg, **end;
+ for (arg= func->arguments()+2, end= arg+func->argument_count()-2;
+ arg < end ; arg++)
+ {
+ tree= tree_and(param, tree, get_ne_mm_tree(param, cond_func, field,
+ *arg, *arg, cmp_type));
+ }
}
}
}