Fix pushdown of constants in aggregate queries

pull/3961/head
Marco Slot 2020-06-30 09:48:48 +02:00 committed by Hadi Moshayedi
parent 392c5e2c34
commit eeffbde8bd
4 changed files with 29 additions and 3 deletions

View File

@ -79,6 +79,9 @@ BuildExtendedOpNodeProperties(MultiExtendedOp *extendedOpNode,
hasNonPartitionColumnDistinctAgg, hasNonPartitionColumnDistinctAgg,
extendedOpNode->onlyPushableWindowFunctions); extendedOpNode->onlyPushableWindowFunctions);
extendedOpNodeProperties.hasGroupBy = extendedOpNode->groupClauseList != NIL;
extendedOpNodeProperties.hasAggregate = TargetListHasAggregates(targetList);
extendedOpNodeProperties.groupedByDisjointPartitionColumn = extendedOpNodeProperties.groupedByDisjointPartitionColumn =
groupedByDisjointPartitionColumn; groupedByDisjointPartitionColumn;
extendedOpNodeProperties.repartitionSubquery = repartitionSubquery; extendedOpNodeProperties.repartitionSubquery = repartitionSubquery;

View File

@ -228,7 +228,6 @@ static Expr * AddTypeConversion(Node *originalAggregate, Node *newExpression);
static MultiExtendedOp * WorkerExtendedOpNode(MultiExtendedOp *originalOpNode, static MultiExtendedOp * WorkerExtendedOpNode(MultiExtendedOp *originalOpNode,
ExtendedOpNodeProperties * ExtendedOpNodeProperties *
extendedOpNodeProperties); extendedOpNodeProperties);
static bool TargetListHasAggregates(List *targetEntryList);
static void ProcessTargetListForWorkerQuery(List *targetEntryList, static void ProcessTargetListForWorkerQuery(List *targetEntryList,
ExtendedOpNodeProperties * ExtendedOpNodeProperties *
extendedOpNodeProperties, extendedOpNodeProperties,
@ -2830,7 +2829,7 @@ BuildOrderByLimitReference(bool hasDistinctOn, bool groupedByDisjointPartitionCo
* target list contain aggregates that are not inside the window functions. * target list contain aggregates that are not inside the window functions.
* This function should not be called if window functions are being pulled up. * This function should not be called if window functions are being pulled up.
*/ */
static bool bool
TargetListHasAggregates(List *targetEntryList) TargetListHasAggregates(List *targetEntryList)
{ {
TargetEntry *targetEntry = NULL; TargetEntry *targetEntry = NULL;
@ -3839,9 +3838,26 @@ CanPushDownExpression(Node *expression,
bool hasAggregate = contain_aggs_of_level(expression, 0); bool hasAggregate = contain_aggs_of_level(expression, 0);
bool hasWindowFunction = contain_window_function(expression); bool hasWindowFunction = contain_window_function(expression);
if (!hasAggregate && !hasWindowFunction) if (!hasAggregate && !hasWindowFunction)
{
/*
* If the query has the form SELECT expression, agg(..) FROM table;
* then expression should be evaluated on the coordinator.
*
* Other than the efficiency part of this, we could also crash if
* we pushed down the expression to the workers. When pushing down
* expressions to workers we create a Var reference to the worker
* tuples. If the result from worker is empty, but we need to have
* at least a row in coordinator result, postgres will crash when
* trying to evaluate the Var.
*
* For details, see https://github.com/citusdata/citus/pull/3961
*/
if (!extendedOpNodeProperties->hasAggregate ||
extendedOpNodeProperties->hasGroupBy)
{ {
return true; return true;
} }
}
/* aggregates inside pushed down window functions can be pushed down */ /* aggregates inside pushed down window functions can be pushed down */
bool hasPushableWindowFunction = bool hasPushableWindowFunction =

View File

@ -31,6 +31,12 @@ typedef struct ExtendedOpNodeProperties
bool onlyPushableWindowFunctions; bool onlyPushableWindowFunctions;
bool pullUpIntermediateRows; bool pullUpIntermediateRows;
bool pushDownGroupingAndHaving; bool pushDownGroupingAndHaving;
/* indicates whether the MultiExtendedOp has a GROUP BY */
bool hasGroupBy;
/* indicates whether the MultiExtendedOp has an aggregate on the target list */
bool hasAggregate;
} ExtendedOpNodeProperties; } ExtendedOpNodeProperties;

View File

@ -176,5 +176,6 @@ extern void FindReferencedTableColumn(Expr *columnExpression, List *parentQueryL
Query *query, Oid *relationId, Var **column); Query *query, Oid *relationId, Var **column);
extern char * WorkerColumnName(AttrNumber resno); extern char * WorkerColumnName(AttrNumber resno);
extern bool IsGroupBySubsetOfDistinct(List *groupClauses, List *distinctClauses); extern bool IsGroupBySubsetOfDistinct(List *groupClauses, List *distinctClauses);
extern bool TargetListHasAggregates(List *targetEntryList);
#endif /* MULTI_LOGICAL_OPTIMIZER_H */ #endif /* MULTI_LOGICAL_OPTIMIZER_H */