Commit 356cbe4f authored by igor@rurik.mysql.com's avatar igor@rurik.mysql.com

join_nested.test, join_nested.result:

  new file
Many files:
  Nested joins added.
parent f9e2c6cd
This diff is collapsed.
......@@ -356,13 +356,7 @@ select t1.name, t2.name, t2.id, t2.owner, t3.id from t1 left join t2 on (t1.id =
name name id owner id
Antonio Paz El Gato 1 1 1
Antonio Paz Perrito 2 1 1
Lilliana Angelovska NULL NULL NULL 1
Thimble Smith NULL NULL NULL 1
Antonio Paz NULL NULL NULL 2
Lilliana Angelovska NULL NULL NULL 2
Thimble Smith NULL NULL NULL 2
Antonio Paz NULL NULL NULL 3
Lilliana Angelovska NULL NULL NULL 3
NULL NULL NULL NULL 2
Thimble Smith Happy 3 3 3
drop table t1,t2;
create table t1 (id int not null, str char(10), index(str));
......
......@@ -2157,13 +2157,10 @@ a a a
3 3 3
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
a a a
1 1 NULL
2 1 1
3 1 1
1 2 NULL
2 2 2
3 2 2
1 3 NULL
2 3 3
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) inner join t1 using ( a );
......@@ -2174,13 +2171,7 @@ a a a
select * from t1 inner join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
1 1 1
2 1 NULL
3 1 NULL
1 2 NULL
2 2 2
3 2 NULL
1 3 NULL
2 3 NULL
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) left outer join t1 on t1.a>1;
a a a
......@@ -2192,14 +2183,12 @@ a a a
3 3 3
select * from t1 left outer join (t1 as t2 left join t1 as t3 using (a)) on t1.a>1;
a a a
1 1 NULL
1 NULL NULL
2 1 1
3 1 1
1 2 NULL
2 2 2
3 2 2
1 3 NULL
2 3 3
3 1 1
3 2 2
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) left join t1 using ( a );
a a a
......@@ -2209,13 +2198,7 @@ a a a
select * from t1 left join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
1 1 1
2 1 NULL
3 1 NULL
1 2 NULL
2 2 2
3 2 NULL
1 3 NULL
2 3 NULL
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) natural left join t1;
a a a
......@@ -2229,9 +2212,7 @@ a a a
3 3 3
select * from (t1 as t2 left join t1 as t3 using (a)) right join t1 on t1.a>1;
a a a
1 NULL 1
2 NULL 1
3 NULL 1
NULL NULL 1
1 1 2
2 2 2
3 3 2
......@@ -2249,13 +2230,7 @@ a a a
select * from (t1 as t2 left join t1 as t3 using (a)) right outer join t1 using ( a );
a a a
1 1 1
2 NULL 1
3 NULL 1
1 NULL 2
2 2 2
3 NULL 2
1 NULL 3
2 NULL 3
3 3 3
select * from t1 right outer join (t1 as t2 left join t1 as t3 using (a)) using ( a );
a a a
......@@ -2265,13 +2240,7 @@ a a a
select * from (t1 as t2 left join t1 as t3 using (a)) natural right join t1;
a a a
1 1 1
2 NULL 1
3 NULL 1
1 NULL 2
2 2 2
3 NULL 2
1 NULL 3
2 NULL 3
3 3 3
select * from t1 natural right join (t1 as t2 left join t1 as t3 using (a));
a a a
......
This diff is collapsed.
......@@ -214,6 +214,40 @@ class Item_func_not :public Item_bool_func
Item *neg_transformer();
};
/*
The class Item_func_trig_cond is used for guarded predicates
which are employed only for internal purposes.
A guarded predicates is an object consisting of an a regular or
a guarded predicate P and a pointer to a boolean guard variable g.
A guarded predicate P/g is evaluated to true if the value of the
guard g is false, otherwise it is evaluated to the same value that
the predicate P: val(P/g)= g ? val(P):true.
Guarded predicates allow us to include predicates into a conjunction
conditionally. Currently they are utilized for pushed down predicates
in queries with outer join operations.
In the future, probably, it makes sense to extend this class to
the objects consisting of three elements: a predicate P, a pointer
to a variable g and a firing value s with following evaluation
rule: val(P/g,s)= g==s? val(P) : true. It will allow us to build only
one item for the objects of the form P/g1/g2...
Objects of this class are built only for query execution after
the execution plan has been already selected. That's why this
class needs only val_int out of generic methods.
*/
class Item_func_trig_cond: public Item_bool_func
{
bool *trig_var;
public:
Item_func_trig_cond(Item *a, bool *f) : Item_bool_func(a) { trig_var= f; }
longlong val_int() { return *trig_var ? args[0]->val_int() : 1; }
enum Functype functype() const { return TRIG_COND_FUNC; };
const char *func_name() const { return "trigcond"; };
};
class Item_func_not_all :public Item_func_not
{
bool abort_on_null;
......@@ -793,7 +827,7 @@ class Item_func_isnotnull :public Item_bool_func
}
const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
table_map not_null_tables() const { return 0; }
table_map not_null_tables() const { return used_tables(); }
Item *neg_transformer();
void print(String *str);
};
......
......@@ -47,7 +47,7 @@ class Item_func :public Item_result_field
SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN,
NOT_FUNC, NOT_ALL_FUNC,
NOT_FUNC, NOT_ALL_FUNC, TRIG_COND_FUNC,
GUSERVAR_FUNC};
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
enum Type type() const { return FUNC_ITEM; }
......
......@@ -2204,80 +2204,110 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
thd->where="where clause";
if ((*conds)->fix_fields(thd, tables, conds) || (*conds)->check_cols(1))
DBUG_RETURN(1);
not_null_tables= (*conds)->not_null_tables();
}
/* Check if we are using outer joins */
for (TABLE_LIST *table=tables ; table ; table=table->next)
{
if (table->on_expr)
{
/* Make a join an a expression */
thd->where="on clause";
if (table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
table->on_expr->check_cols(1))
DBUG_RETURN(1);
thd->lex->current_select->cond_count++;
/*
If it's a normal join or a LEFT JOIN which can be optimized away
add the ON/USING expression to the WHERE
*/
if (!table->outer_join ||
((table->table->map & not_null_tables) &&
!(specialflag & SPECIAL_NO_NEW_FUNC)))
TABLE_LIST *embedded;
TABLE_LIST *embedding= table;
do
{
embedded= embedding;
if (embedded->on_expr)
{
table->outer_join= 0;
if (!(*conds=and_conds(*conds, table->on_expr)))
/* Make a join an a expression */
thd->where="on clause";
if (embedded->on_expr->fix_fields(thd, tables, &embedded->on_expr) ||
embedded->on_expr->check_cols(1))
DBUG_RETURN(1);
table->on_expr=0;
thd->lex->current_select->cond_count++;
}
}
if (table->natural_join)
{
/* Make a join of all fields with have the same name */
TABLE *t1=table->table;
TABLE *t2=table->natural_join->table;
Item_cond_and *cond_and=new Item_cond_and();
if (!cond_and) // If not out of memory
DBUG_RETURN(1);
cond_and->top_level_item();
uint i,j;
for (i=0 ; i < t1->fields ; i++)
if (embedded->natural_join)
{
// TODO: This could be optimized to use hashed names if t2 had a hash
for (j=0 ; j < t2->fields ; j++)
{
if (!my_strcasecmp(system_charset_info,
t1->field[i]->field_name,
t2->field[j]->field_name))
/* Make a join of all fields with have the same name */
TABLE_LIST *tab1= embedded;
TABLE_LIST *tab2= embedded->natural_join;
if (!(embedded->outer_join & JOIN_TYPE_RIGHT))
{
while (tab1->nested_join)
{
TABLE_LIST *next;
List_iterator_fast<TABLE_LIST> it(tab1->nested_join->join_list);
tab1= it++;
while ((next= it++))
tab1= next;
}
}
else
{
while (tab1->nested_join)
tab1= tab1->nested_join->join_list.head();
}
if (embedded->outer_join & JOIN_TYPE_RIGHT)
{
while (tab2->nested_join)
{
TABLE_LIST *next;
List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
tab2= it++;
while ((next= it++))
tab2= next;
}
}
else
{
while (tab2->nested_join)
tab2= tab2->nested_join->join_list.head();
}
TABLE *t1=tab1->table;
TABLE *t2=tab2->table;
Item_cond_and *cond_and=new Item_cond_and();
if (!cond_and) // If not out of memory
DBUG_RETURN(1);
cond_and->top_level_item();
uint i,j;
for (i=0 ; i < t1->fields ; i++)
{
// TODO: This could be optimized to use hashed names if t2 had a hash
for (j=0 ; j < t2->fields ; j++)
{
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
new Item_field(t2->field[j]));
if (!tmp)
DBUG_RETURN(1);
tmp->fix_length_and_dec(); // Update cmp_type
tmp->const_item_cache=0;
/* Mark field used for table cache */
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
cond_and->list.push_back(tmp);
t1->used_keys.intersect(t1->field[i]->part_of_key);
t2->used_keys.intersect(t2->field[j]->part_of_key);
break;
if (!my_strcasecmp(system_charset_info,
t1->field[i]->field_name,
t2->field[j]->field_name))
{
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
new Item_field(t2->field[j]));
if (!tmp)
DBUG_RETURN(1);
tmp->fix_length_and_dec(); // Update cmp_type
tmp->const_item_cache=0;
/* Mark field used for table cache */
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
cond_and->list.push_back(tmp);
t1->used_keys.intersect(t1->field[i]->part_of_key);
t2->used_keys.intersect(t2->field[j]->part_of_key);
break;
}
}
}
}
cond_and->used_tables_cache= t1->map | t2->map;
thd->lex->current_select->cond_count+= cond_and->list.elements;
COND *on_expr= cond_and;
on_expr->fix_fields(thd, 0, &on_expr);
if (!embedded->outer_join) // Not left join
{
if (!(*conds=and_conds(*conds, on_expr)))
DBUG_RETURN(1);
}
else
embedded->on_expr=and_conds(embedded->on_expr,on_expr);
}
cond_and->used_tables_cache= t1->map | t2->map;
thd->lex->current_select->cond_count+= cond_and->list.elements;
if (!table->outer_join) // Not left join
{
if (!(*conds=and_conds(*conds, cond_and)))
DBUG_RETURN(1);
}
else
table->on_expr=and_conds(table->on_expr,cond_and);
embedding= embedded->embedding;
}
while (embedding &&
embedding->nested_join->join_list.head() == embedded);
}
DBUG_RETURN(test(thd->net.report_error));
}
......
......@@ -1014,6 +1014,9 @@ void st_select_lex::init_query()
{
st_select_lex_node::init_query();
table_list.empty();
top_join_list.empty();
join_list= &top_join_list;
embedding= 0;
item_list.empty();
join= 0;
where= 0;
......
......@@ -400,7 +400,10 @@ class st_select_lex: public st_select_lex_node
List<Item_func_match> *ftfunc_list;
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 */
List<TABLE_LIST> top_join_list; /* join list of the top level */
List<TABLE_LIST> *join_list; /* list for the currently parsed join */
TABLE_LIST *embedding; /* table embedding to the above list */
const char *type; /* type of select for EXPLAIN */
SQL_LIST order_list; /* ORDER clause */
List<List_item> expr_list;
......@@ -488,6 +491,12 @@ class st_select_lex: public st_select_lex_node
List<String> *ignore_index= 0,
LEX_STRING *option= 0);
TABLE_LIST* get_table_list();
bool init_nested_join(THD *thd);
TABLE_LIST *end_nested_join(THD *thd);
TABLE_LIST *nest_last_join(THD *thd);
void save_names_for_using_list(TABLE_LIST *tab1, TABLE_LIST *tab2);
void add_joined_table(TABLE_LIST *table);
TABLE_LIST *convert_right_join();
List<Item>* get_item_list();
List<String>* get_use_index();
List<String>* get_ignore_index();
......
......@@ -4686,6 +4686,238 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
}
/*
Initialize a new table list for a nested join
SYNOPSIS
init_table_list()
thd current thread
DESCRIPTION
The function initializes a structure of the TABLE_LIST type
for a nested join. It sets up its nested join list as empty.
The created structure is added to the front of the current
join list in the st_select_lex object. Then the function
changes the current nest level for joins to refer to the newly
created empty list after having saved the info on the old level
in the initialized structure.
RETURN VALUE
0, if success
1, otherwise
*/
bool st_select_lex::init_nested_join(THD *thd)
{
TABLE_LIST *ptr;
NESTED_JOIN *nested_join;
DBUG_ENTER("init_nested_join");
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
!(nested_join= ptr->nested_join=
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
DBUG_RETURN(1);
join_list->push_front(ptr);
ptr->embedding= embedding;
ptr->join_list= join_list;
embedding= ptr;
join_list= &nested_join->join_list;
join_list->empty();
nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
DBUG_RETURN(0);
}
/*
End a nested join table list
SYNOPSIS
end_nested_join()
thd current thread
DESCRIPTION
The function returns to the previous join nest level.
If the current level contains only one member, the function
moves it one level up, eliminating the nest.
RETURN VALUE
Pointer to TABLE_LIST element added to the total table list, if success
0, otherwise
*/
TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
{
TABLE_LIST *ptr;
DBUG_ENTER("end_nested_join");
ptr= embedding;
join_list= ptr->join_list;
embedding= ptr->embedding;
NESTED_JOIN *nested_join= ptr->nested_join;
if (nested_join->join_list.elements == 1)
{
TABLE_LIST *embedded= nested_join->join_list.head();
join_list->pop();
embedded->join_list= join_list;
embedded->embedding= embedding;
join_list->push_front(embedded);
ptr= embedded;
}
DBUG_RETURN(ptr);
}
/*
Nest last join operation
SYNOPSIS
nest_last_join()
thd current thread
DESCRIPTION
The function nest last join operation as if it was enclosed in braces.
RETURN VALUE
Pointer to TABLE_LIST element created for the new nested join, if success
0, otherwise
*/
TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
{
TABLE_LIST *ptr;
NESTED_JOIN *nested_join;
DBUG_ENTER("nest_last_join");
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
!(nested_join= ptr->nested_join=
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
DBUG_RETURN(0);
ptr->embedding= embedding;
ptr->join_list= join_list;
List<TABLE_LIST> *embedded_list= &nested_join->join_list;
embedded_list->empty();
for (int i=0; i < 2; i++)
{
TABLE_LIST *table= join_list->pop();
table->join_list= embedded_list;
table->embedding= ptr;
embedded_list->push_back(table);
}
join_list->push_front(ptr);
nested_join->used_tables= nested_join->not_null_tables= (table_map) 0;
DBUG_RETURN(ptr);
}
/*
Save names for a join with using clase
SYNOPSIS
save_names_for_using_list
tab1 left table in join
tab2 right table in join
DESCRIPTION
The function saves the full names of the tables in st_select_lex
to be able to build later an on expression to replace the using clause.
RETURN VALUE
None
*/
void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
TABLE_LIST *tab2)
{
while (tab1->nested_join)
{
tab1= tab1->nested_join->join_list.head();
}
db1= tab1->db;
table1= tab1->alias;
while (tab2->nested_join)
{
TABLE_LIST *next;
List_iterator_fast<TABLE_LIST> it(tab2->nested_join->join_list);
tab2= it++;
while ((next= it++))
tab2= next;
}
db2= tab2->db;
table2= tab2->alias;
}
/*
Add a table to the current join list
SYNOPSIS
add_joined_table()
table the table to add
DESCRIPTION
The function puts a table in front of the current join list
of st_select_lex object.
Thus, joined tables are put into this list in the reverse order
(the most outer join operation follows first).
RETURN VALUE
None
*/
void st_select_lex::add_joined_table(TABLE_LIST *table)
{
DBUG_ENTER("add_joined_table");
join_list->push_front(table);
table->join_list= join_list;
table->embedding= embedding;
DBUG_VOID_RETURN;
}
/*
Convert a right join into equivalent left join
SYNOPSIS
convert_right_join()
thd current thread
DESCRIPTION
The function takes the current join list t[0],t[1] ... and
effectively converts it into the list t[1],t[0] ...
Although the outer_join flag for the new nested table contains
JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
operation.
EXAMPLES
SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
SELECT * FROM t2 LEFT JOIN t1 ON on_expr
SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr
SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr
SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 =>
SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1
RETURN
Pointer to the table representing the inner table, if success
0, otherwise
*/
TABLE_LIST *st_select_lex::convert_right_join()
{
TABLE_LIST *tab2= join_list->pop();
TABLE_LIST *tab1= join_list->pop();
DBUG_ENTER("convert_right_join");
join_list->push_front(tab2);
join_list->push_front(tab1);
tab1->outer_join|= JOIN_TYPE_RIGHT;
DBUG_RETURN(tab1);
}
/*
Set lock for all tables in current select level
......
This diff is collapsed.
......@@ -73,7 +73,6 @@ typedef struct st_join_cache {
/*
** The structs which holds the join connections and join states
*/
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY, JT_INDEX_MERGE};
......@@ -86,7 +85,13 @@ typedef struct st_join_table {
SQL_SELECT *select;
COND *select_cond;
QUICK_SELECT_I *quick;
Item *on_expr;
Item *on_expr; /* associated on expression */
st_join_table *first_inner; /* first inner table for including outerjoin */
bool found; /* true after all matches or null complement */
bool not_null_compl;/* true before null complement is added */
st_join_table *last_inner; /* last table table for embedding outer join */
st_join_table *first_upper; /* first inner table for embedding outer join */
st_join_table *first_unmatched; /* used for optimization purposes only */
const char *info;
byte *null_ref_key;
int (*read_first_record)(struct st_join_table *tab);
......@@ -196,8 +201,10 @@ class JOIN :public Sql_alloc
ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
COND *conds; // ---"---
Item *conds_history; // store WHERE for explain
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_select
List<TABLE_LIST> *join_list; // list of joined tables in reverse order
SQL_SELECT *select; //created in optimisation phase
JOIN_TAB *return_tab; //used only for outer joins
Item **ref_pointer_array; //used pointer reference for this select
// Copy of above to be used with different lists
Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
......@@ -221,6 +228,7 @@ class JOIN :public Sql_alloc
table= 0;
tables= 0;
const_tables= 0;
join_list= 0;
sort_and_group= 0;
first_record= 0;
do_send_rows= 1;
......@@ -251,6 +259,7 @@ class JOIN :public Sql_alloc
fields_list= fields_arg;
error= 0;
select= 0;
return_tab= 0;
ref_pointer_array= items0= items1= items2= items3= 0;
ref_pointer_array_size= 0;
zero_result_cause= 0;
......
......@@ -698,6 +698,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <table_list>
join_table_list join_table
table_factor table_ref
%type <udf>
UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC
......@@ -4192,59 +4193,80 @@ when_list2:
sel->when_list.head()->push_back($5);
};
table_ref:
table_factor { $$=$1; }
| join_table { $$=$1; }
{
LEX *lex= Lex;
if (!($$= lex->current_select->nest_last_join(lex->thd)))
YYABORT;
}
;
join_table_list:
'(' join_table_list ')' { $$=$2; }
| join_table { $$=$1; }
| join_table_list ',' join_table_list { $$=$3; }
| join_table_list normal_join join_table_list { $$=$3; }
| join_table_list STRAIGHT_JOIN join_table_list
{ $$=$3 ; $1->next->straight=1; }
| join_table_list normal_join join_table_list ON expr
table_ref { $$=$1; }
| join_table_list ',' table_ref { $$=$3; }
;
join_table:
table_ref normal_join table_ref { $$=$3; }
| table_ref STRAIGHT_JOIN table_factor
{ $3->straight=1; $$=$3 ; }
| table_ref normal_join table_ref ON expr
{ add_join_on($3,$5); $$=$3; }
| join_table_list normal_join join_table_list
| table_ref normal_join table_ref
USING
{
SELECT_LEX *sel= Select;
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$3->db; sel->table2=$3->alias;
sel->save_names_for_using_list($1, $3);
}
'(' using_list ')'
{ add_join_on($3,$7); $$=$3; }
| join_table_list LEFT opt_outer JOIN_SYM join_table_list ON expr
| table_ref LEFT opt_outer JOIN_SYM table_ref ON expr
{ add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| join_table_list LEFT opt_outer JOIN_SYM join_table_list
| table_ref LEFT opt_outer JOIN_SYM table_ref
{
SELECT_LEX *sel= Select;
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$5->db; sel->table2=$5->alias;
sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
{ add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table_list
| table_ref NATURAL LEFT opt_outer JOIN_SYM table_factor
{
add_join_natural($1,$1->next);
$1->next->outer_join|=JOIN_TYPE_LEFT;
add_join_natural($1,$6);
$6->outer_join|=JOIN_TYPE_LEFT;
$$=$6;
}
| join_table_list RIGHT opt_outer JOIN_SYM join_table_list ON expr
{ add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; }
| join_table_list RIGHT opt_outer JOIN_SYM join_table_list
| table_ref RIGHT opt_outer JOIN_SYM table_ref ON expr
{
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
add_join_on($$, $7);
}
| table_ref RIGHT opt_outer JOIN_SYM table_ref
{
SELECT_LEX *sel= Select;
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$5->db; sel->table2=$5->alias;
sel->save_names_for_using_list($1, $5);
}
USING '(' using_list ')'
{ add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; }
| join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table_list
{
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
add_join_on($$, $9);
}
| table_ref NATURAL RIGHT opt_outer JOIN_SYM table_factor
{
add_join_natural($1->next,$1);
$1->outer_join|=JOIN_TYPE_RIGHT;
$$=$6;
add_join_natural($6,$1);
LEX *lex= Lex;
if (!($$= lex->current_select->convert_right_join()))
YYABORT;
}
| join_table_list NATURAL JOIN_SYM join_table_list
{ add_join_natural($1,$1->next); $$=$4; };
| table_ref NATURAL JOIN_SYM table_factor
{ add_join_natural($1,$4); $$=$4; };
normal_join:
JOIN_SYM {}
......@@ -4252,7 +4274,7 @@ normal_join:
| CROSS JOIN_SYM {}
;
join_table:
table_factor:
{
SELECT_LEX *sel= Select;
sel->use_index_ptr=sel->ignore_index_ptr=0;
......@@ -4268,8 +4290,21 @@ join_table:
sel->get_use_index(),
sel->get_ignore_index())))
YYABORT;
sel->add_joined_table($$);
}
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
| '('
{
LEX *lex= Lex;
if (lex->current_select->init_nested_join(lex->thd))
YYABORT;
}
join_table_list ')'
{
LEX *lex= Lex;
if (!($$= lex->current_select->end_nested_join(lex->thd)))
YYABORT;
}
| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref ON expr '}'
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
| '(' SELECT_SYM select_derived ')' opt_table_alias
{
......@@ -4289,6 +4324,7 @@ join_table:
(List<String> *)0)))
YYABORT;
lex->current_select->add_joined_table($$);
};
select_derived:
......
......@@ -143,12 +143,8 @@ struct st_table {
uint quick_key_parts[MAX_KEY];
key_part_map const_key_parts[MAX_KEY];
ulong query_id;
union /* Temporary variables */
{
uint temp_pool_slot; /* Used by intern temp tables */
struct st_table_list *pos_in_table_list;
};
uint temp_pool_slot; /* Used by intern temp tables */
struct st_table_list *pos_in_table_list;/* Element referring to this table */
/* number of select if it is derived table */
uint derived_select_number;
THD *in_use; /* Which thread uses this */
......@@ -178,10 +174,24 @@ typedef struct st_table_list
uint32 db_length, real_name_length;
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
bool force_index; /* Prefer index over table scan */
bool ignore_leaves; /* Preload only non-leaf nodes */
bool force_index; /* prefer index over table scan */
bool ignore_leaves; /* preload only non-leaf nodes */
table_map dep_tables; /* tables the table depends on */
table_map on_expr_dep_tables; /* tables on expression depends on */
struct st_nested_join *nested_join; /* if the element is a nested join */
st_table_list *embedding; /* nested join containing the table */
List<struct st_table_list> *join_list;/* join list the table belongs to */
} TABLE_LIST;
typedef struct st_nested_join
{
List<TABLE_LIST> join_list; /* list of elements in the nested join */
table_map used_tables; /* bitmap of tables in the nested join */
table_map not_null_tables; /* tables that rejects nulls */
struct st_join_table *first_nested;/* the first nested table in the plan */
uint counter; /* to count tables in the nested join */
} NESTED_JOIN;
typedef struct st_changed_table_list
{
struct st_changed_table_list *next;
......@@ -189,8 +199,7 @@ typedef struct st_changed_table_list
uint32 key_length;
} CHANGED_TABLE_LIST;
typedef struct st_open_table_list
{
typedef struct st_open_table_list{
struct st_open_table_list *next;
char *db,*table;
uint32 in_use,locked;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment