Commit 1d97c19a authored by Tom Lane's avatar Tom Lane

Fix estimate_num_groups() to not fail on PlaceHolderVars, per report from

Stefan Kaltenbrunner.  The most reasonable behavior (at least for the near
term) seems to be to ignore the PlaceHolderVar and examine its argument
instead.  In support of this, change the API of pull_var_clause() to allow
callers to request recursion into PlaceHolderVars.  Currently
estimate_num_groups() is the only customer for that behavior, but where
there's one there may be others.
parent 3a624e92
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.352 2009/03/31 17:59:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.353 2009/04/19 19:46:32 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1621,7 +1621,7 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr, ...@@ -1621,7 +1621,7 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
* in check constraints; it would fail to examine the contents of * in check constraints; it would fail to examine the contents of
* subselects. * subselects.
*/ */
varList = pull_var_clause(expr, false); varList = pull_var_clause(expr, PVC_REJECT_PLACEHOLDERS);
keycount = list_length(varList); keycount = list_length(varList);
if (keycount > 0) if (keycount > 0)
...@@ -1915,7 +1915,7 @@ AddRelationNewConstraints(Relation rel, ...@@ -1915,7 +1915,7 @@ AddRelationNewConstraints(Relation rel,
List *vars; List *vars;
char *colname; char *colname;
vars = pull_var_clause(expr, false); vars = pull_var_clause(expr, PVC_REJECT_PLACEHOLDERS);
/* eliminate duplicates */ /* eliminate duplicates */
vars = list_union(NIL, vars); vars = list_union(NIL, vars);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.181 2009/03/10 20:58:26 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.182 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1122,7 +1122,7 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, ...@@ -1122,7 +1122,7 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
* Examine all Vars used in clause; since it's a restriction clause, all * Examine all Vars used in clause; since it's a restriction clause, all
* such Vars must refer to subselect output columns. * such Vars must refer to subselect output columns.
*/ */
vars = pull_var_clause(qual, true); vars = pull_var_clause(qual, PVC_INCLUDE_PLACEHOLDERS);
foreach(vl, vars) foreach(vl, vars)
{ {
Var *var = (Var *) lfirst(vl); Var *var = (Var *) lfirst(vl);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.17 2009/02/06 23:43:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.18 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -689,7 +689,8 @@ generate_base_implied_equalities_no_const(PlannerInfo *root, ...@@ -689,7 +689,8 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
foreach(lc, ec->ec_members) foreach(lc, ec->ec_members)
{ {
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc); EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc);
List *vars = pull_var_clause((Node *) cur_em->em_expr, true); List *vars = pull_var_clause((Node *) cur_em->em_expr,
PVC_INCLUDE_PLACEHOLDERS);
add_vars_to_targetlist(root, vars, ec->ec_relids); add_vars_to_targetlist(root, vars, ec->ec_relids);
list_free(vars); list_free(vars);
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.257 2009/03/26 17:15:35 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.258 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3022,7 +3022,8 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, ...@@ -3022,7 +3022,8 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys,
if (em->em_is_const || em->em_is_child) if (em->em_is_const || em->em_is_child)
continue; continue;
sortexpr = em->em_expr; sortexpr = em->em_expr;
exprvars = pull_var_clause((Node *) sortexpr, true); exprvars = pull_var_clause((Node *) sortexpr,
PVC_INCLUDE_PLACEHOLDERS);
foreach(k, exprvars) foreach(k, exprvars)
{ {
if (!tlist_member_ignore_relabel(lfirst(k), tlist)) if (!tlist_member_ignore_relabel(lfirst(k), tlist))
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.150 2009/04/16 20:42:16 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.151 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -130,7 +130,8 @@ add_base_rels_to_query(PlannerInfo *root, Node *jtnode) ...@@ -130,7 +130,8 @@ add_base_rels_to_query(PlannerInfo *root, Node *jtnode)
void void
build_base_rel_tlists(PlannerInfo *root, List *final_tlist) build_base_rel_tlists(PlannerInfo *root, List *final_tlist)
{ {
List *tlist_vars = pull_var_clause((Node *) final_tlist, true); List *tlist_vars = pull_var_clause((Node *) final_tlist,
PVC_INCLUDE_PLACEHOLDERS);
if (tlist_vars != NIL) if (tlist_vars != NIL)
{ {
...@@ -981,7 +982,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -981,7 +982,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
*/ */
if (bms_membership(relids) == BMS_MULTIPLE) if (bms_membership(relids) == BMS_MULTIPLE)
{ {
List *vars = pull_var_clause(clause, true); List *vars = pull_var_clause(clause, PVC_INCLUDE_PLACEHOLDERS);
add_vars_to_targetlist(root, vars, relids); add_vars_to_targetlist(root, vars, relids);
list_free(vars); list_free(vars);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.253 2009/03/30 17:30:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.254 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2236,7 +2236,7 @@ make_subplanTargetList(PlannerInfo *root, ...@@ -2236,7 +2236,7 @@ make_subplanTargetList(PlannerInfo *root,
* and window specifications. * and window specifications.
*/ */
sub_tlist = flatten_tlist(tlist); sub_tlist = flatten_tlist(tlist);
extravars = pull_var_clause(parse->havingQual, true); extravars = pull_var_clause(parse->havingQual, PVC_INCLUDE_PLACEHOLDERS);
sub_tlist = add_to_flat_tlist(sub_tlist, extravars); sub_tlist = add_to_flat_tlist(sub_tlist, extravars);
list_free(extravars); list_free(extravars);
*need_tlist_eval = false; /* only eval if not flat tlist */ *need_tlist_eval = false; /* only eval if not flat tlist */
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.95 2009/01/01 17:23:44 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.96 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -193,7 +193,8 @@ preprocess_targetlist(PlannerInfo *root, List *tlist) ...@@ -193,7 +193,8 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
List *vars; List *vars;
ListCell *l; ListCell *l;
vars = pull_var_clause((Node *) parse->returningList, true); vars = pull_var_clause((Node *) parse->returningList,
PVC_INCLUDE_PLACEHOLDERS);
foreach(l, vars) foreach(l, vars)
{ {
Var *var = (Var *) lfirst(l); Var *var = (Var *) lfirst(l);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/placeholder.c,v 1.3 2009/01/01 17:23:45 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/placeholder.c,v 1.4 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -162,7 +162,7 @@ fix_placeholder_eval_levels(PlannerInfo *root) ...@@ -162,7 +162,7 @@ fix_placeholder_eval_levels(PlannerInfo *root)
if (bms_membership(eval_at) == BMS_MULTIPLE) if (bms_membership(eval_at) == BMS_MULTIPLE)
{ {
List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr, List *vars = pull_var_clause((Node *) phinfo->ph_var->phexpr,
true); PVC_INCLUDE_PLACEHOLDERS);
add_vars_to_targetlist(root, vars, eval_at); add_vars_to_targetlist(root, vars, eval_at);
list_free(vars); list_free(vars);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.85 2009/01/01 17:23:45 momjian Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.86 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -91,7 +91,8 @@ tlist_member_ignore_relabel(Node *node, List *targetlist) ...@@ -91,7 +91,8 @@ tlist_member_ignore_relabel(Node *node, List *targetlist)
List * List *
flatten_tlist(List *tlist) flatten_tlist(List *tlist)
{ {
List *vlist = pull_var_clause((Node *) tlist, true); List *vlist = pull_var_clause((Node *) tlist,
PVC_INCLUDE_PLACEHOLDERS);
List *new_tlist; List *new_tlist;
new_tlist = add_to_flat_tlist(NIL, vlist); new_tlist = add_to_flat_tlist(NIL, vlist);
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.84 2009/02/25 03:30:37 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.85 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,7 +56,7 @@ typedef struct ...@@ -56,7 +56,7 @@ typedef struct
typedef struct typedef struct
{ {
List *varlist; List *varlist;
bool includePlaceHolderVars; PVCPlaceHolderBehavior behavior;
} pull_var_clause_context; } pull_var_clause_context;
typedef struct typedef struct
...@@ -614,11 +614,13 @@ find_minimum_var_level_walker(Node *node, ...@@ -614,11 +614,13 @@ find_minimum_var_level_walker(Node *node,
* pull_var_clause * pull_var_clause
* Recursively pulls all Var nodes from an expression clause. * Recursively pulls all Var nodes from an expression clause.
* *
* PlaceHolderVars are included too, if includePlaceHolderVars is true. * PlaceHolderVars are handled according to 'behavior':
* If it isn't true, an error is thrown if any are found. * PVC_REJECT_PLACEHOLDERS throw error if PlaceHolderVar found
* Note that Vars within a PHV's expression are *not* included. * PVC_INCLUDE_PLACEHOLDERS include PlaceHolderVars in output list
* PVC_RECURSE_PLACEHOLDERS recurse into PlaceHolderVar argument
* Vars within a PHV's expression are included only in the last case.
* *
* CurrentOfExpr nodes are *not* included. * CurrentOfExpr nodes are ignored in all cases.
* *
* Upper-level vars (with varlevelsup > 0) are not included. * Upper-level vars (with varlevelsup > 0) are not included.
* (These probably represent errors too, but we don't complain.) * (These probably represent errors too, but we don't complain.)
...@@ -630,12 +632,12 @@ find_minimum_var_level_walker(Node *node, ...@@ -630,12 +632,12 @@ find_minimum_var_level_walker(Node *node,
* of sublinks to subplans! * of sublinks to subplans!
*/ */
List * List *
pull_var_clause(Node *node, bool includePlaceHolderVars) pull_var_clause(Node *node, PVCPlaceHolderBehavior behavior)
{ {
pull_var_clause_context context; pull_var_clause_context context;
context.varlist = NIL; context.varlist = NIL;
context.includePlaceHolderVars = includePlaceHolderVars; context.behavior = behavior;
pull_var_clause_walker(node, &context); pull_var_clause_walker(node, &context);
return context.varlist; return context.varlist;
...@@ -654,12 +656,20 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context) ...@@ -654,12 +656,20 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
} }
if (IsA(node, PlaceHolderVar)) if (IsA(node, PlaceHolderVar))
{ {
if (!context->includePlaceHolderVars) switch (context->behavior)
elog(ERROR, "PlaceHolderVar found where not expected"); {
if (((PlaceHolderVar *) node)->phlevelsup == 0) case PVC_REJECT_PLACEHOLDERS:
context->varlist = lappend(context->varlist, node); elog(ERROR, "PlaceHolderVar found where not expected");
/* we do NOT descend into the contained expression */ break;
return false; case PVC_INCLUDE_PLACEHOLDERS:
if (((PlaceHolderVar *) node)->phlevelsup == 0)
context->varlist = lappend(context->varlist, node);
/* we do NOT descend into the contained expression */
return false;
case PVC_RECURSE_PLACEHOLDERS:
/* ignore the placeholder, look at its argument instead */
break;
}
} }
return expression_tree_walker(node, pull_var_clause_walker, return expression_tree_walker(node, pull_var_clause_walker,
(void *) context); (void *) context);
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.259 2009/02/15 20:16:21 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.260 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2984,9 +2984,12 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows) ...@@ -2984,9 +2984,12 @@ estimate_num_groups(PlannerInfo *root, List *groupExprs, double input_rows)
ReleaseVariableStats(vardata); ReleaseVariableStats(vardata);
/* /*
* Else pull out the component Vars * Else pull out the component Vars. Handle PlaceHolderVars by
* recursing into their arguments (effectively assuming that the
* PlaceHolderVar doesn't change the number of groups, which boils
* down to ignoring the possible addition of nulls to the result set).
*/ */
varshere = pull_var_clause(groupexpr, true); varshere = pull_var_clause(groupexpr, PVC_RECURSE_PLACEHOLDERS);
/* /*
* If we find any variable-free GROUP BY item, then either it is a * If we find any variable-free GROUP BY item, then either it is a
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/var.h,v 1.40 2009/01/01 17:24:00 momjian Exp $ * $PostgreSQL: pgsql/src/include/optimizer/var.h,v 1.41 2009/04/19 19:46:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,6 +16,12 @@ ...@@ -16,6 +16,12 @@
#include "nodes/relation.h" #include "nodes/relation.h"
typedef enum
{
PVC_REJECT_PLACEHOLDERS, /* throw error if PlaceHolderVar found */
PVC_INCLUDE_PLACEHOLDERS, /* include PlaceHolderVars in output list */
PVC_RECURSE_PLACEHOLDERS /* recurse into PlaceHolderVar argument */
} PVCPlaceHolderBehavior;
extern Relids pull_varnos(Node *node); extern Relids pull_varnos(Node *node);
extern void pull_varattnos(Node *node, Bitmapset **varattnos); extern void pull_varattnos(Node *node, Bitmapset **varattnos);
...@@ -24,7 +30,7 @@ extern bool contain_vars_of_level(Node *node, int levelsup); ...@@ -24,7 +30,7 @@ extern bool contain_vars_of_level(Node *node, int levelsup);
extern int locate_var_of_level(Node *node, int levelsup); extern int locate_var_of_level(Node *node, int levelsup);
extern int locate_var_of_relation(Node *node, int relid, int levelsup); extern int locate_var_of_relation(Node *node, int relid, int levelsup);
extern int find_minimum_var_level(Node *node); extern int find_minimum_var_level(Node *node);
extern List *pull_var_clause(Node *node, bool includePlaceHolderVars); extern List *pull_var_clause(Node *node, PVCPlaceHolderBehavior behavior);
extern Node *flatten_join_alias_vars(PlannerInfo *root, Node *node); extern Node *flatten_join_alias_vars(PlannerInfo *root, Node *node);
#endif /* VAR_H */ #endif /* VAR_H */
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