I wrote:
> Thanks for the report. I traced through this, and the problem seems to
> be that split_pathtarget_at_srfs() is neglecting to attach sortgroupref
> labeling to the extra PathTargets it constructs. I don't remember
> whether that code is my fault or Andres', but I'll take a look at
> fixing it.
Here's a proposed patch for that.
regards, tom lane
diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index 32160d5..5500f33 100644
*** a/src/backend/optimizer/util/tlist.c
--- b/src/backend/optimizer/util/tlist.c
***
*** 25,44
((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
(IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
! /* Workspace for split_pathtarget_walker */
typedef struct
{
List *input_target_exprs; /* exprs available from input */
! List *level_srfs; /* list of lists of SRF exprs */
! List *level_input_vars; /* vars needed by SRFs of each level */
! List *level_input_srfs; /* SRFs needed by SRFs of each level */
List *current_input_vars; /* vars needed in current subexpr */
List *current_input_srfs; /* SRFs needed in current subexpr */
int current_depth; /* max SRF depth in current subexpr */
} split_pathtarget_context;
static bool split_pathtarget_walker(Node *node,
split_pathtarget_context *context);
/*
--- 25,62
((IsA(node, FuncExpr) && ((FuncExpr *) (node))->funcretset) || \
(IsA(node, OpExpr) && ((OpExpr *) (node))->opretset))
! /*
! * Data structures for split_pathtarget_at_srfs(). To preserve the identity
! * of sortgroupref items even if they are textually equal(), what we track is
! * not just bare expressions but expressions plus their sortgroupref indexes.
! */
typedef struct
{
+ Node *expr; /* some subexpression of a PathTarget */
+ Index sortgroupref; /* its sortgroupref, or 0 if none */
+ } split_pathtarget_item;
+
+ typedef struct
+ {
+ /* This is a List of bare expressions: */
List *input_target_exprs; /* exprs available from input */
! /* These are Lists of Lists of split_pathtarget_items: */
! List *level_srfs; /* SRF exprs to evaluate at each level */
! List *level_input_vars; /* input vars needed at each level */
! List *level_input_srfs; /* input SRFs needed at each level */
! /* These are Lists of split_pathtarget_items: */
List *current_input_vars; /* vars needed in current subexpr */
List *current_input_srfs; /* SRFs needed in current subexpr */
+ /* Auxiliary data for current split_pathtarget_walker traversal: */
int current_depth; /* max SRF depth in current subexpr */
+ Index current_sgref; /* current subexpr's sortgroupref, or 0 */
} split_pathtarget_context;
static bool split_pathtarget_walker(Node *node,
split_pathtarget_context *context);
+ static void add_sp_item_to_pathtarget(PathTarget *target,
+ split_pathtarget_item *item);
+ static void add_sp_items_to_pathtarget(PathTarget *target, List *items);
/*
*** apply_pathtarget_labeling_to_tlist(List
*** 822,827
--- 840,848
* already meant as a reference to a lower subexpression). So, don't expand
* any tlist expressions that appear in input_target, if that's not NULL.
*
+ * It's also important that we preserve any sortgroupref annotation appearing
+ * in the given target, especially on expressions matching input_target items.
+ *
* The outputs of this function are two parallel lists, one a list of
* PathTargets and the other an integer list of bool flags indicating
* whether the corresponding PathTarget contains any evaluatable SRFs.
*** split_pathtarget_at_srfs(PlannerInfo *ro
*** 845,850
--- 866,872
int max_depth;
bool need_extra_projection;
List *prev_level_tlist;
+ int lci;
ListCell *lc,
*lc1,
*lc2,
*** split_pathtarget_at_srfs(PlannerInfo *ro
*** 884,893
--- 906,920
need_extra_projection = false;
/* Scan each expression in the PathTarget looking for SRFs */
+ lci = 0;
foreach(lc, target->exprs)
{
Node *node = (Node *) lfirst(lc);
+ /* Tell split_pathtarget_walker about this expr's sortgroupref */
+ context.current_sgref = get_pathtarget_sortgroupref(target, lci);
+ lci++;
+
/*
* Find all SRFs and Vars (and Var-like nodes) in this expression, and
* enter them into appropriate lists within the context struct.
*** split_pathtarget_at_srfs(PlannerInfo *ro
*** 981,996
* This target should actually evaluate any SRFs of the current
* level, and it needs to propagate forward any Vars needed by
* later levels, as well as SRFs computed earlier and needed by
! * later levels. We rely