Commit fef409cb authored by Sergey Petrunya's avatar Sergey Petrunya

MWL#17: Table elimination

- More function renames, added comments
parent a2839036
...@@ -93,11 +93,9 @@ class Equality_dep : public Func_dep ...@@ -93,11 +93,9 @@ class Equality_dep : public Func_dep
/* /*
A field. A table field. There is only one such object for any tblX.fieldY
- Depends on table or equality - the field epends on its table and equalities
- Has expressions it participates as dependencies - expressions that use the field are its dependencies
There is no counter, bound fields are in $list, not bound are not.
*/ */
class Field_dep : public Func_dep class Field_dep : public Func_dep
{ {
...@@ -107,19 +105,23 @@ class Field_dep : public Func_dep ...@@ -107,19 +105,23 @@ class Field_dep : public Func_dep
{ {
type= Func_dep::FD_FIELD; type= Func_dep::FD_FIELD;
} }
/* Table we're from. It also has pointers to keys that we're part of */
Table_dep *table; Table_dep *table; /* Table this field is from */
Field *field; Field *field;
/*
Field_deps that belong to one table form a linked list. list members are
ordered by field_index
*/
Field_dep *next_table_field; Field_dep *next_table_field;
uint bitmap_offset; /* Offset of our part of the bitmap */ uint bitmap_offset; /* Offset of our part of the bitmap */
}; };
/* /*
A unique key. A Unique key.
- Depends on all its components - Unique key depends on all of its components
- Has its table as dependency - Key's table is its dependency
*/ */
class Key_dep: public Func_dep class Key_dep: public Func_dep
{ {
...@@ -133,14 +135,15 @@ class Key_dep: public Func_dep ...@@ -133,14 +135,15 @@ class Key_dep: public Func_dep
Table_dep *table; /* Table this key is from */ Table_dep *table; /* Table this key is from */
uint keyno; uint keyno;
uint n_missing_keyparts; uint n_missing_keyparts;
/* Unique keys form a linked list, ordered by keyno */
Key_dep *next_table_key; Key_dep *next_table_key;
}; };
/* /*
A table. A table.
- Depends on any of its unique keys - table depends on any of its unique keys
- Has its fields and embedding outer join as dependency. - has its fields and embedding outer join as dependency.
*/ */
class Table_dep : public Func_dep class Table_dep : public Func_dep
{ {
...@@ -151,16 +154,16 @@ class Table_dep : public Func_dep ...@@ -151,16 +154,16 @@ class Table_dep : public Func_dep
type= Func_dep::FD_TABLE; type= Func_dep::FD_TABLE;
} }
TABLE *table; TABLE *table;
Field_dep *fields; /* Fields that belong to this table */ Field_dep *fields; /* Ordered list of fields that belong to this table */
Key_dep *keys; /* Unique keys */ Key_dep *keys; /* Ordered list of Unique keys in this table */
Outer_join_dep *outer_join_dep; Outer_join_dep *outer_join_dep; /* Innermost eliminable outer join we're in */
}; };
/* /*
An outer join nest. An outer join nest that is subject to elimination
- Depends on all tables inside it. - it depends on all tables inside it
- (And that's it). - has its parent outer join as dependency
*/ */
class Outer_join_dep: public Func_dep class Outer_join_dep: public Func_dep
{ {
...@@ -171,14 +174,27 @@ class Outer_join_dep: public Func_dep ...@@ -171,14 +174,27 @@ class Outer_join_dep: public Func_dep
{ {
type= Func_dep::FD_OUTER_JOIN; type= Func_dep::FD_OUTER_JOIN;
} }
/*
Outer join we're representing. This can be a join nest or a one table that
is outer join'ed.
*/
TABLE_LIST *table_list; TABLE_LIST *table_list;
/*
Tables within this outer join (and its descendants) that are not yet known
to be functionally dependent.
*/
table_map missing_tables; table_map missing_tables;
/* All tables within this outer join and its descendants */
table_map all_tables; table_map all_tables;
/* Parent eliminable outer join, if any */
Outer_join_dep *parent; Outer_join_dep *parent;
}; };
/* TODO need this? */ /*
Table elimination context
*/
class Table_elimination class Table_elimination
{ {
public: public:
...@@ -204,20 +220,22 @@ class Table_elimination ...@@ -204,20 +220,22 @@ class Table_elimination
static static
void build_funcdeps_for_cond(Table_elimination *te, Equality_dep **fdeps, void build_eq_deps_for_cond(Table_elimination *te, Equality_dep **fdeps,
uint *and_level, Item *cond, uint *and_level, Item *cond,
table_map usable_tables); table_map usable_tables);
static static
void add_funcdep(Table_elimination *te, void add_eq_dep(Table_elimination *te,
Equality_dep **eq_dep, uint and_level, Equality_dep **eq_dep, uint and_level,
Item_func *cond, Field *field, Item_func *cond, Field *field,
bool eq_func, Item **value, bool eq_func, Item **value,
uint num_values, table_map usable_tables); uint num_values, table_map usable_tables);
static static
Equality_dep *merge_func_deps(Equality_dep *start, Equality_dep *new_fields, Equality_dep *merge_func_deps(Equality_dep *start, Equality_dep *new_fields,
Equality_dep *end, uint and_level); Equality_dep *end, uint and_level);
Field_dep *get_field_dep(Table_elimination *te, Field *field); static Table_dep *get_table_dep(Table_elimination *te, TABLE *table);
static Field_dep *get_field_dep(Table_elimination *te, Field *field);
void eliminate_tables(JOIN *join); void eliminate_tables(JOIN *join);
static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl); static void mark_as_eliminated(JOIN *join, TABLE_LIST *tbl);
...@@ -228,24 +246,25 @@ static void dbug_print_deps(Table_elimination *te); ...@@ -228,24 +246,25 @@ static void dbug_print_deps(Table_elimination *te);
/*******************************************************************************************/ /*******************************************************************************************/
/* /*
Produce FUNC_DEP elements for the given item (i.e. condition) and add them Produce Eq_dep elements for given condition.
to fdeps array.
SYNOPSIS SYNOPSIS
build_funcdeps_for_cond() build_eq_deps_for_cond()
fdeps INOUT Put created FUNC_DEP structures here te Table elimination context
fdeps INOUT Put produced equality conditions here
and_level INOUT AND-level (like in add_key_fields)
cond Condition to process
usable_tables Tables which fields we're interested in. That is,
Equality_dep represent "tbl.col=expr" and we'll
produce them only if tbl is in usable_tables.
DESCRIPTION DESCRIPTION
a This function is modeled after add_key_fields()
SEE ALSO
add_key_fields()
*/ */
static static
void build_funcdeps_for_cond(Table_elimination *te, void build_eq_deps_for_cond(Table_elimination *te, Equality_dep **fdeps,
Equality_dep **fdeps, uint *and_level, Item *cond, uint *and_level, Item *cond,
table_map usable_tables) table_map usable_tables)
{ {
if (cond->type() == Item_func::COND_ITEM) if (cond->type() == Item_func::COND_ITEM)
{ {
...@@ -258,7 +277,7 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -258,7 +277,7 @@ void build_funcdeps_for_cond(Table_elimination *te,
Item *item; Item *item;
while ((item=li++)) while ((item=li++))
{ {
build_funcdeps_for_cond(te, fdeps, and_level, item, usable_tables); build_eq_deps_for_cond(te, fdeps, and_level, item, usable_tables);
} }
/* /*
TODO: inject here a "if we have {t.col=const AND t.col=smth_else}, then TODO: inject here a "if we have {t.col=const AND t.col=smth_else}, then
...@@ -270,13 +289,13 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -270,13 +289,13 @@ void build_funcdeps_for_cond(Table_elimination *te,
else else
{ {
(*and_level)++; (*and_level)++;
build_funcdeps_for_cond(te, fdeps, and_level, li++, usable_tables); build_eq_deps_for_cond(te, fdeps, and_level, li++, usable_tables);
Item *item; Item *item;
while ((item=li++)) while ((item=li++))
{ {
Equality_dep *start_key_fields= *fdeps; Equality_dep *start_key_fields= *fdeps;
(*and_level)++; (*and_level)++;
build_funcdeps_for_cond(te, fdeps, and_level, item, usable_tables); build_eq_deps_for_cond(te, fdeps, and_level, item, usable_tables);
*fdeps= merge_func_deps(org_key_fields, start_key_fields, *fdeps, *fdeps= merge_func_deps(org_key_fields, start_key_fields, *fdeps,
++(*and_level)); ++(*and_level));
} }
...@@ -304,11 +323,11 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -304,11 +323,11 @@ void build_funcdeps_for_cond(Table_elimination *te,
values--; values--;
DBUG_ASSERT(cond_func->functype() != Item_func::IN_FUNC || DBUG_ASSERT(cond_func->functype() != Item_func::IN_FUNC ||
cond_func->argument_count() != 2); cond_func->argument_count() != 2);
add_funcdep(te, fdeps, *and_level, cond_func, add_eq_dep(te, fdeps, *and_level, cond_func,
((Item_field*)(cond_func->key_item()->real_item()))->field, ((Item_field*)(cond_func->key_item()->real_item()))->field,
0, values, 0, values,
cond_func->argument_count()-1, cond_func->argument_count()-1,
usable_tables); usable_tables);
} }
if (cond_func->functype() == Item_func::BETWEEN) if (cond_func->functype() == Item_func::BETWEEN)
{ {
...@@ -321,8 +340,8 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -321,8 +340,8 @@ void build_funcdeps_for_cond(Table_elimination *te,
!(cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT)) !(cond_func->arguments()[i]->used_tables() & OUTER_REF_TABLE_BIT))
{ {
field_item= (Item_field *) (cond_func->arguments()[i]->real_item()); field_item= (Item_field *) (cond_func->arguments()[i]->real_item());
add_funcdep(te, fdeps, *and_level, cond_func, add_eq_dep(te, fdeps, *and_level, cond_func,
field_item->field, 0, values, 1, usable_tables); field_item->field, 0, values, 1, usable_tables);
} }
} }
} }
...@@ -336,19 +355,19 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -336,19 +355,19 @@ void build_funcdeps_for_cond(Table_elimination *te,
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT)) !(cond_func->arguments()[0]->used_tables() & OUTER_REF_TABLE_BIT))
{ {
add_funcdep(te, fdeps, *and_level, cond_func, add_eq_dep(te, fdeps, *and_level, cond_func,
((Item_field*)(cond_func->arguments()[0])->real_item())->field, ((Item_field*)(cond_func->arguments()[0])->real_item())->field,
equal_func, equal_func,
cond_func->arguments()+1, 1, usable_tables); cond_func->arguments()+1, 1, usable_tables);
} }
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
cond_func->functype() != Item_func::LIKE_FUNC && cond_func->functype() != Item_func::LIKE_FUNC &&
!(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT)) !(cond_func->arguments()[1]->used_tables() & OUTER_REF_TABLE_BIT))
{ {
add_funcdep(te, fdeps, *and_level, cond_func, add_eq_dep(te, fdeps, *and_level, cond_func,
((Item_field*)(cond_func->arguments()[1])->real_item())->field, ((Item_field*)(cond_func->arguments()[1])->real_item())->field,
equal_func, equal_func,
cond_func->arguments(),1,usable_tables); cond_func->arguments(),1,usable_tables);
} }
break; break;
} }
...@@ -360,10 +379,10 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -360,10 +379,10 @@ void build_funcdeps_for_cond(Table_elimination *te,
Item *tmp=new Item_null; Item *tmp=new Item_null;
if (unlikely(!tmp)) // Should never be true if (unlikely(!tmp)) // Should never be true
return; return;
add_funcdep(te, fdeps, *and_level, cond_func, add_eq_dep(te, fdeps, *and_level, cond_func,
((Item_field*)(cond_func->arguments()[0])->real_item())->field, ((Item_field*)(cond_func->arguments()[0])->real_item())->field,
cond_func->functype() == Item_func::ISNULL_FUNC, cond_func->functype() == Item_func::ISNULL_FUNC,
&tmp, 1, usable_tables); &tmp, 1, usable_tables);
} }
break; break;
case Item_func::OPTIMIZE_EQUAL: case Item_func::OPTIMIZE_EQUAL:
...@@ -380,8 +399,8 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -380,8 +399,8 @@ void build_funcdeps_for_cond(Table_elimination *te,
*/ */
while ((item= it++)) while ((item= it++))
{ {
add_funcdep(te, fdeps, *and_level, cond_func, item->field, add_eq_dep(te, fdeps, *and_level, cond_func, item->field,
TRUE, &const_item, 1, usable_tables); TRUE, &const_item, 1, usable_tables);
} }
} }
else else
...@@ -400,8 +419,8 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -400,8 +419,8 @@ void build_funcdeps_for_cond(Table_elimination *te,
{ {
if (!field->eq(item->field)) if (!field->eq(item->field))
{ {
add_funcdep(te, fdeps, *and_level, cond_func, field/*item*/, add_eq_dep(te, fdeps, *and_level, cond_func, field,
TRUE, (Item **) &item, 1, usable_tables); TRUE, (Item **) &item, 1, usable_tables);
} }
} }
it.rewind(); it.rewind();
...@@ -411,15 +430,19 @@ void build_funcdeps_for_cond(Table_elimination *te, ...@@ -411,15 +430,19 @@ void build_funcdeps_for_cond(Table_elimination *te,
} }
} }
/* /*
Perform an OR operation on two (adjacent) FUNC_DEP arrays. Perform an OR operation on two (adjacent) Equality_dep arrays.
SYNOPSIS SYNOPSIS
merge_func_deps() merge_func_deps()
start Start of left OR-part
new_fields Start of right OR-part
end End of right OR-part
and_level AND-level.
DESCRIPTION DESCRIPTION
This function is invoked for two adjacent arrays of Equality_dep elements:
This function is invoked for two adjacent arrays of FUNC_DEP elements:
$LEFT_PART $RIGHT_PART $LEFT_PART $RIGHT_PART
+-----------------------+-----------------------+ +-----------------------+-----------------------+
...@@ -527,17 +550,18 @@ Equality_dep *merge_func_deps(Equality_dep *start, Equality_dep *new_fields, ...@@ -527,17 +550,18 @@ Equality_dep *merge_func_deps(Equality_dep *start, Equality_dep *new_fields,
/* /*
Add a funcdep for a given equality. Add an Equality_dep element for a given predicate, if applicable
DESCRIPTION
This function is modeled after add_key_field().
*/ */
static static
void add_funcdep(Table_elimination *te, void add_eq_dep(Table_elimination *te, Equality_dep **eq_dep,
Equality_dep **eq_dep, uint and_level, uint and_level, Item_func *cond, Field *field,
Item_func *cond, Field *field, bool eq_func, Item **value, uint num_values,
bool eq_func, Item **value, table_map usable_tables)
uint num_values, table_map usable_tables)
{ {
// Field *field= item_field->field;
if (!(field->table->map & usable_tables)) if (!(field->table->map & usable_tables))
return; return;
...@@ -606,7 +630,11 @@ void add_funcdep(Table_elimination *te, ...@@ -606,7 +630,11 @@ void add_funcdep(Table_elimination *te,
} }
Table_dep *get_table_dep(Table_elimination *te, TABLE *table) /*
Get a Table_dep object for the given table, creating it if necessary.
*/
static Table_dep *get_table_dep(Table_elimination *te, TABLE *table)
{ {
Table_dep *tbl_dep= new Table_dep(table); Table_dep *tbl_dep= new Table_dep(table);
Key_dep **key_list= &(tbl_dep->keys); Key_dep **key_list= &(tbl_dep->keys);
...@@ -625,19 +653,21 @@ Table_dep *get_table_dep(Table_elimination *te, TABLE *table) ...@@ -625,19 +653,21 @@ Table_dep *get_table_dep(Table_elimination *te, TABLE *table)
return te->table_deps[table->tablenr] = tbl_dep; return te->table_deps[table->tablenr] = tbl_dep;
} }
/* /*
Given a field, get its dependency element: if it already exists, find it, Get a Field_dep object for the given field, creating it if necessary
otherwise create it.
*/ */
Field_dep *get_field_dep(Table_elimination *te, Field *field) static Field_dep *get_field_dep(Table_elimination *te, Field *field)
{ {
TABLE *table= field->table; TABLE *table= field->table;
Table_dep *tbl_dep; Table_dep *tbl_dep;
/* First, get the table*/
if (!(tbl_dep= te->table_deps[table->tablenr])) if (!(tbl_dep= te->table_deps[table->tablenr]))
tbl_dep= get_table_dep(te, table); tbl_dep= get_table_dep(te, table);
/* Try finding the field in field list */
Field_dep **pfield= &(tbl_dep->fields); Field_dep **pfield= &(tbl_dep->fields);
while (*pfield && (*pfield)->field->field_index < field->field_index) while (*pfield && (*pfield)->field->field_index < field->field_index)
{ {
...@@ -646,20 +676,34 @@ Field_dep *get_field_dep(Table_elimination *te, Field *field) ...@@ -646,20 +676,34 @@ Field_dep *get_field_dep(Table_elimination *te, Field *field)
if (*pfield && (*pfield)->field->field_index == field->field_index) if (*pfield && (*pfield)->field->field_index == field->field_index)
return *pfield; return *pfield;
/* Create the field and insert it in the list */
Field_dep *new_field= new Field_dep(tbl_dep, field); Field_dep *new_field= new Field_dep(tbl_dep, field);
new_field->next_table_field= *pfield; new_field->next_table_field= *pfield;
*pfield= new_field; *pfield= new_field;
return new_field; return new_field;
} }
/*
Create an Outer_join_dep object for the given outer join
DESCRIPTION
Outer_join_dep objects for children (or further descendants) are always
created before the parents.
*/
static
Outer_join_dep *get_outer_join_dep(Table_elimination *te, Outer_join_dep *get_outer_join_dep(Table_elimination *te,
TABLE_LIST *outer_join, table_map deps_map) TABLE_LIST *outer_join, table_map deps_map)
{ {
Outer_join_dep *oj_dep; Outer_join_dep *oj_dep;
oj_dep= new Outer_join_dep(outer_join, deps_map); oj_dep= new Outer_join_dep(outer_join, deps_map);
/*
Collect a bitmap fo tables that we depend on, and also set parent pointer
for descendant outer join elements.
*/
Table_map_iterator it(deps_map); Table_map_iterator it(deps_map);
int idx; int idx;
while ((idx= it.next_bit()) != Table_map_iterator::BITMAP_END) while ((idx= it.next_bit()) != Table_map_iterator::BITMAP_END)
...@@ -667,6 +711,11 @@ Outer_join_dep *get_outer_join_dep(Table_elimination *te, ...@@ -667,6 +711,11 @@ Outer_join_dep *get_outer_join_dep(Table_elimination *te,
Table_dep *table_dep; Table_dep *table_dep;
if (!(table_dep= te->table_deps[idx])) if (!(table_dep= te->table_deps[idx]))
{ {
/*
We get here only when ON expression had no references to inner tables
and Table_map objects weren't created for them. This is a rare/
unimportant case so it's ok to do not too efficient searches.
*/
TABLE *table= NULL; TABLE *table= NULL;
for (TABLE_LIST *tlist= te->join->select_lex->leaf_tables; tlist; for (TABLE_LIST *tlist= te->join->select_lex->leaf_tables; tlist;
tlist=tlist->next_leaf) tlist=tlist->next_leaf)
...@@ -680,7 +729,13 @@ Outer_join_dep *get_outer_join_dep(Table_elimination *te, ...@@ -680,7 +729,13 @@ Outer_join_dep *get_outer_join_dep(Table_elimination *te,
DBUG_ASSERT(table); DBUG_ASSERT(table);
table_dep= get_table_dep(te, table); table_dep= get_table_dep(te, table);
} }
/*
Walk from the table up to its embedding outer joins. The goal is to
find the least embedded outer join nest and set its parent pointer to
point to the newly created Outer_join_dep.
to set the pointer of its near
*/
if (!table_dep->outer_join_dep) if (!table_dep->outer_join_dep)
table_dep->outer_join_dep= oj_dep; table_dep->outer_join_dep= oj_dep;
else else
...@@ -690,43 +745,35 @@ Outer_join_dep *get_outer_join_dep(Table_elimination *te, ...@@ -690,43 +745,35 @@ Outer_join_dep *get_outer_join_dep(Table_elimination *te,
oj= oj->parent; oj= oj->parent;
oj->parent=oj_dep; oj->parent=oj_dep;
} }
} }
return oj_dep; return oj_dep;
} }
/* /*
Perform table elimination in a given join list Build functional dependency graph for elements of given join list
SYNOPSIS SYNOPSIS
collect_funcdeps_for_join_list() collect_funcdeps_for_join_list()
te Table elimination context. te Table elimination context.
join_list Join list to work on join_list Join list to work on
its_outer_join TRUE <=> the join_list is an inner side of an build_eq_deps TRUE <=> build Equality_dep elements for all
outer join members of the join list, even if they cannot
FALSE <=> otherwise (this is top-level join be individually eliminated
list, simplify_joins flattens out all tables_used_elsewhere Bitmap of tables that are referred to from
other kinds of join lists) somewhere outside of this join list (e.g.
select list, HAVING, ON expressions of parent
tables_in_list Bitmap of tables embedded in the join_list. joins, etc).
tables_used_elsewhere Bitmap of tables that are referred to from eliminable_tables INOUT Tables that can potentially be eliminated
somewhere outside of the join list (e.g. (needed so we know for which tables to build
select list, HAVING, etc). dependencies for)
eq_dep INOUT End of array of equality dependencies.
DESCRIPTION DESCRIPTION
Perform table elimination for a join list. .
Try eliminating children nests first.
The "all tables in join nest can produce only one matching record
combination" property checking is modeled after constant table detection,
plus we reuse info attempts to eliminate child join nests.
RETURN
Number of children left after elimination. 0 means everything was
eliminated.
*/ */
static uint static void
collect_funcdeps_for_join_list(Table_elimination *te, collect_funcdeps_for_join_list(Table_elimination *te,
List<TABLE_LIST> *join_list, List<TABLE_LIST> *join_list,
bool build_eq_deps, bool build_eq_deps,
...@@ -771,7 +818,7 @@ collect_funcdeps_for_join_list(Table_elimination *te, ...@@ -771,7 +818,7 @@ collect_funcdeps_for_join_list(Table_elimination *te,
{ {
// build comp_cond from ON expression // build comp_cond from ON expression
uint and_level=0; uint and_level=0;
build_funcdeps_for_cond(te, eq_dep, &and_level, tbl->on_expr, build_eq_deps_for_cond(te, eq_dep, &and_level, tbl->on_expr,
*eliminable_tables); *eliminable_tables);
} }
...@@ -781,19 +828,13 @@ collect_funcdeps_for_join_list(Table_elimination *te, ...@@ -781,19 +828,13 @@ collect_funcdeps_for_join_list(Table_elimination *te,
tables_used_on_left |= tbl->on_expr->used_tables(); tables_used_on_left |= tbl->on_expr->used_tables();
} }
} }
return 0; return;
} }
/*
Analyze exising FUNC_DEP array and add elements for tables and uniq keys
SYNOPSIS /*
This is used to analyse expressions in "tbl.col=expr" dependencies so
DESCRIPTION that we can figure out which fields the expression depends on.
Add FUNC_DEP elements
RETURN
.
*/ */
class Field_dependency_setter : public Field_enumerator class Field_dependency_setter : public Field_enumerator
...@@ -819,20 +860,41 @@ class Field_dependency_setter : public Field_enumerator ...@@ -819,20 +860,41 @@ class Field_dependency_setter : public Field_enumerator
return; return;
} }
} }
/* We didn't find the field. Bump the dependency anyway */ /*
We got here if didn't find this field. It's not a part of
a unique key, and/or there is no field=expr element for it.
Bump the dependency anyway, this will signal that this dependency
cannot be satisfied.
*/
te->equality_deps[expr_offset].unknown_args++; te->equality_deps[expr_offset].unknown_args++;
} }
} }
Table_elimination *te; Table_elimination *te;
uint expr_offset; /* Offset of the expression we're processing */ /* Offset of the expression we're processing in the dependency bitmap */
uint expr_offset;
}; };
/*
Setup equality dependencies
SYNOPSIS
setup_equality_deps()
te Table elimination context
bound_deps_list OUT Start of linked list of elements that were found to
be bound (caller will use this to see if that
allows to declare further elements bound)
*/
static static
bool setup_equality_deps(Table_elimination *te, Func_dep **bound_deps_list) bool setup_equality_deps(Table_elimination *te, Func_dep **bound_deps_list)
{ {
DBUG_ENTER("setup_equality_deps"); DBUG_ENTER("setup_equality_deps");
/*
Count Field_dep objects and assign each of them a unique bitmap_offset.
*/
uint offset= 0; uint offset= 0;
for (Table_dep **tbl_dep=te->table_deps; for (Table_dep **tbl_dep=te->table_deps;
tbl_dep < te->table_deps + MAX_TABLES; tbl_dep < te->table_deps + MAX_TABLES;
...@@ -859,7 +921,10 @@ bool setup_equality_deps(Table_elimination *te, Func_dep **bound_deps_list) ...@@ -859,7 +921,10 @@ bool setup_equality_deps(Table_elimination *te, Func_dep **bound_deps_list)
bitmap_clear_all(&te->expr_deps); bitmap_clear_all(&te->expr_deps);
/* /*
Walk through all field=expr elements and collect all fields. Analyze all "field=expr" dependencies, and have te->expr_deps encode
dependencies of expressions from fields.
Also collect a linked list of equalities that are bound.
*/ */
Func_dep *bound_dep= NULL; Func_dep *bound_dep= NULL;
Field_dependency_setter deps_setter(te); Field_dependency_setter deps_setter(te);
......
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