diff options
Diffstat (limited to 'sql/sql_select.cc')
-rw-r--r-- | sql/sql_select.cc | 150 |
1 files changed, 115 insertions, 35 deletions
diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9dacb2c2ce4..27ffb491173 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -633,6 +633,18 @@ JOIN::prepare(Item ***rref_pointer_array, MYF(0)); /* purecov: inspected */ goto err; /* purecov: inspected */ } + if (thd->lex->derived_tables) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", + thd->lex->derived_tables & DERIVED_VIEW ? + "view" : "subquery"); + goto err; + } + if (thd->lex->sql_command != SQLCOM_SELECT) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "non-SELECT"); + goto err; + } } if (!procedure && result && result->prepare(fields_list, unit_arg)) @@ -644,8 +656,11 @@ JOIN::prepare(Item ***rref_pointer_array, this->group= group_list != 0; unit= unit_arg; + if (tmp_table_param.sum_func_count && !group_list) + implicit_grouping= TRUE; + #ifdef RESTRICTED_GROUP - if (sum_func_count && !group_list && (func_count || field_count)) + if (implicit_grouping) { my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0)); goto err; @@ -881,15 +896,23 @@ JOIN::optimize() } #endif - /* Optimize count(*), min() and max() */ - if (tables_list && tmp_table_param.sum_func_count && ! group_list) + /* + Try to optimize count(*), min() and max() to const fields if + there is implicit grouping (aggregate functions but no + group_list). In this case, the result set shall only contain one + row. + */ + if (tables_list && implicit_grouping) { int res; /* opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match to the WHERE conditions, - or 1 if all items were resolved, + or 1 if all items were resolved (optimized away), or 0, or an error number HA_ERR_... + + If all items were resolved by opt_sum_query, there is no need to + open any tables. */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { @@ -958,6 +981,12 @@ JOIN::optimize() DBUG_RETURN(1); } + if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields()) + { + DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); + DBUG_RETURN(1); + } + /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); thd_proc_info(thd, "preparing"); @@ -1088,7 +1117,7 @@ JOIN::optimize() join_tab[const_tables].select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) { - if (group_list && + if (group_list && rollup.state == ROLLUP::STATE_NONE && list_contains_unique_index(join_tab[const_tables].table, find_field_in_order_list, (void *) group_list)) @@ -1132,7 +1161,8 @@ JOIN::optimize() if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) select_distinct=0; } - else if (select_distinct && tables - const_tables == 1) + else if (select_distinct && tables - const_tables == 1 && + rollup.state == ROLLUP::STATE_NONE) { /* We are only using one table. In this case we change DISTINCT to a @@ -2024,7 +2054,8 @@ JOIN::exec() count_field_types(select_lex, &curr_join->tmp_table_param, *curr_all_fields, 0); - if (curr_join->group || curr_join->tmp_table_param.sum_func_count || + if (curr_join->group || curr_join->implicit_grouping || + curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { if (make_group_fields(this, curr_join)) @@ -3548,7 +3579,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) { if (!(form->keys_in_use_for_query.is_set(key))) continue; - if (form->key_info[key].flags & HA_FULLTEXT) + if (form->key_info[key].flags & (HA_FULLTEXT | HA_SPATIAL)) continue; // ToDo: ft-keys in non-ft queries. SerG uint key_parts= (uint) form->key_info[key].key_parts; @@ -8952,7 +8983,10 @@ static void restore_prev_nj_state(JOIN_TAB *last) join->cur_embedding_map&= ~last_emb->nested_join->nj_map; else if (last_emb->nested_join->join_list.elements-1 == last_emb->nested_join->counter) + { join->cur_embedding_map|= last_emb->nested_join->nj_map; + break; + } else break; last_emb= last_emb->embedding; @@ -10200,6 +10234,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, for (; cur_group ; cur_group= cur_group->next, key_part_info++) { Field *field=(*cur_group->item)->get_tmp_table_field(); + DBUG_ASSERT(field->table == table); bool maybe_null=(*cur_group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; @@ -10811,6 +10846,12 @@ Next_select_func setup_end_select_func(JOIN *join) } else { + /* + Choose method for presenting result to user. Use end_send_group + if the query requires grouping (has a GROUP BY clause and/or one or + more aggregate functions). Use end_send if the query should not + be grouped. + */ if ((join->sort_and_group || (join->procedure && join->procedure->flags & PROC_GROUP)) && !tmp_tbl->precomputed_group_by) @@ -11171,6 +11212,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, bool not_used_in_distinct=join_tab->not_used_in_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; + bool select_cond_result= TRUE; if (error > 0 || (join->thd->is_error())) // Fatal error return NESTED_LOOP_ERROR; @@ -11182,7 +11224,17 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_KILLED; /* purecov: inspected */ } DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); - if (!select_cond || select_cond->val_int()) + + if (select_cond) + { + select_cond_result= test(select_cond->val_int()); + + /* check for errors evaluating the condition */ + if (join->thd->is_error()) + return NESTED_LOOP_ERROR; + } + + if (!select_cond || select_cond_result) { /* There is no select condition or the attached pushed down @@ -15619,32 +15671,7 @@ bool JOIN::rollup_init() { item->maybe_null= 1; found_in_group= 1; - if (item->const_item()) - { - /* - For ROLLUP queries each constant item referenced in GROUP BY list - is wrapped up into an Item_func object yielding the same value - as the constant item. The objects of the wrapper class are never - considered as constant items and besides they inherit all - properties of the Item_result_field class. - This wrapping allows us to ensure writing constant items - into temporary tables whenever the result of the ROLLUP - operation has to be written into a temporary table, e.g. when - ROLLUP is used together with DISTINCT in the SELECT list. - Usually when creating temporary tables for a intermidiate - result we do not include fields for constant expressions. - */ - Item* new_item= new Item_func_rollup_const(item); - if (!new_item) - return 1; - new_item->fix_fields(thd, (Item **) 0); - thd->change_item_tree(it.ref(), new_item); - for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) - { - if (*tmp->item == item) - thd->change_item_tree(tmp->item, new_item); - } - } + break; } } if (item->type() == Item::FUNC_ITEM && !found_in_group) @@ -15663,6 +15690,59 @@ bool JOIN::rollup_init() } return 0; } + +/** + Wrap all constant Items in GROUP BY list. + + For ROLLUP queries each constant item referenced in GROUP BY list + is wrapped up into an Item_func object yielding the same value + as the constant item. The objects of the wrapper class are never + considered as constant items and besides they inherit all + properties of the Item_result_field class. + This wrapping allows us to ensure writing constant items + into temporary tables whenever the result of the ROLLUP + operation has to be written into a temporary table, e.g. when + ROLLUP is used together with DISTINCT in the SELECT list. + Usually when creating temporary tables for a intermidiate + result we do not include fields for constant expressions. + + @retval + 0 if ok + @retval + 1 on error +*/ + +bool JOIN::rollup_process_const_fields() +{ + ORDER *group_tmp; + Item *item; + List_iterator<Item> it(all_fields); + + for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) + { + if (!(*group_tmp->item)->const_item()) + continue; + while ((item= it++)) + { + if (*group_tmp->item == item) + { + Item* new_item= new Item_func_rollup_const(item); + if (!new_item) + return 1; + new_item->fix_fields(thd, (Item **) 0); + thd->change_item_tree(it.ref(), new_item); + for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) + { + if (*tmp->item == item) + thd->change_item_tree(tmp->item, new_item); + } + break; + } + } + it.rewind(); + } + return 0; +} /** |