summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/subselect.result55
-rw-r--r--mysql-test/t/subselect.test34
-rw-r--r--sql/item.cc87
-rw-r--r--sql/item.h52
-rw-r--r--sql/item_cmpfunc.cc31
-rw-r--r--sql/item_cmpfunc.h8
-rw-r--r--sql/item_func.cc17
-rw-r--r--sql/item_func.h6
-rw-r--r--sql/item_row.cc12
-rw-r--r--sql/item_row.h3
-rw-r--r--sql/item_strfunc.h13
-rw-r--r--sql/item_subselect.cc473
-rw-r--r--sql/item_subselect.h37
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/mysql_priv.h21
-rw-r--r--sql/sql_base.cc13
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_derived.cc5
-rw-r--r--sql/sql_lex.cc160
-rw-r--r--sql/sql_lex.h115
-rw-r--r--sql/sql_olap.cc3
-rw-r--r--sql/sql_parse.cc34
-rw-r--r--sql/sql_select.cc41
-rw-r--r--sql/sql_select.h81
-rw-r--r--sql/sql_union.cc153
-rw-r--r--sql/sql_yacc.yy107
-rw-r--r--sql/table.h11
27 files changed, 938 insertions, 642 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 41fba93db5b..38a0e1341c0 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -46,7 +46,7 @@ SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1;
1
1
SELECT (SELECT 1), a;
-ERROR 42S22: Unknown column 'a' in 'field list'
+ERROR 42S22: Unknown column 'a' in 'checking transformed subquery'
SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1;
a
1
@@ -677,7 +677,6 @@ id
EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1));
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ref id id 5 const 1 Using where; Using index
-3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1247 Select 3 was reduced during optimisation
Note 1247 Select 2 was reduced during optimisation
@@ -1025,7 +1024,7 @@ CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
- `a` bigint(1) NOT NULL default '0'
+ `a` bigint(17) NOT NULL default '0'
) TYPE=MyISAM CHARSET=latin1
drop table t1;
create table t1 (a int);
@@ -1213,6 +1212,56 @@ SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1
'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t1.FOLDERNAME = 'Level1')
0
drop table t1;
+create table t1 (a int not null, b int, primary key (a));
+create table t2 (a int not null, primary key (a));
+create table t3 (a int not null, b int, primary key (a));
+insert into t1 values (1,10), (2,20), (3,30), (4,40);
+insert into t2 values (2), (3), (4), (5);
+insert into t3 values (10,3), (20,4), (30,5);
+select * from t2 where t2.a in (select a from t1);
+a
+2
+3
+4
+explain select * from t2 where t2.a in (select a from t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index
+2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Using index
+select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+a
+2
+3
+explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index
+2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where
+2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where; Using index
+drop table t1, t2, t3;
+create table t1 (a int, b int, index a (a));
+create table t2 (a int, index a (a));
+create table t3 (a int, b int, index a (a));
+insert into t1 values (1,10), (2,20), (3,30), (4,40);
+insert into t2 values (2), (3), (4), (5);
+insert into t3 values (10,3), (20,4), (30,5);
+select * from t2 where t2.a in (select a from t1);
+a
+2
+3
+4
+explain select * from t2 where t2.a in (select a from t1);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
+2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where; Using index
+select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+a
+2
+3
+explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index
+2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where
+2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using where; Using index
+drop table t1, t2, t3;
create table t1 (a int, b int);
create table t2 (a int, b int);
create table t3 (a int, b int);
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 1d7da94d455..4c124d431da 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -809,6 +809,40 @@ SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1
drop table t1;
#
+# IN subselect optimization test
+#
+create table t1 (a int not null, b int, primary key (a));
+create table t2 (a int not null, primary key (a));
+create table t3 (a int not null, b int, primary key (a));
+insert into t1 values (1,10), (2,20), (3,30), (4,40);
+insert into t2 values (2), (3), (4), (5);
+insert into t3 values (10,3), (20,4), (30,5);
+select * from t2 where t2.a in (select a from t1);
+explain select * from t2 where t2.a in (select a from t1);
+select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+drop table t1, t2, t3;
+create table t1 (a int, b int, index a (a));
+create table t2 (a int, index a (a));
+create table t3 (a int, b int, index a (a));
+insert into t1 values (1,10), (2,20), (3,30), (4,40);
+disable_query_log;
+# making table large enough
+let $1 = 10000;
+while ($1)
+ {
+ eval insert into t1 values (rand()*100000+200,rand()*100000);
+ dec $1;
+ }
+enable_query_log;
+insert into t2 values (2), (3), (4), (5);
+insert into t3 values (10,3), (20,4), (30,5);
+select * from t2 where t2.a in (select a from t1);
+explain select * from t2 where t2.a in (select a from t1);
+select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a);
+drop table t1, t2, t3;
+#
# alloc_group_fields() working
#
create table t1 (a int, b int);
diff --git a/sql/item.cc b/sql/item.cc
index 17b0519b61c..58c47025a6f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -23,8 +23,7 @@
#include <m_ctype.h>
#include "my_dir.h"
-static void mark_as_dependent(bool outer_resolving,
- SELECT_LEX *last, SELECT_LEX_NODE *current,
+static void mark_as_dependent(SELECT_LEX *last, SELECT_LEX *current,
Item_ident *item);
/*****************************************************************************
@@ -95,6 +94,15 @@ Item_ident::Item_ident(THD *thd, Item_ident &item):
depended_from(item.depended_from)
{}
+bool Item_ident::remove_dependence_processor(byte * arg)
+{
+ DBUG_ENTER("Item_ident::remove_dependence_processor");
+ if (depended_from == (st_select_lex *) arg)
+ depended_from= 0;
+ DBUG_RETURN(1);
+}
+
+
bool Item::check_cols(uint c)
{
if (c != 1)
@@ -810,28 +818,17 @@ bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate)
SYNOPSIS
mark_as_dependent()
- outer_resolving - flag of outer resolving
last - select from which current item depend
current - current select
item - item which should be marked
*/
-static void mark_as_dependent(bool outer_resolving,
- SELECT_LEX *last, SELECT_LEX_NODE *current,
+static void mark_as_dependent(SELECT_LEX *last, SELECT_LEX *current,
Item_ident *item)
{
- /*
- only last check is need, i.e.
- "last != current"
- first check added for speed up (check boolean should be faster
- then comparing pointers and this condition usually true)
- */
- if (!outer_resolving || ((SELECT_LEX_NODE *)last) != current)
- {
- // store pointer on SELECT_LEX from wich item is dependent
- item->depended_from= last;
- current->mark_as_dependent(last);
- }
+ // store pointer on SELECT_LEX from wich item is dependent
+ item->depended_from= last;
+ current->mark_as_dependent(last);
}
@@ -841,8 +838,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
TABLE_LIST *where= 0;
Field *tmp= (Field *)not_found_field;
- if (outer_resolving ||
- (tmp= find_field_in_tables(thd, this, tables, &where, 0)) ==
+ if ((tmp= find_field_in_tables(thd, this, tables, &where, 0)) ==
not_found_field)
{
/*
@@ -863,9 +859,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
uint counter;
// Prevent using outer fields in subselects, that is not supported now
SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
- if (outer_resolving ||
- cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
- for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select());
+ if (cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
+ for (SELECT_LEX *sl= cursel->outer_select();
sl;
sl= sl->outer_select())
{
@@ -916,12 +911,12 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1))
return 1;
- mark_as_dependent(outer_resolving, last, cursel, rf);
+ mark_as_dependent(last, cursel, rf);
return 0;
}
else
{
- mark_as_dependent(outer_resolving, last, cursel, this);
+ mark_as_dependent(last, cursel, this);
if (last->having_fix_field)
{
Item_ref *rf;
@@ -930,7 +925,6 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
(char *)field_name);
if (!rf)
return 1;
- (rf)->outer_resolving= outer_resolving;
return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
}
}
@@ -1325,16 +1319,13 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
if (!ref)
{
TABLE_LIST *where= 0, *table_list;
- SELECT_LEX *sl= (outer_resolving?
- thd->lex.current_select->select_lex():
- thd->lex.current_select->outer_select());
+ SELECT_LEX *sl= thd->lex.current_select->outer_select();
/*
Finding only in current select will be performed for selects that have
not outer one and for derived tables (which not support using outer
fields for now)
*/
- if (outer_resolving ||
- (ref= find_item_in_list(this,
+ if ((ref= find_item_in_list(this,
*(thd->lex.current_select->get_item_list()),
&counter,
((sl &&
@@ -1400,7 +1391,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
Item_field* fld;
if (!((*reference)= fld= new Item_field(tmp)))
return 1;
- mark_as_dependent(outer_resolving, last, thd->lex.current_select, fld);
+ mark_as_dependent(last, thd->lex.current_select, fld);
return 0;
}
else
@@ -1411,7 +1402,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list");
return -1;
}
- mark_as_dependent(outer_resolving, last, thd->lex.current_select,
+ mark_as_dependent(last, thd->lex.current_select,
this);
ref= last->ref_pointer_array + counter;
}
@@ -1430,19 +1421,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
}
}
-/*
- * The following conditional is changed as to correctly identify
- * incorrect references in group functions or forward references
- * with sub-select's / derived tables, while it prevents this
- * check when Item_ref is created in an expression involving
- * summing function, which is to be placed in the user variable.
- *
- */
-
+ /*
+ The following conditional is changed as to correctly identify
+ incorrect references in group functions or forward references
+ with sub-select's / derived tables, while it prevents this
+ check when Item_ref is created in an expression involving
+ summing function, which is to be placed in the user variable.
+ */
if (((*ref)->with_sum_func && name &&
- (depended_from ||
+ (depended_from ||
!(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- thd->lex.current_select->select_lex()->having_fix_field))) ||
+ thd->lex.current_select->having_fix_field))) ||
!(*ref)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
@@ -1687,11 +1676,11 @@ Item_cache* Item_cache::get_cache(Item_result type)
void Item_cache_str::store(Item *item)
{
- str_value.set(buffer, sizeof(buffer), item->collation.collation);
- value= item->str_result(&str_value);
+ value_buff.set(buffer, sizeof(buffer), item->collation.collation);
+ value= item->str_result(&value_buff);
if ((null_value= item->null_value))
value= 0;
- else if (value != &str_value)
+ else if (value != &value_buff)
{
/*
We copy string value to avoid changing value if 'item' is table field
@@ -1701,10 +1690,10 @@ void Item_cache_str::store(Item *item)
(select c from t1 where a=t2.a)
from t2;
*/
- str_value.copy(*value);
- value= &str_value;
+ value_buff.copy(*value);
+ value= &value_buff;
}
-
+ set_charset(&item->collation);
}
double Item_cache_str::val()
{
diff --git a/sql/item.h b/sql/item.h
index 621dc017d25..82c61466200 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -82,6 +82,8 @@ public:
}
};
+typedef bool (Item::*Item_processor)(byte *arg);
+
class Item {
Item(const Item &); /* Prevent use of these */
void operator=(Item &);
@@ -158,7 +160,7 @@ public:
virtual bool get_time(TIME *ltime);
virtual bool get_date_result(TIME *ltime,bool fuzzydate)
{ return get_date(ltime,fuzzydate); }
- virtual bool is_null() { return 0; };
+ virtual bool is_null() { return 0; }
virtual void top_level_item() {}
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
@@ -169,8 +171,14 @@ public:
virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
CHARSET_INFO *default_charset() const;
- virtual void set_outer_resolving() {}
+ virtual bool walk(Item_processor processor, byte *arg)
+ {
+ return (this->*processor)(arg);
+ }
+
+ virtual bool remove_dependence_processor(byte * arg) { return 0; }
+
// Row emulation
virtual uint cols() { return 1; }
virtual Item* el(uint i) { return this; }
@@ -191,16 +199,16 @@ public:
const char *table_name;
const char *field_name;
st_select_lex *depended_from;
- bool outer_resolving; /* used for items from reduced subselect */
Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par)
:db_name(db_name_par), table_name(table_name_par),
- field_name(field_name_par), depended_from(0), outer_resolving(0)
+ field_name(field_name_par), depended_from(0)
{ name = (char*) field_name_par; }
// Constructor used by Item_field & Item_ref (see Item comment)
Item_ident(THD *thd, Item_ident &item);
const char *full_name() const;
- void set_outer_resolving() { outer_resolving= 1; }
+
+ bool remove_dependence_processor(byte * arg);
};
@@ -607,6 +615,15 @@ public:
longlong val_int();
String* val_str(String* s);
bool get_date(TIME *ltime, bool fuzzydate);
+ void print(String *str)
+ {
+ str->append("ref_null_helper(");
+ if (ref && *ref)
+ (*ref)->print(str);
+ else
+ str->append('?');
+ str->append(')');
+ }
};
@@ -652,6 +669,15 @@ public:
{}
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
Item **storage() {return &item;}
+ void print(String *str)
+ {
+ str->append("ref_null_helper('");
+ if (item)
+ item->print(str);
+ else
+ str->append('?');
+ str->append(')');
+ }
};
/*
@@ -788,7 +814,6 @@ public:
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, struct st_table_list *, Item **);
- void set_outer_resolving() { arg->set_outer_resolving(); }
void print(String *str);
virtual bool basic_const_item() const { return true; }
int save_in_field(Field *field, bool no_conversions)
@@ -801,6 +826,12 @@ public:
return Item_field::save_in_field(field, no_conversions);
}
table_map used_tables() const { return (table_map)0L; }
+
+ bool walk(Item_processor processor, byte *args)
+ {
+ return arg->walk(processor, args) ||
+ (this->*processor)(args);
+ }
};
class Item_insert_value : public Item_field
@@ -811,7 +842,6 @@ public:
Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, struct st_table_list *, Item **);
- void set_outer_resolving() { arg->set_outer_resolving(); }
void print(String *str);
virtual bool basic_const_item() const { return true; }
int save_in_field(Field *field, bool no_conversions)
@@ -819,6 +849,12 @@ public:
return Item_field::save_in_field(field, no_conversions);
}
table_map used_tables() const { return (table_map)0L; }
+
+ bool walk(Item_processor processor, byte *args)
+ {
+ return arg->walk(processor, args) ||
+ (this->*processor)(args);
+ }
};
class Item_cache: public Item
@@ -883,7 +919,7 @@ public:
class Item_cache_str: public Item_cache
{
char buffer[80];
- String *value;
+ String *value, value_buff;
public:
Item_cache_str(): Item_cache() { }
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 7d8da16338b..c78e032c943 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -373,16 +373,24 @@ int Arg_comparator::compare_e_row()
return 1;
}
-bool Item_in_optimizer::preallocate_row()
+
+bool Item_in_optimizer::fix_left(THD *thd,
+ struct st_table_list *tables,
+ Item **ref)
{
- return (!(cache= Item_cache::get_cache(ROW_RESULT)));
+ if (args[0]->fix_fields(thd, tables, ref) ||
+ (!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))))
+ return 1;
+ cache->setup(args[0]);
+ return 0;
}
+
bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref)
{
- if (args[0]->fix_fields(thd, tables, args))
+ if (fix_left(thd, tables, ref))
return 1;
if (args[0]->maybe_null)
maybe_null=1;
@@ -390,9 +398,6 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
with_sum_func= args[0]->with_sum_func;
used_tables_cache= args[0]->used_tables();
const_item_cache= args[0]->const_item();
- if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
- return 1;
- cache->setup(args[0]);
if (cache->cols() == 1)
{
if (args[0]->used_tables())
@@ -411,7 +416,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
((Item_cache *)cache->el(i))->set_used_tables(0);
}
}
- if (args[1]->fix_fields(thd, tables, args))
+ if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args))
return 1;
Item_in_subselect * sub= (Item_in_subselect *)args[1];
if (args[0]->cols() != sub->engine->cols())
@@ -1554,7 +1559,8 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
if (abort_on_null)
item->top_level_item();
- if (item->fix_fields(thd, tables, li.ref()) || item->check_cols(1))
+ if ((!item->fixed &&
+ item->fix_fields(thd, tables, li.ref())) || item->check_cols(1))
return 1; /* purecov: inspected */
used_tables_cache|=item->used_tables();
with_sum_func= with_sum_func || item->with_sum_func;
@@ -1569,13 +1575,14 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
-void Item_cond::set_outer_resolving()
+bool Item_cond::walk(Item_processor processor, byte *arg)
{
- Item_func::set_outer_resolving();
- List_iterator<Item> li(list);
+ List_iterator_fast<Item> li(list);
Item *item;
while ((item= li++))
- item->set_outer_resolving();
+ if (item->walk(processor, arg))
+ return 1;
+ return Item_func::walk(processor, arg);
}
void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 25cc97d60bf..42ece007a54 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -93,9 +93,8 @@ protected:
public:
Item_in_optimizer(Item *a, Item_in_subselect *b):
Item_bool_func(a, (Item *)b), cache(0) {}
- // used by row in transformer
- bool preallocate_row();
bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool fix_left(THD *thd, struct st_table_list *tables, Item **ref);
bool is_null();
/*
Item_in_optimizer item is special boolean function. On value request
@@ -105,7 +104,7 @@ public:
Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
*/
longlong val_int();
-
+ const char *func_name() const { return "IN_OPTIMIZER"; }
Item_cache **get_cache() { return &cache; }
};
@@ -790,7 +789,8 @@ public:
void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
void top_level_item() { abort_on_null=1; }
- void set_outer_resolving();
+
+ bool walk(Item_processor processor, byte *arg);
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index a7c5b35b8db..660b623987c 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -198,14 +198,18 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
-void Item_func::set_outer_resolving()
+bool Item_func::walk (Item_processor processor, byte *argument)
{
if (arg_count)
{
Item **arg,**arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
- (*arg)->set_outer_resolving();
+ {
+ if ((*arg)->walk(processor, argument))
+ return 1;
+ }
}
+ return (this->*processor)(argument);
}
void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
@@ -2524,13 +2528,14 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
return 0;
}
-void Item_func_match::set_outer_resolving()
+bool Item_func_match::walk(Item_processor processor, byte *arg)
{
- Item_real_func::set_outer_resolving();
- List_iterator<Item> li(fields);
+ List_iterator_fast<Item> li(fields);
Item *item;
while ((item= li++))
- item->set_outer_resolving();
+ if (item->walk(processor, arg))
+ return 1;
+ return Item_func::walk(processor, arg);
}
bool Item_func_match::fix_index()
diff --git a/sql/item_func.h b/sql/item_func.h
index 56ee0379cd5..e55313c6ad0 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -134,11 +134,12 @@ public:
friend class udf_handler;
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg);
- void set_outer_resolving();
Item *get_tmp_table_item(THD *thd);
bool agg_arg_collations(DTCollation &c, Item **items, uint nitems);
bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems);
+
+ bool walk(Item_processor processor, byte *arg);
};
@@ -1011,7 +1012,8 @@ public:
bool fix_index();
void init_search(bool no_order);
- void set_outer_resolving();
+
+ bool walk(Item_processor processor, byte *arg);
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
index cf745e21e45..43e38763aa6 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -118,14 +118,18 @@ bool Item_row::check_cols(uint c)
return 0;
}
-void Item_row::bring_value()
+bool Item_row::walk(Item_processor processor, byte *arg)
{
for (uint i= 0; i < arg_count; i++)
- items[i]->bring_value();
+ {
+ if (items[i]->walk(processor, arg))
+ return 1;
+ }
+ return (this->*processor)(arg);
}
-void Item_row::set_outer_resolving()
+void Item_row::bring_value()
{
for (uint i= 0; i < arg_count; i++)
- items[i]->set_outer_resolving();
+ items[i]->bring_value();
}
diff --git a/sql/item_row.h b/sql/item_row.h
index 4f674d8a561..6dd955ed426 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -68,7 +68,8 @@ public:
bool const_item() const { return const_item_cache; };
enum Item_result result_type() const { return ROW_RESULT; }
void update_used_tables();
- void set_outer_resolving();
+
+ bool walk(Item_processor processor, byte *arg);
uint cols() { return arg_count; }
Item* el(uint i) { return items[i]; }
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index dfcc22b3443..f64a145b136 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -107,10 +107,10 @@ public:
}
void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
const char *func_name() const { return "concat_ws"; }
- void set_outer_resolving()
+ bool walk(Item_processor processor, byte *arg)
{
- separator->set_outer_resolving();
- Item_func::set_outer_resolving();
+ return separator->walk(processor, arg) ||
+ Item_str_func::walk(processor, arg);
}
};
@@ -399,10 +399,11 @@ public:
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "make_set"; }
- void set_outer_resolving()
+
+ bool walk(Item_processor processor, byte *arg)
{
- item->set_outer_resolving();
- Item_str_func::set_outer_resolving();
+ return item->walk(processor, arg) ||
+ Item_str_func::walk(processor, arg);
}
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 32edaaca0fd..de6ba791a97 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -20,9 +20,6 @@
SUBSELECT TODO:
- add function from mysql_select that use JOIN* as parameter to JOIN methods
(sql_select.h/sql_select.cc)
- - remove double 'having' & 'having_list' from JOIN
- (sql_select.h/sql_select.cc)
-
*/
#ifdef __GNUC__
@@ -56,7 +53,6 @@ void Item_subselect::init(THD *thd, st_select_lex *select_lex,
DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
- select_transformer(thd, select_lex->master_unit());
if (select_lex->next_select())
engine= new subselect_union_engine(thd, select_lex->master_unit(), result,
this);
@@ -72,10 +68,11 @@ Item_subselect::~Item_subselect()
delete engine;
}
-void Item_subselect::select_transformer(THD *thd, st_select_lex_unit *unit)
+Item_subselect::trans_res
+Item_subselect::select_transformer(JOIN *join)
{
DBUG_ENTER("Item_subselect::select_transformer");
- DBUG_VOID_RETURN;
+ DBUG_RETURN(OK);
}
@@ -83,27 +80,28 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
thd= thd_param;
- if (substitution)
- {
- (*ref)= substitution;
- substitution->name= name;
- if (have_to_be_excluded)
- engine->exclude();
- substitution= 0;
- int ret= (*ref)->fix_fields(thd, tables, ref);
- // We can't substitute aggregate functions (like (SELECT (max(i)))
- if ((*ref)->with_sum_func)
- {
- my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
- return 1;
- }
- return ret;
- }
-
char const *save_where= thd->where;
int res= engine->prepare();
if (!res)
{
+ if (substitution)
+ {
+ (*ref)= substitution;
+ substitution->name= name;
+ if (have_to_be_excluded)
+ engine->exclude();
+ substitution= 0;
+ fixed= 1;
+ thd->where= "checking transformed subquery";
+ int ret= (*ref)->fix_fields(thd, tables, ref);
+ // We can't substitute aggregate functions (like (SELECT (max(i)))
+ if ((*ref)->with_sum_func)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
+ return 1;
+ }
+ return ret;
+ }
// Is it one field subselect?
if (engine->cols() > max_columns)
{
@@ -166,12 +164,13 @@ void Item_singlerow_subselect::reset()
value->null_value= 1;
}
-void Item_singlerow_subselect::select_transformer(THD *thd,
- st_select_lex_unit *unit)
+Item_subselect::trans_res
+Item_singlerow_subselect::select_transformer(JOIN *join)
{
- SELECT_LEX *select_lex= unit->first_select();
+ SELECT_LEX *select_lex= join->select_lex;
- if (!select_lex->next_select() && !select_lex->table_list.elements &&
+ if (!select_lex->master_unit()->first_select()->next_select() &&
+ !select_lex->table_list.elements &&
select_lex->item_list.elements == 1 &&
/*
We cant change name of Item_field or Item_ref, because it will
@@ -186,31 +185,37 @@ void Item_singlerow_subselect::select_transformer(THD *thd,
{
have_to_be_excluded= 1;
- if (thd->lex.describe)
+ if (join->thd->lex.describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning(join->thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
substitution= select_lex->item_list.head();
- substitution->set_outer_resolving();
-
+ /*
+ as far as we moved content to upper leven, field which depend of
+ 'upper' select is not really dependent => we remove this dependence
+ */
+ substitution->walk(&Item::remove_dependence_processor,
+ (byte *) select_lex->outer_select());
if (select_lex->where || select_lex->having)
{
Item *cond;
- if (!select_lex->having)
- cond= select_lex->where;
- else if (!select_lex->where)
- cond= select_lex->having;
+ if (!join->having)
+ cond= join->conds;
+ else if (!join->conds)
+ cond= join->having;
else
- if (!(cond= new Item_cond_and(select_lex->having, select_lex->where)))
- return;
+ if (!(cond= new Item_cond_and(join->conds, join->having)))
+ return ERROR;
if (!(substitution= new Item_func_if(cond, substitution,
new Item_null())))
- return;
+ return ERROR;
}
+ return REDUCE;
}
+ return OK;
}
void Item_singlerow_subselect::store(uint i, Item *item)
@@ -329,6 +334,21 @@ Item_exists_subselect::Item_exists_subselect(THD *thd,
DBUG_VOID_RETURN;
}
+bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit)
+{
+ if (unit->fake_select_lex &&
+ unit->fake_select_lex->test_limit())
+ return(1);
+
+ SELECT_LEX *sl= unit->first_select();
+ for (; sl; sl= sl->next_select())
+ {
+ if (sl->test_limit())
+ return(1);
+ }
+ return(0);
+}
+
Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
st_select_lex *select_lex):
Item_exists_subselect()
@@ -338,25 +358,27 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
init(thd, select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX;
maybe_null= 1;
+ abort_on_null= 0;
reset();
- // We need only 1 row to determinate existence
- select_lex->master_unit()->global_parameters->select_limit= 1;
+ //if test_limit will fail then error will be reported to client
+ test_limit(select_lex->master_unit());
DBUG_VOID_RETURN;
}
Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
- compare_func_creator f,
+ compare_func_creator fn,
st_select_lex *select_lex):
Item_in_subselect()
{
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
left_expr= left_exp;
- func= f;
+ func= fn;
init(thd, select_lex, new select_exists_subselect(this));
max_columns= 1;
+ abort_on_null= 0;
reset();
- // We need only 1 row to determinate existence
- select_lex->master_unit()->global_parameters->select_limit= 1;
+ //if test_limit will fail then error will be reported to client
+ test_limit(select_lex->master_unit());
DBUG_VOID_RETURN;
}
@@ -446,6 +468,7 @@ Item_in_subselect::Item_in_subselect(Item_in_subselect *item):
Item_exists_subselect(item)
{
left_expr= item->left_expr;
+ abort_on_null= item->abort_on_null;
}
Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item):
@@ -454,227 +477,257 @@ Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item):
func= item->func;
}
-void Item_in_subselect::single_value_transformer(THD *thd,
- st_select_lex_unit *unit,
- Item *left_expr,
- compare_func_creator func)
+Item_subselect::trans_res
+Item_in_subselect::single_value_transformer(JOIN *join,
+ Item *left_expr,
+ compare_func_creator func)
{
DBUG_ENTER("Item_in_subselect::single_value_transformer");
- if (unit->global_parameters->select_limit != HA_POS_ERROR)
- {
- 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();
+ SELECT_LEX *select_lex= join->select_lex;
- Item_in_optimizer *optimizer;
- substitution= optimizer= new Item_in_optimizer(left_expr, this);
- if (!optimizer)
- DBUG_VOID_RETURN;
+ THD *thd= join->thd;
+ thd->where= "scalar IN/ALL/ANY subquery";
- /*
- As far as Item_ref_in_optimizer do not substitude itself on fix_fields
- we can use same item for all selects.
- */
- Item *expr= new Item_ref((Item**)optimizer->get_cache(),
- (char *)"<no matter>",
- (char*)"<left expr>");
- unit->dependent= 1;
- for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select())
+ if (!substitution)
{
- if (sl->select_limit != HA_POS_ERROR)
- {
- my_error(ER_NOT_SUPPORTED_YET, MYF(0),
- "LIMIT & IN/ALL/ANY/SOME subquery");
- DBUG_VOID_RETURN;
- }
+ //first call for this unit
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ substitution= optimizer= new Item_in_optimizer(left_expr, this);
- sl->dependent= 1;
- Item *item;
- if (sl->item_list.elements > 1)
+ SELECT_LEX *current= thd->lex.current_select, *up;
+
+ thd->lex.current_select= up= current->return_after_parsing();
+ //optimizer never use Item **ref => we can pass 0 as parameter
+ if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
- my_error(ER_CARDINALITY_COL, MYF(0), 1);
- DBUG_VOID_RETURN;
+ thd->lex.current_select= current;
+ DBUG_RETURN(ERROR);
}
- else
- item= (Item*) sl->item_list.pop();
+ thd->lex.current_select= current;
- sl->order_list.empty(); // no sense in ORDER BY without LIMIT
+ /*
+ As far as Item_ref_in_optimizer do not substitude itself on fix_fields
+ we can use same item for all selects.
+ */
+ expr= new Item_ref((Item**)optimizer->get_cache(),
+ (char *)"<no matter>",
+ (char *)"<left expr>");
+
+ unit->dependent= 1;
+ }
- if (sl->having || sl->with_sum_func || sl->group_list.elements)
+ select_lex->dependent= 1;
+ Item *item;
+ if (select_lex->item_list.elements > 1)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ DBUG_RETURN(ERROR);
+ }
+
+ item= (Item*) select_lex->item_list.head();
+
+ if (join->having || select_lex->with_sum_func ||
+ select_lex->group_list.elements)
+ {
+ item= (*func)(expr,
+ new Item_ref_null_helper(this,
+ select_lex->ref_pointer_array,
+ (char *)"<ref>",
+ this->full_name()));
+ join->having= and_items(join->having, item);
+ select_lex->having_fix_field= 1;
+ if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
- sl->item_list.push_back(item);
- setup_ref_array(thd, &sl->ref_pointer_array,
- 1 + sl->select_n_having_items +
- sl->order_list.elements + sl->group_list.elements);
- // To prevent crash on Item_ref_null_helper destruction in case of error
- sl->ref_pointer_array[0]= 0;
- item= (*func)(expr, new Item_ref_null_helper(this,
- sl->ref_pointer_array,
- (char *)"<ref>",
- this->full_name()));
- sl->having= and_items(sl->having, item);
+ select_lex->having_fix_field= 0;
+ DBUG_RETURN(ERROR);
}
- else
+ select_lex->having_fix_field= 0;
+ }
+ else
+ {
+ select_lex->item_list.empty();
+ select_lex->item_list.push_back(new Item_int("Not_used",
+ (longlong) 1, 21));
+ select_lex->ref_pointer_array[0]= select_lex->item_list.head();
+ if (select_lex->table_list.elements)
{
- sl->item_list.empty();
- sl->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21));
- if (sl->table_list.elements)
+ Item *having= item, *isnull= item;
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
{
- Item *having= item, *isnull= item;
- if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*) item)->field_name[0] == '*')
+ Item_asterisk_remover *remover;
+ item= remover= new Item_asterisk_remover(this, item,
+ (char *)"<no matter>",
+ (char *)"<result>");
+ if (!abort_on_null)
{
- Item_asterisk_remover *remover;
- item= remover= new Item_asterisk_remover(this, item,
- (char*)"<no matter>",
- (char*)"<result>");
having=
new Item_is_not_null_test(this,
new Item_ref(remover->storage(),
- (char*)"<no matter>",
- (char*)"<null test>"));
+ (char *)"<no matter>",
+ (char *)"<null test>"));
isnull=
new Item_is_not_null_test(this,
new Item_ref(remover->storage(),
- (char*)"<no matter>",
- (char*)"<null test>"));
+ (char *)"<no matter>",
+ (char *)"<null test>"));
}
- having= new Item_is_not_null_test(this, having);
- sl->having= (sl->having ?
- new Item_cond_and(having, sl->having) :
- having);
- item= new Item_cond_or((*func)(expr, item),
- new Item_func_isnull(isnull));
- sl->where= and_items(sl->where, item);
}
- else
+ item= (*func)(expr, item);
+ if (!abort_on_null)
{
- if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*) item)->field_name[0] == '*')
+ having= new Item_is_not_null_test(this, having);
+ join->having= (join->having ?
+ new Item_cond_and(having, join->having) :
+ having);
+ select_lex->having_fix_field= 1;
+ if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
- my_error(ER_NO_TABLES_USED, MYF(0));
- DBUG_VOID_RETURN;
+ select_lex->having_fix_field= 0;
+ DBUG_RETURN(ERROR);
}
- if (unit->first_select()->next_select())
- {
- /*
- It is in union => we should perform it.
- Item_asterisk_remover used only as wrapper to receine NULL value
- */
- sl->having= (*func)(expr,
+ select_lex->having_fix_field= 0;
+ item= new Item_cond_or(item,
+ new Item_func_isnull(isnull));
+ }
+ join->conds= and_items(join->conds, item);
+ if (join->conds->fix_fields(thd, join->tables_list, &join->conds))
+ DBUG_RETURN(ERROR);
+ }
+ else
+ {
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
+ {
+ my_error(ER_NO_TABLES_USED, MYF(0));
+ DBUG_RETURN(ERROR);
+ }
+ if (select_lex->master_unit()->first_select()->next_select())
+ {
+ /*
+ It is in union => we should perform it.
+ Item_asterisk_remover used only as wrapper to receine NULL value
+ */
+ join->having= (*func)(expr,
new Item_asterisk_remover(this, item,
(char *)"<no matter>",
- (char*)"<result>"));
+ (char *)"<result>"));
+ select_lex->having_fix_field= 1;
+ if (join->having->fix_fields(thd, join->tables_list, &join->having))
+ {
+ select_lex->having_fix_field= 0;
+ DBUG_RETURN(ERROR);
}
- else
+ select_lex->having_fix_field= 0;
+ }
+ else
+ {
+ // it is single select without tables => possible optimization
+ item= (*func)(left_expr, item);
+ // fix_field of item will be done in time of substituting
+ substitution= item;
+ have_to_be_excluded= 1;
+ if (thd->lex.describe)
{
- // it is single select without tables => possible optimization
- item= (*func)(left_expr, item);
- substitution= item;
- have_to_be_excluded= 1;
- if (thd->lex.describe)
- {
- char warn_buff[MYSQL_ERRMSG_SIZE];
- sprintf(warn_buff, ER(ER_SELECT_REDUCED), sl->select_number);
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_SELECT_REDUCED, warn_buff);
- }
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SELECT_REDUCED, warn_buff);
}
+ DBUG_RETURN(REDUCE);
}
}
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(OK);
}
-void Item_in_subselect::row_value_transformer(THD *thd,
- st_select_lex_unit *unit,
- Item *left_expr)
+Item_subselect::trans_res
+Item_in_subselect::row_value_transformer(JOIN *join,
+ Item *left_expr)
{
DBUG_ENTER("Item_in_subselect::row_value_transformer");
- 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();
+ THD *thd= join->thd;
+ thd->where= "row IN/ALL/ANY subquery";
- Item_in_optimizer *optimizer;
- substitution= optimizer= new Item_in_optimizer(left_expr, this);
- if (!optimizer)
- DBUG_VOID_RETURN;
+ SELECT_LEX *select_lex= join->select_lex;
- unit->dependent= 1;
- uint n= left_expr->cols();
- if (optimizer->preallocate_row() || (*optimizer->get_cache())->allocate(n))
- DBUG_VOID_RETURN;
- for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select())
+ if (!substitution)
{
- if (sl->select_limit != HA_POS_ERROR)
+ //first call for this unit
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ substitution= optimizer= new Item_in_optimizer(left_expr, this);
+
+ SELECT_LEX *current= thd->lex.current_select, *up;
+ thd->lex.current_select= up= current->return_after_parsing();
+ //optimizer never use Item **ref => we can pass 0 as parameter
+ if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
- my_error(ER_NOT_SUPPORTED_YET, MYF(0),
- "LIMIT & IN/ALL/ANY/SOME subquery");
- DBUG_VOID_RETURN;
+ thd->lex.current_select= current;
+ DBUG_RETURN(ERROR);
}
- sl->order_list.empty(); // no sense in ORDER BY without LIMIT
+ thd->lex.current_select= current;
+
+ unit->dependent= 1;
+ }
- sl->dependent= 1;
+ uint n= left_expr->cols();
+
+ select_lex->dependent= 1;
+
+ Item *item= 0;
+ List_iterator_fast<Item> li(select_lex->item_list);
+ for (uint i= 0; i < n; i++)
+ {
+ Item *func=
+ new Item_ref_on_list_position(this, select_lex, i,
+ (char *) "<no matter>",
+ (char *) "<list ref>");
+ func=
+ Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)"<left expr>"),
+ func);
+ item= and_items(item, func);
+ }
- Item *item= 0;
- List_iterator_fast<Item> li(sl->item_list);
- for (uint i= 0; i < n; i++)
+ if (join->having || select_lex->with_sum_func ||
+ select_lex->group_list.first ||
+ !select_lex->table_list.elements)
+ {
+ join->having= and_items(join->having, item);
+ select_lex->having_fix_field= 1;
+ if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
- Item *func=
- new Item_ref_on_list_position(this, sl, i,
- (char *) "<no matter>",
- (char *) "<list ref>");
- func=
- Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())->
- addr(i),
- (char *)"<no matter>",
- (char *)"<left expr>"),
- func);
- item= and_items(item, func);
+ select_lex->having_fix_field= 0;
+ DBUG_RETURN(ERROR);
}
-
- if (sl->having || sl->with_sum_func || sl->group_list.first ||
- !sl->table_list.elements)
- sl->having= and_items(sl->having, item);
- else
- sl->where= and_items(sl->where, item);
+ select_lex->having_fix_field= 0;
}
- DBUG_VOID_RETURN;
+ else
+ {
+ join->conds= and_items(join->conds, item);
+ if (join->conds->fix_fields(thd, join->tables_list, &join->having))
+ DBUG_RETURN(ERROR);
+ }
+ DBUG_RETURN(OK);
}
-
-void Item_in_subselect::select_transformer(THD *thd, st_select_lex_unit *unit)
+Item_subselect::trans_res
+Item_in_subselect::select_transformer(JOIN *join)
{
if (left_expr->cols() == 1)
- single_value_transformer(thd, unit, left_expr,
- &Item_bool_func2::eq_creator);
- else
- row_value_transformer(thd, unit, left_expr);
+ return single_value_transformer(join, left_expr,
+ &Item_bool_func2::eq_creator);
+ return row_value_transformer(join, left_expr);
}
-void Item_allany_subselect::select_transformer(THD *thd,
- st_select_lex_unit *unit)
+Item_subselect::trans_res
+Item_allany_subselect::select_transformer(JOIN *join)
{
- single_value_transformer(thd, unit, left_expr, func);
+ return single_value_transformer(join, left_expr, func);
}
subselect_single_select_engine::subselect_single_select_engine(THD *thd,
@@ -719,7 +772,7 @@ int subselect_single_select_engine::prepare()
if (prepared)
return 0;
prepared= 1;
- SELECT_LEX_NODE *save_select= thd->lex.current_select;
+ SELECT_LEX *save_select= thd->lex.current_select;
thd->lex.current_select= select_lex;
if (join->prepare(&select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
@@ -826,7 +879,7 @@ int subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
char const *save_where= join->thd->where;
- SELECT_LEX_NODE *save_select= join->thd->lex.current_select;
+ SELECT_LEX *save_select= join->thd->lex.current_select;
join->thd->lex.current_select= select_lex;
if (!optimized)
{
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 3ed3f2af0e9..bf165289cff 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -48,6 +48,8 @@ protected:
bool have_to_be_excluded;
public:
+ enum trans_res {OK, REDUCE, ERROR};
+
Item_subselect();
Item_subselect(Item_subselect *item)
{
@@ -73,7 +75,7 @@ public:
{
null_value= 1;
}
- virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
+ virtual trans_res select_transformer(JOIN *join);
bool assigned() { return value_assigned; }
void assigned(bool a) { value_assigned= a; }
enum Type type() const;
@@ -86,6 +88,13 @@ public:
bool exec();
virtual void fix_length_and_dec();
table_map used_tables() const;
+ void print(String *str)
+ {
+ if (name)
+ str->append(name);
+ else
+ str->append("-subselect-");
+ }
friend class select_subselect;
friend class Item_in_optimizer;
@@ -108,7 +117,7 @@ public:
decimals= item->decimals;
}
void reset();
- void select_transformer(THD *thd, st_select_lex_unit *unit);
+ trans_res select_transformer(JOIN *join);
void store(uint i, Item* item);
double val();
longlong val_int ();
@@ -164,25 +173,35 @@ class Item_in_subselect :public Item_exists_subselect
{
protected:
Item * left_expr;
+ /*
+ expr & optimizer used in subselect rewriting to store Item for
+ all JOIN in UNION
+ */
+ Item *expr;
+ Item_in_optimizer *optimizer;
bool was_null;
+ bool abort_on_null;
public:
Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
Item_in_subselect(Item_in_subselect *item);
- Item_in_subselect(): Item_exists_subselect() {}
+ Item_in_subselect(): Item_exists_subselect(), abort_on_null(0) {}
void reset()
{
value= 0;
null_value= 0;
was_null= 0;
}
- virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
- void single_value_transformer(THD *thd, st_select_lex_unit *unit,
- Item *left_expr, compare_func_creator func);
- void row_value_transformer(THD *thd, st_select_lex_unit *unit,
- Item *left_expr);
+ trans_res select_transformer(JOIN *join);
+ trans_res single_value_transformer(JOIN *join,
+ Item *left_expr,
+ compare_func_creator func);
+ trans_res row_value_transformer(JOIN * join,
+ Item *left_expr);
longlong val_int();
double val();
String *val_str(String*);
+ void top_level_item() { abort_on_null=1; }
+ bool test_limit(st_select_lex_unit *unit);
friend class Item_asterisk_remover;
friend class Item_ref_null_helper;
@@ -199,7 +218,7 @@ public:
Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f,
st_select_lex *select_lex);
Item_allany_subselect(Item_allany_subselect *item);
- virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
+ trans_res select_transformer(JOIN *join);
};
class subselect_engine: public Sql_alloc
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 0da2725f3ab..7ab83c1e7b2 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1116,7 +1116,7 @@ void Item_sum_count_distinct::make_unique()
bool Item_sum_count_distinct::setup(THD *thd)
{
List<Item> list;
- SELECT_LEX *select_lex= thd->lex.current_select->select_lex();
+ SELECT_LEX *select_lex= thd->lex.current_select;
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
return 1;
@@ -1610,7 +1610,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
quick_group= 0;
mark_as_sum_func();
item_thd= current_thd;
- SELECT_LEX *select_lex= item_thd->lex.current_select->select_lex();
+ SELECT_LEX *select_lex= item_thd->lex.current_select;
order= 0;
group_concat_max_len= item_thd->variables.group_concat_max_len;
@@ -1792,7 +1792,7 @@ bool Item_func_group_concat::setup(THD *thd)
{
DBUG_ENTER("Item_func_group_concat::setup");
List<Item> list;
- SELECT_LEX *select_lex= thd->lex.current_select->select_lex();
+ SELECT_LEX *select_lex= thd->lex.current_select;
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
DBUG_RETURN(1);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 2c41d973f2e..05a2cf4c7f8 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -952,3 +952,24 @@ compare_func_creator comp_le_creator(bool invert);
compare_func_creator comp_lt_creator(bool invert);
compare_func_creator comp_ne_creator(bool invert);
+/*
+ clean/setup table fields and map
+
+ SYNOPSYS
+ setup_table_map()
+ table - TABLE structure pointer (which should be setup)
+ table_list TABLE_LIST structure pointer (owner of TABLE)
+ tablenr - table number
+*/
+inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
+{
+ table->used_fields= 0;
+ table->const_table= 0;
+ table->outer_join= table->null_row= 0;
+ table->status= STATUS_NO_RECORD;
+ table->keys_in_use_for_query= table->keys_in_use;
+ table->maybe_null= test(table->outer_join= table_list->outer_join);
+ table->tablenr= tablenr;
+ table->map= (table_map) 1 << tablenr;
+ table->force_index= table_list->force_index;
+}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index a5807914abd..f33533d9eb7 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2020,18 +2020,9 @@ bool setup_tables(TABLE_LIST *tables)
for (TABLE_LIST *table_list=tables ; table_list ;
table_list=table_list->next,tablenr++)
{
- TABLE *table=table_list->table;
-
- table->used_fields=0;
- table->const_table=0;
- table->outer_join=table->null_row=0;
- table->status=STATUS_NO_RECORD;
- table->keys_in_use_for_query= table->keys_in_use;
+ TABLE *table= table_list->table;
+ setup_table_map(table, table_list, tablenr);
table->used_keys= table->keys_for_keyread;
- table->maybe_null=test(table->outer_join=table_list->outer_join);
- table->tablenr=tablenr;
- table->map= (table_map) 1 << tablenr;
- table->force_index= table_list->force_index;
if (table_list->use_index)
{
key_map map= get_key_map_from_key_list(table,
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index ebb09b99df7..876c4f9e670 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -304,7 +304,7 @@ multi_delete::initialize_tables(JOIN *join)
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
}
- init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
+ init_ftfuncs(thd, thd->lex.current_select, 1);
DBUG_RETURN(thd->is_fatal_error != 0);
}
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 81439a19918..d7a88ecd53e 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -74,7 +74,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
bool is_union= select_cursor->next_select() &&
select_cursor->next_select()->linkage == UNION_TYPE;
bool is_subsel= select_cursor->first_inner_unit() ? 1: 0;
- SELECT_LEX_NODE *save_current_select= lex->current_select;
+ SELECT_LEX *save_current_select= lex->current_select;
DBUG_ENTER("mysql_derived");
/*
@@ -211,7 +211,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if (tables)
{
for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
- cursor->table_list->table=cursor->table;
+ if (cursor->table_list)
+ cursor->table_list->table=cursor->table;
}
}
else
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 57e39a0dc83..2d1d08aa596 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -948,27 +948,17 @@ void st_select_lex_node::init_query()
options= 0;
linkage= UNSPECIFIED_TYPE;
no_error= no_table_names_allowed= uncacheable= dependent= 0;
- ref_pointer_array= 0;
- cond_count= 0;
}
void st_select_lex_node::init_select()
{
- order_list.elements= 0;
- order_list.first= 0;
- order_list.next= (byte**) &order_list.first;
- select_limit= HA_POS_ERROR;
- offset_limit= 0;
- select_n_having_items= 0;
- with_sum_func= 0;
- parsing_place= SELECT_LEX_NODE::NO_MATTER;
}
void st_select_lex_unit::init_query()
{
st_select_lex_node::init_query();
linkage= GLOBAL_OPTIONS_TYPE;
- global_parameters= this;
+ global_parameters= first_select();
select_limit_cnt= HA_POS_ERROR;
offset_limit_cnt= 0;
union_option= 0;
@@ -976,6 +966,7 @@ void st_select_lex_unit::init_query()
item= 0;
union_result= 0;
table= 0;
+ fake_select_lex= 0;
}
void st_select_lex::init_query()
@@ -988,7 +979,8 @@ void st_select_lex::init_query()
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
resolve_mode= NOMATTER_MODE;
- with_wild= 0;
+ cond_count= with_wild= 0;
+ ref_pointer_array= 0;
}
void st_select_lex::init_select()
@@ -1010,6 +1002,14 @@ void st_select_lex::init_select()
ftfunc_list_alloc.empty();
ftfunc_list= &ftfunc_list_alloc;
linkage= UNSPECIFIED_TYPE;
+ order_list.elements= 0;
+ order_list.first= 0;
+ order_list.next= (byte**) &order_list.first;
+ select_limit= HA_POS_ERROR;
+ offset_limit= 0;
+ select_n_having_items= 0;
+ with_sum_func= 0;
+ parsing_place= SELECT_LEX_NODE::NO_MATTER;
}
/*
@@ -1027,6 +1027,23 @@ void st_select_lex_node::include_down(st_select_lex_node *upper)
slave= 0;
}
+/*
+ include on level down (but do not link)
+
+ SYNOPSYS
+ st_select_lex_node::include_standalone()
+ upper - reference on node underr which this node should be included
+ ref - references on reference on this node
+*/
+void st_select_lex_node::include_standalone(st_select_lex_node *upper,
+ st_select_lex_node **ref)
+{
+ next= 0;
+ prev= ref;
+ master= upper;
+ slave= 0;
+}
+
/* include neighbour (on same level) */
void st_select_lex_node::include_neighbour(st_select_lex_node *before)
{
@@ -1108,33 +1125,6 @@ void st_select_lex_unit::exclude_level()
(*prev)= next;
}
-st_select_lex* st_select_lex_node::select_lex()
-{
- DBUG_ENTER("st_select_lex_node::select_lex (never should be called)");
- DBUG_ASSERT(0);
- DBUG_RETURN(0);
-}
-
-bool st_select_lex_node::add_item_to_list(THD *thd, Item *item)
-{
- return 1;
-}
-
-bool st_select_lex_node::add_group_to_list(THD *thd, Item *item, bool asc)
-{
- return 1;
-}
-
-bool st_select_lex_node::add_order_to_list(THD *thd, Item *item, bool asc)
-{
- return add_to_list(thd, order_list, item, asc);
-}
-
-bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func)
-{
- return 1;
-}
-
/*
st_select_lex_node::mark_as_dependent mark all st_select_lex struct from
this to 'last' as dependent
@@ -1148,31 +1138,26 @@ bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func)
*/
-void st_select_lex_node::mark_as_dependent(SELECT_LEX *last)
+void st_select_lex::mark_as_dependent(SELECT_LEX *last)
{
/*
Mark all selects from resolved to 1 before select where was
found table as depended (of select where was found table)
*/
- for (SELECT_LEX_NODE *s= this;
+ for (SELECT_LEX *s= this;
s &&s != last;
s= s->outer_select())
if ( !s->dependent )
{
// Select is dependent of outer select
s->dependent= 1;
- if (s->linkage != GLOBAL_OPTIONS_TYPE)
- {
- //s is st_select_lex*
-
- s->master_unit()->dependent= 1;
- //Tables will be reopened many times
- for (TABLE_LIST *tbl=
- s->get_table_list();
- tbl;
- tbl= tbl->next)
- tbl->shared= 1;
- }
+ s->master_unit()->dependent= 1;
+ //Tables will be reopened many times
+ for (TABLE_LIST *tbl=
+ s->get_table_list();
+ tbl;
+ tbl= tbl->next)
+ tbl->shared= 1;
}
}
@@ -1183,17 +1168,29 @@ TABLE_LIST* st_select_lex_node::get_table_list() { return 0; }
List<Item>* st_select_lex_node::get_item_list() { return 0; }
List<String>* st_select_lex_node::get_use_index() { return 0; }
List<String>* st_select_lex_node::get_ignore_index() { return 0; }
-TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
- LEX_STRING *alias,
- ulong table_join_options,
- thr_lock_type flags,
- List<String> *use_index,
- List<String> *ignore_index)
+
+ulong st_select_lex_node::get_table_join_options()
{
return 0;
}
-ulong st_select_lex_node::get_table_join_options() { return 0; }
+/*
+ prohibit using LIMIT clause
+*/
+bool st_select_lex::test_limit()
+{
+ if (select_limit != HA_POS_ERROR)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "LIMIT & IN/ALL/ANY/SOME subquery");
+ return(1);
+ }
+ // We need only 1 row to determinate existence
+ select_limit= 1;
+ // no sense in ORDER BY without LIMIT
+ order_list.empty();
+ return(0);
+}
/*
Interface method of table list creation for query
@@ -1255,22 +1252,39 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first;
TABLE_LIST **new_table_list= *result, *aux;
SELECT_LEX *sl= (SELECT_LEX*)slave;
- for (; sl; sl= sl->next_select())
+
+ /*
+ iterate all inner selects + fake_select (if exists),
+ fake_select->next_select() always is 0
+ */
+ for (;
+ sl;
+ sl= (sl->next_select() ?
+ sl->next_select() :
+ (sl == fake_select_lex ?
+ 0 :
+ fake_select_lex)))
{
// check usage of ORDER BY in union
- if (sl->order_list.first && sl->next_select() && !sl->braces)
+ if (sl->order_list.first && sl->next_select() && !sl->braces &&
+ sl->linkage != GLOBAL_OPTIONS_TYPE)
{
net_printf(thd,ER_WRONG_USAGE,"UNION","ORDER BY");
return 1;
}
+
if (sl->linkage == DERIVED_TABLE_TYPE && !check_derived)
- continue;
+ goto end;
+
for (SELECT_LEX_UNIT *inner= sl->first_inner_unit();
inner;
inner= inner->next_unit())
+ {
if (inner->create_total_list_n_last_return(thd, lex,
&slave_list_last, 0))
return 1;
+ }
+
if ((aux= (TABLE_LIST*) sl->table_list.first))
{
TABLE_LIST *next;
@@ -1293,15 +1307,18 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
return 1;
}
*new_table_list= cursor;
+ cursor->table_list= aux; //to be able mark this table as shared
new_table_list= &cursor->next;
*new_table_list= 0; // end result list
}
else
- aux->shared= 1; // Mark that it's used twice
+ // Mark that it's used twice
+ cursor->table_list->shared= aux->shared= 1;
aux->table_list= cursor;
}
}
}
+end:
if (slave_list_first)
{
*new_table_list= slave_list_first;
@@ -1321,9 +1338,9 @@ st_select_lex* st_select_lex_unit::outer_select()
return (st_select_lex*) master;
}
-st_select_lex* st_select_lex::select_lex()
+bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc)
{
- return this;
+ return add_to_list(thd, order_list, item, asc);
}
bool st_select_lex::add_item_to_list(THD *thd, Item *item)
@@ -1393,17 +1410,6 @@ ulong st_select_lex::get_table_join_options()
return table_join_options;
}
-st_select_lex::st_select_lex(struct st_lex *lex)
-{
- select_number= ++lex->thd->select_number;
- init_query();
- init_select();
- include_neighbour(lex->current_select);
- include_global((st_select_lex_node**)&lex->all_selects_list);
- lex->current_select= this;
-}
-
-
/*
There are st_select_lex::add_table_to_list &
st_select_lex::set_lock_for_tables in sql_parse.cc
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6b3da620fc1..d310aa5c06f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -118,6 +118,12 @@ enum olap_type
subselects or derived tables) for ordinary select_lex
- list of all select_lex (for group operation like correcting list of opened
tables)
+ - if unit contain several selects (union) then it have special
+ select_lex called fake_select_lex. It used for storing global parameters
+ and executing union. subqueries of global ORDER BY clause will be
+ attached to this fake_select_lex, which will allow them correctly
+ resolve fields of 'upper' union and other more outer selects.
+
for example for following query:
select *
@@ -138,6 +144,7 @@ enum olap_type
main unit
+ fake0
select1 select2 select3
|^^ |^
s||| ||master
@@ -146,7 +153,8 @@ enum olap_type
v|||master slave ||
e||+-------------------------+ ||
V| neighbor | V|
- unit 1.1<==================>unit1.2 unit2.1
+ unit1.1<+==================>unit1.2 unit2.1
+ fake1.1 fake2.1
select1.1.1 select 1.1.2 select1.2.1 select2.1.1 select2.1.2
|^
||
@@ -158,13 +166,14 @@ enum olap_type
relation in main unit will be following:
main unit
- |^^^
- ||||
- |||+------------------------------+
- ||+--------------+ |
- slave||master | |
- V| neighbor | neighbor |
- select1<========>select2<========>select3
+ |^^^^|fake_select_lex
+ |||||+--------------------------------------------+
+ ||||+--------------------------------------------+|
+ |||+------------------------------+ ||
+ ||+--------------+ | ||
+ slave||master | | ||
+ V| neighbor | neighbor | master|V
+ select1<========>select2<========>select3 fake0
list of all select_lex will be following (as it will be constructed by
parser):
@@ -199,21 +208,6 @@ public:
ulong options;
enum sub_select_type linkage;
- SQL_LIST order_list; /* ORDER clause */
- List<List_item> expr_list;
- List<List_item> when_list; /* WHEN clause (expression) */
- ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
- // Arrays of pointers to top elements of all_fields list
- Item **ref_pointer_array;
- /*
- number of items in select_list and HAVING clause used to get number
- bigger then can be number of entries that will be added to all item
- list during split_sum_func
- */
- uint select_n_having_items;
- uint cond_count; /* number of arguments of and/or/xor in where/having */
- enum_parsing_place parsing_place; /* where we are parsing expression */
- bool with_sum_func; /* sum function indicator */
bool dependent; /* dependent from outer select subselect */
bool uncacheable; /* result of this query can't be cached */
bool no_table_names_allowed; /* used for global order by */
@@ -231,18 +225,13 @@ public:
virtual void init_select();
void include_down(st_select_lex_node *upper);
void include_neighbour(st_select_lex_node *before);
+ void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref);
void include_global(st_select_lex_node **plink);
void exclude();
- virtual st_select_lex* select_lex();
- virtual bool add_item_to_list(THD *thd, Item *item);
- bool add_order_to_list(THD *thd, Item *item, bool asc);
- virtual bool add_group_to_list(THD *thd, Item *item, bool asc);
- virtual bool add_ftfunc_to_list(Item_func_match *func);
-
virtual st_select_lex_unit* master_unit()= 0;
virtual st_select_lex* outer_select()= 0;
- virtual st_select_lex_node* return_after_parsing()= 0;
+ virtual st_select_lex* return_after_parsing()= 0;
virtual bool set_braces(bool value);
virtual bool inc_in_sum_expr();
@@ -252,14 +241,7 @@ public:
virtual List<String>* get_use_index();
virtual List<String>* get_ignore_index();
virtual ulong get_table_join_options();
- virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table,
- LEX_STRING *alias,
- ulong table_options,
- thr_lock_type flags= TL_UNLOCK,
- List<String> *use_index= 0,
- List<String> *ignore_index= 0);
virtual void set_lock_for_tables(thr_lock_type lock_type) {}
- void mark_as_dependent(st_select_lex *last);
friend class st_select_lex_unit;
friend bool mysql_new_select(struct st_lex *lex, bool move_down);
@@ -296,14 +278,17 @@ public:
Pointer to 'last' select or pointer to unit where stored
global parameters for union
*/
- st_select_lex_node *global_parameters;
+ st_select_lex *global_parameters;
//node on wich we should return current_select pointer after parsing subquery
- st_select_lex_node *return_to;
+ st_select_lex *return_to;
/* LIMIT clause runtime counters */
ha_rows select_limit_cnt, offset_limit_cnt;
/* not NULL if union used in subselect, point to subselect item */
Item_subselect *item;
+ /* thread handler */
THD *thd;
+ /* fake SELECT_LEX for union processing */
+ st_select_lex *fake_select_lex;
uint union_option;
@@ -315,11 +300,10 @@ public:
st_select_lex* first_select() { return (st_select_lex*) slave; }
st_select_lex* first_select_in_union()
{
- return (slave && slave->linkage == GLOBAL_OPTIONS_TYPE) ?
- (st_select_lex*) slave->next : (st_select_lex*) slave;
+ return (st_select_lex*) slave;
}
st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; }
- st_select_lex_node* return_after_parsing() { return return_to; }
+ st_select_lex* return_after_parsing() { return return_to; }
void exclude_level();
/* UNION methods */
@@ -357,6 +341,24 @@ public:
List<Item_func_match> ftfunc_list_alloc;
JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */
const char *type; /* type of select for EXPLAIN */
+
+ SQL_LIST order_list; /* ORDER clause */
+ List<List_item> expr_list;
+ List<List_item> when_list; /* WHEN clause (expression) */
+ ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
+ // Arrays of pointers to top elements of all_fields list
+ Item **ref_pointer_array;
+
+ /*
+ number of items in select_list and HAVING clause used to get number
+ bigger then can be number of entries that will be added to all item
+ list during split_sum_func
+ */
+ uint select_n_having_items;
+ uint cond_count; /* number of arguments of and/or/xor in where/having */
+ enum_parsing_place parsing_place; /* where we are parsing expression */
+ bool with_sum_func; /* sum function indicator */
+
ulong table_join_options;
uint in_sum_expr;
uint select_number; /* number of select (used for EXPLAIN) */
@@ -403,31 +405,33 @@ public:
{
return &link_next;
}
- st_select_lex_node* return_after_parsing()
+ st_select_lex* return_after_parsing()
{
return master_unit()->return_after_parsing();
}
+ void mark_as_dependent(st_select_lex *last);
+
bool set_braces(bool value);
bool inc_in_sum_expr();
uint get_in_sum_expr();
- st_select_lex* select_lex();
bool add_item_to_list(THD *thd, Item *item);
bool add_group_to_list(THD *thd, Item *item, bool asc);
bool add_ftfunc_to_list(Item_func_match *func);
-
- TABLE_LIST* get_table_list();
- List<Item>* get_item_list();
- List<String>* get_use_index();
- List<String>* get_ignore_index();
- ulong get_table_join_options();
+ bool add_order_to_list(THD *thd, Item *item, bool asc);
TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_options,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0);
+
+ TABLE_LIST* get_table_list();
+ List<Item>* get_item_list();
+ List<String>* get_use_index();
+ List<String>* get_ignore_index();
+ ulong get_table_join_options();
void set_lock_for_tables(thr_lock_type lock_type);
inline void init_order()
{
@@ -436,15 +440,14 @@ public:
order_list.next= (byte**) &order_list.first;
}
+ bool test_limit();
+
friend void mysql_init_query(THD *thd);
- st_select_lex(struct st_lex *lex);
st_select_lex() {}
- void make_empty_select(st_select_lex *last_select)
+ void make_empty_select()
{
- select_number=INT_MAX;
init_query();
init_select();
- include_neighbour(last_select);
}
};
typedef class st_select_lex SELECT_LEX;
@@ -459,7 +462,7 @@ typedef struct st_lex
SELECT_LEX_UNIT unit; /* most upper unit */
SELECT_LEX select_lex; /* first SELECT_LEX */
/* current SELECT_LEX in parsing */
- SELECT_LEX_NODE *current_select;
+ SELECT_LEX *current_select;
/* list of all SELECT_LEX */
SELECT_LEX *all_selects_list;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
@@ -531,7 +534,7 @@ typedef struct st_lex
but we should merk all subselects as uncacheable from current till
most upper
*/
- SELECT_LEX_NODE *sl;
+ SELECT_LEX *sl;
SELECT_LEX_UNIT *un;
for (sl= current_select, un= sl->master_unit();
un != &unit;
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index a5f164e1e38..ef7bf013be8 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -150,7 +150,8 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
{
if (cursor->do_redirect)
{
- cursor->table= ((TABLE_LIST*) cursor->table)->table;
+ //Sinisa TODO: there are function for this purpose: fix_tables_pointers
+ cursor->table= cursor->table_list->table;
cursor->do_redirect= 0;
}
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 5880a9d4c8a..f0eba167b90 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3490,10 +3490,10 @@ mysql_init_query(THD *thd)
lex->select_lex.init_query();
lex->value_list.empty();
lex->param_list.empty();
- lex->unit.next= lex->unit.master= lex->unit.return_to=
- lex->unit.link_next= 0;
+ lex->unit.next= lex->unit.master=
+ lex->unit.link_next= lex->unit.return_to=0;
lex->unit.prev= lex->unit.link_prev= 0;
- lex->unit.global_parameters= lex->unit.slave= lex->current_select=
+ lex->unit.slave= lex->unit.global_parameters= lex->current_select=
lex->all_selects_list= &lex->select_lex;
lex->select_lex.master= &lex->unit;
lex->select_lex.prev= &lex->unit.slave;
@@ -3522,10 +3522,9 @@ mysql_init_query(THD *thd)
void
mysql_init_select(LEX *lex)
{
- SELECT_LEX *select_lex= lex->current_select->select_lex();
+ SELECT_LEX *select_lex= lex->current_select;
select_lex->init_select();
- select_lex->master_unit()->select_limit= select_lex->select_limit=
- lex->thd->variables.select_limit;
+ select_lex->select_limit= lex->thd->variables.select_limit;
if (select_lex == &lex->select_lex)
{
lex->exchange= 0;
@@ -3553,10 +3552,7 @@ mysql_new_select(LEX *lex, bool move_down)
unit->init_query();
unit->init_select();
unit->thd= lex->thd;
- if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
- unit->include_neighbour(lex->current_select);
- else
- unit->include_down(lex->current_select);
+ unit->include_down(lex->current_select);
unit->link_next= 0;
unit->link_prev= 0;
unit->return_to= lex->current_select;
@@ -3564,7 +3560,25 @@ mysql_new_select(LEX *lex, bool move_down)
// TODO: assign resolve_mode for fake subquery after merging with new tree
}
else
+ {
select_lex->include_neighbour(lex->current_select);
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ SELECT_LEX *fake= unit->fake_select_lex;
+ if (!fake)
+ {
+ /*
+ as far as we included SELECT_LEX for UNION unit should have
+ fake SELECT_LEX for UNION processing
+ */
+ fake= unit->fake_select_lex= new SELECT_LEX();
+ fake->include_standalone(unit,
+ (SELECT_LEX_NODE**)&unit->fake_select_lex);
+ fake->select_number= INT_MAX;
+ fake->make_empty_select();
+ fake->linkage= GLOBAL_OPTIONS_TYPE;
+ fake->select_limit= lex->thd->variables.select_limit;
+ }
+ }
select_lex->master_unit()->global_parameters= select_lex;
select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 71c0d0bdddc..6c92f1f5dcf 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -206,7 +206,8 @@ void relink_tables(SELECT_LEX *select_lex)
for (TABLE_LIST *cursor= (TABLE_LIST *) select_lex->table_list.first;
cursor;
cursor=cursor->next)
- cursor->table= cursor->table_list->table;
+ if (cursor->table_list)
+ cursor->table= cursor->table_list->table;
}
@@ -320,6 +321,19 @@ JOIN::prepare(Item ***rref_pointer_array,
having->split_sum_func(ref_pointer_array, all_fields);
}
+ // Is it subselect
+ {
+ Item_subselect *subselect;
+ if ((subselect= select_lex->master_unit()->item) &&
+ select_lex->linkage != GLOBAL_OPTIONS_TYPE)
+ {
+ Item_subselect::trans_res res;
+ if ((res= subselect->select_transformer(this)) !=
+ Item_subselect::OK)
+ DBUG_RETURN((res == Item_subselect::ERROR));
+ }
+ }
+
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
@@ -1386,12 +1400,24 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
JOIN *join;
if (select_lex->join != 0)
{
- //here is EXPLAIN of subselect or derived table
join= select_lex->join;
- join->result= result;
- if (!join->procedure && result->prepare(join->fields_list, unit))
+ if (select_lex->linkage != GLOBAL_OPTIONS_TYPE)
{
- DBUG_RETURN(-1);
+ //here is EXPLAIN of subselect or derived table
+ join->result= result;
+ if (!join->procedure && result->prepare(join->fields_list, unit))
+ {
+ DBUG_RETURN(-1);
+ }
+ }
+ else
+ {
+ if (join->prepare(rref_pointer_array, tables, wild_num,
+ conds, og_num, order, group, having, proc_param,
+ select_lex, unit, tables_and_fields_initied))
+ {
+ DBUG_RETURN(-1);
+ }
}
join->select_options= select_options;
free_join= 0;
@@ -1401,7 +1427,6 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
join= new JOIN(thd, fields, select_options, result);
thd->proc_info="init";
thd->used_tables=0; // Updated by setup_fields
-
if (join->prepare(rref_pointer_array, tables, wild_num,
conds, og_num, order, group, having, proc_param,
select_lex, unit, tables_and_fields_initied))
@@ -4297,6 +4322,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
default:
// This case should never be choosen
DBUG_ASSERT(0);
+ new_field= 0; // to satisfy compiler (uninitialized variable)
break;
}
if (copy_func && item->is_result_field())
@@ -5797,7 +5823,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
else
{
join->do_send_rows= 0;
- join->unit->select_limit= HA_POS_ERROR;
+ if (join->unit->fake_select_lex)
+ join->unit->fake_select_lex->select_limit= HA_POS_ERROR;
DBUG_RETURN(0);
}
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 76960876158..d84a3715707 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -192,45 +192,62 @@ class JOIN :public Sql_alloc
bool optimized; // flag to avoid double optimization in EXPLAIN
JOIN(THD *thd_arg, List<Item> &fields, ulong select_options_arg,
- select_result *result_arg):
- join_tab(0),
- table(0),
- tables(0), const_tables(0),
- sort_and_group(0), first_record(0),
- do_send_rows(1),
- send_records(0), found_records(0), examined_rows(0),
- exec_tmp_table1(0), exec_tmp_table2(0),
- thd(thd_arg),
- sum_funcs(0),sum_funcs2(0),
- procedure(0),
- having(0), tmp_having(0),
- select_options(select_options_arg),
- result(result_arg),
- lock(thd_arg->lock),
- select_lex(0), //for safety
- tmp_join(0),
- select_distinct(test(select_options & SELECT_DISTINCT)),
- no_order(0), simple_order(0), simple_group(0), skip_sort_order(0),
- need_tmp(0),
- hidden_group_fields (0), /*safety*/
- buffer_result(test(select_options & OPTION_BUFFER_RESULT) &&
- !test(select_options & OPTION_FOUND_ROWS)),
- all_fields(fields),
- fields_list(fields),
- error(0),
- select(0),
- ref_pointer_array(0), items0(0), items1(0), items2(0), items3(0),
- ref_pointer_array_size(0),
- zero_result_cause(0),
- optimized(0)
+ select_result *result_arg)
+ :fields_list(fields)
{
+ init(thd_arg, fields, select_options_arg, result_arg);
+ }
+
+ void init(THD *thd_arg, List<Item> &fields, ulong select_options_arg,
+ select_result *result_arg)
+ {
+ join_tab= 0;
+ table= 0;
+ tables= 0;
+ const_tables= 0;
+ sort_and_group= 0;
+ first_record= 0;
+ do_send_rows= 1;
+ send_records= 0;
+ found_records= 0;
+ examined_rows= 0;
+ exec_tmp_table1= 0;
+ exec_tmp_table2= 0;
+ thd= thd_arg;
+ sum_funcs= sum_funcs2= 0;
+ procedure= 0;
+ having= 0;
+ tmp_having= 0;
+ select_options= select_options_arg;
+ result= result_arg;
+ lock= thd_arg->lock;
+ select_lex= 0; //for safety
+ tmp_join= 0;
+ select_distinct= test(select_options & SELECT_DISTINCT);
+ no_order= 0;
+ simple_order= 0;
+ simple_group= 0;
+ skip_sort_order= 0;
+ need_tmp= 0;
+ hidden_group_fields= 0; /*safety*/
+ buffer_result= test(select_options & OPTION_BUFFER_RESULT) &&
+ !test(select_options & OPTION_FOUND_ROWS);
+ all_fields= fields;
+ fields_list= fields;
+ error= 0;
+ select= 0;
+ ref_pointer_array= items0= items1= items2= items3= 0;
+ ref_pointer_array_size= 0;
+ zero_result_cause= 0;
+ optimized= 0;
+
fields_list = fields;
bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.copy_field=0;
tmp_table_param.end_write_records= HA_POS_ERROR;
rollup.state= ROLLUP::STATE_NONE;
}
-
+
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, SELECT_LEX *select,
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 57044a8370a..0d50348f199 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -115,7 +115,7 @@ bool select_union::flush()
int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
bool tables_and_fields_initied)
{
- SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
+ SELECT_LEX *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor;
DBUG_ENTER("st_select_lex_unit::prepare");
@@ -193,42 +193,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
union_result->not_describe=1;
union_result->tmp_table_param=tmp_table_param;
- /*
- The following piece of code is placed here solely for the purpose of
- getting correct results with EXPLAIN when UNION is withing a sub-select
- or derived table ...
- */
-
- if (thd->lex.describe)
+ for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
- for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
- {
- JOIN *join= new JOIN(thd, sl->item_list,
- sl->options | thd->options | SELECT_NO_UNLOCK,
- union_result);
- thd->lex.current_select= sl;
- offset_limit_cnt= sl->offset_limit;
- select_limit_cnt= sl->select_limit+sl->offset_limit;
- if (select_limit_cnt < sl->select_limit)
- select_limit_cnt= HA_POS_ERROR; // no limit
- if (select_limit_cnt == HA_POS_ERROR)
- sl->options&= ~OPTION_FOUND_ROWS;
-
- res= join->prepare(&sl->ref_pointer_array,
- (TABLE_LIST*) sl->table_list.first, sl->with_wild,
- sl->where,
- ((sl->braces) ? sl->order_list.elements : 0) +
- sl->group_list.elements,
- (sl->braces) ?
- (ORDER *)sl->order_list.first : (ORDER *) 0,
- (ORDER*) sl->group_list.first,
- sl->having,
- (ORDER*) NULL,
- sl, this, t_and_f);
- t_and_f= 0;
- if (res || thd->is_fatal_error)
- goto err;
- }
+ JOIN *join= new JOIN(thd, sl->item_list,
+ sl->options | thd->options | SELECT_NO_UNLOCK,
+ union_result);
+ thd->lex.current_select= sl;
+ offset_limit_cnt= sl->offset_limit;
+ select_limit_cnt= sl->select_limit+sl->offset_limit;
+ if (select_limit_cnt < sl->select_limit)
+ select_limit_cnt= HA_POS_ERROR; // no limit
+ if (select_limit_cnt == HA_POS_ERROR)
+ sl->options&= ~OPTION_FOUND_ROWS;
+
+ res= join->prepare(&sl->ref_pointer_array,
+ (TABLE_LIST*) sl->table_list.first, sl->with_wild,
+ sl->where,
+ ((sl->braces) ? sl->order_list.elements : 0) +
+ sl->group_list.elements,
+ (sl->braces) ?
+ (ORDER *)sl->order_list.first : (ORDER *) 0,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (ORDER*) NULL,
+ sl, this, t_and_f);
+ t_and_f= 0;
+ if (res || thd->is_fatal_error)
+ goto err;
}
item_list.empty();
@@ -254,7 +245,7 @@ err:
int st_select_lex_unit::exec()
{
- SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
+ SELECT_LEX *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor=first_select_in_union();
DBUG_ENTER("st_select_lex_unit::exec");
@@ -272,14 +263,12 @@ int st_select_lex_unit::exec()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
+ thd->lex.current_select= sl;
+
if (optimized)
res= sl->join->reinit();
else
{
- JOIN *join= new JOIN(thd, sl->item_list,
- sl->options | thd->options | SELECT_NO_UNLOCK,
- union_result);
- thd->lex.current_select= sl;
offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit)
@@ -287,22 +276,27 @@ int st_select_lex_unit::exec()
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
- res= join->prepare(&sl->ref_pointer_array,
- (TABLE_LIST*) sl->table_list.first, sl->with_wild,
- sl->where,
- ((sl->braces) ? sl->order_list.elements : 0) +
- sl->group_list.elements,
- (sl->braces) ?
- (ORDER *)sl->order_list.first : (ORDER *) 0,
- (ORDER*) sl->group_list.first,
- sl->having,
- (ORDER*) NULL,
- sl, this, t_and_f);
- t_and_f=0;
- if (res | thd->is_fatal_error)
+ /*
+ As far as union share table space we should reassign table map,
+ which can be spoiled by 'prepare' of JOIN of other UNION parts
+ if it use same tables
+ */
+ uint tablenr=0;
+ for (TABLE_LIST *table_list= (TABLE_LIST*) sl->table_list.first;
+ table_list;
+ table_list= table_list->next, tablenr++)
{
- thd->lex.current_select= lex_select_save;
- DBUG_RETURN(res);
+ if (table_list->shared)
+ {
+ /*
+ review notes: Check it carefully. I still can't understand
+ why I should not touch table->used_keys. For my point of
+ view we should do here same procedura as it was done by
+ setup_table
+ */
+ DBUG_PRINT("SUBS", ("shared %s", table_list->real_name));
+ setup_table_map(table_list->table, table_list, tablenr);
+ }
}
res= sl->join->optimize();
}
@@ -327,8 +321,7 @@ int st_select_lex_unit::exec()
/* Send result to 'result' */
- // to correct ORDER BY reference resolving
- thd->lex.current_select= select_cursor;
+
res= -1;
{
List<Item_func_match> empty_list;
@@ -336,7 +329,7 @@ int st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
- SELECT_LEX *fake_select = new SELECT_LEX(&thd->lex);
+ thd->lex.current_select= fake_select_lex;
offset_limit_cnt= (select_cursor->braces ?
global_parameters->offset_limit : 0);
select_limit_cnt= (select_cursor->braces ?
@@ -346,19 +339,38 @@ int st_select_lex_unit::exec()
select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt == HA_POS_ERROR)
thd->options&= ~OPTION_FOUND_ROWS;
- fake_select->ftfunc_list= &empty_list;
- fake_select->table_list.link_in_list((byte *)&result_table_list,
- (byte **)&result_table_list.next);
- res= mysql_select(thd, &ref_pointer_array, &result_table_list,
+ fake_select_lex->ftfunc_list= &empty_list;
+ fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
+ (byte **)
+ &result_table_list.next);
+ JOIN *join= fake_select_lex->join;
+ if (!join)
+ {
+ /*
+ allocate JOIN for fake select only once (privent
+ mysql_select automatic allocation)
+ */
+ fake_select_lex->join= new JOIN(thd, item_list, thd->options, result);
+ }
+ else
+ {
+ JOIN_TAB *tab,*end;
+ for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ {
+ delete tab->select;
+ delete tab->quick;
+ }
+ join->init(thd, item_list, thd->options, result);
+ }
+ res= mysql_select(thd, &fake_select_lex->ref_pointer_array,
+ &result_table_list,
0, item_list, NULL,
global_parameters->order_list.elements,
(ORDER*)global_parameters->order_list.first,
(ORDER*) NULL, NULL, (ORDER*) NULL,
- thd->options, result, this, fake_select, 0);
+ thd->options, result, this, fake_select_lex, 0);
if (found_rows_for_union && !res)
thd->limit_found_rows = (ulonglong)table->file->records;
- fake_select->exclude();
- delete fake_select;
/*
Mark for slow query log if any of the union parts didn't use
indexes efficiently
@@ -382,14 +394,21 @@ int st_select_lex_unit::cleanup()
free_tmp_table(thd, table);
table= 0; // Safety
}
+ JOIN *join;
for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
{
- JOIN *join;
if ((join= sl->join))
{
error|= sl->join->cleanup();
delete join;
}
}
+ if (fake_select_lex && (join= fake_select_lex->join))
+ {
+ join->tables_list= 0;
+ join->tables= 0;
+ error|= join->cleanup();
+ delete join;
+ }
DBUG_RETURN(error);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index aef58e6cb94..5af02a7b2ba 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1847,7 +1847,7 @@ table_to_table:
table_ident TO_SYM table_ident
{
LEX *lex=Lex;
- SELECT_LEX_NODE *sl= lex->current_select;
+ SELECT_LEX *sl= lex->current_select;
if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING,
TL_IGNORE) ||
!sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
@@ -1883,7 +1883,7 @@ preload_keys:
;
preload_keys_spec:
- keys_or_index { Select->select_lex()->interval_list.empty(); }
+ keys_or_index { Select->interval_list.empty(); }
preload_key_list_or_empty
{
LEX *lex=Lex;
@@ -1924,7 +1924,7 @@ select_init:
'(' SELECT_SYM select_part2 ')'
{
LEX *lex= Lex;
- SELECT_LEX * sel= lex->current_select->select_lex();
+ SELECT_LEX * sel= lex->current_select;
if (sel->set_braces(1))
{
send_error(lex->thd, ER_SYNTAX_ERROR);
@@ -1938,14 +1938,14 @@ select_init:
}
/* select in braces, can't contain global parameters */
sel->master_unit()->global_parameters=
- sel->master_unit();
+ sel->master_unit()->fake_select_lex;
} union_opt;
select_init2:
select_part2
{
LEX *lex= Lex;
- SELECT_LEX * sel= lex->current_select->select_lex();
+ SELECT_LEX * sel= lex->current_select;
if (lex->current_select->set_braces(0))
{
send_error(lex->thd, ER_SYNTAX_ERROR);
@@ -1964,7 +1964,7 @@ select_init2:
select_part2:
{
LEX *lex=Lex;
- SELECT_LEX * sel= lex->current_select->select_lex();
+ SELECT_LEX * sel= lex->current_select;
if (lex->current_select == &lex->select_lex)
lex->lock_option= TL_READ; /* Only for global SELECT */
if (sel->linkage != UNION_TYPE)
@@ -2055,7 +2055,7 @@ select_item_list:
THD *thd= YYTHD;
if (add_item_to_list(thd, new Item_field(NULL, NULL, "*")))
YYABORT;
- (thd->lex.current_select->select_lex()->with_wild)++;
+ (thd->lex.current_select->with_wild)++;
};
@@ -2706,9 +2706,9 @@ sum_expr:
| COUNT_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_count($3); }
| COUNT_SYM '(' DISTINCT
- { Select->select_lex()->in_sum_expr++; }
+ { Select->in_sum_expr++; }
expr_list
- { Select->select_lex()->in_sum_expr--; }
+ { Select->in_sum_expr--; }
')'
{ $$=new Item_sum_count_distinct(* $5); }
| GROUP_UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' in_sum_expr ')'
@@ -2764,7 +2764,7 @@ in_sum_expr:
}
expr
{
- Select->select_lex()->in_sum_expr--;
+ Select->in_sum_expr--;
$$= $3;
};
@@ -2818,13 +2818,13 @@ when_list:
when_list2:
expr THEN_SYM expr
{
- SELECT_LEX_NODE *sel=Select;
+ SELECT_LEX *sel=Select;
sel->when_list.head()->push_back($1);
sel->when_list.head()->push_back($3);
}
| when_list2 WHEN_SYM expr THEN_SYM expr
{
- SELECT_LEX_NODE *sel=Select;
+ SELECT_LEX *sel=Select;
sel->when_list.head()->push_back($3);
sel->when_list.head()->push_back($5);
};
@@ -2841,7 +2841,7 @@ join_table_list:
| join_table_list normal_join join_table_list
USING
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$3->db; sel->table2=$3->alias;
}
@@ -2852,7 +2852,7 @@ join_table_list:
{ add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| join_table_list LEFT opt_outer JOIN_SYM join_table_list
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$5->db; sel->table2=$5->alias;
}
@@ -2868,7 +2868,7 @@ join_table_list:
{ add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; }
| join_table_list RIGHT opt_outer JOIN_SYM join_table_list
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$5->db; sel->table2=$5->alias;
}
@@ -2891,14 +2891,14 @@ normal_join:
join_table:
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->use_index_ptr=sel->ignore_index_ptr=0;
sel->table_join_options= 0;
}
table_ident opt_table_alias opt_key_definition
{
LEX *lex= Lex;
- SELECT_LEX_NODE *sel= lex->current_select;
+ SELECT_LEX *sel= lex->current_select;
if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
sel->get_table_join_options(),
lex->lock_option,
@@ -2948,28 +2948,28 @@ opt_key_definition:
/* empty */ {}
| USE_SYM key_usage_list
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
}
| FORCE_SYM key_usage_list
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
sel->table_join_options|= TL_OPTION_FORCE_INDEX;
}
| IGNORE_SYM key_usage_list
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->ignore_index= *$2;
sel->ignore_index_ptr= &sel->ignore_index;
};
key_usage_list:
- key_or_index { Select->select_lex()->interval_list.empty(); }
+ key_or_index { Select->interval_list.empty(); }
'(' key_list_or_empty ')'
- { $$= &Select->select_lex()->interval_list; }
+ { $$= &Select->interval_list; }
;
key_list_or_empty:
@@ -2979,22 +2979,22 @@ key_list_or_empty:
key_usage_list2:
key_usage_list2 ',' ident
- { Select->select_lex()->
+ { Select->
interval_list.push_back(new String((const char*) $3.str, $3.length,
system_charset_info)); }
| ident
- { Select->select_lex()->
+ { Select->
interval_list.push_back(new String((const char*) $1.str, $1.length,
system_charset_info)); }
| PRIMARY_SYM
- { Select->select_lex()->
+ { Select->
interval_list.push_back(new String("PRIMARY", 7,
system_charset_info)); };
using_list:
ident
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1,
$1.str),
new Item_field(sel->db2, sel->table2,
@@ -3003,7 +3003,7 @@ using_list:
}
| using_list ',' ident
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1)))
YYABORT;
};
@@ -3044,10 +3044,10 @@ opt_all:
;
where_clause:
- /* empty */ { Select->select_lex()->where= 0; }
+ /* empty */ { Select->where= 0; }
| WHERE expr
{
- Select->select_lex()->where= $2;
+ Select->where= $2;
if ($2)
$2->top_level_item();
}
@@ -3057,11 +3057,11 @@ having_clause:
/* empty */
| HAVING
{
- Select->select_lex()->parsing_place= SELECT_LEX_NODE::IN_HAVING;
+ Select->parsing_place= SELECT_LEX_NODE::IN_HAVING;
}
expr
{
- SELECT_LEX *sel= Select->select_lex();
+ SELECT_LEX *sel= Select;
sel->having= $3;
sel->parsing_place= SELECT_LEX_NODE::NO_MATTER;
if ($3)
@@ -3099,7 +3099,7 @@ olap_opt:
"global union parameters");
YYABORT;
}
- lex->current_select->select_lex()->olap= CUBE_TYPE;
+ lex->current_select->olap= CUBE_TYPE;
net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE");
YYABORT; /* To be deleted in 5.1 */
}
@@ -3112,7 +3112,7 @@ olap_opt:
"global union parameters");
YYABORT;
}
- lex->current_select->select_lex()->olap= ROLLUP_TYPE;
+ lex->current_select->olap= ROLLUP_TYPE;
}
;
@@ -3129,7 +3129,7 @@ order_clause:
{
LEX *lex=Lex;
if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- lex->current_select->select_lex()->olap !=
+ lex->current_select->olap !=
UNSPECIFIED_OLAP_TYPE)
{
net_printf(lex->thd, ER_WRONG_USAGE,
@@ -3154,7 +3154,7 @@ order_dir:
opt_limit_clause_init:
/* empty */
{
- SELECT_LEX_NODE *sel= Select;
+ SELECT_LEX *sel= Select;
sel->offset_limit= 0L;
sel->select_limit= Lex->thd->variables.select_limit;
}
@@ -3173,19 +3173,19 @@ limit_clause:
limit_options:
ULONG_NUM
{
- SELECT_LEX_NODE *sel= Select;
+ SELECT_LEX *sel= Select;
sel->select_limit= $1;
sel->offset_limit= 0L;
}
| ULONG_NUM ',' ULONG_NUM
{
- SELECT_LEX_NODE *sel= Select;
+ SELECT_LEX *sel= Select;
sel->select_limit= $3;
sel->offset_limit= $1;
}
| ULONG_NUM OFFSET_SYM ULONG_NUM
{
- SELECT_LEX_NODE *sel= Select;
+ SELECT_LEX *sel= Select;
sel->select_limit= $1;
sel->offset_limit= $3;
}
@@ -4165,14 +4165,14 @@ table_wild:
ident '.' '*'
{
$$ = new Item_field(NullS,$1.str,"*");
- Lex->current_select->select_lex()->with_wild++;
+ Lex->current_select->with_wild++;
}
| ident '.' ident '.' '*'
{
$$ = new Item_field((YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str,"*");
- Lex->current_select->select_lex()->with_wild++;
+ Lex->current_select->with_wild++;
}
;
@@ -4182,7 +4182,7 @@ order_ident:
simple_ident:
ident
{
- SELECT_LEX_NODE *sel=Select;
+ SELECT_LEX *sel=Select;
$$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
sel->get_in_sum_expr() > 0) ?
(Item*) new Item_field(NullS,NullS,$1.str) :
@@ -4192,7 +4192,7 @@ simple_ident:
{
THD *thd= YYTHD;
LEX *lex= &thd->lex;
- SELECT_LEX_NODE *sel= lex->current_select;
+ SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
@@ -4208,7 +4208,7 @@ simple_ident:
{
THD *thd= YYTHD;
LEX *lex= &thd->lex;
- SELECT_LEX_NODE *sel= lex->current_select;
+ SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
@@ -4224,7 +4224,7 @@ simple_ident:
{
THD *thd= YYTHD;
LEX *lex= &thd->lex;
- SELECT_LEX_NODE *sel= lex->current_select;
+ SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
@@ -4928,7 +4928,7 @@ opt_table:
'*'
{
LEX *lex= Lex;
- lex->current_select->select_lex()->db= lex->thd->db;
+ lex->current_select->db= lex->thd->db;
if (lex->grant == GLOBAL_ACLS)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
@@ -4940,7 +4940,7 @@ opt_table:
| ident '.' '*'
{
LEX *lex= Lex;
- lex->current_select->select_lex()->db = $1.str;
+ lex->current_select->db = $1.str;
if (lex->grant == GLOBAL_ACLS)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
@@ -4952,7 +4952,7 @@ opt_table:
| '*' '.' '*'
{
LEX *lex= Lex;
- lex->current_select->select_lex()->db = NULL;
+ lex->current_select->db = NULL;
if (lex->grant == GLOBAL_ACLS)
lex->grant= GLOBAL_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
@@ -5147,11 +5147,12 @@ optional_order_or_limit:
THD *thd= YYTHD;
LEX *lex= &thd->lex;
DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
- SELECT_LEX *sel= lex->current_select->select_lex();
+ SELECT_LEX *sel= lex->current_select;
SELECT_LEX_UNIT *unit= sel->master_unit();
- unit->global_parameters= unit;
- unit->no_table_names_allowed= 1;
- lex->current_select= unit;
+ SELECT_LEX *fake= unit->fake_select_lex;
+ unit->global_parameters= fake;
+ fake->no_table_names_allowed= 1;
+ lex->current_select= fake;
thd->where= "global ORDER clause";
}
order_or_limit
@@ -5219,7 +5220,9 @@ subselect_start:
{
LEX *lex=Lex;
if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
- lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) {
+ lex->sql_command <= (int)SQLCOM_HA_READ) ||
+ lex->sql_command == (int)SQLCOM_KILL)
+ {
send_error(lex->thd, ER_SYNTAX_ERROR);
YYABORT;
}
diff --git a/sql/table.h b/sql/table.h
index 2fab0087da4..fce2d97e393 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -165,15 +165,8 @@ typedef struct st_table_list
struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */
List<String> *use_index, *ignore_index;
- /*
- Usually hold reference on opened table, but may hold reference
- to node of complete list of tables used in UNION & subselect.
- */
- union
- {
- TABLE *table; /* opened table */
- st_table_list *table_list; /* pointer to node of list of all tables */
- };
+ TABLE *table; /* opened table */
+ st_table_list *table_list; /* pointer to node of list of all tables */
class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
GRANT_INFO grant;
thr_lock_type lock_type;