diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 930 |
1 files changed, 578 insertions, 352 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5b8e2085982..50bea2376c3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -58,7 +58,7 @@ static bool make_simple_join(JOIN *join,TABLE *tmp_table); static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item); static void make_join_readinfo(JOIN *join,uint options); static void join_free(JOIN *join, bool full); -static bool only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables); +static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables); static void update_depend_map(JOIN *join); static void update_depend_map(JOIN *join, ORDER *order); static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond, @@ -140,8 +140,16 @@ static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables); static void calc_group_buffer(JOIN *join,ORDER *group); static bool alloc_group_fields(JOIN *join,ORDER *group); static bool make_sum_func_list(JOIN *join,List<Item> &fields); -static bool change_to_use_tmp_fields(List<Item> &func); -static bool change_refs_to_tmp_fields(THD *thd, List<Item> &func); +// Create list for using with tempory table +static bool change_to_use_tmp_fields(Item **ref_pointer_array, + List<Item> &new_list1, + List<Item> &new_list2, + uint elements, List<Item> &items); +// Create list for using with tempory table +static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, + List<Item> &new_list1, + List<Item> &new_list2, + uint elements, List<Item> &items); static void init_tmptable_sum_functions(Item_sum **func); static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table); static void copy_sum_funcs(Item_sum **func_ptr); @@ -164,17 +172,21 @@ int handle_select(THD *thd, LEX *lex, select_result *result) if (select_lex->next_select()) res=mysql_union(thd,lex,result); else - res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, - select_lex->item_list, - select_lex->where, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, - select_lex->having, - (ORDER*) lex->proc_list.first, - select_lex->options | thd->options, - result, &(lex->unit), &(lex->select_lex), 0); + res= mysql_select(thd, &select_lex->ref_pointer_array, + (TABLE_LIST*) select_lex->table_list.first, + select_lex->with_wild, select_lex->item_list, + select_lex->where, + select_lex->order_list.elements + + select_lex->group_list.elements, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) lex->proc_list.first, + select_lex->options | thd->options, + result, &(lex->unit), &(lex->select_lex), 0); if (res && result) result->abort(); + if (res || thd->net.report_error) { send_error(thd, 0, NullS); @@ -204,7 +216,8 @@ void fix_tables_pointers(SELECT_LEX *select_lex) /* Inline function to setup clauses without sum functions */ -inline int setup_without_group(THD *thd, TABLE_LIST *tables, +inline int setup_without_group(THD *thd, Item **ref_pointer_array, + TABLE_LIST *tables, List<Item> &fields, List<Item> &all_fields, COND **conds, @@ -213,10 +226,11 @@ inline int setup_without_group(THD *thd, TABLE_LIST *tables, { bool save_allow_sum_func= thd->allow_sum_func; thd->allow_sum_func= 0; - int res= (setup_conds(thd,tables, conds) || - setup_order(thd,tables, fields, all_fields, order) || - setup_group(thd,tables, fields, all_fields, group, - hidden_group_fields)); + int res= (setup_conds(thd, tables, conds) || + setup_order(thd, ref_pointer_array, tables, fields, all_fields, + order) || + setup_group(thd, ref_pointer_array, tables, fields, all_fields, + group, hidden_group_fields)); thd->allow_sum_func= save_allow_sum_func; return res; } @@ -232,8 +246,10 @@ inline int setup_without_group(THD *thd, TABLE_LIST *tables, 0 on success */ int -JOIN::prepare(TABLE_LIST *tables_init, - COND *conds_init, ORDER *order_init, ORDER *group_init, +JOIN::prepare(Item ***rref_pointer_array, + TABLE_LIST *tables_init, + uint wild_num, COND *conds_init, uint og_num, + ORDER *order_init, ORDER *group_init, Item *having_init, ORDER *proc_param_init, SELECT_LEX *select, SELECT_LEX_UNIT *unit, bool fake_select_lex) @@ -254,11 +270,19 @@ JOIN::prepare(TABLE_LIST *tables_init, /* Check that all tables, fields, conds and order are ok */ if (setup_tables(tables_list) || - setup_fields(thd,tables_list,fields_list,1,&all_fields,1) || - setup_without_group(thd, tables_list, fields_list, all_fields, - &conds, order, group_list, &hidden_group_fields)) + setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || + setup_ref_array(thd, rref_pointer_array, (fields_list.elements + + select_lex->with_sum_func + + og_num)) || + setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1, + &all_fields, 1) || + setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list, + all_fields, &conds, order, group_list, + &hidden_group_fields)) DBUG_RETURN(-1); /* purecov: inspected */ + ref_pointer_array= *rref_pointer_array; + if (having) { thd->where="having clause"; @@ -270,7 +294,7 @@ JOIN::prepare(TABLE_LIST *tables_init, if (having_fix_rc || thd->net.report_error) DBUG_RETURN(-1); /* purecov: inspected */ if (having->with_sum_func) - having->split_sum_func(all_fields); + having->split_sum_func(ref_pointer_array, all_fields); } if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ DBUG_RETURN(-1); @@ -303,7 +327,7 @@ JOIN::prepare(TABLE_LIST *tables_init, for (table=tables_list ; table ; table=table->next) tables++; } - procedure=setup_procedure(thd,proc_param,result,fields_list,&error); + procedure= setup_procedure(thd, proc_param, result, fields_list, &error); if (error) DBUG_RETURN(-1); /* purecov: inspected */ if (procedure) @@ -378,6 +402,9 @@ int JOIN::optimize() { DBUG_ENTER("JOIN::optimize"); + if (optimized) + DBUG_RETURN(0); + optimized= 1; #ifdef HAVE_REF_TO_FIELDS // Not done yet /* Add HAVING to WHERE if possible */ @@ -638,7 +665,7 @@ JOIN::optimize() we must add the removed reference to the select for the table. We only need to do this when we have a simple_order or simple_group as in other cases the join is done before the sort. - */ + */ if ((order || group_list) && join_tab[const_tables].type != JT_ALL && join_tab[const_tables].type != JT_FT && (order && simple_order || group_list && simple_group)) @@ -658,19 +685,117 @@ JOIN::optimize() { need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + + if (select_options & SELECT_DESCRIBE) + DBUG_RETURN(0); + + tmp_having= having; + having= 0; + + /* Perform FULLTEXT search before all regular searches */ + init_ftfuncs(thd, select_lex, test(order)); + /* Create a tmp table if distinct or if the sort is too complicated */ + if (need_tmp) + { + DBUG_PRINT("info",("Creating tmp table")); + thd->proc_info="Creating tmp table"; + + init_items_ref_array(); + + tmp_table_param.hidden_field_count= (all_fields.elements - + fields_list.elements); + if (!(exec_tmp_table1 = + create_tmp_table(thd, &tmp_table_param, all_fields, + ((!simple_group && !procedure && + !(test_flags & TEST_NO_KEY_GROUP)) ? + group_list : (ORDER*) 0), + group_list ? 0 : select_distinct, + group_list && simple_group, + select_options, + (order == 0 || skip_sort_order) ? select_limit : + HA_POS_ERROR))) + DBUG_RETURN(1); + + //thd->temporary_tables_should_be_free.push_front(exec_tmp_table1); + if (having && + (sort_and_group || (exec_tmp_table1->distinct && !group_list))) + having= tmp_having; + + /* if group or order on first table, sort first */ + if (group_list && simple_group) + { + DBUG_PRINT("info",("Sorting for group")); + thd->proc_info="Sorting for group"; + if (create_sort_index(thd, &join_tab[const_tables], group_list, + HA_POS_ERROR, HA_POS_ERROR) || + make_sum_func_list(this, all_fields) || + alloc_group_fields(this, group_list)) + DBUG_RETURN(1); + group_list=0; + } + else + { + if (make_sum_func_list(this, all_fields)) + DBUG_RETURN(1); + if (!group_list && ! exec_tmp_table1->distinct && order && simple_order) + { + DBUG_PRINT("info",("Sorting for order")); + thd->proc_info="Sorting for order"; + if (create_sort_index(thd, &join_tab[const_tables], order, + HA_POS_ERROR, HA_POS_ERROR)) + DBUG_RETURN(1); + order=0; + } + } + + /* + Optimize distinct when used on some of the tables + SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b + In this case we can stop scanning t2 when we have found one t1.a + */ + + if (exec_tmp_table1->distinct) + { + table_map used_tables= thd->used_tables; + JOIN_TAB *join_tab= this->join_tab+tables-1; + do + { + if (used_tables & join_tab->table->map) + break; + join_tab->not_used_in_distinct=1; + } while (join_tab-- != this->join_tab); + /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ + if (order && skip_sort_order) + { + /* Should always succeed */ + if (test_if_skip_sort_order(&this->join_tab[const_tables], + order, unit->select_limit_cnt, 0)) + order=0; + } + } + + if (select_lex != &thd->lex.select_lex && + select_lex->linkage != DERIVED_TABLE_TYPE) + { + if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN)))) + DBUG_RETURN(-1); + restore_tmp(); + } + } + DBUG_RETURN(0); } /* - Global optimization (with subselect) must be here (TODO) + Restore values in temporary join */ -int -JOIN::global_optimize() +void JOIN::restore_tmp() { - return 0; + memcpy(tmp_join, this, (size_t) sizeof(JOIN)); } + int JOIN::reinit() { @@ -695,6 +820,28 @@ JOIN::reinit() func->null_value= 1; } + if (exec_tmp_table1) + { + exec_tmp_table1->file->extra(HA_EXTRA_RESET_STATE); + exec_tmp_table1->file->delete_all_rows(); + free_io_cache(exec_tmp_table1); + memcpy(ref_pointer_array, items0, ref_pointer_array_size); + } + if (exec_tmp_table2) + { + exec_tmp_table2->file->extra(HA_EXTRA_RESET_STATE); + exec_tmp_table2->file->delete_all_rows(); + free_io_cache(exec_tmp_table2); + } + if (items0) + memcpy(ref_pointer_array, items0, ref_pointer_array_size); + + tmp_table_param.copy_funcs.empty(); + tmp_table_param.copy_field= tmp_table_param.copy_field_end= 0; + + if (tmp_join) + restore_tmp(); + DBUG_RETURN(0); } @@ -743,14 +890,11 @@ JOIN::exec() !group_list, select_options, zero_result_cause, - having,procedure, + having, procedure, unit); DBUG_VOID_RETURN; } - Item *having_list = having; - having = 0; - if (select_options & SELECT_DESCRIBE) { if (!order && !no_order) @@ -761,6 +905,7 @@ JOIN::exec() test_if_skip_sort_order(&join_tab[const_tables], order, select_limit, 0)))) order=0; + having= tmp_having; select_describe(this, need_tmp, order != 0 && !skip_sort_order, select_distinct); @@ -769,120 +914,85 @@ JOIN::exec() } /* Perform FULLTEXT search before all regular searches */ - init_ftfuncs(thd, select_lex, test(order)); + //init_ftfuncs(thd, select_lex, test(order)); + + JOIN *curr_join= this; + List<Item> *curr_all_fields= &all_fields; + List<Item> *curr_fields_list= &fields_list; + TABLE *curr_tmp_table= 0; /* Create a tmp table if distinct or if the sort is too complicated */ if (need_tmp) { - DBUG_PRINT("info",("Creating tmp table")); - thd->proc_info="Creating tmp table"; - - tmp_table_param.hidden_field_count= (all_fields.elements - - fields_list.elements); - if (!(exec_tmp_table = - create_tmp_table(thd, &tmp_table_param, all_fields, - ((!simple_group && !procedure && - !(test_flags & TEST_NO_KEY_GROUP)) ? - group_list : (ORDER*) 0), - group_list ? 0 : select_distinct, - group_list && simple_group, - select_options, - (order == 0 || skip_sort_order) ? select_limit : - HA_POS_ERROR))) - DBUG_VOID_RETURN; - - if (having_list && - (sort_and_group || (exec_tmp_table->distinct && !group_list))) - having=having_list; - - /* if group or order on first table, sort first */ - if (group_list && simple_group) - { - DBUG_PRINT("info",("Sorting for group")); - thd->proc_info="Sorting for group"; - if (create_sort_index(thd, &join_tab[const_tables], group_list, - HA_POS_ERROR, HA_POS_ERROR) || - make_sum_func_list(this, all_fields) || - alloc_group_fields(this, group_list)) - DBUG_VOID_RETURN; - group_list=0; - } - else - { - if (make_sum_func_list(this, all_fields)) - DBUG_VOID_RETURN; - if (!group_list && ! exec_tmp_table->distinct && order && simple_order) - { - DBUG_PRINT("info",("Sorting for order")); - thd->proc_info="Sorting for order"; - if (create_sort_index(thd, &join_tab[const_tables], order, - HA_POS_ERROR, HA_POS_ERROR)) - DBUG_VOID_RETURN; - order=0; - } - } - - /* - Optimize distinct when used on some of the tables - SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b - In this case we can stop scanning t2 when we have found one t1.a - */ - - if (exec_tmp_table->distinct) - { - table_map used_tables= thd->used_tables; - JOIN_TAB *join_tab= this->join_tab+tables-1; - do - { - if (used_tables & join_tab->table->map) - break; - join_tab->not_used_in_distinct=1; - } while (join_tab-- != this->join_tab); - /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ - if (order && skip_sort_order) - { - /* Should always succeed */ - if (test_if_skip_sort_order(&this->join_tab[const_tables], - order, unit->select_limit_cnt, 0)) - order=0; - } - } - + if (tmp_join) + curr_join= tmp_join; + curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ thd->proc_info= "Copying to tmp table"; - if ((tmp_error= do_select(this, (List<Item> *) 0, exec_tmp_table, 0))) + + if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0))) { error= tmp_error; DBUG_VOID_RETURN; } - if (having) - having= having_list= 0; // Allready done - + curr_tmp_table->file->info(HA_STATUS_VARIABLE); + + if (curr_join->having) + curr_join->having= curr_join->tmp_having= 0; // Allready done + /* Change sum_fields reference to calculated fields in tmp_table */ - if (sort_and_group || exec_tmp_table->group) + curr_join->all_fields= *curr_all_fields; + if (!items1) { - if (change_to_use_tmp_fields(all_fields)) - DBUG_VOID_RETURN; - tmp_table_param.field_count+= tmp_table_param.sum_func_count+ - tmp_table_param.func_count; - tmp_table_param.sum_func_count= tmp_table_param.func_count= 0; + items1= items0 + all_fields.elements; + if (sort_and_group || curr_tmp_table->group) + { + if (change_to_use_tmp_fields(items1, + tmp_fields_list1, tmp_all_fields1, + fields_list.elements, all_fields)) + DBUG_VOID_RETURN; + } + else + { + if (change_refs_to_tmp_fields(thd, items1, + tmp_fields_list1, tmp_all_fields1, + fields_list.elements, all_fields)) + DBUG_VOID_RETURN; + } + curr_join->tmp_all_fields1= tmp_all_fields1; + curr_join->tmp_fields_list1= tmp_fields_list1; + curr_join->items1= items1; + } + curr_all_fields= &tmp_all_fields1; + curr_fields_list= &tmp_fields_list1; + memcpy(ref_pointer_array, items1, ref_pointer_array_size); + + if (sort_and_group || curr_tmp_table->group) + { + curr_join->tmp_table_param.field_count+= + curr_join->tmp_table_param.sum_func_count+ + curr_join->tmp_table_param.func_count; + curr_join->tmp_table_param.sum_func_count= + curr_join->tmp_table_param.func_count= 0; } else { - if (change_refs_to_tmp_fields(thd,all_fields)) - DBUG_VOID_RETURN; - tmp_table_param.field_count+= tmp_table_param.func_count; - tmp_table_param.func_count= 0; + curr_join->tmp_table_param.field_count+= + curr_join->tmp_table_param.func_count; + curr_join->tmp_table_param.func_count= 0; } + + // procedure can't be used inside subselect => we do nothing special for it if (procedure) procedure->update_refs(); - if (exec_tmp_table->group) + + if (curr_tmp_table->group) { // Already grouped - if (!order && !no_order) - order= group_list; /* order by group */ - group_list= 0; + if (!curr_join->order && !curr_join->no_order) + curr_join->order= curr_join->group_list; /* order by group */ + curr_join->group_list= 0; } - + /* If we have different sort & group then we must sort the data by group and copy it to another tmp table @@ -891,142 +1001,199 @@ JOIN::exec() like SEC_TO_TIME(SUM(...)). */ - if (group_list && (!test_if_subpart(group_list,order) || - select_distinct) || - (select_distinct && - tmp_table_param.using_indirect_summary_function)) + if (curr_join->group_list && (!test_if_subpart(curr_join->group_list, + curr_join->order) || + curr_join->select_distinct) || + (curr_join->select_distinct && + curr_join->tmp_table_param.using_indirect_summary_function)) { /* Must copy to another table */ - TABLE *tmp_table2; DBUG_PRINT("info",("Creating group table")); - + /* Free first data from old join */ - join_free(this, 0); - if (make_simple_join(this, exec_tmp_table)) - DBUG_VOID_RETURN; - calc_group_buffer(this, group_list); - count_field_types(&tmp_table_param, all_fields, - select_distinct && !group_list); - tmp_table_param.hidden_field_count= (all_fields.elements- - fields_list.elements); - - /* group data to new table */ - if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields, - (ORDER*) 0, - select_distinct && !group_list, - 1, select_options, HA_POS_ERROR))) + join_free(curr_join, 0); + if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; + calc_group_buffer(curr_join, group_list); + count_field_types(&curr_join->tmp_table_param, curr_join->tmp_all_fields1, + curr_join->select_distinct && !curr_join->group_list); + curr_join->tmp_table_param.hidden_field_count= + (curr_join->tmp_all_fields1.elements- + curr_join->tmp_fields_list1.elements); + + + if (exec_tmp_table2) + curr_tmp_table= exec_tmp_table2; + else + { + /* group data to new table */ + if (!(curr_tmp_table= + exec_tmp_table2= create_tmp_table(thd, + &curr_join->tmp_table_param, + *curr_all_fields, + (ORDER*) 0, + curr_join->select_distinct && + !curr_join->group_list, + 1, curr_join->select_options, + HA_POS_ERROR))) + DBUG_VOID_RETURN; + //thd->temporary_tables_should_be_free.push_front(exec_tmp_table2); + curr_join->exec_tmp_table2= exec_tmp_table2; + } if (group_list) { - thd->proc_info="Creating sort index"; - if (create_sort_index(thd, join_tab, group_list, HA_POS_ERROR, - HA_POS_ERROR) || - alloc_group_fields(this, group_list)) + thd->proc_info= "Creating sort index"; + if (create_sort_index(thd, curr_join->join_tab, curr_join->group_list, + HA_POS_ERROR, HA_POS_ERROR) || + alloc_group_fields(curr_join, curr_join->group_list)) { - free_tmp_table(thd,tmp_table2); /* purecov: inspected */ DBUG_VOID_RETURN; } - group_list= 0; + curr_join->group_list= 0; } + thd->proc_info="Copying to group table"; tmp_error= -1; - if (make_sum_func_list(this, all_fields) || - (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0))) + if (make_sum_func_list(curr_join, *curr_all_fields) || + (tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, + 0))) { - error=tmp_error; - free_tmp_table(thd,tmp_table2); + error= tmp_error; DBUG_VOID_RETURN; } - end_read_record(&join_tab->read_record); - free_tmp_table(thd,exec_tmp_table); - const_tables= tables; // Mark free for join_free() - exec_tmp_table= tmp_table2; - join_tab[0].table= 0; // Table is freed - - if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore - DBUG_VOID_RETURN; - tmp_table_param.field_count+= tmp_table_param.sum_func_count; - tmp_table_param.sum_func_count= 0; - } - - if (exec_tmp_table->distinct) - select_distinct=0; /* Each row is unique */ - - join_free(this, 0); /* Free quick selects */ + end_read_record(&curr_join->join_tab->read_record); + curr_join->const_tables= curr_join->tables; // Mark free for join_free() + curr_join->join_tab[0].table= 0; // Table is freed + + // No sum funcs anymore + if (!items2) + { + items2= items1 + all_fields.elements; + if (change_to_use_tmp_fields(items2, + tmp_fields_list2, tmp_all_fields2, + fields_list.elements, tmp_all_fields1)) + DBUG_VOID_RETURN; + curr_join->tmp_fields_list2= tmp_fields_list2; + curr_join->tmp_all_fields2= tmp_all_fields2; + } + curr_fields_list= &curr_join->tmp_fields_list2; + curr_all_fields= &curr_join->tmp_all_fields2; + memcpy(ref_pointer_array, items2, ref_pointer_array_size); + curr_join->tmp_table_param.field_count+= + curr_join->tmp_table_param.sum_func_count; + curr_join->tmp_table_param.sum_func_count= 0; + } + if (curr_tmp_table->distinct) + curr_join->select_distinct=0; /* Each row is unique */ + + join_free(curr_join, 0); /* Free quick selects */ if (select_distinct && ! group_list) { thd->proc_info="Removing duplicates"; - if (having_list) - having_list->update_used_tables(); - if (remove_duplicates(this, exec_tmp_table, fields_list, having_list)) + if (curr_join->tmp_having) + curr_join->tmp_having->update_used_tables(); + if (remove_duplicates(curr_join, curr_tmp_table, + curr_join->fields_list, curr_join->tmp_having)) DBUG_VOID_RETURN; - having_list=0; - select_distinct=0; + curr_join->tmp_having=0; + curr_join->select_distinct=0; } - exec_tmp_table->reginfo.lock_type=TL_UNLOCK; - if (make_simple_join(this, exec_tmp_table)) + curr_tmp_table->reginfo.lock_type= TL_UNLOCK; + if (make_simple_join(curr_join, curr_tmp_table)) DBUG_VOID_RETURN; - calc_group_buffer(this, group_list); - count_field_types(&tmp_table_param, all_fields, 0); + calc_group_buffer(curr_join, curr_join->group_list); + count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0); + } if (procedure) { - if (procedure->change_columns(fields_list) || - result->prepare(fields_list, unit)) + if (procedure->change_columns(*curr_fields_list) || + result->prepare(*curr_fields_list, unit)) DBUG_VOID_RETURN; - count_field_types(&tmp_table_param, all_fields, 0); + count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0); } - if (group || tmp_table_param.sum_func_count || + + if (curr_join->group || curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { - alloc_group_fields(this, group_list); - setup_copy_fields(thd, &tmp_table_param,all_fields); - if (make_sum_func_list(this, all_fields) || thd->fatal_error) + alloc_group_fields(curr_join, curr_join->group_list); + if (!items3) + { + if (!items0) + init_items_ref_array(); + items3= ref_pointer_array + (all_fields.elements*4); + setup_copy_fields(thd, &curr_join->tmp_table_param, + items3, tmp_fields_list3, tmp_all_fields3, + curr_fields_list->elements, *curr_all_fields); + tmp_table_param.save_copy_funcs= curr_join->tmp_table_param.copy_funcs; + tmp_table_param.save_copy_field= curr_join->tmp_table_param.copy_field; + tmp_table_param.save_copy_field_end= + curr_join->tmp_table_param.copy_field_end; + curr_join->tmp_all_fields3= tmp_all_fields3; + curr_join->tmp_fields_list3= tmp_fields_list3; + } + else + { + curr_join->tmp_table_param.copy_funcs= tmp_table_param.save_copy_funcs; + curr_join->tmp_table_param.copy_field= tmp_table_param.save_copy_field; + curr_join->tmp_table_param.copy_field_end= + tmp_table_param.save_copy_field_end; + } + curr_fields_list= &tmp_fields_list3; + curr_all_fields= &tmp_all_fields3; + memcpy(ref_pointer_array, items3, ref_pointer_array_size); + + if (make_sum_func_list(curr_join, *curr_all_fields) || + thd->fatal_error) DBUG_VOID_RETURN; } - if (group_list || order) + if (curr_join->group_list || curr_join->order) { DBUG_PRINT("info",("Sorting for send_fields")); thd->proc_info="Sorting result"; /* If we have already done the group, add HAVING to sorted table */ - if (having_list && ! group_list && ! sort_and_group) + if (curr_join->tmp_having && ! curr_join->group_list && + ! curr_join->sort_and_group) { - having_list->update_used_tables(); // Some tables may have been const - JOIN_TAB *table= &join_tab[const_tables]; - table_map used_tables= const_table_map | table->table->map; + // Some tables may have been const + curr_join->tmp_having->update_used_tables(); + JOIN_TAB *table= &curr_join->join_tab[const_tables]; + table_map used_tables= curr_join->const_table_map | table->table->map; - Item* sort_table_cond= make_cond_for_table(having_list, used_tables, + Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having, + used_tables, used_tables); if (sort_table_cond) { if (!table->select) - if (!(table->select=new SQL_SELECT)) + if (!(table->select= new SQL_SELECT)) DBUG_VOID_RETURN; if (!table->select->cond) - table->select->cond=sort_table_cond; + table->select->cond= sort_table_cond; else // This should never happen - if (!(table->select->cond=new Item_cond_and(table->select->cond, - sort_table_cond))) + if (!(table->select->cond= new Item_cond_and(table->select->cond, + sort_table_cond))) DBUG_VOID_RETURN; table->select_cond=table->select->cond; table->select_cond->top_level_item(); DBUG_EXECUTE("where",print_where(table->select->cond, "select and having");); - having_list= make_cond_for_table(having_list, ~ (table_map) 0, - ~used_tables); + curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having, + ~ (table_map) 0, + ~used_tables); DBUG_EXECUTE("where",print_where(conds,"having after sort");); } } { if (group) - select_limit= HA_POS_ERROR; + curr_join->select_limit= HA_POS_ERROR; else { /* We can abort sorting after thd->select_limit rows if we there is no WHERE clause for any tables after the sorted one. */ - JOIN_TAB *table= &join_tab[const_tables+1]; - JOIN_TAB *end_table= &join_tab[tables]; + JOIN_TAB *table= &curr_join->join_tab[const_tables+1]; + JOIN_TAB *end_table= &curr_join->join_tab[tables]; for (; table < end_table ; table++) { /* @@ -1038,21 +1205,22 @@ JOIN::exec() if (table->select_cond || (table->keyuse && !table->on_expr)) { /* We have to sort all rows */ - select_limit= HA_POS_ERROR; + curr_join->select_limit= HA_POS_ERROR; break; } } } - if (create_sort_index(thd, &join_tab[const_tables], - group_list ? group_list : order, - select_limit, unit->select_limit_cnt)) - DBUG_VOID_RETURN; + if (create_sort_index(thd, &curr_join->join_tab[curr_join->const_tables], + curr_join->group_list ? + curr_join->group_list : curr_join->order, + curr_join->select_limit, unit->select_limit_cnt)) + DBUG_VOID_RETURN; } } - having=having_list; // Actually a parameter + curr_join->having= curr_join->tmp_having; thd->proc_info="Sending data"; error= thd->net.report_error || - do_select(this, &fields_list, NULL, procedure); + do_select(curr_join, curr_fields_list, NULL, procedure); DBUG_VOID_RETURN; } @@ -1065,10 +1233,18 @@ JOIN::cleanup(THD *thd) { DBUG_ENTER("JOIN::cleanup"); + select_lex->join= 0; + + if (tmp_join) + memcpy(this, tmp_join, sizeof(tmp_join)); + + lock=0; // It's faster to unlock later join_free(this, 1); - if (exec_tmp_table) - free_tmp_table(thd, exec_tmp_table); + if (exec_tmp_table1) + free_tmp_table(thd, exec_tmp_table1); + if (exec_tmp_table2) + free_tmp_table(thd, exec_tmp_table2); delete select; delete_dynamic(&keyuse); delete procedure; @@ -1076,18 +1252,7 @@ JOIN::cleanup(THD *thd) unit != 0; unit= unit->next_unit()) { - for (SELECT_LEX *sl= unit->first_select(); - sl != 0; - sl= sl->next_select()) - { - if (sl->join) - { - int err= sl->join->cleanup(thd); - if (err) - error= err; - sl->join= 0; - } - } + error|= unit->cleanup(); } DBUG_RETURN(error); } @@ -1111,11 +1276,12 @@ bool JOIN::check_loop(uint id) } int -mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, - ORDER *order, ORDER *group,Item *having, ORDER *proc_param, - ulong select_options, select_result *result, - SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, - bool fake_select_lex) +mysql_select(THD *thd, Item ***rref_pointer_array, + TABLE_LIST *tables, uint wild_num, List<Item> &fields, + COND *conds, uint og_num, ORDER *order, ORDER *group, + Item *having, ORDER *proc_param, ulong select_options, + select_result *result, SELECT_LEX_UNIT *unit, + SELECT_LEX *select_lex, bool fake_select_lex) { int err; bool free_join= 1; @@ -1140,7 +1306,8 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, thd->proc_info="init"; thd->used_tables=0; // Updated by setup_fields - if (join->prepare(tables, conds, order, group, having, proc_param, + if (join->prepare(rref_pointer_array, tables, wild_num, + conds, og_num, order, group, having, proc_param, select_lex, unit, fake_select_lex)) { DBUG_RETURN(-1); @@ -1172,7 +1339,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, goto err; // 1 } - if (thd->net.report_error || (free_join && join->global_optimize())) + if (thd->net.report_error) goto err; join->exec(); @@ -1180,10 +1347,14 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, err: if (free_join) { - thd->limit_found_rows = join->send_records; - thd->examined_row_count = join->examined_rows; + JOIN *curr_join= (join->need_tmp&&join->tmp_join? + (join->tmp_join->error=join->error,join->tmp_join): + join); + + thd->limit_found_rows= curr_join->send_records; + thd->examined_row_count= curr_join->examined_rows; thd->proc_info="end"; - err= (fake_select_lex ? join->error : join->cleanup(thd)); + err= (fake_select_lex ? curr_join->error : join->cleanup(thd)); if (thd->net.report_error) err= -1; delete join; @@ -3068,6 +3239,7 @@ join_free(JOIN *join, bool full) delete tab->select; delete tab->quick; x_free(tab->cache.buff); + tab->cache.buff= 0; if (tab->table) { if (tab->table->key_read) @@ -3094,9 +3266,12 @@ join_free(JOIN *join, bool full) mysql_unlock_read_tables(join->thd, join->lock);// Don't free join->lock join->lock=0; } - join->group_fields.delete_elements(); - join->tmp_table_param.copy_funcs.delete_elements(); - join->tmp_table_param.cleanup(); + if (full) + { + join->group_fields.delete_elements(); + join->tmp_table_param.copy_funcs.delete_elements(); + join->tmp_table_param.cleanup(); + } DBUG_VOID_RETURN; } @@ -4124,9 +4299,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, { uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1); table->rec_buff_length=alloc_length; - if (!(table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME)))) + byte * t; + if (!(t= table->record[0]= (byte *) my_malloc(alloc_length*3, MYF(MY_WME)))) goto err; - table->record[1]= table->record[0]+alloc_length; + table->record[1]= t+alloc_length; + //table->record[1]= table->record[0]+alloc_length; table->record[2]= table->record[1]+alloc_length; } copy_func[0]=0; // End marker @@ -6752,31 +6929,32 @@ cp_buffer_from_ref(TABLE_REF *ref) */ static int -find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, +find_order_in_list(THD *thd, Item **ref_pointer_array, + TABLE_LIST *tables,ORDER *order, List<Item> &fields, List<Item> &all_fields) { if ((*order->item)->type() == Item::INT_ITEM) { /* Order by position */ Item *item=0; - List_iterator<Item> li(fields); - for (uint count= (uint) ((Item_int*) (*order->item))->value ; - count-- && (item=li++) ;) ; - if (!item) + uint count= (uint) ((Item_int*) (*order->item))->value; + if (count > fields.elements) { my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR), MYF(0),(*order->item)->full_name(), thd->where); return 1; } - order->item=li.ref(); - order->in_field_list=1; + order->item= ref_pointer_array + count-1; + order->in_field_list= 1; return 0; } - Item **item= find_item_in_list(*order->item, fields, IGNORE_ERRORS); + uint counter= 0; + Item **item= find_item_in_list(*order->item, fields, &counter, + IGNORE_ERRORS); if (item) { - order->item=item; // use it + order->item= ref_pointer_array + counter-1; order->in_field_list=1; return 0; } @@ -6785,24 +6963,43 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, if (it->check_cols(1) || it->fix_fields(thd, tables, order->item) || thd->fatal_error) return 1; // Wrong field - all_fields.push_front(*order->item); // Add new field to field list - order->item=(Item**) all_fields.head_ref(); + uint el= all_fields.elements; + all_fields.push_front(it); // Add new field to field list + ref_pointer_array[el]= it; + order->item= ref_pointer_array + el; return 0; } +/* + Allocate array of references to address all_fileds list elements +*/ + +int setup_ref_array(THD* thd, Item ***rref_pointer_array, uint elements) +{ + if (*rref_pointer_array) + return 0; + + /* TODO: may be better allocate only one and all other on demand? */ + if (!(*rref_pointer_array= + (Item **)thd->alloc(sizeof(Item*) * elements * 5))) + return -1; + else + return 0; +} /* Change order to point at item in select list. If item isn't a number and doesn't exits in the select list, add it the the field list. */ -int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields, ORDER *order) +int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List<Item> &all_fields, ORDER *order) { thd->where="order clause"; for (; order; order=order->next) { - if (find_order_in_list(thd,tables,order,fields,all_fields)) + if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, + all_fields)) return 1; } return 0; @@ -6810,8 +7007,9 @@ int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields, int -setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields, ORDER *order, bool *hidden_group_fields) +setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, + List<Item> &fields, List<Item> &all_fields, ORDER *order, + bool *hidden_group_fields) { *hidden_group_fields=0; if (!order) @@ -6829,7 +7027,8 @@ setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, thd->where="group statement"; for (; order; order=order->next) { - if (find_order_in_list(thd,tables,order,fields,all_fields)) + if (find_order_in_list(thd, ref_pointer_array, tables, order, fields, + all_fields)) return 1; (*order->item)->marker=1; /* Mark found */ if ((*order->item)->with_sum_func) @@ -6873,9 +7072,11 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, DBUG_ENTER("setup_new_fields"); thd->set_query_id=1; // Not really needed, but... + uint counter= 0; for (; new_field ; new_field= new_field->next) { - if ((item= find_item_in_list(*new_field->item, fields, IGNORE_ERRORS))) + if ((item= find_item_in_list(*new_field->item, fields, &counter, + IGNORE_ERRORS))) new_field->item=item; /* Change to shared Item */ else { @@ -7126,41 +7327,55 @@ test_if_group_changed(List<Item_buff> &list) */ bool -setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields) +setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, + Item **ref_pointer_array, + List<Item> &new_list1, List<Item> &new_list2, + uint elements, List<Item> &fields) { Item *pos; - List_iterator<Item> li(fields); + List_iterator_fast<Item> li(fields); Copy_field *copy; DBUG_ENTER("setup_copy_fields"); + new_list1.empty(); + new_list2.empty(); + List_iterator_fast<Item> itr(new_list2); + + uint i, border= fields.elements - elements; if (!(copy=param->copy_field= new Copy_field[param->field_count])) goto err2; param->copy_funcs.empty(); - while ((pos=li++)) + for (i= 0; (pos= li++); i++) { if (pos->type() == Item::FIELD_ITEM) { - Item_field *item=(Item_field*) pos; + Item_field *item; + if (!(item= new Item_field(*((Item_field*) pos)))) + goto err; + pos= item; if (item->field->flags & BLOB_FLAG) { - if (!(pos=new Item_copy_string(pos))) + if (!(pos= new Item_copy_string(pos))) goto err; - VOID(li.replace(pos)); if (param->copy_funcs.push_back(pos)) goto err; - continue; } - - /* set up save buffer and change result_field to point at saved value */ - Field *field= item->field; - item->result_field=field->new_field(&thd->mem_root,field->table); - char *tmp=(char*) sql_alloc(field->pack_length()+1); - if (!tmp) - goto err; - copy->set(tmp, item->result_field); - item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1); - copy++; + else + { + /* + set up save buffer and change result_field to point at + saved value + */ + Field *field= item->field; + item->result_field=field->new_field(&thd->mem_root,field->table); + char *tmp=(char*) sql_alloc(field->pack_length()+1); + if (!tmp) + goto err; + copy->set(tmp, item->result_field); + item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1); + copy++; + } } else if ((pos->type() == Item::FUNC_ITEM || pos->type() == Item::COND_ITEM) && @@ -7174,12 +7389,18 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields) */ if (!(pos=new Item_copy_string(pos))) goto err; - VOID(li.replace(pos)); if (param->copy_funcs.push_back(pos)) goto err; } + new_list2.push_back(pos); + ref_pointer_array[((i < border)? fields.elements-i-1 : i-border)]= + pos; } param->copy_field_end= copy; + + for (i= 0; i < border; i++) + itr++; + itr.sublist(new_list1, elements); DBUG_RETURN(0); err: @@ -7244,51 +7465,63 @@ make_sum_func_list(JOIN *join,List<Item> &fields) /* - Change all funcs and sum_funcs to fields in tmp table + Change all funcs and sum_funcs to fields in tmp table, and create + new list of all items */ static bool -change_to_use_tmp_fields(List<Item> &items) +change_to_use_tmp_fields(Item **ref_pointer_array, + List<Item> &new_list1, List<Item> &new_list2, + uint elements, List<Item> &items) { - List_iterator<Item> it(items); + List_iterator_fast<Item> it(items); Item *item_field,*item; + new_list1.empty(); + new_list2.empty(); - while ((item=it++)) + uint i, border= items.elements - elements; + for (i= 0; (item= it++); i++) { Field *field; + if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) - continue; - if (item->type() == Item::FIELD_ITEM) - { - ((Item_field*) item)->field= - ((Item_field*) item)->result_field; - } - else if ((field=item->tmp_table_field())) - { - if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) - item_field=((Item_sum*) item)->result_item(field); - else - item_field=(Item*) new Item_field(field); - if (!item_field) - return TRUE; // Fatal error - item_field->name=item->name; /*lint -e613 */ -#ifndef DBUG_OFF - if (_db_on_ && !item_field->name) + item_field= item; + else + if (item->type() == Item::FIELD_ITEM) { - char buff[256]; - String str(buff,sizeof(buff),default_charset_info); - str.length(0); - item->print(&str); - item_field->name=sql_strmake(str.ptr(),str.length()); + item_field= item->get_tmp_table_item(); } + else if ((field= item->tmp_table_field())) + { + if (item->type() == Item::SUM_FUNC_ITEM && field->table->group) + item_field= ((Item_sum*) item)->result_item(field); + else + item_field= (Item*) new Item_field(field); + if (!item_field) + return TRUE; // Fatal error + item_field->name= item->name; /*lint -e613 */ +#ifndef DBUG_OFF + if (_db_on_ && !item_field->name) + { + char buff[256]; + String str(buff,sizeof(buff),default_charset_info); + str.length(0); + item->print(&str); + item_field->name= sql_strmake(str.ptr(),str.length()); + } #endif -#ifdef DELETE_ITEMS - delete it.replace(item_field); /*lint -e613 */ -#else - (void) it.replace(item_field); /*lint -e613 */ -#endif - } + } + else + item_field= item; + new_list2.push_back(item_field); + ref_pointer_array[((i < border)? items.elements-i-1 : i-border)]= + item_field; } + + List_iterator_fast<Item> itr(new_list2); + for (i= 0; i < border; i++) + itr++; + itr.sublist(new_list1, elements); return FALSE; } @@ -7299,52 +7532,29 @@ change_to_use_tmp_fields(List<Item> &items) */ static bool -change_refs_to_tmp_fields(THD *thd,List<Item> &items) +change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, + List<Item> &new_list1, + List<Item> &new_list2, uint elements, + List<Item> &items) { - List_iterator<Item> it(items); - Item *item; + List_iterator_fast<Item> it(items); + Item *item, *new_item; + new_list1.empty(); + new_list2.empty(); - while ((item= it++)) + uint i, border= items.elements - elements; + for (i= 0; (item= it++); i++) { - if (item->type() == Item::SUM_FUNC_ITEM) - { - if (!item->const_item()) - { - Item_sum *sum_item= (Item_sum*) item; - if (sum_item->result_field) // If not a const sum func - { - Field *result_field=sum_item->result_field; - for (uint i=0 ; i < sum_item->arg_count ; i++) - { - Item *arg= sum_item->args[i]; - if (!arg->const_item()) - { - if (arg->type() == Item::FIELD_ITEM) - ((Item_field*) arg)->field= result_field++; - else - sum_item->args[i]= new Item_field(result_field++); - } - } - } - } - } - else if (item->with_sum_func) - continue; - else if ((item->type() == Item::FUNC_ITEM || - item->type() == Item::COND_ITEM) && - !item->const_item()) - { /* All funcs are stored */ -#ifdef DELETE_ITEMS - delete it.replace(new Item_field(((Item_func*) item)->result_field)); -#else - (void) it.replace(new Item_field(((Item_func*) item)->result_field)); -#endif - } - else if (item->type() == Item::FIELD_ITEM) /* Change refs */ - { - ((Item_field*)item)->field=((Item_field*) item)->result_field; - } + new_list2.push_back(new_item= item->get_tmp_table_item()); + ref_pointer_array[((i < border)? items.elements-i-1 : i-border)]= + new_item; } + + List_iterator_fast<Item> itr(new_list2); + for (i= 0; i < border; i++) + itr++; + itr.sublist(new_list1, elements); + return thd->fatal_error; } @@ -7683,9 +7893,12 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, select_lex->type= type; thd->lex.current_select= select_lex; SELECT_LEX_UNIT *unit= select_lex->master_unit(); - int res= mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, - select_lex->item_list, + int res= mysql_select(thd, &select_lex->ref_pointer_array, + (TABLE_LIST*) select_lex->table_list.first, + select_lex->with_wild, select_lex->item_list, select_lex->where, + select_lex->order_list.elements + + select_lex->group_list.elements, (ORDER*) select_lex->order_list.first, (ORDER*) select_lex->group_list.first, select_lex->having, @@ -7694,4 +7907,17 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, result, unit, select_lex, 0); DBUG_RETURN(res); } + +/* +*/ + +void free_ulderlayed_joins(THD *thd, SELECT_LEX *select) +{ + for (SELECT_LEX_UNIT *unit= select->first_inner_unit(); + unit; + unit= unit->next_unit()) + unit->cleanup(); +} + + |