diff options
author | unknown <igor@rurik.mysql.com> | 2005-10-15 14:32:37 -0700 |
---|---|---|
committer | unknown <igor@rurik.mysql.com> | 2005-10-15 14:32:37 -0700 |
commit | 6a0695fe9329a61df182c8714c4b1cdeceac07bc (patch) | |
tree | 5f5c67db9ee4935287f4852c5bc05fcc067ce082 /sql/item_sum.cc | |
parent | 11541107b83d8e361722dff601192bd7d7f70ca9 (diff) | |
download | mariadb-git-6a0695fe9329a61df182c8714c4b1cdeceac07bc.tar.gz |
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
mysql-test/r/func_gconcat.result:
Changed a query when fixing bug #12762.
mysql-test/r/subselect.result:
Added test cases for bug #12762.
Allowed set functions aggregated in outer subqueries. Allowed nested set functions.
mysql-test/t/func_gconcat.test:
Changed a query when fixing bug #12762.
mysql-test/t/subselect.test:
Added test cases for bug #12762.
Allowed set functions aggregated in outer subqueries. Allowed nested set functions.
sql/item.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added a parameter to Item::split_sum_func2 aliowing to defer splitting for set functions
aggregated in outer subquries.
Changed Item_field::fix_fields to calculate attributes used when checking context conditions
for set functions.
Allowed alliases for set functions defined in outer subqueries.
sql/item.h:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added a parameter to Item::split_sum_func2 aliowing to defer splitting for set functions
aggregated in outer subquries.
sql/item_cmpfunc.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added a parameter to Item::split_sum_func2 aliowing to defer splitting for set functions
aggregated in outer subquries.
sql/item_func.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added a parameter to Item::split_sum_func2 aliowing to defer splitting for set functions
aggregated in outer subquries.
sql/item_row.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added a parameter to Item::split_sum_func2 aliowing to defer splitting for set functions
aggregated in outer subquries.
sql/item_strfunc.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added a parameter to Item::split_sum_func2 aliowing to defer splitting for set functions
aggregated in outer subquries.
sql/item_subselect.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced next levels for subqueries and a bitmap of nesting levels showing
in what subqueries a set function can be aggregated.
sql/item_sum.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added Item_sum methods to check context conditions imposed on set functions.
sql/item_sum.h:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Added Item_sum methods to check context conditions imposed on set functions.
sql/mysql_priv.h:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced a type of bitmaps to be used for nesting constructs.
sql/sql_base.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced next levels for subqueries and a bitmap of nesting levels showing
in what subqueries a set function can be aggregated.
sql/sql_class.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced a bitmap of nesting levels showing in what subqueries a set function can be aggregated.
sql/sql_class.h:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced a bitmap of nesting levels showing in what subqueries a set function can be aggregated.
sql/sql_delete.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced a bitmap of nesting levels showing in what subqueries a set function can be aggregated.
sql/sql_lex.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced next levels for subqueries and a bitmap of nesting levels showing
in what subqueries a set function can be aggregated.
sql/sql_lex.h:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced next levels for subqueries and a bitmap of nesting levels showing
in what subqueries a set function can be aggregated.
sql/sql_parse.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced next levels for subqueries.
sql/sql_prepare.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced a bitmap of nesting levels showingin what subqueries a set function can be aggregated.
sql/sql_select.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced next levels for subqueries and a bitmap of nesting levels showing
in what subqueries a set function can be aggregated.
sql/sql_update.cc:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced a bitmap of nesting levels showing in what subqueries a set function can be aggregated.
sql/sql_yacc.yy:
Fixed bug #12762:
allowed set functions aggregated in outer subqueries, allowed nested set functions.
Introduced next levels for subqueries.
Diffstat (limited to 'sql/item_sum.cc')
-rw-r--r-- | sql/item_sum.cc | 266 |
1 files changed, 245 insertions, 21 deletions
diff --git a/sql/item_sum.cc b/sql/item_sum.cc index b56d99cf245..85b2888712d 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -24,6 +24,234 @@ #include "mysql_priv.h" #include "sql_select.h" +/* + Prepare an aggregate function item for checking context conditions + + SYNOPSIS + init_sum_func_check() + thd reference to the thread context info + + DESCRIPTION + The function initializes the members of the Item_sum object created + for a set function that are used to check validity of the set function + occurrence. + If the set function is not allowed in any subquery where it occurs + an error is reported immediately. + + NOTES + This function is to be called for any item created for a set function + object when the traversal of trees built for expressions used in the query + is performed at the phase of context analysis. This function is to + be invoked at the descent of this traversal. + + RETURN + TRUE if an error is reported + FALSE otherwise +*/ + +bool Item_sum::init_sum_func_check(THD *thd) +{ + if (!thd->lex->allow_sum_func) + { + my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), + MYF(0)); + return TRUE; + } + /* Set a reference to the nesting set function if there is any */ + in_sum_func= thd->lex->in_sum_func; + /* Save a pointer to object to be used in items for nested set functions */ + thd->lex->in_sum_func= this; + nest_level= thd->lex->current_select->nest_level; + ref_by= 0; + aggr_level= -1; + max_arg_level= -1; + max_sum_func_level= -1; + return FALSE; +} + +/* + Check constraints imposed on a usage of a set function + + SYNOPSIS + check_sum_func() + thd reference to the thread context info + ref location of the pointer to this item in the embedding expression + + DESCRIPTION + The method verifies whether context conditions imposed on a usage + of any set function are met for this occurrence. + It checks whether the set function occurs in the position where it + can be aggregated and, when it happens to occur in argument of another + set function, the method checks that these two functions are aggregated in + different subqueries. + If the context conditions are not met the method reports an error. + If the set function is aggregated in some outer subquery the method + adds it to the chain of items for such set functions that is attached + to the the st_select_lex structure for this subquery. + + NOTES + This function is to be called for any item created for a set function + object when the traversal of trees built for expressions used in the query + is performed at the phase of context analysis. This function is to + be invoked at the ascent of this traversal. + + IMPLEMENTATION + A number of designated members of the object are used to check the + conditions. They are specified in the comment before the Item_sum + class declaration. + Additionally a bitmap variable called allow_sum_func is employed. + It is included into the thd->lex structure. + The bitmap contains 1 at n-th position if the set function happens + to occur under a construct of the n-th level subquery where usage + of set functions are allowed (i.e either in the SELECT list or + in the HAVING clause of the corresponding subquery) + Consider the query: + SELECT SUM(t1.b) FROM t1 GROUP BY t1.a + HAVING t1.a IN (SELECT t2.c FROM t2 WHERE AVG(t1.b) > 20) AND + t1.a > (SELECT MIN(t2.d) FROM t2); + allow_sum_func will contain: + for SUM(t1.b) - 1 at the first position + for AVG(t1.b) - 1 at the first position, 0 at the second position + for MIN(t2.d) - 1 at the first position, 1 at the second position. + + RETURN + TRUE if an error is reported + FALSE otherwise +*/ + +bool Item_sum::check_sum_func(THD *thd, Item **ref) +{ + bool invalid= FALSE; + nesting_map allow_sum_func= thd->lex->allow_sum_func; + /* + The value of max_arg_level is updated if an argument of the set function + contains a column reference resolved against a subquery whose level is + greater than the current value of max_arg_level. + max_arg_level cannot be greater than nest level. + nest level is always >= 0 + */ + if (nest_level == max_arg_level) + { + /* + The function must be aggregated in the current subquery, + If it is there under a construct where it is not allowed + we report an error. + */ + invalid= !(allow_sum_func & (1 << max_arg_level)); + } + else if (max_arg_level >= 0 || !(allow_sum_func & (1 << nest_level))) + { + /* + The set function can be aggregated only in outer subqueries. + Try to find a subquery where it can be aggregated; + If we fail to find such a subquery report an error. + */ + if (register_sum_func(thd, ref)) + return TRUE; + invalid= aggr_level < 0 && !(allow_sum_func & (1 << nest_level)); + } + if (!invalid && aggr_level < 0) + aggr_level= nest_level; + /* + By this moment we either found a subquery where the set function is + to be aggregated and assigned a value that is >= 0 to aggr_level, + or set the value of 'invalid' to TRUE to report later an error. + */ + /* + Additionally we have to check whether possible nested set functions + are acceptable here: they are not, if the level of aggregation of + some of them is less than aggr_level. + */ + invalid= aggr_level <= max_sum_func_level; + if (invalid) + { + my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), + MYF(0)); + return TRUE; + } + if (in_sum_func && in_sum_func->nest_level == nest_level) + { + /* + If the set function is nested adjust the value of + max_sum_func_level for the nesting set function. + */ + set_if_bigger(in_sum_func->max_sum_func_level, aggr_level); + } + thd->lex->in_sum_func= in_sum_func; + return FALSE; +} + +/* + Attach a set function to the subquery where it must be aggregated + + SYNOPSIS + register_sum_func() + thd reference to the thread context info + ref location of the pointer to this item in the embedding expression + + DESCRIPTION + The function looks for an outer subquery where the set function must be + aggregated. If it finds such a subquery then aggr_level is set to + the nest level of this subquery and the item for the set function + is added to the list of set functions used in nested subqueries + inner_sum_func_list defined for each subquery. When the item is placed + there the field 'ref_by' is set to ref. + + NOTES. + Now we 'register' only set functions that are aggregated in outer + subqueries. Actually it makes sense to link all set function for + a subquery in one chain. It would simplify the process of 'splitting' + for set functions. + + RETURN + FALSE if the executes without failures (currently always) + TRUE otherwise +*/ + +bool Item_sum::register_sum_func(THD *thd, Item **ref) +{ + SELECT_LEX *sl; + SELECT_LEX *aggr_sl= NULL; + nesting_map allow_sum_func= thd->lex->allow_sum_func; + for (sl= thd->lex->current_select->master_unit()->outer_select() ; + sl && sl->nest_level > max_arg_level; + sl= sl->master_unit()->outer_select() ) + { + if (aggr_level < 0 && (allow_sum_func & (1 << sl->nest_level))) + { + /* Found the most nested subquery where the function can be aggregated */ + aggr_level= sl->nest_level; + aggr_sl= sl; + } + } + if (sl && (allow_sum_func & (1 << sl->nest_level))) + { + /* + We reached the subquery of level max_arg_level and checked + that the function can be aggregated here. + The set function will be aggregated in this subquery. + */ + aggr_level= sl->nest_level; + aggr_sl= sl; + } + if (aggr_level >= 0) + { + ref_by= ref; + /* Add the object to the list of registered objects assigned to aggr_sl */ + if (!aggr_sl->inner_sum_func_list) + next= this; + else + { + next= aggr_sl->inner_sum_func_list->next; + aggr_sl->inner_sum_func_list->next= this; + } + aggr_sl->inner_sum_func_list= this; + + } + return FALSE; +} + + Item_sum::Item_sum(List<Item> &list) :arg_count(list.elements) { @@ -197,13 +425,9 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - if (!thd->allow_sum_func) - { - my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), - MYF(0)); + if (init_sum_func_check(thd)) return TRUE; - } - thd->allow_sum_func=0; // No included group funcs + decimals=0; maybe_null=0; for (uint i=0 ; i < arg_count ; i++) @@ -217,7 +441,10 @@ Item_sum_num::fix_fields(THD *thd, Item **ref) max_length=float_length(decimals); null_value=1; fix_length_and_dec(); - thd->allow_sum_func=1; // Allow group functions + + if (check_sum_func(thd, ref)) + return TRUE; + fixed= 1; return FALSE; } @@ -258,13 +485,9 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) DBUG_ASSERT(fixed == 0); Item *item= args[0]; - if (!thd->allow_sum_func) - { - my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), - MYF(0)); + + if (init_sum_func_check(thd)) return TRUE; - } - thd->allow_sum_func=0; // No included group funcs // 'item' can be changed during fix_fields if (!item->fixed && @@ -300,11 +523,14 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref) result_field=0; null_value=1; fix_length_and_dec(); - thd->allow_sum_func=1; // Allow group functions if (item->type() == Item::FIELD_ITEM) hybrid_field_type= ((Item_field*) item)->field->type(); else hybrid_field_type= Item::field_type(); + + if (check_sum_func(thd, ref)) + return TRUE; + fixed= 1; return FALSE; } @@ -2979,14 +3205,9 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) uint i; /* for loop variable */ DBUG_ASSERT(fixed == 0); - if (!thd->allow_sum_func) - { - my_message(ER_INVALID_GROUP_FUNC_USE, ER(ER_INVALID_GROUP_FUNC_USE), - MYF(0)); + if (init_sum_func_check(thd)) return TRUE; - } - thd->allow_sum_func= 0; maybe_null= 1; /* @@ -3008,8 +3229,11 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) result.set_charset(collation.collation); result_field= 0; null_value= 1; - thd->allow_sum_func= 1; max_length= thd->variables.group_concat_max_len; + + if (check_sum_func(thd, ref)) + return TRUE; + fixed= 1; return FALSE; } |