aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2001-01-09 03:48:51 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2001-01-09 03:48:51 +0000
commit07c741e61c8cb1fd945907a225d15467a08aca70 (patch)
tree68ab78fd412905df40da36058e4f35ec31858c6f
parent4cb0950cfe4055ca54d08b9639ee4e462cb009a3 (diff)
downloadpostgresql-07c741e61c8cb1fd945907a225d15467a08aca70.tar.gz
postgresql-07c741e61c8cb1fd945907a225d15467a08aca70.zip
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.
-rw-r--r--src/backend/optimizer/plan/setrefs.c66
-rw-r--r--src/backend/optimizer/plan/subselect.c5
-rw-r--r--src/backend/optimizer/util/tlist.c5
-rw-r--r--src/include/optimizer/tlist.h3
4 files changed, 67 insertions, 12 deletions
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index deb020e2565..5a54c956912 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -9,7 +9,7 @@
*
*
* 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 @@
#include "postgres.h"
+#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
@@ -270,22 +271,75 @@ set_join_references(Join *join)
* to refer to the tuples returned by its lefttree subplan.
*
* 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
set_uppernode_references(Plan *plan, Index subvarno)
{
Plan *subplan = plan->lefttree;
- List *subplanTargetList;
+ List *subplanTargetList,
+ *outputTargetList,
+ *l;
if (subplan != NULL)
subplanTargetList = subplan->targetlist;
else
subplanTargetList = NIL;
- plan->targetlist = (List *)
- replace_vars_with_subplan_refs((Node *) plan->targetlist,
- subvarno,
- subplanTargetList);
+ outputTargetList = NIL;
+ foreach (l, plan->targetlist)
+ {
+ 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 *)
replace_vars_with_subplan_refs((Node *) plan->qual,
diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c
index 4ebabc1e875..61dd2baa7fd 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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)
{
SubPlan *node = makeNode(SubPlan);
Query *subquery = (Query *) (slink->subselect);
+ Oid result_type = exprType((Node *) slink);
double tuple_fraction;
Plan *plan;
List *lst;
@@ -368,7 +369,7 @@ make_subplan(SubLink *slink)
/*
* Make expression of SUBPLAN type
*/
- expr->typeOid = BOOLOID;/* bogus, but we don't really care */
+ expr->typeOid = result_type;
expr->opType = SUBPLAN_EXPR;
expr->oper = (Node *) node;
diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index 93b3fc6f568..fa542a8828a 100644
--- a/src/backend/optimizer/util/tlist.c
+++ b/src/backend/optimizer/util/tlist.c
@@ -8,7 +8,7 @@
*
*
* 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 @@
#include "optimizer/tlist.h"
#include "optimizer/var.h"
-static TargetEntry *tlistentry_member(Node *node, List *targetlist);
/*****************************************************************************
* ---------- RELATION node target list routines ----------
@@ -29,7 +28,7 @@ static TargetEntry *tlistentry_member(Node *node, List *targetlist);
* Finds the (first) member of the given tlist whose expression is
* equal() to the given expression. Result is NULL if no such member.
*/
-static TargetEntry *
+TargetEntry *
tlistentry_member(Node *node, List *targetlist)
{
List *temp;
diff --git a/src/include/optimizer/tlist.h b/src/include/optimizer/tlist.h
index 8d3eb20d024..2159cbe2b8b 100644
--- a/src/include/optimizer/tlist.h
+++ b/src/include/optimizer/tlist.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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 @@
#include "nodes/relation.h"
+extern TargetEntry *tlistentry_member(Node *node, List *targetlist);
extern Resdom *tlist_member(Node *node, List *targetlist);
extern void add_var_to_tlist(RelOptInfo *rel, Var *var);