diff options
author | unknown <sergefp@mysql.com> | 2006-04-26 00:30:54 +0400 |
---|---|---|
committer | unknown <sergefp@mysql.com> | 2006-04-26 00:30:54 +0400 |
commit | 7c018c39bbd11a343a99a548db4b0bdfcb904739 (patch) | |
tree | 1aff809dffefd3380e838ef241933451d794acfa /sql | |
parent | 9f5cec76223311e12715936163b92d756ccf80a8 (diff) | |
parent | 15e00f1f3dc8ed6220e69bd20ba5d9335da070d2 (diff) | |
download | mariadb-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.cc | 10 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 77 | ||||
-rw-r--r-- | sql/opt_range.cc | 93 |
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)); + } } } } |