MWL#17: Table-elimination
- Addressing review feedback, generation 4. include/my_global.h: Make ALIGN_PTR's action correspond to that of ALIGN_SIZE sql/item.cc: MWL#17: Table-elimination - Review feedback: function renames, better comments sql/item.h: MWL#17: Table-elimination - Review feedback: function renames, better comments sql/item_cmpfunc.cc: MWL#17: Table-elimination - Review feedback: function renames, better comments sql/item_subselect.cc: MWL#17: Table-elimination - Review feedback: function renames, better comments sql/item_subselect.h: MWL#17: Table-elimination - Review feedback: function renames, better comments sql/opt_table_elimination.cc: MWL#17: Table-elimination - Addressing review feedback, generation 4: abstract everything in case we would need to change it for something else in the future. sql/sql_list.h: MWL#17: Table-elimination - Introduce exchange_sort(List<T> ...) template function sql/sql_select.cc: MWL#17: Table-elimination - Review feedback: function renames, better comments
This commit is contained in:
parent
005c24e973
commit
d762bf21cc
@ -950,8 +950,7 @@ typedef long long my_ptrdiff_t;
|
|||||||
#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1))
|
#define MY_ALIGN(A,L) (((A) + (L) - 1) & ~((L) - 1))
|
||||||
#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double))
|
#define ALIGN_SIZE(A) MY_ALIGN((A),sizeof(double))
|
||||||
/* Size to make adressable obj. */
|
/* Size to make adressable obj. */
|
||||||
#define ALIGN_PTR(A, t) ((t*) MY_ALIGN((A),sizeof(t)))
|
#define ALIGN_PTR(A, t) ((t*) MY_ALIGN((A), sizeof(double)))
|
||||||
/* Offset of field f in structure t */
|
|
||||||
#define OFFSET(t, f) ((size_t)(char *)&((t *)0)->f)
|
#define OFFSET(t, f) ((size_t)(char *)&((t *)0)->f)
|
||||||
#define ADD_TO_PTR(ptr,size,type) (type) ((uchar*) (ptr)+size)
|
#define ADD_TO_PTR(ptr,size,type) (type) ((uchar*) (ptr)+size)
|
||||||
#define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((uchar*) (A) - (uchar*) (B))
|
#define PTR_BYTE_DIFF(A,B) (my_ptrdiff_t) ((uchar*) (A) - (uchar*) (B))
|
||||||
|
@ -1916,10 +1916,10 @@ void Item_field::reset_field(Field *f)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_field::check_column_usage_processor(uchar *arg)
|
bool Item_field::enumerate_field_refs_processor(uchar *arg)
|
||||||
{
|
{
|
||||||
Field_enumerator *fe= (Field_enumerator*)arg;
|
Field_enumerator *fe= (Field_enumerator*)arg;
|
||||||
fe->see_field(field);
|
fe->visit_field(field);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
sql/item.h
27
sql/item.h
@ -734,7 +734,7 @@ public:
|
|||||||
/*
|
/*
|
||||||
Bitmap of tables used by item
|
Bitmap of tables used by item
|
||||||
(note: if you need to check dependencies on individual columns, check out
|
(note: if you need to check dependencies on individual columns, check out
|
||||||
check_column_usage_processor)
|
class Field_enumerator)
|
||||||
*/
|
*/
|
||||||
virtual table_map used_tables() const { return (table_map) 0L; }
|
virtual table_map used_tables() const { return (table_map) 0L; }
|
||||||
/*
|
/*
|
||||||
@ -892,7 +892,7 @@ public:
|
|||||||
virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
|
virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; }
|
||||||
virtual bool is_expensive_processor(uchar *arg) { return 0; }
|
virtual bool is_expensive_processor(uchar *arg) { return 0; }
|
||||||
virtual bool register_field_in_read_map(uchar *arg) { return 0; }
|
virtual bool register_field_in_read_map(uchar *arg) { return 0; }
|
||||||
virtual bool check_column_usage_processor(uchar *arg) { return 0; }
|
virtual bool enumerate_field_refs_processor(uchar *arg) { return 0; }
|
||||||
virtual bool mark_as_eliminated_processor(uchar *arg) { return 0; }
|
virtual bool mark_as_eliminated_processor(uchar *arg) { return 0; }
|
||||||
/*
|
/*
|
||||||
Check if a partition function is allowed
|
Check if a partition function is allowed
|
||||||
@ -1018,14 +1018,29 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Data for Item::check_column_usage_processor */
|
/*
|
||||||
|
Class to be used to enumerate all field references in an item tree.
|
||||||
|
Suggested usage:
|
||||||
|
|
||||||
|
class My_enumerator : public Field_enumerator
|
||||||
|
{
|
||||||
|
virtual void visit_field() { ... your actions ...}
|
||||||
|
}
|
||||||
|
|
||||||
|
My_enumerator enumerator;
|
||||||
|
item->walk(Item::enumerate_field_refs_processor, ...,(uchar*)&enumerator);
|
||||||
|
|
||||||
|
This is similar to Visitor pattern.
|
||||||
|
*/
|
||||||
|
|
||||||
class Field_enumerator
|
class Field_enumerator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void see_field(Field *field)= 0;
|
virtual void visit_field(Field *field)= 0;
|
||||||
virtual ~Field_enumerator() {}; /* Shut up compiler warning */
|
virtual ~Field_enumerator() {}; /* purecov: inspected */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class sp_head;
|
class sp_head;
|
||||||
|
|
||||||
|
|
||||||
@ -1491,7 +1506,7 @@ public:
|
|||||||
bool find_item_in_field_list_processor(uchar *arg);
|
bool find_item_in_field_list_processor(uchar *arg);
|
||||||
bool register_field_in_read_map(uchar *arg);
|
bool register_field_in_read_map(uchar *arg);
|
||||||
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
|
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
|
||||||
bool check_column_usage_processor(uchar *arg);
|
bool enumerate_field_refs_processor(uchar *arg);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
bool result_as_longlong()
|
bool result_as_longlong()
|
||||||
{
|
{
|
||||||
|
@ -5168,33 +5168,7 @@ void Item_equal::merge(Item_equal *item)
|
|||||||
|
|
||||||
void Item_equal::sort(Item_field_cmpfunc cmp, void *arg)
|
void Item_equal::sort(Item_field_cmpfunc cmp, void *arg)
|
||||||
{
|
{
|
||||||
bool swap;
|
exchange_sort<Item_field>(&fields, cmp, arg);
|
||||||
List_iterator<Item_field> it(fields);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Item_field *item1= it++;
|
|
||||||
Item_field **ref1= it.ref();
|
|
||||||
Item_field *item2;
|
|
||||||
|
|
||||||
swap= FALSE;
|
|
||||||
while ((item2= it++))
|
|
||||||
{
|
|
||||||
Item_field **ref2= it.ref();
|
|
||||||
if (cmp(item1, item2, arg) < 0)
|
|
||||||
{
|
|
||||||
Item_field *item= *ref1;
|
|
||||||
*ref1= *ref2;
|
|
||||||
*ref2= item;
|
|
||||||
swap= TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
item1= item2;
|
|
||||||
ref1= ref2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it.rewind();
|
|
||||||
} while (swap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,13 +215,13 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Item_subselect::check_column_usage_processor(uchar *arg)
|
bool Item_subselect::enumerate_field_refs_processor(uchar *arg)
|
||||||
{
|
{
|
||||||
List_iterator<Item> it(refers_to);
|
List_iterator<Item> it(refers_to);
|
||||||
Item *item;
|
Item *item;
|
||||||
while ((item= it++))
|
while ((item= it++))
|
||||||
{
|
{
|
||||||
if (item->walk(&Item::check_column_usage_processor,FALSE, arg))
|
if (item->walk(&Item::enumerate_field_refs_processor, FALSE, arg))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -135,7 +135,7 @@ public:
|
|||||||
enum_parsing_place place() { return parsing_place; }
|
enum_parsing_place place() { return parsing_place; }
|
||||||
bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
|
bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
|
||||||
bool mark_as_eliminated_processor(uchar *arg);
|
bool mark_as_eliminated_processor(uchar *arg);
|
||||||
bool check_column_usage_processor(uchar *arg);
|
bool enumerate_field_refs_processor(uchar *arg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the SELECT_LEX structure associated with this Item.
|
Get the SELECT_LEX structure associated with this Item.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -442,6 +442,43 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Exchange sort algorithm for List<T>.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
inline void exchange_sort(List<T> *list_to_sort,
|
||||||
|
int (*sort_func)(T *a, T *b, void *arg), void *arg)
|
||||||
|
{
|
||||||
|
bool swap;
|
||||||
|
List_iterator<T> it(*list_to_sort);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
T *item1= it++;
|
||||||
|
T **ref1= it.ref();
|
||||||
|
T *item2;
|
||||||
|
|
||||||
|
swap= FALSE;
|
||||||
|
while ((item2= it++))
|
||||||
|
{
|
||||||
|
T **ref2= it.ref();
|
||||||
|
if (sort_func(item1, item2, arg) < 0)
|
||||||
|
{
|
||||||
|
T *item= *ref1;
|
||||||
|
*ref1= *ref2;
|
||||||
|
*ref2= item;
|
||||||
|
swap= TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item1= item2;
|
||||||
|
ref1= ref2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.rewind();
|
||||||
|
} while (swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A simple intrusive list which automaticly removes element from list
|
A simple intrusive list which automaticly removes element from list
|
||||||
on delete (for THD element)
|
on delete (for THD element)
|
||||||
|
@ -2991,22 +2991,33 @@ typedef struct key_field_t {
|
|||||||
elements that would correspond to "$LEFT_PART OR $RIGHT_PART".
|
elements that would correspond to "$LEFT_PART OR $RIGHT_PART".
|
||||||
|
|
||||||
The rules for combining elements are as follows:
|
The rules for combining elements are as follows:
|
||||||
|
|
||||||
(keyfieldA1 AND keyfieldA2 AND ...) OR (keyfieldB1 AND keyfieldB2 AND ...)=
|
(keyfieldA1 AND keyfieldA2 AND ...) OR (keyfieldB1 AND keyfieldB2 AND ...)=
|
||||||
AND_ij (keyfieldA_i OR keyfieldB_j)
|
|
||||||
|
= AND_ij (keyfieldA_i OR keyfieldB_j)
|
||||||
|
|
||||||
We discard all (keyfieldA_i OR keyfieldB_j) that refer to different
|
We discard all (keyfieldA_i OR keyfieldB_j) that refer to different
|
||||||
fields. For those referring to the same field, the logic is as follows:
|
fields. For those referring to the same field, the logic is as follows:
|
||||||
|
|
||||||
t.keycol=
|
t.keycol=expr1 OR t.keycol=expr2 -> (since expr1 and expr2 are different
|
||||||
|
we can't produce a single equality,
|
||||||
|
so produce nothing)
|
||||||
|
|
||||||
To be able to do 'ref_or_null' we merge a comparison of a column
|
t.keycol=expr1 OR t.keycol=expr1 -> t.keycol=expr1
|
||||||
and 'column IS NULL' to one test. This is useful for sub select queries
|
|
||||||
that are internally transformed to something like:.
|
t.keycol=expr1 OR t.keycol IS NULL -> t.keycol=expr1, and also set
|
||||||
|
KEY_OPTIMIZE_REF_OR_NULL flag
|
||||||
|
|
||||||
|
The last one is for ref_or_null access. We have handling for this special
|
||||||
|
because it's needed for evaluating IN subqueries that are internally
|
||||||
|
transformed into
|
||||||
|
|
||||||
@code
|
@code
|
||||||
SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL
|
EXISTS(SELECT * FROM t1 WHERE t1.key=outer_ref_field or t1.key IS NULL)
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
See add_key_fields() for discussion of what is and_level.
|
||||||
|
|
||||||
KEY_FIELD::null_rejecting is processed as follows: @n
|
KEY_FIELD::null_rejecting is processed as follows: @n
|
||||||
result has null_rejecting=true if it is set for both ORed references.
|
result has null_rejecting=true if it is set for both ORed references.
|
||||||
for example:
|
for example:
|
||||||
@ -3346,6 +3357,26 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
In this and other functions, and_level is a number that is ever-growing
|
||||||
|
and is different for the contents of every AND or OR clause. For example,
|
||||||
|
when processing clause
|
||||||
|
|
||||||
|
(a AND b AND c) OR (x AND y)
|
||||||
|
|
||||||
|
we'll have
|
||||||
|
* KEY_FIELD elements for (a AND b AND c) are assigned and_level=1
|
||||||
|
* KEY_FIELD elements for (x AND y) are assigned and_level=2
|
||||||
|
* OR operation is performed, and whatever elements are left after it are
|
||||||
|
assigned and_level=3.
|
||||||
|
|
||||||
|
The primary reason for having and_level attribute is the OR operation which
|
||||||
|
uses and_level to mark KEY_FIELDs that should get into the result of the OR
|
||||||
|
operation
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
|
add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level,
|
||||||
COND *cond, table_map usable_tables,
|
COND *cond, table_map usable_tables,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user