Commit 07c741e6 authored by Tom Lane's avatar Tom Lane

Fix oversight in planning of GROUP queries: when an expression is used

as both a GROUP BY item and an output expression, the top-level Group
node should just copy up the evaluated expression value from its input,
rather than re-evaluating the expression.  Aside from any performance
benefit this might offer, this avoids a crash when there is a sub-SELECT
in said expression.
parent 4cb0950c
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.68 2000/10/26 21:36:09 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.69 2001/01/09 03:48:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "postgres.h" #include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
...@@ -270,22 +271,75 @@ set_join_references(Join *join) ...@@ -270,22 +271,75 @@ set_join_references(Join *join)
* to refer to the tuples returned by its lefttree subplan. * to refer to the tuples returned by its lefttree subplan.
* *
* This is used for single-input plan types like Agg, Group, Result. * This is used for single-input plan types like Agg, Group, Result.
*
* In most cases, we have to match up individual Vars in the tlist and
* qual expressions with elements of the subplan's tlist (which was
* generated by flatten_tlist() from these selfsame expressions, so it
* should have all the required variables). There is an important exception,
* however: a GROUP BY expression that is also an output expression will
* have been pushed into the subplan tlist unflattened. We want to detect
* this case and reference the subplan output directly. Therefore, check
* for equality of the whole tlist expression to any subplan element before
* we resort to picking the expression apart for individual Vars.
*/ */
static void static void
set_uppernode_references(Plan *plan, Index subvarno) set_uppernode_references(Plan *plan, Index subvarno)
{ {
Plan *subplan = plan->lefttree; Plan *subplan = plan->lefttree;
List *subplanTargetList; List *subplanTargetList,
*outputTargetList,
*l;
if (subplan != NULL) if (subplan != NULL)
subplanTargetList = subplan->targetlist; subplanTargetList = subplan->targetlist;
else else
subplanTargetList = NIL; subplanTargetList = NIL;
plan->targetlist = (List *) outputTargetList = NIL;
replace_vars_with_subplan_refs((Node *) plan->targetlist, foreach (l, plan->targetlist)
subvarno, {
subplanTargetList); TargetEntry *tle = (TargetEntry *) lfirst(l);
TargetEntry *subplantle;
Node *newexpr;
subplantle = tlistentry_member(tle->expr, subplanTargetList);
if (subplantle)
{
/* Found a matching subplan output expression */
Resdom *resdom = subplantle->resdom;
Var *newvar;
newvar = makeVar(subvarno,
resdom->resno,
resdom->restype,
resdom->restypmod,
0);
/* If we're just copying a simple Var, copy up original info */
if (subplantle->expr && IsA(subplantle->expr, Var))
{
Var *subvar = (Var *) subplantle->expr;
newvar->varnoold = subvar->varnoold;
newvar->varoattno = subvar->varoattno;
}
else
{
newvar->varnoold = 0;
newvar->varoattno = 0;
}
newexpr = (Node *) newvar;
}
else
{
/* No matching expression, so replace individual Vars */
newexpr = replace_vars_with_subplan_refs(tle->expr,
subvarno,
subplanTargetList);
}
outputTargetList = lappend(outputTargetList,
makeTargetEntry(tle->resdom, newexpr));
}
plan->targetlist = outputTargetList;
plan->qual = (List *) plan->qual = (List *)
replace_vars_with_subplan_refs((Node *) plan->qual, replace_vars_with_subplan_refs((Node *) plan->qual,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.46 2000/11/21 00:17:59 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.47 2001/01/09 03:48:51 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -125,6 +125,7 @@ make_subplan(SubLink *slink) ...@@ -125,6 +125,7 @@ make_subplan(SubLink *slink)
{ {
SubPlan *node = makeNode(SubPlan); SubPlan *node = makeNode(SubPlan);
Query *subquery = (Query *) (slink->subselect); Query *subquery = (Query *) (slink->subselect);
Oid result_type = exprType((Node *) slink);
double tuple_fraction; double tuple_fraction;
Plan *plan; Plan *plan;
List *lst; List *lst;
...@@ -368,7 +369,7 @@ make_subplan(SubLink *slink) ...@@ -368,7 +369,7 @@ make_subplan(SubLink *slink)
/* /*
* Make expression of SUBPLAN type * Make expression of SUBPLAN type
*/ */
expr->typeOid = BOOLOID;/* bogus, but we don't really care */ expr->typeOid = result_type;
expr->opType = SUBPLAN_EXPR; expr->opType = SUBPLAN_EXPR;
expr->oper = (Node *) node; expr->oper = (Node *) node;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.47 2000/08/08 15:41:53 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.48 2001/01/09 03:48:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include "optimizer/tlist.h" #include "optimizer/tlist.h"
#include "optimizer/var.h" #include "optimizer/var.h"
static TargetEntry *tlistentry_member(Node *node, List *targetlist);
/***************************************************************************** /*****************************************************************************
* ---------- RELATION node target list routines ---------- * ---------- RELATION node target list routines ----------
...@@ -29,7 +28,7 @@ static TargetEntry *tlistentry_member(Node *node, List *targetlist); ...@@ -29,7 +28,7 @@ static TargetEntry *tlistentry_member(Node *node, List *targetlist);
* Finds the (first) member of the given tlist whose expression is * Finds the (first) member of the given tlist whose expression is
* equal() to the given expression. Result is NULL if no such member. * equal() to the given expression. Result is NULL if no such member.
*/ */
static TargetEntry * TargetEntry *
tlistentry_member(Node *node, List *targetlist) tlistentry_member(Node *node, List *targetlist)
{ {
List *temp; List *temp;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: tlist.h,v 1.26 2000/06/08 22:37:51 momjian Exp $ * $Id: tlist.h,v 1.27 2001/01/09 03:48:50 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "nodes/relation.h" #include "nodes/relation.h"
extern TargetEntry *tlistentry_member(Node *node, List *targetlist);
extern Resdom *tlist_member(Node *node, List *targetlist); extern Resdom *tlist_member(Node *node, List *targetlist);
extern void add_var_to_tlist(RelOptInfo *rel, Var *var); extern void add_var_to_tlist(RelOptInfo *rel, Var *var);
......
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