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+1],best_positions[MAX_TABLES+1]; /* * 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[1]; // 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= 0; all_tables= 0; tables= 0; const_tables= 0; join_list= 0; implicit_grouping= FALSE; sort_and_group= 0; first_record= 0; do_send_rows= 1; send_records= 0; found_records= 0; fetch_limit= HA_POS_ERROR; examined_rows= 0; exec_tmp_table1= 0; exec_tmp_table2= 0; sortorder= 0; table_reexec[0]= 0; join_tab_reexec= 0; thd= thd_arg; sum_funcs= sum_funcs2= 0; procedure= 0; having= tmp_having= having_history= 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*/ error= 0; select= 0; return_tab= 0; ref_pointer_array= items0= items1= items2= items3= 0; ref_pointer_array_size= 0; zero_result_cause= 0; optimized= 0; cond_equal= 0; group_optimized_away= 0; 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 != 0 && !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 == 0 || 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; };