Commit 03728942 authored by Tom Lane's avatar Tom Lane

For non-projecting plan node types such as Limit, set_plan_references

has to recopy the input plan node's targetlist if it removes a
SubqueryScan node just below the non-projecting node.  For simplicity
I made it recopy always.  Per bug report from Allan Wang and Michael Fuhr.
parent 2739e1d1
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.112 2005/08/27 18:04:49 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.113 2005/09/05 17:25:01 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -130,6 +130,7 @@ static void set_sa_opfuncid(ScalarArrayOpExpr *opexpr); ...@@ -130,6 +130,7 @@ static void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
Plan * Plan *
set_plan_references(Plan *plan, List *rtable) set_plan_references(Plan *plan, List *rtable)
{ {
bool copy_lefttree_tlist = false;
ListCell *l; ListCell *l;
if (plan == NULL) if (plan == NULL)
...@@ -218,14 +219,13 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -218,14 +219,13 @@ set_plan_references(Plan *plan, List *rtable)
/* /*
* These plan types don't actually bother to evaluate their * These plan types don't actually bother to evaluate their
* targetlists (because they just return their unmodified * targetlists, because they just return their unmodified
* input tuples). The optimizer is lazy about creating really * input tuples; so their targetlists should just be copies
* valid targetlists for them --- it tends to just put in a * of their input plan nodes' targetlists. The actual copying
* pointer to the child plan node's tlist. Hence, we leave * has to be done after we've finalized the input node.
* the tlist alone. In particular, we do not want to process */
* subplans in the tlist, since we will likely end up reprocessing copy_lefttree_tlist = true;
* subplans that also appear in lower levels of the plan tree! /*
*
* Since these plan types don't check quals either, we should * Since these plan types don't check quals either, we should
* not find any qual expression attached to them. * not find any qual expression attached to them.
*/ */
...@@ -238,6 +238,7 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -238,6 +238,7 @@ set_plan_references(Plan *plan, List *rtable)
* or quals. It does have live expressions for limit/offset, * or quals. It does have live expressions for limit/offset,
* however. * however.
*/ */
copy_lefttree_tlist = true;
Assert(plan->qual == NIL); Assert(plan->qual == NIL);
fix_expr_references(plan, ((Limit *) plan)->limitOffset); fix_expr_references(plan, ((Limit *) plan)->limitOffset);
fix_expr_references(plan, ((Limit *) plan)->limitCount); fix_expr_references(plan, ((Limit *) plan)->limitCount);
...@@ -266,9 +267,10 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -266,9 +267,10 @@ set_plan_references(Plan *plan, List *rtable)
/* /*
* Append, like Sort et al, doesn't actually evaluate its * Append, like Sort et al, doesn't actually evaluate its
* targetlist or check quals, and we haven't bothered to give it * targetlist or check quals, so don't fix targetlist/qual.
* its own tlist copy. So, don't fix targetlist/qual. But do * But do recurse into child plans. (Unlike Sort et al, the
* recurse into child plans. * correct tlist was made by createplan.c and we shouldn't
* replace it.)
*/ */
Assert(plan->qual == NIL); Assert(plan->qual == NIL);
foreach(l, ((Append *) plan)->appendplans) foreach(l, ((Append *) plan)->appendplans)
...@@ -315,6 +317,20 @@ set_plan_references(Plan *plan, List *rtable) ...@@ -315,6 +317,20 @@ set_plan_references(Plan *plan, List *rtable)
sp->plan = set_plan_references(sp->plan, sp->rtable); sp->plan = set_plan_references(sp->plan, sp->rtable);
} }
/*
* If this is a non-projecting plan node, create a minimally valid
* targetlist for it. Someday we might need to make this look really
* real, with Vars referencing the input node's outputs, but for now
* the executor only cares that the tlist has the right TargetEntry
* fields (resname, resjunk etc) and exprType results. So we can
* get away with just copying the input node's tlist. (Note:
* createplan.c already did copy the input, but we have to do it
* over in case we removed a SubqueryScan node: the new input plan
* node might have extra resjunk fields.)
*/
if (copy_lefttree_tlist)
plan->targetlist = copyObject(plan->lefttree->targetlist);
return plan; return plan;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment