agg cannot contain set-returning function calls

This commit is contained in:
chenxiaobin19 2022-12-26 17:50:46 +08:00
parent 7ff965f389
commit 785a596df1
6 changed files with 93 additions and 22 deletions

View File

@ -211,6 +211,14 @@ void transformAggregateCall(ParseState* pstate, Aggref* agg, List* args, List* a
}
}
/* It can't contain set-returning functions either */
if (checkExprHasSetReturningFuncs((Node*)agg->args)) {
ereport(ERROR,
(errcode(ERRCODE_GROUPING_ERROR),
errmsg("aggregate function calls cannot contain set-returning function calls"),
parser_errposition(pstate, locate_srfunc((Node*)agg->args))));
}
/* It can't contain window functions either */
if (pstate->p_hasWindowFuncs && checkExprHasWindowFuncs((Node*)agg->args)) {
ereport(ERROR,

View File

@ -36,14 +36,16 @@ typedef struct {
} locate_agg_of_level_context;
typedef struct {
int win_location;
} locate_windowfunc_context;
int location;
} locate_func_context;
static bool contain_aggs_of_level_or_above_walker(Node* node, int* sublevels_up);
static bool contain_aggs_of_level_walker(Node* node, contain_aggs_of_level_context* context);
static bool locate_agg_of_level_walker(Node* node, locate_agg_of_level_context* context);
static bool contain_srfunc_walker(Node* node, void* context);
static bool locate_srfunc_walker(Node* node, locate_func_context* context);
static bool contain_windowfuncs_walker(Node* node, void* context);
static bool locate_windowfunc_walker(Node* node, locate_windowfunc_context* context);
static bool locate_windowfunc_walker(Node* node, locate_func_context* context);
static bool checkExprHasSubLink_walker(Node* node, void* context);
static Relids offset_relid_set(Relids relids, int offset);
static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
@ -210,6 +212,60 @@ static bool locate_agg_of_level_walker(Node* node, locate_agg_of_level_context*
return expression_tree_walker(node, (bool (*)())locate_agg_of_level_walker, (void*)context);
}
/*
* checkExprHasSetReturningFuncs -
* Check if an expression contains a set-returning function call of the
* current query level.
*/
bool checkExprHasSetReturningFuncs(Node* node)
{
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_walker(node, (bool (*)())contain_srfunc_walker, NULL, 0);
}
static bool contain_srfunc_walker(Node* node, void* context)
{
if (node == NULL)
return false;
if (IsA(node, FuncExpr) && ((FuncExpr*)node)->funcretset)
return true; /* abort the tree traversal and return true */
/* Mustn't recurse into subselects */
return expression_tree_walker(node, (bool (*)())contain_srfunc_walker, (void*)context);
}
int locate_srfunc(Node* node)
{
locate_func_context context;
context.location = -1; /* in case we find nothing */
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
(void)query_or_expression_tree_walker(node, (bool (*)())locate_srfunc_walker, (void*)&context, 0);
return context.location;
}
static bool locate_srfunc_walker(Node* node, locate_func_context* context)
{
if (node == NULL)
return false;
if (IsA(node, FuncExpr) && ((FuncExpr*)node)->funcretset) {
if (((FuncExpr*)node)->location >= 0) {
context->location = ((FuncExpr*)node)->location;
return true; /* abort the tree traversal and return true */
}
/* else fall through to examine argument */
}
/* Mustn't recurse into subselects */
return expression_tree_walker(node, (bool (*)())locate_srfunc_walker, (void*)context);
}
/*
* checkExprHasWindowFuncs -
* Check if an expression contains a window function call of the
@ -249,9 +305,9 @@ static bool contain_windowfuncs_walker(Node* node, void* context)
*/
int locate_windowfunc(Node* node)
{
locate_windowfunc_context context;
locate_func_context context;
context.win_location = -1; /* in case we find nothing */
context.location = -1; /* in case we find nothing */
/*
* Must be prepared to start with a Query or a bare expression tree; if
@ -259,16 +315,16 @@ int locate_windowfunc(Node* node)
*/
(void)query_or_expression_tree_walker(node, (bool (*)())locate_windowfunc_walker, (void*)&context, 0);
return context.win_location;
return context.location;
}
static bool locate_windowfunc_walker(Node* node, locate_windowfunc_context* context)
static bool locate_windowfunc_walker(Node* node, locate_func_context* context)
{
if (node == NULL)
return false;
if (IsA(node, WindowFunc)) {
if (((WindowFunc*)node)->location >= 0) {
context->win_location = ((WindowFunc*)node)->location;
context->location = ((WindowFunc*)node)->location;
return true; /* abort the tree traversal and return true */
}
/* else fall through to examine argument */

View File

@ -50,8 +50,10 @@ extern void AddInvertedQual(Query* parsetree, Node* qual);
extern bool contain_aggs_of_level_or_above(Node* node, int levelsup);
extern bool contain_aggs_of_level(Node* node, int levelsup);
extern int locate_agg_of_level(Node* node, int levelsup);
extern int locate_srfunc(Node* node);
extern int locate_windowfunc(Node* node);
extern bool checkExprHasAggs(Node* node);
extern bool checkExprHasSetReturningFuncs(Node* node);
extern bool checkExprHasWindowFuncs(Node* node);
extern bool checkExprHasSubLink(Node* node);

View File

@ -5,21 +5,23 @@ insert into t1 values(1,2);
set enable_hashagg = off;
--force hash agg, if used sort agg will report error.
select a , count(distinct generate_series(1,2)) from t1 group by a;
ERROR: set-valued function called in context when calculate targetlist that cannot accept a set
ERROR: aggregate function calls cannot contain set-returning function calls
LINE 1: select a , count(distinct generate_series(1,2)) from t1 gro...
^
CONTEXT: referenced column: count
explain (verbose, costs off)
select a , count(distinct generate_series(1,2)) from t1 group by a;
QUERY PLAN
----------------------------------------------------
GroupAggregate
Output: a, count(DISTINCT generate_series(1, 2))
Group By Key: t1.a
-> Sort
Output: a
Sort Key: t1.a
-> Seq Scan on aggregate.t1
Output: a
(8 rows)
ERROR: aggregate function calls cannot contain set-returning function calls
LINE 2: select a , count(distinct generate_series(1,2)) from t1 gro...
^
CONTEXT: referenced column: count
set query_dop = 2;
select a , count(distinct generate_series(1,2)) from t1 group by a;
ERROR: aggregate function calls cannot contain set-returning function calls
LINE 1: select a , count(distinct generate_series(1,2)) from t1 gro...
^
CONTEXT: referenced column: count
reset query_dop;
--test const-false agg
CREATE TABLE bmsql_item (
i_id int4 NoT NULL,i_name varchar(24),i_price numeric(5,2),i_data varchar( 50),i_im_id int4,

View File

@ -8,6 +8,9 @@ set enable_hashagg = off;
select a , count(distinct generate_series(1,2)) from t1 group by a;
explain (verbose, costs off)
select a , count(distinct generate_series(1,2)) from t1 group by a;
set query_dop = 2;
select a , count(distinct generate_series(1,2)) from t1 group by a;
reset query_dop;
--test const-false agg
CREATE TABLE bmsql_item (

View File

@ -2066,7 +2066,7 @@ locale_t
locate_agg_of_level_context
locate_var_of_level_context
locate_var_of_relation_context
locate_windowfunc_context
locate_func_context
logstreamer_param
lquery
lquery_level