summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sanja@askmonty.org>2013-11-11 16:40:46 +0200
committerunknown <sanja@askmonty.org>2013-11-11 16:40:46 +0200
commitc85db2c4943b644c34cc4c67a95cfb5e5f0a09a4 (patch)
tree31a00735fded4bba3b8a833c4a7925a607f48559 /sql
parent542ce5a068f2139c5b57ace8ba15b425fb570703 (diff)
downloadmariadb-git-c85db2c4943b644c34cc4c67a95cfb5e5f0a09a4.tar.gz
MDEV-5103: server crashed on singular Item_equal
Singular Item_equal support added. The problem was that during constant table substitution Item_equal become containing only one constant which was not supported internally.
Diffstat (limited to 'sql')
-rw-r--r--sql/item_cmpfunc.cc22
-rw-r--r--sql/item_cmpfunc.h1
2 files changed, 22 insertions, 1 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index d1075c3c47f..22554c71d90 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -5564,6 +5564,12 @@ void Item_equal::add_const(Item *c, Item *f)
func->quick_fix_field();
cond_false= !func->val_int();
}
+ /*
+ TODO: also support the case where Item_equal becomes singular with
+ this->is_cond_true()=1. When I attempted to mark the item as constant,
+ the optimizer attempted to remove it, however it is still referenced from
+ COND_EQUAL and I got a crash.
+ */
if (cond_false)
const_item_cache= 1;
}
@@ -5768,7 +5774,8 @@ void Item_equal::merge_into_list(List<Item_equal> *list,
void Item_equal::sort(Item_field_cmpfunc compare, void *arg)
{
- bubble_sort<Item>(&equal_items, compare, arg);
+ if (equal_items.elements > 1)
+ bubble_sort<Item>(&equal_items, compare, arg);
}
@@ -5868,6 +5875,12 @@ bool Item_equal::fix_fields(THD *thd, Item **ref)
void Item_equal::update_used_tables()
{
not_null_tables_cache= used_tables_cache= 0;
+ /*
+ TODO: also support the case where Item_equal becomes singular with
+ this->is_cond_true()=1. When I attempted to mark the item as constant,
+ the optimizer attempted to remove it, however it is still referenced from
+ COND_EQUAL and I got a crash.
+ */
if ((const_item_cache= cond_false))
return;
Item_equal_fields_iterator it(*this);
@@ -5916,6 +5929,8 @@ longlong Item_equal::val_int()
{
if (cond_false)
return 0;
+ if (is_cond_true())
+ return 1;
Item *item= get_const();
Item_equal_fields_iterator it(*this);
if (!item)
@@ -5940,6 +5955,11 @@ longlong Item_equal::val_int()
void Item_equal::fix_length_and_dec()
{
Item *item= get_first(NO_PARTICULAR_TAB, NULL);
+ if (!item)
+ {
+ DBUG_ASSERT(is_cond_true()); // it should be the only constant
+ item= equal_items.head();
+ }
eval_item= cmp_item::get_comparator(item->cmp_type(), item,
item->collation.collation);
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c1ef680f3ee..cdb4963e857 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1725,6 +1725,7 @@ public:
Item_equal(Item_equal *item_equal);
/* Currently the const item is always the first in the list of equal items */
inline Item* get_const() { return with_const ? equal_items.head() : NULL; }
+ inline bool is_cond_true() { return equal_items.elements == 1; }
void add_const(Item *c, Item *f = NULL);
/** Add a non-constant item to the multiple equality */
void add(Item *f) { equal_items.push_back(f); }