summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/subselect.result3
-rw-r--r--sql/item.cc5
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_cmpfunc.h9
-rw-r--r--sql/item_row.cc28
-rw-r--r--sql/item_row.h17
-rw-r--r--sql/item_strfunc.cc3
-rw-r--r--sql/item_subselect.cc37
8 files changed, 63 insertions, 43 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 7059054104f..7dc03a31878 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -39,9 +39,8 @@ Reference 'a' not supported (forward reference in item list)
EXPLAIN SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived2> system NULL NULL NULL NULL 1
+3 DEPENDENT SUBSELECT NULL NULL NULL NULL NULL NULL NULL No tables used
2 DERIVED NULL NULL NULL NULL NULL NULL NULL No tables used
-Warnings:
-Note 1247 Select 3 was reduced during optimisation
SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1;
1
1
diff --git a/sql/item.cc b/sql/item.cc
index 5de4c6951e5..8feeabd306e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1289,9 +1289,10 @@ bool Item_cache_row::setup(Item * item)
return 1;
for (uint i= 0; i < item_count; i++)
{
- if (!(values[i]= Item_cache::get_cache(item->el(i)->result_type())))
+ Item *el= item->el(i);
+ if (!(values[i]= Item_cache::get_cache(el->result_type())))
return 1;
- values[i]->setup(item->el(i));
+ values[i]->setup(el);
}
return 0;
}
diff --git a/sql/item.h b/sql/item.h
index 046464da97d..3decdc388eb 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -515,6 +515,10 @@ public:
/*
Used to find item in list of select items after '*' items processing.
+
+ Because item '*' can be used in item list. when we create
+ Item_ref_on_list_position we do not know how item list will be changed, but
+ we know number of item position (I mean queries like "select * from t").
*/
class Item_ref_on_list_position: public Item_ref_null_helper
{
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 2aca3e1fabb..44c788f381c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -97,6 +97,13 @@ public:
bool preallocate_row();
bool fix_fields(THD *, struct st_table_list *, Item **);
bool is_null();
+ /*
+ Item_in_optimizer item is special boolean function. On value request
+ (one of val, val_int or val_str methods) it evaluate left expression
+ of IN by storing it value in cache item (one of Item_cache* items),
+ then it test cache is it NULL. If left expression (cache) is NULL then
+ Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
+ */
longlong val_int();
Item_cache **get_cache() { return &cache; }
@@ -546,8 +553,10 @@ public:
{
if (comparators)
for (uint i= 0; i < n; i++)
+ {
if (comparators[i])
delete comparators[i];
+ }
}
void store_value(Item *item);
int cmp(Item *arg);
diff --git a/sql/item_row.cc b/sql/item_row.cc
index b54653f4183..ba4ac19b880 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -54,7 +54,14 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
if (items[i]->fix_fields(thd, tabl, items+i))
return 1;
used_tables_cache |= items[i]->used_tables();
- const_item_cache&= items[i]->const_item();
+ if (const_item_cache&= items[i]->const_item() && !with_null)
+ if (items[i]->cols() > 1)
+ with_null|= items[i]->null_inside();
+ else
+ {
+ items[i]->val_int();
+ with_null|= items[i]->null_value;
+ }
maybe_null|= items[i]->maybe_null;
}
return 0;
@@ -82,25 +89,6 @@ bool Item_row::check_cols(uint c)
return 0;
}
-bool Item_row::null_inside()
-{
- for (uint i= 0; i < arg_count; i++)
- {
- if (items[i]->cols() > 1)
- {
- if (items[i]->null_inside())
- return 1;
- }
- else
- {
- items[i]->val_int();
- if (items[i]->null_value)
- return 1;
- }
- }
- return 0;
-}
-
void Item_row::bring_value()
{
for (uint i= 0; i < arg_count; i++)
diff --git a/sql/item_row.h b/sql/item_row.h
index 82580797ebc..ccaf68bed64 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -16,19 +16,22 @@
class Item_row: public Item
{
- bool array_holder;
+ Item **items;
table_map used_tables_cache;
- bool const_item_cache;
uint arg_count;
- Item **items;
+ bool array_holder;
+ bool const_item_cache;
+ bool with_null;
public:
Item_row(List<Item> &);
Item_row(Item_row *item):
- Item(), array_holder(0),
+ Item(),
+ items(item->items),
used_tables_cache(item->used_tables_cache),
- const_item_cache(item->const_item_cache),
arg_count(item->arg_count),
- items(item->items)
+ array_holder(0),
+ const_item_cache(item->const_item_cache),
+ with_null(0)
{}
~Item_row()
@@ -71,6 +74,6 @@ public:
Item* el(uint i) { return items[i]; }
Item** addr(uint i) { return items + i; }
bool check_cols(uint c);
- bool null_inside();
+ bool null_inside() { return with_null; };
void bring_value();
};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 43eee0abf1c..ce362d6b972 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1961,7 +1961,8 @@ String *Item_func_conv_charset::val_str(String *str)
d0=d=(unsigned char*)str->ptr();
de=d+dmaxlen;
- while (s < se && d < de){
+ while (s < se && d < de)
+ {
cnvres=from->mb_wc(from,&wc,s,se);
if (cnvres>0)
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 8763701b7a3..75aef846b17 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -157,7 +157,11 @@ void Item_singlerow_subselect::select_transformer(THD *thd,
SELECT_LEX *select_lex= unit->first_select();
if (!select_lex->next_select() && !select_lex->table_list.elements &&
- select_lex->item_list.elements == 1)
+ select_lex->item_list.elements == 1 &&
+ // TODO: mark subselect items from item list separately
+ !(select_lex->item_list.head()->type() == FIELD_ITEM ||
+ select_lex->item_list.head()->type() == REF_ITEM)
+ )
{
have_to_be_excluded= 1;
@@ -170,9 +174,6 @@ void Item_singlerow_subselect::select_transformer(THD *thd,
}
substitution= select_lex->item_list.head();
substitution->set_outer_resolving();
- if (substitution->type() == FIELD_ITEM ||
- substitution->type() == REF_ITEM)
- name= substitution->name; // Save name for correct resolving
if (select_lex->where || select_lex->having)
{
@@ -444,6 +445,9 @@ void Item_in_subselect::single_value_transformer(THD *thd,
"LIMIT & IN/ALL/ANY/SOME subquery");
DBUG_VOID_RETURN;
}
+ // no sense in ORDER BY without LIMIT
+ unit->global_parameters->order_list.empty();
+
Item_in_optimizer *optimizer;
substitution= optimizer= new Item_in_optimizer(left_expr, this);
if (!optimizer)
@@ -476,18 +480,16 @@ void Item_in_subselect::single_value_transformer(THD *thd,
else
item= (Item*) sl->item_list.pop();
- if (sl->having || sl->with_sum_func || sl->group_list.first ||
- sl->order_list.first)
+ sl->order_list.empty(); // no sense in ORDER BY without LIMIT
+
+ if (sl->having || sl->with_sum_func || sl->group_list.first)
{
sl->item_list.push_back(item);
item= (*func)(expr, new Item_ref_null_helper(this,
sl->item_list.head_ref(),
(char *)"<no matter>",
(char*)"<result>"));
- if (sl->having || sl->with_sum_func || sl->group_list.first)
- sl->having= and_items(sl->having, item);
- else
- sl->where= and_items(sl->where, item);
+ sl->having= and_items(sl->having, item);
}
else
{
@@ -547,10 +549,22 @@ void Item_in_subselect::row_value_transformer(THD *thd,
if (unit->global_parameters->select_limit !=
HA_POS_ERROR)
{
+ /*
+ Because we do the following (not exactly, following is just explenation)
+ transformation
+ SELECT * from t1 WHERE t1.a IN (SELECT t2.a FROM t2)
+ ->
+ SELECT * from t1 WHERE EXISTS(SELECT 1 FROM t2 t1.a = t2.a LIMIT 1)
+
+ it's impossible to support limit in the sub select.
+ */
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"LIMIT & IN/ALL/ANY/SOME subquery");
DBUG_VOID_RETURN;
}
+ // no sense in ORDER BY without LIMIT
+ unit->global_parameters->order_list.empty();
+
Item_in_optimizer *optimizer;
substitution= optimizer= new Item_in_optimizer(left_expr, this);
if (!optimizer)
@@ -568,6 +582,7 @@ void Item_in_subselect::row_value_transformer(THD *thd,
"LIMIT & IN/ALL/ANY/SOME subquery");
DBUG_VOID_RETURN;
}
+ sl->order_list.empty(); // no sense in ORDER BY without LIMIT
sl->dependent= 1;
@@ -589,7 +604,7 @@ void Item_in_subselect::row_value_transformer(THD *thd,
}
if (sl->having || sl->with_sum_func || sl->group_list.first ||
- !sl->table_list.elements)
+ !sl->table_list.elements || !sl->table_list.elements)
sl->having= and_items(sl->having, item);
else
sl->where= and_items(sl->where, item);