diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 39ade99155f..6eeeb0e1d03 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8086,7 +8086,10 @@ group_by_has_partkey(RelOptInfo *input_rel, * child query's targetlist entries may already have a tleSortGroupRef * assigned for other purposes, such as GROUP BYs. Here we keep the * SortGroupClause list in the same order as 'op' groupClauses and just adjust - * the tleSortGroupRef to reference the TargetEntry's 'ressortgroupref'. + * the tleSortGroupRef to reference the TargetEntry's 'ressortgroupref'. If + * any of the columns in the targetlist don't match to the setop's colTypes + * then we return an empty list. This may leave some TLEs with unreferenced + * ressortgroupref markings, but that's harmless. */ static List * generate_setop_child_grouplist(SetOperationStmt *op, List *targetlist) @@ -8094,25 +8097,42 @@ generate_setop_child_grouplist(SetOperationStmt *op, List *targetlist) List *grouplist = copyObject(op->groupClauses); ListCell *lg; ListCell *lt; + ListCell *ct; lg = list_head(grouplist); + ct = list_head(op->colTypes); foreach(lt, targetlist) { TargetEntry *tle = (TargetEntry *) lfirst(lt); SortGroupClause *sgc; + Oid coltype; /* resjunk columns could have sortgrouprefs. Leave these alone */ if (tle->resjunk) continue; - /* we expect every non-resjunk target to have a SortGroupClause */ + /* + * We expect every non-resjunk target to have a SortGroupClause and + * colTypes. + */ Assert(lg != NULL); + Assert(ct != NULL); sgc = (SortGroupClause *) lfirst(lg); + coltype = lfirst_oid(ct); + + /* reject if target type isn't the same as the setop target type */ + if (coltype != exprType((Node *) tle->expr)) + return NIL; + lg = lnext(grouplist, lg); + ct = lnext(op->colTypes, ct); /* assign a tleSortGroupRef, or reuse the existing one */ sgc->tleSortGroupRef = assignSortGroupRef(tle, targetlist); } + Assert(lg == NULL); + Assert(ct == NULL); + return grouplist; }