class JOIN

class JOIN :public Sql_alloc
{
JOIN(const JOIN &rhs); /**< not implemented */
JOIN& operator=(const JOIN &rhs); /**< not implemented */
public:
JOIN_TAB *join_tab,**best_ref;
JOIN_TAB **map2table; ///< mapping between table indexes and JOIN_TABs
JOIN_TAB *join_tab_save; ///< saved join_tab for subquery reexecution
TABLE **all_tables,*sort_by_table;
uint tables,const_tables;
uint send_group_parts;
/**
Indicates that grouping will be performed on the result set during
query execution. This field belongs to query execution. @see make_group_fields, alloc_group_fields, JOIN::exec
*/
bool sort_and_group;
bool first_record,full_join,group, no_field_update;
bool do_send_rows;
table_map const_table_map,found_const_table_map;
/*
Bitmap of all inner tables from outer joins
*/
table_map outer_join;
ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
/**
Used to fetch no more than given amount of rows per one
fetch operation of server side cursor.
The value is checked in end_send and end_send_group in fashion, similar
to offset_limit_cnt:
- fetch_limit= HA_POS_ERROR if there is no cursor.
- when we open a cursor, we set fetch_limit to 0,
- on each fetch iteration we add num_rows to fetch to fetch_limit
*/
ha_rows fetch_limit;
POSITION positions[MAX_TABLES+],best_positions[MAX_TABLES+]; /* *
Bitmap of nested joins embedding the position at the end of the current
partial join (valid only during join optimizer run).
*/
nested_join_map cur_embedding_map; double best_read;
List<Item> *fields;
List<Cached_item> group_fields, group_fields_cache;
TABLE *tmp_table;
/// used to store 2 possible tmp table of SELECT
TABLE *exec_tmp_table1, *exec_tmp_table2;
THD *thd;
Item_sum **sum_funcs, ***sum_funcs_end;
/** second copy of sumfuncs (for queries with 2 temporary tables */
Item_sum **sum_funcs2, ***sum_funcs_end2;
Procedure *procedure;
Item *having;
Item *tmp_having; ///< To store having when processed temporary table
Item *having_history; ///< Store having for explain
ulonglong select_options;
select_result *result;
TMP_TABLE_PARAM tmp_table_param;
MYSQL_LOCK *lock;
/// unit structure (with global parameters) for this select
SELECT_LEX_UNIT *unit;
/// select that processed
SELECT_LEX *select_lex;
/**
TRUE <=> optimizer must not mark any table as a constant table.
This is needed for subqueries in form "a IN (SELECT .. UNION SELECT ..):
when we optimize the select that reads the results of the union from a
temporary table, we must not mark the temp. table as constant because
the number of rows in it may vary from one subquery execution to another.
*/
bool no_const_tables; /**
Copy of this JOIN to be used with temporary tables. tmp_join is used when the JOIN needs to be "reusable" (e.g. in a subquery
that gets re-executed several times) and we know will use temporary tables
for materialization. The materialization to a temporary table overwrites the
JOIN structure to point to the temporary table after the materialization is
done. This is where tmp_join is used : it's a copy of the JOIN before the
materialization and is used in restoring before re-execution by overwriting
the current JOIN structure with the saved copy.
Because of this we should pay extra care of not freeing up helper structures
that are referenced by the original contents of the JOIN. We can check for
this by making sure the "current" join is not the temporary copy, e.g.
!tmp_join || tmp_join != join We should free these sub-structures at JOIN::destroy() if the "current" join
has a copy is not that copy.
*/
JOIN *tmp_join;
ROLLUP rollup; ///< Used with rollup bool select_distinct; ///< Set if SELECT DISTINCT
/**
If we have the GROUP BY statement in the query,
but the group_list was emptied by optimizer, this
flag is TRUE.
It happens when fields in the GROUP BY are from
constant table
*/
bool group_optimized_away; /*
simple_xxxxx is set if ORDER/GROUP BY doesn't include any references
to other tables than the first non-constant table in the JOIN.
It's also set if ORDER/GROUP BY is empty.
Used for deciding for or against using a temporary table to compute
GROUP/ORDER BY.
*/
bool simple_order, simple_group;
/**
Is set only in case if we have a GROUP BY clause
and no ORDER BY after constant elimination of 'order'.
*/
bool no_order;
/** Is set if we have a GROUP BY and we have ORDER BY on a constant. */
bool skip_sort_order; bool need_tmp, hidden_group_fields;
DYNAMIC_ARRAY keyuse;
Item::cond_result cond_value, having_value;
List<Item> all_fields; ///< to store all fields that used in query
///Above list changed to use temporary table
List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
///Part, shared with list above, emulate following list
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
List<Item> &fields_list; ///< hold field list passed to mysql_select
List<Item> procedure_fields_list;
int error; 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_select
List<TABLE_LIST> *join_list; ///< list of joined tables in reverse order
COND_EQUAL *cond_equal;
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;
uint ref_pointer_array_size; ///< size of above in bytes
const char *zero_result_cause; ///< not 0 if exec must return zero result bool union_part; ///< this subselect is part of union
bool optimized; ///< flag to avoid double optimization in EXPLAIN /*
storage for caching buffers allocated during query execution.
These buffers allocations need to be cached as the thread memory pool is
cleared only at the end of the execution of the whole query and not caching
allocations that occur in repetition at execution time will result in
excessive memory usage.
Note: make_simple_join always creates an execution plan that accesses
a single table, thus it is sufficient to have a one-element array for
table_reexec.
*/
SORT_FIELD *sortorder; // make_unireg_sortorder()
TABLE *table_reexec[]; // make_simple_join()
JOIN_TAB *join_tab_reexec; // make_simple_join()
/* end of allocation caching storage */ JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
:fields_list(fields_arg)
{
init(thd_arg, fields_arg, select_options_arg, result_arg);
} void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg,
select_result *result_arg)
{
join_tab= join_tab_save= ;
all_tables= ;
tables= ;
const_tables= ;
join_list= ;
implicit_grouping= FALSE;
sort_and_group= ;
first_record= ;
do_send_rows= ;
send_records= ;
found_records= ;
fetch_limit= HA_POS_ERROR;
examined_rows= ;
exec_tmp_table1= ;
exec_tmp_table2= ;
sortorder= ;
table_reexec[]= ;
join_tab_reexec= ;
thd= thd_arg;
sum_funcs= sum_funcs2= ;
procedure= ;
having= tmp_having= having_history= ;
select_options= select_options_arg;
result= result_arg;
lock= thd_arg->lock;
select_lex= ; //for safety
tmp_join= ;
select_distinct= test(select_options & SELECT_DISTINCT);
no_order= ;
simple_order= ;
simple_group= ;
skip_sort_order= ;
need_tmp= ;
hidden_group_fields= ; /*safety*/
error= ;
select= ;
return_tab= ;
ref_pointer_array= items0= items1= items2= items3= ;
ref_pointer_array_size= ;
zero_result_cause= ;
optimized= ;
cond_equal= ;
group_optimized_away= ; all_fields= fields_arg;
if (&fields_list != &fields_arg) /* Avoid valgrind-warning */
fields_list= fields_arg;
bzero((char*) &keyuse,sizeof(keyuse));
tmp_table_param.init();
tmp_table_param.end_write_records= HA_POS_ERROR;
rollup.state= ROLLUP::STATE_NONE; no_const_tables= FALSE;
} 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,
SELECT_LEX_UNIT *unit);
int optimize();
int reinit();
void exec();
int destroy();
void restore_tmp();
bool alloc_func_list();
bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
bool before_group_by, bool recompute= FALSE); inline void set_items_ref_array(Item **ptr)
{
memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size);
current_ref_pointer_array= ptr;
}
inline void init_items_ref_array()
{
items0= ref_pointer_array + all_fields.elements;
memcpy(items0, ref_pointer_array, ref_pointer_array_size);
current_ref_pointer_array= items0;
} bool rollup_init();
bool rollup_process_const_fields();
bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields,
Item_sum ***func);
int rollup_send_data(uint idx);
int rollup_write_data(uint idx, TABLE *table);
void remove_subq_pushed_predicates(Item **where);
/**
Release memory and, if possible, the open tables held by this execution
plan (and nested plans). It's used to release some tables before
the end of execution in order to increase concurrency and reduce
memory consumption.
*/
void join_free();
/** Cleanup this JOIN, possibly for reuse */
void cleanup(bool full);
void clear();
bool save_join_tab();
bool init_save_join_tab();
bool send_row_on_empty_set()
{
return (do_send_rows && tmp_table_param.sum_func_count != &&
!group_list && having_value != Item::COND_FALSE);
}
bool change_result(select_result *result);
bool is_top_level_join() const
{
return (unit == &thd->lex->unit && (unit->fake_select_lex == ||
select_lex == unit->fake_select_lex));
}
void cache_const_exprs();
private:
/**
TRUE if the query contains an aggregate function but has no GROUP
BY clause.
*/
bool implicit_grouping;
bool make_simple_join(JOIN *join, TABLE *tmp_table);
void cleanup_item_list(List<Item> &items) const;
};
上一篇:静态链接库与动态链接库----C/C++


下一篇:MySQL优化器join顺序