Skip to content

Commit 9b27eab

Browse files
committed
Fix set_append_rel_pathlist() to deal intelligently with cases where
substituting a child rel's output expressions into the appendrel's restriction clauses yields a pseudoconstant restriction. We might be able to skip scanning that child rel entirely (if we get constant FALSE), or generate a one-time filter. 8.3 more or less accidentally generated plans that weren't completely stupid in these cases, but that was only because an extra recursive level of subquery_planner() always occurred and allowed const-simplification to happen. 8.4's ability to pull up appendrel members with non-Var outputs exposes the fact that we need to work harder here. Per gripe from Sergey Burladyan.
1 parent bf6570a commit 9b27eab

File tree

4 files changed

+114
-58
lines changed

4 files changed

+114
-58
lines changed

src/backend/optimizer/path/allpaths.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.183 2009/06/11 14:48:58 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.184 2009/07/06 18:26:30 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -29,6 +29,7 @@
2929
#include "optimizer/plancat.h"
3030
#include "optimizer/planner.h"
3131
#include "optimizer/prep.h"
32+
#include "optimizer/restrictinfo.h"
3233
#include "optimizer/var.h"
3334
#include "parser/parse_clause.h"
3435
#include "parser/parsetree.h"
@@ -318,6 +319,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
318319
int childRTindex;
319320
RangeTblEntry *childRTE;
320321
RelOptInfo *childrel;
322+
List *childquals;
323+
Node *childqual;
321324
Path *childpath;
322325
ListCell *parentvars;
323326
ListCell *childvars;
@@ -342,10 +345,34 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
342345
* baserestrictinfo quals are needed before we can check for
343346
* constraint exclusion; so do that first and then check to see if we
344347
* can disregard this child.
348+
*
349+
* As of 8.4, the child rel's targetlist might contain non-Var
350+
* expressions, which means that substitution into the quals
351+
* could produce opportunities for const-simplification, and perhaps
352+
* even pseudoconstant quals. To deal with this, we strip the
353+
* RestrictInfo nodes, do the substitution, do const-simplification,
354+
* and then reconstitute the RestrictInfo layer.
345355
*/
346-
childrel->baserestrictinfo = (List *)
347-
adjust_appendrel_attrs((Node *) rel->baserestrictinfo,
348-
appinfo);
356+
childquals = get_all_actual_clauses(rel->baserestrictinfo);
357+
childquals = (List *) adjust_appendrel_attrs((Node *) childquals,
358+
appinfo);
359+
childqual = eval_const_expressions(root, (Node *)
360+
make_ands_explicit(childquals));
361+
if (childqual && IsA(childqual, Const) &&
362+
(((Const *) childqual)->constisnull ||
363+
!DatumGetBool(((Const *) childqual)->constvalue)))
364+
{
365+
/*
366+
* Restriction reduces to constant FALSE or constant NULL after
367+
* substitution, so this child need not be scanned.
368+
*/
369+
set_dummy_rel_pathlist(childrel);
370+
continue;
371+
}
372+
childquals = make_ands_implicit((Expr *) childqual);
373+
childquals = make_restrictinfos_from_actual_clauses(root,
374+
childquals);
375+
childrel->baserestrictinfo = childquals;
349376

350377
if (relation_excluded_by_constraints(root, childrel, childRTE))
351378
{

src/backend/optimizer/prep/prepunion.c

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
*
2323
*
2424
* IDENTIFICATION
25-
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.171 2009/06/11 14:48:59 momjian Exp $
25+
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.172 2009/07/06 18:26:30 tgl Exp $
2626
*
2727
*-------------------------------------------------------------------------
2828
*/
@@ -1636,57 +1636,7 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
16361636
Assert(!IsA(node, SpecialJoinInfo));
16371637
Assert(!IsA(node, AppendRelInfo));
16381638
Assert(!IsA(node, PlaceHolderInfo));
1639-
1640-
/*
1641-
* We have to process RestrictInfo nodes specially.
1642-
*/
1643-
if (IsA(node, RestrictInfo))
1644-
{
1645-
RestrictInfo *oldinfo = (RestrictInfo *) node;
1646-
RestrictInfo *newinfo = makeNode(RestrictInfo);
1647-
1648-
/* Copy all flat-copiable fields */
1649-
memcpy(newinfo, oldinfo, sizeof(RestrictInfo));
1650-
1651-
/* Recursively fix the clause itself */
1652-
newinfo->clause = (Expr *)
1653-
adjust_appendrel_attrs_mutator((Node *) oldinfo->clause, context);
1654-
1655-
/* and the modified version, if an OR clause */
1656-
newinfo->orclause = (Expr *)
1657-
adjust_appendrel_attrs_mutator((Node *) oldinfo->orclause, context);
1658-
1659-
/* adjust relid sets too */
1660-
newinfo->clause_relids = adjust_relid_set(oldinfo->clause_relids,
1661-
context->parent_relid,
1662-
context->child_relid);
1663-
newinfo->required_relids = adjust_relid_set(oldinfo->required_relids,
1664-
context->parent_relid,
1665-
context->child_relid);
1666-
newinfo->left_relids = adjust_relid_set(oldinfo->left_relids,
1667-
context->parent_relid,
1668-
context->child_relid);
1669-
newinfo->right_relids = adjust_relid_set(oldinfo->right_relids,
1670-
context->parent_relid,
1671-
context->child_relid);
1672-
1673-
/*
1674-
* Reset cached derivative fields, since these might need to have
1675-
* different values when considering the child relation.
1676-
*/
1677-
newinfo->eval_cost.startup = -1;
1678-
newinfo->norm_selec = -1;
1679-
newinfo->outer_selec = -1;
1680-
newinfo->left_ec = NULL;
1681-
newinfo->right_ec = NULL;
1682-
newinfo->left_em = NULL;
1683-
newinfo->right_em = NULL;
1684-
newinfo->scansel_cache = NIL;
1685-
newinfo->left_bucketsize = -1;
1686-
newinfo->right_bucketsize = -1;
1687-
1688-
return (Node *) newinfo;
1689-
}
1639+
Assert(!IsA(node, RestrictInfo));
16901640

16911641
/*
16921642
* NOTE: we do not need to recurse into sublinks, because they should

src/backend/optimizer/util/restrictinfo.c

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.60 2009/06/11 14:48:59 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.61 2009/07/06 18:26:30 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -271,6 +271,57 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
271271
return result;
272272
}
273273

274+
/*
275+
* make_restrictinfos_from_actual_clauses
276+
*
277+
* Given a list of implicitly-ANDed restriction clauses, produce a list
278+
* of RestrictInfo nodes. This is used to reconstitute the RestrictInfo
279+
* representation after doing transformations of a list of clauses.
280+
*
281+
* We assume that the clauses are relation-level restrictions and therefore
282+
* we don't have to worry about is_pushed_down, outerjoin_delayed, or
283+
* nullable_relids (these can be assumed true, false, and NULL, respectively).
284+
* We do take care to recognize pseudoconstant clauses properly.
285+
*/
286+
List *
287+
make_restrictinfos_from_actual_clauses(PlannerInfo *root,
288+
List *clause_list)
289+
{
290+
List *result = NIL;
291+
ListCell *l;
292+
293+
foreach(l, clause_list)
294+
{
295+
Expr *clause = (Expr *) lfirst(l);
296+
bool pseudoconstant;
297+
RestrictInfo *rinfo;
298+
299+
/*
300+
* It's pseudoconstant if it contains no Vars and no volatile
301+
* functions. We probably can't see any sublinks here, so
302+
* contain_var_clause() would likely be enough, but for safety
303+
* use contain_vars_of_level() instead.
304+
*/
305+
pseudoconstant =
306+
!contain_vars_of_level((Node *) clause, 0) &&
307+
!contain_volatile_functions((Node *) clause);
308+
if (pseudoconstant)
309+
{
310+
/* tell createplan.c to check for gating quals */
311+
root->hasPseudoConstantQuals = true;
312+
}
313+
314+
rinfo = make_restrictinfo(clause,
315+
true,
316+
false,
317+
pseudoconstant,
318+
NULL,
319+
NULL);
320+
result = lappend(result, rinfo);
321+
}
322+
return result;
323+
}
324+
274325
/*
275326
* make_restrictinfo_internal
276327
*
@@ -481,6 +532,31 @@ get_actual_clauses(List *restrictinfo_list)
481532
return result;
482533
}
483534

535+
/*
536+
* get_all_actual_clauses
537+
*
538+
* Returns a list containing the bare clauses from 'restrictinfo_list'.
539+
*
540+
* This loses the distinction between regular and pseudoconstant clauses,
541+
* so be careful what you use it for.
542+
*/
543+
List *
544+
get_all_actual_clauses(List *restrictinfo_list)
545+
{
546+
List *result = NIL;
547+
ListCell *l;
548+
549+
foreach(l, restrictinfo_list)
550+
{
551+
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
552+
553+
Assert(IsA(rinfo, RestrictInfo));
554+
555+
result = lappend(result, rinfo->clause);
556+
}
557+
return result;
558+
}
559+
484560
/*
485561
* extract_actual_clauses
486562
*

src/include/optimizer/restrictinfo.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.44 2009/05/09 22:51:41 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.45 2009/07/06 18:26:30 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -30,8 +30,11 @@ extern RestrictInfo *make_restrictinfo(Expr *clause,
3030
extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
3131
bool is_pushed_down,
3232
bool include_predicates);
33+
extern List *make_restrictinfos_from_actual_clauses(PlannerInfo *root,
34+
List *clause_list);
3335
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
3436
extern List *get_actual_clauses(List *restrictinfo_list);
37+
extern List *get_all_actual_clauses(List *restrictinfo_list);
3538
extern List *extract_actual_clauses(List *restrictinfo_list,
3639
bool pseudoconstant);
3740
extern void extract_actual_join_clauses(List *restrictinfo_list,

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy