Skip to content

Commit 2310064

Browse files
committed
Fix UNION planner datatype issue
66c0185 gave the planner the ability to have union child queries provide the union planner with pre-sorted input so that UNION queries could be more efficiently implemented using Merge Append. That commit overlooked checking that the UNION target list and the union child target list's types all match. In some corner cases, this could result in the planner producing sorts using the sort operator of the top-level UNION's target list type rather than of the union child's target list's type. The implications of this range from silently working correctly, despite using the wrong sort operator all the way up to a segmentation fault. Here we fix by adjusting the planner so it makes no attempt to have the subquery produce pre-sorted results when the data type of the UNION target list and the types from the subquery target list don't match exactly. Backpatch to 17, where 66c0185 was introduced. Reported-by: Jason Smith <dqetool@126.com> Diagnosed-by: Tom Lane <tgl@sss.pgh.pa.us> Bug: 18764 Discussion: https://postgr.es/m/18764-63ad667ea26e877a%40postgresql.org Backpatch-through: 17
1 parent f0bf785 commit 2310064

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8077,33 +8077,53 @@ group_by_has_partkey(RelOptInfo *input_rel,
80778077
* child query's targetlist entries may already have a tleSortGroupRef
80788078
* assigned for other purposes, such as GROUP BYs. Here we keep the
80798079
* SortGroupClause list in the same order as 'op' groupClauses and just adjust
8080-
* the tleSortGroupRef to reference the TargetEntry's 'ressortgroupref'.
8080+
* the tleSortGroupRef to reference the TargetEntry's 'ressortgroupref'. If
8081+
* any of the columns in the targetlist don't match to the setop's colTypes
8082+
* then we return an empty list. This may leave some TLEs with unreferenced
8083+
* ressortgroupref markings, but that's harmless.
80818084
*/
80828085
static List *
80838086
generate_setop_child_grouplist(SetOperationStmt *op, List *targetlist)
80848087
{
80858088
List *grouplist = copyObject(op->groupClauses);
80868089
ListCell *lg;
80878090
ListCell *lt;
8091+
ListCell *ct;
80888092

80898093
lg = list_head(grouplist);
8094+
ct = list_head(op->colTypes);
80908095
foreach(lt, targetlist)
80918096
{
80928097
TargetEntry *tle = (TargetEntry *) lfirst(lt);
80938098
SortGroupClause *sgc;
8099+
Oid coltype;
80948100

80958101
/* resjunk columns could have sortgrouprefs. Leave these alone */
80968102
if (tle->resjunk)
80978103
continue;
80988104

8099-
/* we expect every non-resjunk target to have a SortGroupClause */
8105+
/*
8106+
* We expect every non-resjunk target to have a SortGroupClause and
8107+
* colTypes.
8108+
*/
81008109
Assert(lg != NULL);
8110+
Assert(ct != NULL);
81018111
sgc = (SortGroupClause *) lfirst(lg);
8112+
coltype = lfirst_oid(ct);
8113+
8114+
/* reject if target type isn't the same as the setop target type */
8115+
if (coltype != exprType((Node *) tle->expr))
8116+
return NIL;
8117+
81028118
lg = lnext(grouplist, lg);
8119+
ct = lnext(op->colTypes, ct);
81038120

81048121
/* assign a tleSortGroupRef, or reuse the existing one */
81058122
sgc->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
81068123
}
8124+
81078125
Assert(lg == NULL);
8126+
Assert(ct == NULL);
8127+
81088128
return grouplist;
81098129
}

0 commit comments

Comments
 (0)