mirror of
https://github.com/postgres/postgres.git
synced 2025-11-07 19:06:32 +03:00
Pgindent run for 8.0.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.70 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_eval.c,v 1.71 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
|
||||
static bool desirable_join(Query *root,
|
||||
RelOptInfo *outer_rel, RelOptInfo *inner_rel);
|
||||
RelOptInfo *outer_rel, RelOptInfo *inner_rel);
|
||||
|
||||
|
||||
/*
|
||||
@@ -56,8 +56,8 @@ geqo_eval(Gene *tour, int num_gene, GeqoEvalData *evaldata)
|
||||
* redundant cost calculations, we simply reject tours where tour[0] >
|
||||
* tour[1], assigning them an artificially bad fitness.
|
||||
*
|
||||
* init_tour() is aware of this rule and so we should never reject a
|
||||
* tour during the initial filling of the pool. It seems difficult to
|
||||
* init_tour() is aware of this rule and so we should never reject a tour
|
||||
* during the initial filling of the pool. It seems difficult to
|
||||
* persuade the recombination logic never to break the rule, however.
|
||||
*/
|
||||
if (num_gene >= 2 && tour[0] > tour[1])
|
||||
@@ -151,23 +151,24 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
|
||||
/*
|
||||
* Push each relation onto the stack in the specified order. After
|
||||
* pushing each relation, see whether the top two stack entries are
|
||||
* joinable according to the desirable_join() heuristics. If so,
|
||||
* join them into one stack entry, and try again to combine with the
|
||||
* next stack entry down (if any). When the stack top is no longer
|
||||
* joinable, continue to the next input relation. After we have pushed
|
||||
* the last input relation, the heuristics are disabled and we force
|
||||
* joining all the remaining stack entries.
|
||||
* joinable according to the desirable_join() heuristics. If so, join
|
||||
* them into one stack entry, and try again to combine with the next
|
||||
* stack entry down (if any). When the stack top is no longer
|
||||
* joinable, continue to the next input relation. After we have
|
||||
* pushed the last input relation, the heuristics are disabled and we
|
||||
* force joining all the remaining stack entries.
|
||||
*
|
||||
* If desirable_join() always returns true, this produces a straight
|
||||
* left-to-right join just like the old code. Otherwise we may produce
|
||||
* a bushy plan or a left/right-sided plan that really corresponds to
|
||||
* some tour other than the one given. To the extent that the heuristics
|
||||
* are helpful, however, this will be a better plan than the raw tour.
|
||||
* left-to-right join just like the old code. Otherwise we may
|
||||
* produce a bushy plan or a left/right-sided plan that really
|
||||
* corresponds to some tour other than the one given. To the extent
|
||||
* that the heuristics are helpful, however, this will be a better
|
||||
* plan than the raw tour.
|
||||
*
|
||||
* Also, when a join attempt fails (because of IN-clause constraints),
|
||||
* we may be able to recover and produce a workable plan, where the old
|
||||
* code just had to give up. This case acts the same as a false result
|
||||
* from desirable_join().
|
||||
* Also, when a join attempt fails (because of IN-clause constraints), we
|
||||
* may be able to recover and produce a workable plan, where the old
|
||||
* code just had to give up. This case acts the same as a false
|
||||
* result from desirable_join().
|
||||
*/
|
||||
for (rel_count = 0; rel_count < num_gene; rel_count++)
|
||||
{
|
||||
@@ -189,20 +190,20 @@ gimme_tree(Gene *tour, int num_gene, GeqoEvalData *evaldata)
|
||||
RelOptInfo *inner_rel = stack[stack_depth - 1];
|
||||
|
||||
/*
|
||||
* Don't pop if heuristics say not to join now. However,
|
||||
* once we have exhausted the input, the heuristics can't
|
||||
* prevent popping.
|
||||
* Don't pop if heuristics say not to join now. However, once
|
||||
* we have exhausted the input, the heuristics can't prevent
|
||||
* popping.
|
||||
*/
|
||||
if (rel_count < num_gene - 1 &&
|
||||
!desirable_join(evaldata->root, outer_rel, inner_rel))
|
||||
break;
|
||||
|
||||
/*
|
||||
* Construct a RelOptInfo representing the join of these
|
||||
* two input relations. These are always inner joins.
|
||||
* Note that we expect the joinrel not to exist in
|
||||
* root->join_rel_list yet, and so the paths constructed for it
|
||||
* will only include the ones we want.
|
||||
* Construct a RelOptInfo representing the join of these two
|
||||
* input relations. These are always inner joins. Note that
|
||||
* we expect the joinrel not to exist in root->join_rel_list
|
||||
* yet, and so the paths constructed for it will only include
|
||||
* the ones we want.
|
||||
*/
|
||||
joinrel = make_join_rel(evaldata->root, outer_rel, inner_rel,
|
||||
JOIN_INNER);
|
||||
@@ -252,9 +253,9 @@ desirable_join(Query *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* Join if the rels are members of the same IN sub-select. This is
|
||||
* needed to improve the odds that we will find a valid solution in
|
||||
* a case where an IN sub-select has a clauseless join.
|
||||
* Join if the rels are members of the same IN sub-select. This is
|
||||
* needed to improve the odds that we will find a valid solution in a
|
||||
* case where an IN sub-select has a clauseless join.
|
||||
*/
|
||||
foreach(l, root->in_info_list)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.46 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_main.c,v 1.47 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -310,11 +310,11 @@ gimme_pool_size(int nr_rel)
|
||||
|
||||
size = pow(2.0, nr_rel + 1.0);
|
||||
|
||||
maxsize = 50 * Geqo_effort; /* 50 to 500 individuals */
|
||||
maxsize = 50 * Geqo_effort; /* 50 to 500 individuals */
|
||||
if (size > maxsize)
|
||||
return maxsize;
|
||||
|
||||
minsize = 10 * Geqo_effort; /* 10 to 100 individuals */
|
||||
minsize = 10 * Geqo_effort; /* 10 to 100 individuals */
|
||||
if (size < minsize)
|
||||
return minsize;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.24 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_pool.c,v 1.25 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -96,8 +96,9 @@ random_init_pool(Pool *pool, GeqoEvalData *evaldata)
|
||||
int bad = 0;
|
||||
|
||||
/*
|
||||
* We immediately discard any invalid individuals (those that geqo_eval
|
||||
* returns DBL_MAX for), thereby not wasting pool space on them.
|
||||
* We immediately discard any invalid individuals (those that
|
||||
* geqo_eval returns DBL_MAX for), thereby not wasting pool space on
|
||||
* them.
|
||||
*
|
||||
* If we fail to make any valid individuals after 10000 tries, give up;
|
||||
* this probably means something is broken, and we shouldn't just let
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* geqo_recombination.c
|
||||
* misc recombination procedures
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.13 2004/01/23 23:54:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/geqo/geqo_recombination.c,v 1.14 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -62,12 +62,12 @@ init_tour(Gene *tour, int num_gene)
|
||||
}
|
||||
|
||||
/*
|
||||
* Since geqo_eval() will reject tours where tour[0] > tour[1],
|
||||
* we may as well switch the two to make it a valid tour.
|
||||
* Since geqo_eval() will reject tours where tour[0] > tour[1], we may
|
||||
* as well switch the two to make it a valid tour.
|
||||
*/
|
||||
if (num_gene >= 2 && tour[0] > tour[1])
|
||||
{
|
||||
Gene gtmp = tour[0];
|
||||
Gene gtmp = tour[0];
|
||||
|
||||
tour[0] = tour[1];
|
||||
tour[1] = gtmp;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.120 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.121 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -58,9 +58,9 @@ static void compare_tlist_datatypes(List *tlist, List *colTypes,
|
||||
static bool qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
|
||||
bool *differentTypes);
|
||||
static void subquery_push_qual(Query *subquery, List *rtable,
|
||||
Index rti, Node *qual);
|
||||
Index rti, Node *qual);
|
||||
static void recurse_push_qual(Node *setOp, Query *topquery,
|
||||
List *rtable, Index rti, Node *qual);
|
||||
List *rtable, Index rti, Node *qual);
|
||||
|
||||
|
||||
/*
|
||||
@@ -102,7 +102,7 @@ make_one_rel(Query *root)
|
||||
static void
|
||||
set_base_rel_pathlists(Query *root)
|
||||
{
|
||||
ListCell *l;
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, root->base_rel_list)
|
||||
{
|
||||
@@ -156,9 +156,9 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
|
||||
check_partial_indexes(root, rel);
|
||||
|
||||
/*
|
||||
* Check to see if we can extract any restriction conditions from
|
||||
* join quals that are OR-of-AND structures. If so, add them to the
|
||||
* rel's restriction list, and recompute the size estimates.
|
||||
* Check to see if we can extract any restriction conditions from join
|
||||
* quals that are OR-of-AND structures. If so, add them to the rel's
|
||||
* restriction list, and recompute the size estimates.
|
||||
*/
|
||||
if (create_or_index_quals(root, rel))
|
||||
set_baserel_size_estimates(root, rel);
|
||||
@@ -303,7 +303,7 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
|
||||
Var *parentvar = (Var *) lfirst(parentvars);
|
||||
Var *childvar = (Var *) lfirst(childvars);
|
||||
|
||||
if (IsA(parentvar, Var) && IsA(childvar, Var))
|
||||
if (IsA(parentvar, Var) &&IsA(childvar, Var))
|
||||
{
|
||||
int pndx = parentvar->varattno - rel->min_attr;
|
||||
int cndx = childvar->varattno - childrel->min_attr;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.69 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.70 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -128,7 +128,7 @@ clauselist_selectivity(Query *root,
|
||||
/*
|
||||
* See if it looks like a restriction clause with a pseudoconstant
|
||||
* on one side. (Anything more complicated than that might not
|
||||
* behave in the simple way we are expecting.) Most of the tests
|
||||
* behave in the simple way we are expecting.) Most of the tests
|
||||
* here can be done more efficiently with rinfo than without.
|
||||
*/
|
||||
if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
|
||||
@@ -141,10 +141,10 @@ clauselist_selectivity(Query *root,
|
||||
{
|
||||
ok = (bms_membership(rinfo->clause_relids) == BMS_SINGLETON) &&
|
||||
(is_pseudo_constant_clause_relids(lsecond(expr->args),
|
||||
rinfo->right_relids) ||
|
||||
rinfo->right_relids) ||
|
||||
(varonleft = false,
|
||||
is_pseudo_constant_clause_relids(linitial(expr->args),
|
||||
rinfo->left_relids)));
|
||||
is_pseudo_constant_clause_relids(linitial(expr->args),
|
||||
rinfo->left_relids)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -158,9 +158,8 @@ clauselist_selectivity(Query *root,
|
||||
{
|
||||
/*
|
||||
* If it's not a "<" or ">" operator, just merge the
|
||||
* selectivity in generically. But if it's the
|
||||
* right oprrest, add the clause to rqlist for later
|
||||
* processing.
|
||||
* selectivity in generically. But if it's the right
|
||||
* oprrest, add the clause to rqlist for later processing.
|
||||
*/
|
||||
switch (get_oprrest(expr->opno))
|
||||
{
|
||||
@@ -409,16 +408,17 @@ clause_selectivity(Query *root,
|
||||
rinfo = (RestrictInfo *) clause;
|
||||
|
||||
/*
|
||||
* If possible, cache the result of the selectivity calculation for
|
||||
* the clause. We can cache if varRelid is zero or the clause
|
||||
* contains only vars of that relid --- otherwise varRelid will affect
|
||||
* the result, so mustn't cache. We also have to be careful about
|
||||
* the jointype. It's OK to cache when jointype is JOIN_INNER or
|
||||
* one of the outer join types (any given outer-join clause should
|
||||
* always be examined with the same jointype, so result won't change).
|
||||
* It's not OK to cache when jointype is one of the special types
|
||||
* associated with IN processing, because the same clause may be
|
||||
* examined with different jointypes and the result should vary.
|
||||
* If possible, cache the result of the selectivity calculation
|
||||
* for the clause. We can cache if varRelid is zero or the clause
|
||||
* contains only vars of that relid --- otherwise varRelid will
|
||||
* affect the result, so mustn't cache. We also have to be
|
||||
* careful about the jointype. It's OK to cache when jointype is
|
||||
* JOIN_INNER or one of the outer join types (any given outer-join
|
||||
* clause should always be examined with the same jointype, so
|
||||
* result won't change). It's not OK to cache when jointype is one
|
||||
* of the special types associated with IN processing, because the
|
||||
* same clause may be examined with different jointypes and the
|
||||
* result should vary.
|
||||
*/
|
||||
if (varRelid == 0 ||
|
||||
bms_is_subset_singleton(rinfo->clause_relids, varRelid))
|
||||
@@ -481,7 +481,7 @@ clause_selectivity(Query *root,
|
||||
s1 = restriction_selectivity(root,
|
||||
BooleanEqualOperator,
|
||||
list_make2(var,
|
||||
makeBoolConst(true,
|
||||
makeBoolConst(true,
|
||||
false)),
|
||||
varRelid);
|
||||
}
|
||||
@@ -495,7 +495,7 @@ clause_selectivity(Query *root,
|
||||
else if (IsA(clause, Param))
|
||||
{
|
||||
/* see if we can replace the Param */
|
||||
Node *subst = estimate_expression_value(clause);
|
||||
Node *subst = estimate_expression_value(clause);
|
||||
|
||||
if (IsA(subst, Const))
|
||||
{
|
||||
@@ -527,8 +527,8 @@ clause_selectivity(Query *root,
|
||||
else if (or_clause(clause))
|
||||
{
|
||||
/*
|
||||
* Selectivities for an OR clause are computed as s1+s2 - s1*s2
|
||||
* to account for the probable overlap of selected tuple sets.
|
||||
* Selectivities for an OR clause are computed as s1+s2 - s1*s2 to
|
||||
* account for the probable overlap of selected tuple sets.
|
||||
*
|
||||
* XXX is this too conservative?
|
||||
*/
|
||||
@@ -563,7 +563,8 @@ clause_selectivity(Query *root,
|
||||
{
|
||||
/*
|
||||
* Otherwise, it's a join if there's more than one relation
|
||||
* used. We can optimize this calculation if an rinfo was passed.
|
||||
* used. We can optimize this calculation if an rinfo was
|
||||
* passed.
|
||||
*/
|
||||
if (rinfo)
|
||||
is_join_clause = (bms_membership(rinfo->clause_relids) ==
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.133 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.134 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -746,10 +746,10 @@ cost_nestloop(NestPath *path, Query *root)
|
||||
Selectivity joininfactor;
|
||||
|
||||
/*
|
||||
* If inner path is an indexscan, be sure to use its estimated output row
|
||||
* count, which may be lower than the restriction-clause-only row count of
|
||||
* its parent. (We don't include this case in the PATH_ROWS macro because
|
||||
* it applies *only* to a nestloop's inner relation.)
|
||||
* If inner path is an indexscan, be sure to use its estimated output
|
||||
* row count, which may be lower than the restriction-clause-only row
|
||||
* count of its parent. (We don't include this case in the PATH_ROWS
|
||||
* macro because it applies *only* to a nestloop's inner relation.)
|
||||
*/
|
||||
if (IsA(inner_path, IndexPath))
|
||||
inner_path_rows = ((IndexPath *) inner_path)->rows;
|
||||
@@ -761,8 +761,8 @@ cost_nestloop(NestPath *path, Query *root)
|
||||
* If we're doing JOIN_IN then we will stop scanning inner tuples for
|
||||
* an outer tuple as soon as we have one match. Account for the
|
||||
* effects of this by scaling down the cost estimates in proportion to
|
||||
* the JOIN_IN selectivity. (This assumes that all the quals
|
||||
* attached to the join are IN quals, which should be true.)
|
||||
* the JOIN_IN selectivity. (This assumes that all the quals attached
|
||||
* to the join are IN quals, which should be true.)
|
||||
*/
|
||||
joininfactor = join_in_selectivity(path, root);
|
||||
|
||||
@@ -922,7 +922,7 @@ cost_mergejoin(MergePath *path, Query *root)
|
||||
if (mergeclauses)
|
||||
{
|
||||
firstclause = (RestrictInfo *) linitial(mergeclauses);
|
||||
if (firstclause->left_mergescansel < 0) /* not computed yet? */
|
||||
if (firstclause->left_mergescansel < 0) /* not computed yet? */
|
||||
mergejoinscansel(root, (Node *) firstclause->clause,
|
||||
&firstclause->left_mergescansel,
|
||||
&firstclause->right_mergescansel);
|
||||
@@ -1159,7 +1159,7 @@ cost_hashjoin(HashPath *path, Query *root)
|
||||
/* not cached yet */
|
||||
thisbucketsize =
|
||||
estimate_hash_bucketsize(root,
|
||||
get_rightop(restrictinfo->clause),
|
||||
get_rightop(restrictinfo->clause),
|
||||
virtualbuckets);
|
||||
restrictinfo->right_bucketsize = thisbucketsize;
|
||||
}
|
||||
@@ -1175,7 +1175,7 @@ cost_hashjoin(HashPath *path, Query *root)
|
||||
/* not cached yet */
|
||||
thisbucketsize =
|
||||
estimate_hash_bucketsize(root,
|
||||
get_leftop(restrictinfo->clause),
|
||||
get_leftop(restrictinfo->clause),
|
||||
virtualbuckets);
|
||||
restrictinfo->left_bucketsize = thisbucketsize;
|
||||
}
|
||||
@@ -1617,11 +1617,12 @@ join_in_selectivity(JoinPath *path, Query *root)
|
||||
return 1.0;
|
||||
|
||||
/*
|
||||
* Return 1.0 if the inner side is already known unique. The case where
|
||||
* the inner path is already a UniquePath probably cannot happen in
|
||||
* current usage, but check it anyway for completeness. The interesting
|
||||
* case is where we've determined the inner relation itself is unique,
|
||||
* which we can check by looking at the rows estimate for its UniquePath.
|
||||
* Return 1.0 if the inner side is already known unique. The case
|
||||
* where the inner path is already a UniquePath probably cannot happen
|
||||
* in current usage, but check it anyway for completeness. The
|
||||
* interesting case is where we've determined the inner relation
|
||||
* itself is unique, which we can check by looking at the rows
|
||||
* estimate for its UniquePath.
|
||||
*/
|
||||
if (IsA(path->innerjoinpath, UniquePath))
|
||||
return 1.0;
|
||||
@@ -1633,11 +1634,11 @@ join_in_selectivity(JoinPath *path, Query *root)
|
||||
return 1.0;
|
||||
|
||||
/*
|
||||
* Compute same result set_joinrel_size_estimates would compute
|
||||
* for JOIN_INNER. Note that we use the input rels' absolute size
|
||||
* estimates, not PATH_ROWS() which might be less; if we used PATH_ROWS()
|
||||
* we'd be double-counting the effects of any join clauses used in
|
||||
* input scans.
|
||||
* Compute same result set_joinrel_size_estimates would compute for
|
||||
* JOIN_INNER. Note that we use the input rels' absolute size
|
||||
* estimates, not PATH_ROWS() which might be less; if we used
|
||||
* PATH_ROWS() we'd be double-counting the effects of any join clauses
|
||||
* used in input scans.
|
||||
*/
|
||||
selec = clauselist_selectivity(root,
|
||||
path->joinrestrictinfo,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.163 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.164 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -57,11 +57,11 @@ static List *group_clauses_by_indexkey_for_join(Query *root,
|
||||
Relids outer_relids,
|
||||
JoinType jointype, bool isouterjoin);
|
||||
static bool match_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index,
|
||||
int indexcol, Oid opclass,
|
||||
RestrictInfo *rinfo);
|
||||
int indexcol, Oid opclass,
|
||||
RestrictInfo *rinfo);
|
||||
static bool match_join_clause_to_indexcol(RelOptInfo *rel, IndexOptInfo *index,
|
||||
int indexcol, Oid opclass,
|
||||
RestrictInfo *rinfo);
|
||||
int indexcol, Oid opclass,
|
||||
RestrictInfo *rinfo);
|
||||
static Oid indexable_operator(Expr *clause, Oid opclass,
|
||||
bool indexkey_on_left);
|
||||
static bool pred_test(List *predicate_list, List *restrictinfo_list);
|
||||
@@ -137,8 +137,8 @@ create_index_paths(Query *root, RelOptInfo *rel)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* 1. Match the index against non-OR restriction clauses.
|
||||
* (OR clauses will be considered later by orindxpath.c.)
|
||||
* 1. Match the index against non-OR restriction clauses. (OR
|
||||
* clauses will be considered later by orindxpath.c.)
|
||||
*/
|
||||
restrictclauses = group_clauses_by_indexkey(rel, index);
|
||||
|
||||
@@ -312,12 +312,12 @@ group_clauses_by_indexkey_for_join(Query *root,
|
||||
ListCell *l;
|
||||
|
||||
/*
|
||||
* We can always use plain restriction clauses for the rel. We scan
|
||||
* these first because we want them first in the clausegroup list
|
||||
* for the convenience of remove_redundant_join_clauses, which can
|
||||
* never remove non-join clauses and hence won't be able to get rid
|
||||
* of a non-join clause if it appears after a join clause it is
|
||||
* redundant with.
|
||||
* We can always use plain restriction clauses for the rel. We
|
||||
* scan these first because we want them first in the clausegroup
|
||||
* list for the convenience of remove_redundant_join_clauses,
|
||||
* which can never remove non-join clauses and hence won't be able
|
||||
* to get rid of a non-join clause if it appears after a join
|
||||
* clause it is redundant with.
|
||||
*/
|
||||
foreach(l, rel->baserestrictinfo)
|
||||
{
|
||||
@@ -374,8 +374,8 @@ group_clauses_by_indexkey_for_join(Query *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* If we found clauses in more than one list, we may now have clauses
|
||||
* that are known redundant. Get rid of 'em.
|
||||
* If we found clauses in more than one list, we may now have
|
||||
* clauses that are known redundant. Get rid of 'em.
|
||||
*/
|
||||
if (numsources > 1)
|
||||
{
|
||||
@@ -416,7 +416,7 @@ group_clauses_by_indexkey_for_join(Query *root,
|
||||
* top-level restriction clauses of the relation. Furthermore, we demand
|
||||
* that at least one such use be made, otherwise we fail and return NIL.
|
||||
* (Any path we made without such a use would be redundant with non-OR
|
||||
* indexscans. Compare also group_clauses_by_indexkey_for_join.)
|
||||
* indexscans. Compare also group_clauses_by_indexkey_for_join.)
|
||||
*
|
||||
* XXX When we generate an indexqual list that uses both the OR subclause
|
||||
* and top-level restriction clauses, we end up with a slightly inefficient
|
||||
@@ -473,8 +473,8 @@ group_clauses_by_indexkey_for_or(RelOptInfo *rel,
|
||||
* If we found no clauses for this indexkey in the OR subclause
|
||||
* itself, try looking in the rel's top-level restriction list.
|
||||
*
|
||||
* XXX should we always search the top-level list? Slower but
|
||||
* could sometimes yield a better plan.
|
||||
* XXX should we always search the top-level list? Slower but could
|
||||
* sometimes yield a better plan.
|
||||
*/
|
||||
if (clausegroup == NIL)
|
||||
{
|
||||
@@ -910,7 +910,7 @@ pred_test_recurse_pred(Expr *predicate, Node *clause)
|
||||
*
|
||||
* The strategy numbers defined by btree indexes (see access/skey.h) are:
|
||||
* (1) < (2) <= (3) = (4) >= (5) >
|
||||
* and in addition we use (6) to represent <>. <> is not a btree-indexable
|
||||
* and in addition we use (6) to represent <>. <> is not a btree-indexable
|
||||
* operator, but we assume here that if the equality operator of a btree
|
||||
* opclass has a negator operator, the negator behaves as <> for the opclass.
|
||||
*
|
||||
@@ -943,14 +943,14 @@ static const StrategyNumber
|
||||
/*
|
||||
* The target operator:
|
||||
*
|
||||
* LT LE EQ GE GT NE
|
||||
* LT LE EQ GE GT NE
|
||||
*/
|
||||
{BTGE, BTGE, 0, 0, 0, BTGE}, /* LT */
|
||||
{BTGT, BTGE, 0, 0, 0, BTGT}, /* LE */
|
||||
{BTGE, BTGE, 0, 0, 0, BTGE}, /* LT */
|
||||
{BTGT, BTGE, 0, 0, 0, BTGT}, /* LE */
|
||||
{BTGT, BTGE, BTEQ, BTLE, BTLT, BTNE}, /* EQ */
|
||||
{ 0, 0, 0, BTLE, BTLT, BTLT}, /* GE */
|
||||
{ 0, 0, 0, BTLE, BTLE, BTLE}, /* GT */
|
||||
{ 0, 0, 0, 0, 0, BTEQ} /* NE */
|
||||
{0, 0, 0, BTLE, BTLT, BTLT}, /* GE */
|
||||
{0, 0, 0, BTLE, BTLE, BTLE}, /* GT */
|
||||
{0, 0, 0, 0, 0, BTEQ} /* NE */
|
||||
};
|
||||
|
||||
|
||||
@@ -963,21 +963,21 @@ static const StrategyNumber
|
||||
* implies another:
|
||||
*
|
||||
* A simple and general way is to see if they are equal(); this works for any
|
||||
* kind of expression. (Actually, there is an implied assumption that the
|
||||
* kind of expression. (Actually, there is an implied assumption that the
|
||||
* functions in the expression are immutable, ie dependent only on their input
|
||||
* arguments --- but this was checked for the predicate by CheckPredicate().)
|
||||
*
|
||||
* When the predicate is of the form "foo IS NOT NULL", we can conclude that
|
||||
* the predicate is implied if the clause is a strict operator or function
|
||||
* that has "foo" as an input. In this case the clause must yield NULL when
|
||||
* that has "foo" as an input. In this case the clause must yield NULL when
|
||||
* "foo" is NULL, which we can take as equivalent to FALSE because we know
|
||||
* we are within an AND/OR subtree of a WHERE clause. (Again, "foo" is
|
||||
* already known immutable, so the clause will certainly always fail.)
|
||||
*
|
||||
* Our other way works only for binary boolean opclauses of the form
|
||||
* "foo op constant", where "foo" is the same in both clauses. The operators
|
||||
* "foo op constant", where "foo" is the same in both clauses. The operators
|
||||
* and constants can be different but the operators must be in the same btree
|
||||
* operator class. We use the above operator implication table to be able to
|
||||
* operator class. We use the above operator implication table to be able to
|
||||
* derive implications between nonidentical clauses. (Note: "foo" is known
|
||||
* immutable, and constants are surely immutable, but we have to check that
|
||||
* the operators are too. As of 8.0 it's possible for opclasses to contain
|
||||
@@ -1028,7 +1028,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
if (predicate && IsA(predicate, NullTest) &&
|
||||
((NullTest *) predicate)->nulltesttype == IS_NOT_NULL)
|
||||
{
|
||||
Expr *nonnullarg = ((NullTest *) predicate)->arg;
|
||||
Expr *nonnullarg = ((NullTest *) predicate)->arg;
|
||||
|
||||
if (is_opclause(clause) &&
|
||||
list_member(((OpExpr *) clause)->args, nonnullarg) &&
|
||||
@@ -1044,8 +1044,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
/*
|
||||
* Can't do anything more unless they are both binary opclauses with a
|
||||
* Const on one side, and identical subexpressions on the other sides.
|
||||
* Note we don't have to think about binary relabeling of the Const node,
|
||||
* since that would have been folded right into the Const.
|
||||
* Note we don't have to think about binary relabeling of the Const
|
||||
* node, since that would have been folded right into the Const.
|
||||
*
|
||||
* If either Const is null, we also fail right away; this assumes that
|
||||
* the test operator will always be strict.
|
||||
@@ -1097,9 +1097,9 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Check for matching subexpressions on the non-Const sides. We used to
|
||||
* only allow a simple Var, but it's about as easy to allow any
|
||||
* expression. Remember we already know that the pred expression does
|
||||
* Check for matching subexpressions on the non-Const sides. We used
|
||||
* to only allow a simple Var, but it's about as easy to allow any
|
||||
* expression. Remember we already know that the pred expression does
|
||||
* not contain any non-immutable functions, so identical expressions
|
||||
* should yield identical results.
|
||||
*/
|
||||
@@ -1107,9 +1107,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Okay, get the operators in the two clauses we're comparing.
|
||||
* Commute them if needed so that we can assume the variables are
|
||||
* on the left.
|
||||
* Okay, get the operators in the two clauses we're comparing. Commute
|
||||
* them if needed so that we can assume the variables are on the left.
|
||||
*/
|
||||
pred_op = ((OpExpr *) predicate)->opno;
|
||||
if (!pred_var_on_left)
|
||||
@@ -1132,16 +1131,16 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
*
|
||||
* We must find a btree opclass that contains both operators, else the
|
||||
* implication can't be determined. Also, the pred_op has to be of
|
||||
* default subtype (implying left and right input datatypes are the same);
|
||||
* otherwise it's unsafe to put the pred_const on the left side of the
|
||||
* test. Also, the opclass must contain a suitable test operator
|
||||
* matching the clause_const's type (which we take to mean that it has
|
||||
* the same subtype as the original clause_operator).
|
||||
* default subtype (implying left and right input datatypes are the
|
||||
* same); otherwise it's unsafe to put the pred_const on the left side
|
||||
* of the test. Also, the opclass must contain a suitable test
|
||||
* operator matching the clause_const's type (which we take to mean
|
||||
* that it has the same subtype as the original clause_operator).
|
||||
*
|
||||
* If there are multiple matching opclasses, assume we can use any one to
|
||||
* determine the logical relationship of the two operators and the correct
|
||||
* corresponding test operator. This should work for any logically
|
||||
* consistent opclasses.
|
||||
* determine the logical relationship of the two operators and the
|
||||
* correct corresponding test operator. This should work for any
|
||||
* logically consistent opclasses.
|
||||
*/
|
||||
catlist = SearchSysCacheList(AMOPOPID, 1,
|
||||
ObjectIdGetDatum(pred_op),
|
||||
@@ -1160,7 +1159,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
pred_op_negated = true;
|
||||
ReleaseSysCacheList(catlist);
|
||||
catlist = SearchSysCacheList(AMOPOPID, 1,
|
||||
ObjectIdGetDatum(pred_op_negator),
|
||||
ObjectIdGetDatum(pred_op_negator),
|
||||
0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -1197,8 +1196,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
}
|
||||
|
||||
/*
|
||||
* From the same opclass, find a strategy number for the clause_op,
|
||||
* if possible
|
||||
* From the same opclass, find a strategy number for the
|
||||
* clause_op, if possible
|
||||
*/
|
||||
clause_tuple = SearchSysCache(AMOPOPID,
|
||||
ObjectIdGetDatum(clause_op),
|
||||
@@ -1217,7 +1216,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
else if (OidIsValid(clause_op_negator))
|
||||
{
|
||||
clause_tuple = SearchSysCache(AMOPOPID,
|
||||
ObjectIdGetDatum(clause_op_negator),
|
||||
ObjectIdGetDatum(clause_op_negator),
|
||||
ObjectIdGetDatum(opclass_id),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(clause_tuple))
|
||||
@@ -1272,8 +1271,8 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
/*
|
||||
* Last check: test_op must be immutable.
|
||||
*
|
||||
* Note that we require only the test_op to be immutable, not
|
||||
* the original clause_op. (pred_op must be immutable, else it
|
||||
* Note that we require only the test_op to be immutable, not the
|
||||
* original clause_op. (pred_op must be immutable, else it
|
||||
* would not be allowed in an index predicate.) Essentially
|
||||
* we are assuming that the opclass is consistent even if it
|
||||
* contains operators that are merely stable.
|
||||
@@ -1314,7 +1313,7 @@ pred_test_simple_clause(Expr *predicate, Node *clause)
|
||||
|
||||
/* And execute it. */
|
||||
test_result = ExecEvalExprSwitchContext(test_exprstate,
|
||||
GetPerTupleExprContext(estate),
|
||||
GetPerTupleExprContext(estate),
|
||||
&isNull, NULL);
|
||||
|
||||
/* Get back to outer memory context */
|
||||
@@ -1667,9 +1666,7 @@ flatten_clausegroups_list(List *clausegroups)
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, clausegroups)
|
||||
{
|
||||
allclauses = list_concat(allclauses, list_copy((List *) lfirst(l)));
|
||||
}
|
||||
return allclauses;
|
||||
}
|
||||
|
||||
@@ -1692,7 +1689,7 @@ make_expr_from_indexclauses(List *indexclauses)
|
||||
|
||||
foreach(orlist, indexclauses)
|
||||
{
|
||||
List *andlist = (List *) lfirst(orlist);
|
||||
List *andlist = (List *) lfirst(orlist);
|
||||
|
||||
/* Strip RestrictInfos */
|
||||
andlist = get_actual_clauses(andlist);
|
||||
@@ -1994,7 +1991,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
* (The latter is not depended on by any part of the planner, so far as I can
|
||||
* tell; but some parts of the executor do assume that the indxqual list
|
||||
* ultimately delivered to the executor is so ordered. One such place is
|
||||
* _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed
|
||||
* _bt_preprocess_keys() in the btree support. Perhaps that ought to be fixed
|
||||
* someday --- tgl 7/00)
|
||||
*/
|
||||
List *
|
||||
@@ -2019,7 +2016,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
|
||||
resultquals = list_concat(resultquals,
|
||||
expand_indexqual_condition(rinfo,
|
||||
curClass));
|
||||
curClass));
|
||||
}
|
||||
|
||||
clausegroup_item = lnext(clausegroup_item);
|
||||
@@ -2040,6 +2037,7 @@ static List *
|
||||
expand_indexqual_condition(RestrictInfo *rinfo, Oid opclass)
|
||||
{
|
||||
Expr *clause = rinfo->clause;
|
||||
|
||||
/* we know these will succeed */
|
||||
Node *leftop = get_leftop(clause);
|
||||
Node *rightop = get_rightop(clause);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.89 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.90 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -254,7 +254,7 @@ sort_inner_and_outer(Query *root,
|
||||
|
||||
/* Forget it if can't use all the clauses in right/full join */
|
||||
if (useallclauses &&
|
||||
list_length(cur_mergeclauses) != list_length(mergeclause_list))
|
||||
list_length(cur_mergeclauses) != list_length(mergeclause_list))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -492,8 +492,8 @@ match_unsorted_outer(Query *root,
|
||||
/*
|
||||
* Done with this outer path if no chance for a mergejoin.
|
||||
*
|
||||
* Special corner case: for "x FULL JOIN y ON true", there will be
|
||||
* no join clauses at all. Ordinarily we'd generate a clauseless
|
||||
* Special corner case: for "x FULL JOIN y ON true", there will be no
|
||||
* join clauses at all. Ordinarily we'd generate a clauseless
|
||||
* nestloop path, but since mergejoin is our only join type that
|
||||
* supports FULL JOIN, it's necessary to generate a clauseless
|
||||
* mergejoin path instead.
|
||||
@@ -506,7 +506,7 @@ match_unsorted_outer(Query *root,
|
||||
if (mergeclauses == NIL)
|
||||
{
|
||||
if (jointype == JOIN_FULL && restrictlist == NIL)
|
||||
/* okay to try for mergejoin */ ;
|
||||
/* okay to try for mergejoin */ ;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.70 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.71 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -70,7 +70,8 @@ make_rels_by_joins(Query *root, int level, List **joinrels)
|
||||
other_rels = lnext(r); /* only consider remaining initial
|
||||
* rels */
|
||||
else
|
||||
other_rels = list_head(joinrels[1]); /* consider all initial rels */
|
||||
other_rels = list_head(joinrels[1]); /* consider all initial
|
||||
* rels */
|
||||
|
||||
if (old_rel->joininfo != NIL)
|
||||
{
|
||||
@@ -84,12 +85,14 @@ make_rels_by_joins(Query *root, int level, List **joinrels)
|
||||
new_rels = make_rels_by_clause_joins(root,
|
||||
old_rel,
|
||||
other_rels);
|
||||
|
||||
/*
|
||||
* An exception occurs when there is a clauseless join inside an
|
||||
* IN (sub-SELECT) construct. Here, the members of the subselect
|
||||
* all have join clauses (against the stuff outside the IN), but
|
||||
* they *must* be joined to each other before we can make use of
|
||||
* those join clauses. So do the clauseless join bit.
|
||||
* An exception occurs when there is a clauseless join inside
|
||||
* an IN (sub-SELECT) construct. Here, the members of the
|
||||
* subselect all have join clauses (against the stuff outside
|
||||
* the IN), but they *must* be joined to each other before we
|
||||
* can make use of those join clauses. So do the clauseless
|
||||
* join bit.
|
||||
*
|
||||
* See also the last-ditch case below.
|
||||
*/
|
||||
@@ -223,8 +226,8 @@ make_rels_by_joins(Query *root, int level, List **joinrels)
|
||||
other_rels = lnext(r); /* only consider remaining initial
|
||||
* rels */
|
||||
else
|
||||
other_rels = list_head(joinrels[1]); /* consider all initial
|
||||
* rels */
|
||||
other_rels = list_head(joinrels[1]); /* consider all initial
|
||||
* rels */
|
||||
|
||||
new_rels = make_rels_by_clauseless_joins(root,
|
||||
old_rel,
|
||||
@@ -241,11 +244,11 @@ make_rels_by_joins(Query *root, int level, List **joinrels)
|
||||
|
||||
/*----------
|
||||
* When IN clauses are involved, there may be no legal way to make
|
||||
* an N-way join for some values of N. For example consider
|
||||
* an N-way join for some values of N. For example consider
|
||||
*
|
||||
* SELECT ... FROM t1 WHERE
|
||||
* x IN (SELECT ... FROM t2,t3 WHERE ...) AND
|
||||
* y IN (SELECT ... FROM t4,t5 WHERE ...)
|
||||
* x IN (SELECT ... FROM t2,t3 WHERE ...) AND
|
||||
* y IN (SELECT ... FROM t4,t5 WHERE ...)
|
||||
*
|
||||
* We will flatten this query to a 5-way join problem, but there are
|
||||
* no 4-way joins that make_join_rel() will consider legal. We have
|
||||
@@ -486,8 +489,8 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
||||
|
||||
/*
|
||||
* This IN clause is not relevant unless its RHS overlaps the
|
||||
* proposed join. (Check this first as a fast path for dismissing
|
||||
* most irrelevant INs quickly.)
|
||||
* proposed join. (Check this first as a fast path for
|
||||
* dismissing most irrelevant INs quickly.)
|
||||
*/
|
||||
if (!bms_overlap(ininfo->righthand, joinrelids))
|
||||
continue;
|
||||
@@ -516,8 +519,9 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
||||
* some other rel(s).
|
||||
*
|
||||
* If we already joined IN's RHS to any other rels in either
|
||||
* input path, then this join is not constrained (the necessary
|
||||
* work was done at the lower level where that join occurred).
|
||||
* input path, then this join is not constrained (the
|
||||
* necessary work was done at the lower level where that join
|
||||
* occurred).
|
||||
*/
|
||||
if (bms_is_subset(ininfo->righthand, rel1->relids) &&
|
||||
!bms_equal(ininfo->righthand, rel1->relids))
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.61 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.62 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
|
||||
static IndexPath *best_or_subclause_indexes(Query *root, RelOptInfo *rel,
|
||||
List *subclauses);
|
||||
List *subclauses);
|
||||
static bool best_or_subclause_index(Query *root,
|
||||
RelOptInfo *rel,
|
||||
Expr *subclause,
|
||||
@@ -55,7 +55,7 @@ static bool best_or_subclause_index(Query *root,
|
||||
*
|
||||
* The added quals are partially redundant with the original OR, and therefore
|
||||
* will cause the size of the joinrel to be underestimated when it is finally
|
||||
* formed. (This would be true of a full transformation to CNF as well; the
|
||||
* formed. (This would be true of a full transformation to CNF as well; the
|
||||
* fault is not really in the transformation, but in clauselist_selectivity's
|
||||
* inability to recognize redundant conditions.) To minimize the collateral
|
||||
* damage, we want to minimize the number of quals added. Therefore we do
|
||||
@@ -70,7 +70,7 @@ static bool best_or_subclause_index(Query *root,
|
||||
* it is finally formed. This is a MAJOR HACK: it depends on the fact
|
||||
* that clause selectivities are cached and on the fact that the same
|
||||
* RestrictInfo node will appear in every joininfo list that might be used
|
||||
* when the joinrel is formed. And it probably isn't right in cases where
|
||||
* when the joinrel is formed. And it probably isn't right in cases where
|
||||
* the size estimation is nonlinear (i.e., outer and IN joins). But it
|
||||
* beats not doing anything.
|
||||
*
|
||||
@@ -103,9 +103,9 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
|
||||
ListCell *i;
|
||||
|
||||
/*
|
||||
* We use the best_or_subclause_indexes() machinery to locate the
|
||||
* best combination of restriction subclauses. Note we must ignore
|
||||
* any joinclauses that are not marked valid_everywhere, because they
|
||||
* We use the best_or_subclause_indexes() machinery to locate the best
|
||||
* combination of restriction subclauses. Note we must ignore any
|
||||
* joinclauses that are not marked valid_everywhere, because they
|
||||
* cannot be pushed down due to outer-join rules.
|
||||
*/
|
||||
foreach(i, rel->joininfo)
|
||||
@@ -124,12 +124,12 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
|
||||
|
||||
pathnode = best_or_subclause_indexes(root,
|
||||
rel,
|
||||
((BoolExpr *) rinfo->orclause)->args);
|
||||
((BoolExpr *) rinfo->orclause)->args);
|
||||
|
||||
if (pathnode)
|
||||
{
|
||||
if (bestpath == NULL ||
|
||||
pathnode->path.total_cost < bestpath->path.total_cost)
|
||||
pathnode->path.total_cost < bestpath->path.total_cost)
|
||||
{
|
||||
bestpath = pathnode;
|
||||
bestrinfo = rinfo;
|
||||
@@ -144,8 +144,8 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Convert the indexclauses structure to a RestrictInfo tree,
|
||||
* and add it to the rel's restriction list.
|
||||
* Convert the indexclauses structure to a RestrictInfo tree, and add
|
||||
* it to the rel's restriction list.
|
||||
*/
|
||||
newrinfos = make_restrictinfo_from_indexclauses(bestpath->indexclauses,
|
||||
true, true);
|
||||
@@ -157,9 +157,9 @@ create_or_index_quals(Query *root, RelOptInfo *rel)
|
||||
* Adjust the original OR clause's cached selectivity to compensate
|
||||
* for the selectivity of the added (but redundant) lower-level qual.
|
||||
* This should result in the join rel getting approximately the same
|
||||
* rows estimate as it would have gotten without all these shenanigans.
|
||||
* (XXX major hack alert ... this depends on the assumption that the
|
||||
* selectivity will stay cached ...)
|
||||
* rows estimate as it would have gotten without all these
|
||||
* shenanigans. (XXX major hack alert ... this depends on the
|
||||
* assumption that the selectivity will stay cached ...)
|
||||
*/
|
||||
or_selec = clause_selectivity(root, (Node *) or_rinfo,
|
||||
0, JOIN_INNER);
|
||||
@@ -193,8 +193,8 @@ create_or_index_paths(Query *root, RelOptInfo *rel)
|
||||
ListCell *l;
|
||||
|
||||
/*
|
||||
* Check each restriction clause to see if it is an OR clause, and if so,
|
||||
* try to make a path using it.
|
||||
* Check each restriction clause to see if it is an OR clause, and if
|
||||
* so, try to make a path using it.
|
||||
*/
|
||||
foreach(l, rel->baserestrictinfo)
|
||||
{
|
||||
@@ -206,7 +206,7 @@ create_or_index_paths(Query *root, RelOptInfo *rel)
|
||||
|
||||
pathnode = best_or_subclause_indexes(root,
|
||||
rel,
|
||||
((BoolExpr *) rinfo->orclause)->args);
|
||||
((BoolExpr *) rinfo->orclause)->args);
|
||||
|
||||
if (pathnode)
|
||||
add_path(rel, (Path *) pathnode);
|
||||
@@ -264,20 +264,21 @@ best_or_subclause_indexes(Query *root,
|
||||
if (!best_or_subclause_index(root, rel, subclause,
|
||||
&best_indexinfo,
|
||||
&best_indexclauses, &best_indexquals,
|
||||
&best_startup_cost, &best_total_cost))
|
||||
&best_startup_cost, &best_total_cost))
|
||||
return NULL; /* failed to match this subclause */
|
||||
|
||||
infos = lappend(infos, best_indexinfo);
|
||||
clauses = lappend(clauses, best_indexclauses);
|
||||
quals = lappend(quals, best_indexquals);
|
||||
|
||||
/*
|
||||
* Path startup_cost is the startup cost for the first index scan only;
|
||||
* startup costs for later scans will be paid later on, so they just
|
||||
* get reflected in total_cost.
|
||||
* Path startup_cost is the startup cost for the first index scan
|
||||
* only; startup costs for later scans will be paid later on, so
|
||||
* they just get reflected in total_cost.
|
||||
*
|
||||
* Total cost is sum of the per-scan costs.
|
||||
*/
|
||||
if (slist == list_head(subclauses)) /* first scan? */
|
||||
if (slist == list_head(subclauses)) /* first scan? */
|
||||
path_startup_cost = best_startup_cost;
|
||||
path_total_cost += best_total_cost;
|
||||
}
|
||||
@@ -292,8 +293,8 @@ best_or_subclause_indexes(Query *root,
|
||||
|
||||
/*
|
||||
* This is an IndexScan, but the overall result will consist of tuples
|
||||
* extracted in multiple passes (one for each subclause of the OR),
|
||||
* so the result cannot be claimed to have any particular ordering.
|
||||
* extracted in multiple passes (one for each subclause of the OR), so
|
||||
* the result cannot be claimed to have any particular ordering.
|
||||
*/
|
||||
pathnode->path.pathkeys = NIL;
|
||||
|
||||
@@ -339,7 +340,7 @@ best_or_subclause_index(Query *root,
|
||||
RelOptInfo *rel,
|
||||
Expr *subclause,
|
||||
IndexOptInfo **retIndexInfo, /* return value */
|
||||
List **retIndexClauses, /* return value */
|
||||
List **retIndexClauses, /* return value */
|
||||
List **retIndexQuals, /* return value */
|
||||
Cost *retStartupCost, /* return value */
|
||||
Cost *retTotalCost) /* return value */
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.61 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.62 2004/08/29 05:06:43 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -48,10 +48,11 @@ makePathKeyItem(Node *key, Oid sortop, bool checkType)
|
||||
|
||||
/*
|
||||
* Some callers pass expressions that are not necessarily of the same
|
||||
* type as the sort operator expects as input (for example when dealing
|
||||
* with an index that uses binary-compatible operators). We must relabel
|
||||
* these with the correct type so that the key expressions will be seen
|
||||
* as equal() to expressions that have been correctly labeled.
|
||||
* type as the sort operator expects as input (for example when
|
||||
* dealing with an index that uses binary-compatible operators). We
|
||||
* must relabel these with the correct type so that the key
|
||||
* expressions will be seen as equal() to expressions that have been
|
||||
* correctly labeled.
|
||||
*/
|
||||
if (checkType)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.173 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.174 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -45,11 +45,11 @@ static Result *create_result_plan(Query *root, ResultPath *best_path);
|
||||
static Material *create_material_plan(Query *root, MaterialPath *best_path);
|
||||
static Plan *create_unique_plan(Query *root, UniquePath *best_path);
|
||||
static SeqScan *create_seqscan_plan(Query *root, Path *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
List *tlist, List *scan_clauses);
|
||||
static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
static TidScan *create_tidscan_plan(Query *root, TidPath *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
List *tlist, List *scan_clauses);
|
||||
static SubqueryScan *create_subqueryscan_plan(Query *root, Path *best_path,
|
||||
List *tlist, List *scan_clauses);
|
||||
static FunctionScan *create_functionscan_plan(Query *root, Path *best_path,
|
||||
@@ -712,7 +712,7 @@ create_indexscan_plan(Query *root,
|
||||
* If this is a innerjoin scan, the indexclauses will contain join
|
||||
* clauses that are not present in scan_clauses (since the passed-in
|
||||
* value is just the rel's baserestrictinfo list). We must add these
|
||||
* clauses to scan_clauses to ensure they get checked. In most cases
|
||||
* clauses to scan_clauses to ensure they get checked. In most cases
|
||||
* we will remove the join clauses again below, but if a join clause
|
||||
* contains a special operator, we need to make sure it gets into the
|
||||
* scan_clauses.
|
||||
@@ -721,12 +721,12 @@ create_indexscan_plan(Query *root,
|
||||
{
|
||||
/*
|
||||
* We don't currently support OR indexscans in joins, so we only
|
||||
* need to worry about the plain AND case. Also, pointer comparison
|
||||
* should be enough to determine RestrictInfo matches.
|
||||
* need to worry about the plain AND case. Also, pointer
|
||||
* comparison should be enough to determine RestrictInfo matches.
|
||||
*/
|
||||
Assert(list_length(best_path->indexclauses) == 1);
|
||||
scan_clauses = list_union_ptr(scan_clauses,
|
||||
(List *) linitial(best_path->indexclauses));
|
||||
(List *) linitial(best_path->indexclauses));
|
||||
}
|
||||
|
||||
/* Reduce RestrictInfo list to bare expressions */
|
||||
@@ -751,7 +751,7 @@ create_indexscan_plan(Query *root,
|
||||
stripped_indxquals = NIL;
|
||||
foreach(l, indxquals)
|
||||
{
|
||||
List *andlist = (List *) lfirst(l);
|
||||
List *andlist = (List *) lfirst(l);
|
||||
|
||||
stripped_indxquals = lappend(stripped_indxquals,
|
||||
get_actual_clauses(andlist));
|
||||
@@ -759,10 +759,10 @@ create_indexscan_plan(Query *root,
|
||||
|
||||
/*
|
||||
* The qpqual list must contain all restrictions not automatically
|
||||
* handled by the index. All the predicates in the indexquals will
|
||||
* be checked (either by the index itself, or by nodeIndexscan.c), but
|
||||
* if there are any "special" operators involved then they must be
|
||||
* added to qpqual. The upshot is that qpquals must contain scan_clauses
|
||||
* handled by the index. All the predicates in the indexquals will be
|
||||
* checked (either by the index itself, or by nodeIndexscan.c), but if
|
||||
* there are any "special" operators involved then they must be added
|
||||
* to qpqual. The upshot is that qpquals must contain scan_clauses
|
||||
* minus whatever appears in indxquals.
|
||||
*/
|
||||
if (list_length(indxquals) > 1)
|
||||
@@ -770,7 +770,7 @@ create_indexscan_plan(Query *root,
|
||||
/*
|
||||
* Build an expression representation of the indexqual, expanding
|
||||
* the implicit OR and AND semantics of the first- and
|
||||
* second-level lists. (The odds that this will exactly match any
|
||||
* second-level lists. (The odds that this will exactly match any
|
||||
* scan_clause are not great; perhaps we need more smarts here.)
|
||||
*/
|
||||
indxqual_or_expr = make_expr_from_indexclauses(indxquals);
|
||||
@@ -1182,7 +1182,8 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
Relids baserelids = index_path->path.parent->relids;
|
||||
int baserelid = index_path->path.parent->relid;
|
||||
List *index_info = index_path->indexinfo;
|
||||
ListCell *iq, *ii;
|
||||
ListCell *iq,
|
||||
*ii;
|
||||
|
||||
*fixed_indexquals = NIL;
|
||||
*indxstrategy = NIL;
|
||||
@@ -1211,7 +1212,7 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path,
|
||||
*
|
||||
* For each qual clause, commute if needed to put the indexkey operand on the
|
||||
* left, and then fix its varattno. (We do not need to change the other side
|
||||
* of the clause.) Then determine the operator's strategy number and subtype
|
||||
* of the clause.) Then determine the operator's strategy number and subtype
|
||||
* number, and check for lossy index behavior.
|
||||
*
|
||||
* Returns four lists:
|
||||
@@ -1247,7 +1248,7 @@ fix_indxqual_sublist(List *indexqual,
|
||||
|
||||
Assert(IsA(rinfo, RestrictInfo));
|
||||
clause = (OpExpr *) rinfo->clause;
|
||||
if (!IsA(clause, OpExpr) || list_length(clause->args) != 2)
|
||||
if (!IsA(clause, OpExpr) ||list_length(clause->args) != 2)
|
||||
elog(ERROR, "indexqual clause is not binary opclause");
|
||||
|
||||
/*
|
||||
@@ -1272,16 +1273,17 @@ fix_indxqual_sublist(List *indexqual,
|
||||
* indexkey operand as needed, and get the index opclass.
|
||||
*/
|
||||
linitial(newclause->args) = fix_indxqual_operand(linitial(newclause->args),
|
||||
baserelid,
|
||||
index,
|
||||
&opclass);
|
||||
baserelid,
|
||||
index,
|
||||
&opclass);
|
||||
|
||||
*fixed_quals = lappend(*fixed_quals, newclause);
|
||||
|
||||
/*
|
||||
* Look up the (possibly commuted) operator in the operator class to
|
||||
* get its strategy numbers and the recheck indicator. This also
|
||||
* double-checks that we found an operator matching the index.
|
||||
* Look up the (possibly commuted) operator in the operator class
|
||||
* to get its strategy numbers and the recheck indicator. This
|
||||
* also double-checks that we found an operator matching the
|
||||
* index.
|
||||
*/
|
||||
get_op_opclass_properties(newclause->opno, opclass,
|
||||
&stratno, &stratsubtype, &recheck);
|
||||
@@ -1642,7 +1644,7 @@ make_append(List *appendplans, bool isTarget, List *tlist)
|
||||
{
|
||||
Plan *subplan = (Plan *) lfirst(subnode);
|
||||
|
||||
if (subnode == list_head(appendplans)) /* first node? */
|
||||
if (subnode == list_head(appendplans)) /* first node? */
|
||||
plan->startup_cost = subplan->startup_cost;
|
||||
plan->total_cost += subplan->total_cost;
|
||||
plan->plan_rows += subplan->plan_rows;
|
||||
@@ -1837,7 +1839,10 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree, List *pathkeys)
|
||||
AttrNumber *sortColIdx;
|
||||
Oid *sortOperators;
|
||||
|
||||
/* We will need at most list_length(pathkeys) sort columns; possibly less */
|
||||
/*
|
||||
* We will need at most list_length(pathkeys) sort columns; possibly
|
||||
* less
|
||||
*/
|
||||
numsortkeys = list_length(pathkeys);
|
||||
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
|
||||
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
|
||||
@@ -1876,8 +1881,8 @@ make_sort_from_pathkeys(Query *root, Plan *lefttree, List *pathkeys)
|
||||
/* No matching Var; look for a computable expression */
|
||||
foreach(j, keysublist)
|
||||
{
|
||||
List *exprvars;
|
||||
ListCell *k;
|
||||
List *exprvars;
|
||||
ListCell *k;
|
||||
|
||||
pathkey = (PathKeyItem *) lfirst(j);
|
||||
exprvars = pull_var_clause(pathkey->key, false);
|
||||
@@ -1948,7 +1953,10 @@ make_sort_from_sortclauses(Query *root, List *sortcls, Plan *lefttree)
|
||||
AttrNumber *sortColIdx;
|
||||
Oid *sortOperators;
|
||||
|
||||
/* We will need at most list_length(sortcls) sort columns; possibly less */
|
||||
/*
|
||||
* We will need at most list_length(sortcls) sort columns; possibly
|
||||
* less
|
||||
*/
|
||||
numsortkeys = list_length(sortcls);
|
||||
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
|
||||
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
|
||||
@@ -2001,7 +2009,10 @@ make_sort_from_groupcols(Query *root,
|
||||
AttrNumber *sortColIdx;
|
||||
Oid *sortOperators;
|
||||
|
||||
/* We will need at most list_length(groupcls) sort columns; possibly less */
|
||||
/*
|
||||
* We will need at most list_length(groupcls) sort columns; possibly
|
||||
* less
|
||||
*/
|
||||
numsortkeys = list_length(groupcls);
|
||||
sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber));
|
||||
sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.102 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.103 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -451,8 +451,9 @@ distribute_qual_to_rels(Query *root, Node *clause,
|
||||
* tree.
|
||||
*
|
||||
* We also need to determine whether the qual is "valid everywhere",
|
||||
* which is true if the qual mentions no variables that are involved
|
||||
* in lower-level outer joins (this may be an overly strong test).
|
||||
* which is true if the qual mentions no variables that are
|
||||
* involved in lower-level outer joins (this may be an overly
|
||||
* strong test).
|
||||
*/
|
||||
Relids addrelids = NULL;
|
||||
Relids tmprelids;
|
||||
@@ -706,7 +707,7 @@ process_implied_equality(Query *root,
|
||||
{
|
||||
/* delete it from local restrictinfo list */
|
||||
rel1->baserestrictinfo = list_delete_ptr(rel1->baserestrictinfo,
|
||||
restrictinfo);
|
||||
restrictinfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.173 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.174 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -43,7 +43,7 @@
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
|
||||
ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
|
||||
|
||||
|
||||
/* Expression kind codes for preprocess_expression */
|
||||
@@ -88,10 +88,11 @@ planner(Query *parse, bool isCursor, int cursorOptions,
|
||||
* eval_const_expressions tries to pre-evaluate an SQL function). So,
|
||||
* these global state variables must be saved and restored.
|
||||
*
|
||||
* Query level and the param list cannot be moved into the Query structure
|
||||
* since their whole purpose is communication across multiple sub-Queries.
|
||||
* Also, boundParams is explicitly info from outside the Query, and so
|
||||
* is likewise better handled as a global variable.
|
||||
* Query level and the param list cannot be moved into the Query
|
||||
* structure since their whole purpose is communication across
|
||||
* multiple sub-Queries. Also, boundParams is explicitly info from
|
||||
* outside the Query, and so is likewise better handled as a global
|
||||
* variable.
|
||||
*
|
||||
* Note we do NOT save and restore PlannerPlanId: it exists to assign
|
||||
* unique IDs to SubPlan nodes, and we want those IDs to be unique for
|
||||
@@ -391,9 +392,9 @@ preprocess_expression(Query *parse, Node *expr, int kind)
|
||||
expr = flatten_join_alias_vars(parse, expr);
|
||||
|
||||
/*
|
||||
* If it's a qual or havingQual, canonicalize it. It seems most useful
|
||||
* to do this before applying eval_const_expressions, since the latter
|
||||
* can optimize flattened AND/ORs better than unflattened ones.
|
||||
* If it's a qual or havingQual, canonicalize it. It seems most
|
||||
* useful to do this before applying eval_const_expressions, since the
|
||||
* latter can optimize flattened AND/ORs better than unflattened ones.
|
||||
*
|
||||
* Note: all processing of a qual expression after this point must be
|
||||
* careful to maintain AND/OR flatness --- that is, do not generate a
|
||||
@@ -430,8 +431,8 @@ preprocess_expression(Query *parse, Node *expr, int kind)
|
||||
/*
|
||||
* If it's a qual or havingQual, convert it to implicit-AND format.
|
||||
* (We don't want to do this before eval_const_expressions, since the
|
||||
* latter would be unable to simplify a top-level AND correctly. Also,
|
||||
* SS_process_sublinks expects explicit-AND format.)
|
||||
* latter would be unable to simplify a top-level AND correctly.
|
||||
* Also, SS_process_sublinks expects explicit-AND format.)
|
||||
*/
|
||||
if (kind == EXPRKIND_QUAL)
|
||||
expr = (Node *) make_ands_implicit((Expr *) expr);
|
||||
@@ -585,7 +586,7 @@ grouping_planner(Query *parse, double tuple_fraction)
|
||||
|
||||
if (parse->setOperations)
|
||||
{
|
||||
List *set_sortclauses;
|
||||
List *set_sortclauses;
|
||||
|
||||
/*
|
||||
* Construct the plan for set operations. The result will not
|
||||
@@ -600,7 +601,7 @@ grouping_planner(Query *parse, double tuple_fraction)
|
||||
* the sort key information...
|
||||
*/
|
||||
current_pathkeys = make_pathkeys_for_sortclauses(set_sortclauses,
|
||||
result_plan->targetlist);
|
||||
result_plan->targetlist);
|
||||
current_pathkeys = canonicalize_pathkeys(parse, current_pathkeys);
|
||||
|
||||
/*
|
||||
@@ -731,8 +732,8 @@ grouping_planner(Query *parse, double tuple_fraction)
|
||||
*
|
||||
* Note: think not that we can turn off hasAggs if we find no aggs.
|
||||
* It is possible for constant-expression simplification to remove
|
||||
* all explicit references to aggs, but we still have to follow the
|
||||
* aggregate semantics (eg, producing only one output row).
|
||||
* all explicit references to aggs, but we still have to follow
|
||||
* the aggregate semantics (eg, producing only one output row).
|
||||
*/
|
||||
if (parse->hasAggs)
|
||||
numAggs = count_agg_clause((Node *) tlist) +
|
||||
@@ -981,8 +982,8 @@ grouping_planner(Query *parse, double tuple_fraction)
|
||||
{
|
||||
/*
|
||||
* Use hashed grouping if (a) we think we can fit the
|
||||
* hashtable into work_mem, *and* (b) the estimated cost is
|
||||
* no more than doing it the other way. While avoiding
|
||||
* hashtable into work_mem, *and* (b) the estimated cost
|
||||
* is no more than doing it the other way. While avoiding
|
||||
* the need for sorted input is usually a win, the fact
|
||||
* that the output won't be sorted may be a loss; so we
|
||||
* need to do an actual cost comparison.
|
||||
@@ -1452,10 +1453,10 @@ make_subplanTargetList(Query *parse,
|
||||
|
||||
foreach(gl, parse->groupClause)
|
||||
{
|
||||
GroupClause *grpcl = (GroupClause *) lfirst(gl);
|
||||
Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist);
|
||||
TargetEntry *te = NULL;
|
||||
ListCell *sl;
|
||||
GroupClause *grpcl = (GroupClause *) lfirst(gl);
|
||||
Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist);
|
||||
TargetEntry *te = NULL;
|
||||
ListCell *sl;
|
||||
|
||||
/* Find or make a matching sub_tlist entry */
|
||||
foreach(sl, sub_tlist)
|
||||
@@ -1513,10 +1514,10 @@ locate_grouping_columns(Query *parse,
|
||||
|
||||
foreach(gl, parse->groupClause)
|
||||
{
|
||||
GroupClause *grpcl = (GroupClause *) lfirst(gl);
|
||||
Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist);
|
||||
TargetEntry *te = NULL;
|
||||
ListCell *sl;
|
||||
GroupClause *grpcl = (GroupClause *) lfirst(gl);
|
||||
Node *groupexpr = get_sortgroupclause_expr(grpcl, tlist);
|
||||
TargetEntry *te = NULL;
|
||||
ListCell *sl;
|
||||
|
||||
foreach(sl, sub_tlist)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.103 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.104 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -84,7 +84,7 @@ static void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
|
||||
void
|
||||
set_plan_references(Plan *plan, List *rtable)
|
||||
{
|
||||
ListCell *l;
|
||||
ListCell *l;
|
||||
|
||||
if (plan == NULL)
|
||||
return;
|
||||
@@ -184,10 +184,11 @@ set_plan_references(Plan *plan, List *rtable)
|
||||
*/
|
||||
break;
|
||||
case T_Limit:
|
||||
|
||||
/*
|
||||
* Like the plan types above, Limit doesn't evaluate its
|
||||
* tlist or quals. It does have live expressions for
|
||||
* limit/offset, however.
|
||||
* Like the plan types above, Limit doesn't evaluate its tlist
|
||||
* or quals. It does have live expressions for limit/offset,
|
||||
* however.
|
||||
*/
|
||||
fix_expr_references(plan, ((Limit *) plan)->limitOffset);
|
||||
fix_expr_references(plan, ((Limit *) plan)->limitCount);
|
||||
@@ -213,11 +214,12 @@ set_plan_references(Plan *plan, List *rtable)
|
||||
fix_expr_references(plan, ((Result *) plan)->resconstantqual);
|
||||
break;
|
||||
case T_Append:
|
||||
|
||||
/*
|
||||
* Append, like Sort et al, doesn't actually evaluate its
|
||||
* targetlist or quals, and we haven't bothered to give it
|
||||
* its own tlist copy. So, don't fix targetlist/qual. But
|
||||
* do recurse into child plans.
|
||||
* targetlist or quals, and we haven't bothered to give it its
|
||||
* own tlist copy. So, don't fix targetlist/qual. But do
|
||||
* recurse into child plans.
|
||||
*/
|
||||
foreach(l, ((Append *) plan)->appendplans)
|
||||
set_plan_references((Plan *) lfirst(l), rtable);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.92 2004/08/29 04:12:33 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.93 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -119,10 +119,10 @@ replace_outer_var(Var *var)
|
||||
* The correct field should get stored into the Param slot at
|
||||
* execution in each part of the tree.
|
||||
*
|
||||
* We also need to demand a match on vartypmod. This does not matter
|
||||
* for the Param itself, since those are not typmod-dependent, but it
|
||||
* does matter when make_subplan() instantiates a modified copy of the
|
||||
* Var for a subplan's args list.
|
||||
* We also need to demand a match on vartypmod. This does not matter for
|
||||
* the Param itself, since those are not typmod-dependent, but it does
|
||||
* matter when make_subplan() instantiates a modified copy of the Var
|
||||
* for a subplan's args list.
|
||||
*/
|
||||
i = 0;
|
||||
foreach(ppl, PlannerParamList)
|
||||
@@ -509,7 +509,9 @@ convert_sublink_opers(List *lefthand, List *operOids,
|
||||
List **righthandIds)
|
||||
{
|
||||
List *result = NIL;
|
||||
ListCell *l, *lefthand_item, *tlist_item;
|
||||
ListCell *l,
|
||||
*lefthand_item,
|
||||
*tlist_item;
|
||||
|
||||
*righthandIds = NIL;
|
||||
lefthand_item = list_head(lefthand);
|
||||
@@ -533,8 +535,9 @@ convert_sublink_opers(List *lefthand, List *operOids,
|
||||
te->resdom->restype,
|
||||
te->resdom->restypmod,
|
||||
0);
|
||||
|
||||
/*
|
||||
* Copy it for caller. NB: we need a copy to avoid having
|
||||
* Copy it for caller. NB: we need a copy to avoid having
|
||||
* doubly-linked substructure in the modified parse tree.
|
||||
*/
|
||||
*righthandIds = lappend(*righthandIds, copyObject(rightop));
|
||||
@@ -616,8 +619,8 @@ subplan_is_hashable(SubLink *slink, SubPlan *node)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* The estimated size of the subquery result must fit in work_mem. (XXX
|
||||
* what about hashtable overhead?)
|
||||
* The estimated size of the subquery result must fit in work_mem.
|
||||
* (XXX what about hashtable overhead?)
|
||||
*/
|
||||
subquery_size = node->plan->plan_rows *
|
||||
(MAXALIGN(node->plan->plan_width) + MAXALIGN(sizeof(HeapTupleData)));
|
||||
@@ -746,8 +749,8 @@ convert_IN_to_join(Query *parse, SubLink *sublink)
|
||||
|
||||
/*
|
||||
* Build the result qual expressions. As a side effect,
|
||||
* ininfo->sub_targetlist is filled with a list of Vars
|
||||
* representing the subselect outputs.
|
||||
* ininfo->sub_targetlist is filled with a list of Vars representing
|
||||
* the subselect outputs.
|
||||
*/
|
||||
exprs = convert_sublink_opers(sublink->lefthand,
|
||||
sublink->operOids,
|
||||
@@ -851,25 +854,25 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
|
||||
|
||||
/*
|
||||
* Because make_subplan() could return an AND or OR clause, we have to
|
||||
* take steps to preserve AND/OR flatness of a qual. We assume the input
|
||||
* has been AND/OR flattened and so we need no recursion here.
|
||||
* take steps to preserve AND/OR flatness of a qual. We assume the
|
||||
* input has been AND/OR flattened and so we need no recursion here.
|
||||
*
|
||||
* If we recurse down through anything other than an AND node,
|
||||
* we are definitely not at top qual level anymore. (Due to the coding
|
||||
* here, we will not get called on the List subnodes of an AND, so no
|
||||
* check is needed for List.)
|
||||
* If we recurse down through anything other than an AND node, we are
|
||||
* definitely not at top qual level anymore. (Due to the coding here,
|
||||
* we will not get called on the List subnodes of an AND, so no check
|
||||
* is needed for List.)
|
||||
*/
|
||||
if (and_clause(node))
|
||||
{
|
||||
List *newargs = NIL;
|
||||
ListCell *l;
|
||||
List *newargs = NIL;
|
||||
ListCell *l;
|
||||
|
||||
/* Still at qual top-level */
|
||||
locTopQual = *isTopQual;
|
||||
|
||||
foreach(l, ((BoolExpr *) node)->args)
|
||||
{
|
||||
Node *newarg;
|
||||
Node *newarg;
|
||||
|
||||
newarg = process_sublinks_mutator(lfirst(l),
|
||||
(void *) &locTopQual);
|
||||
@@ -886,12 +889,12 @@ process_sublinks_mutator(Node *node, bool *isTopQual)
|
||||
|
||||
if (or_clause(node))
|
||||
{
|
||||
List *newargs = NIL;
|
||||
ListCell *l;
|
||||
List *newargs = NIL;
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, ((BoolExpr *) node)->args)
|
||||
{
|
||||
Node *newarg;
|
||||
Node *newarg;
|
||||
|
||||
newarg = process_sublinks_mutator(lfirst(l),
|
||||
(void *) &locTopQual);
|
||||
@@ -1035,7 +1038,7 @@ finalize_plan(Plan *plan, List *rtable,
|
||||
|
||||
case T_Append:
|
||||
{
|
||||
ListCell *l;
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, ((Append *) plan)->appendplans)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.22 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.23 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -46,7 +46,7 @@ typedef struct reduce_outer_joins_state
|
||||
static bool is_simple_subquery(Query *subquery);
|
||||
static bool has_nullable_targetlist(Query *subquery);
|
||||
static void resolvenew_in_jointree(Node *jtnode, int varno,
|
||||
List *rtable, List *subtlist);
|
||||
List *rtable, List *subtlist);
|
||||
static reduce_outer_joins_state *reduce_outer_joins_pass1(Node *jtnode);
|
||||
static void reduce_outer_joins_pass2(Node *jtnode,
|
||||
reduce_outer_joins_state *state,
|
||||
@@ -151,8 +151,8 @@ pull_up_subqueries(Query *parse, Node *jtnode, bool below_outer_join)
|
||||
* entries for upper Var references would do the wrong thing (the
|
||||
* results wouldn't become NULL when they're supposed to).
|
||||
*
|
||||
* XXX This could be improved by generating pseudo-variables for
|
||||
* such expressions; we'd have to figure out how to get the pseudo-
|
||||
* XXX This could be improved by generating pseudo-variables for such
|
||||
* expressions; we'd have to figure out how to get the pseudo-
|
||||
* variables evaluated at the right place in the modified plan
|
||||
* tree. Fix it someday.
|
||||
*/
|
||||
@@ -167,23 +167,23 @@ pull_up_subqueries(Query *parse, Node *jtnode, bool below_outer_join)
|
||||
/*
|
||||
* Need a modifiable copy of the subquery to hack on. Even if
|
||||
* we didn't sometimes choose not to pull up below, we must do
|
||||
* this to avoid problems if the same subquery is referenced from
|
||||
* multiple jointree items (which can't happen normally, but might
|
||||
* after rule rewriting).
|
||||
* this to avoid problems if the same subquery is referenced
|
||||
* from multiple jointree items (which can't happen normally,
|
||||
* but might after rule rewriting).
|
||||
*/
|
||||
subquery = copyObject(subquery);
|
||||
|
||||
/*
|
||||
* Pull up any IN clauses within the subquery's WHERE,
|
||||
* so that we don't leave unoptimized INs behind.
|
||||
* Pull up any IN clauses within the subquery's WHERE, so that
|
||||
* we don't leave unoptimized INs behind.
|
||||
*/
|
||||
if (subquery->hasSubLinks)
|
||||
subquery->jointree->quals = pull_up_IN_clauses(subquery,
|
||||
subquery->jointree->quals);
|
||||
|
||||
/*
|
||||
* Recursively pull up the subquery's subqueries, so that
|
||||
* this routine's processing is complete for its jointree and
|
||||
* Recursively pull up the subquery's subqueries, so that this
|
||||
* routine's processing is complete for its jointree and
|
||||
* rangetable.
|
||||
*
|
||||
* Note: 'false' is correct here even if we are within an outer
|
||||
@@ -213,9 +213,9 @@ pull_up_subqueries(Query *parse, Node *jtnode, bool below_outer_join)
|
||||
* Give up, return unmodified RangeTblRef.
|
||||
*
|
||||
* Note: The work we just did will be redone when the
|
||||
* subquery gets planned on its own. Perhaps we could avoid
|
||||
* that by storing the modified subquery back into the
|
||||
* rangetable, but I'm not gonna risk it now.
|
||||
* subquery gets planned on its own. Perhaps we could
|
||||
* avoid that by storing the modified subquery back into
|
||||
* the rangetable, but I'm not gonna risk it now.
|
||||
*/
|
||||
return jtnode;
|
||||
}
|
||||
@@ -277,8 +277,8 @@ pull_up_subqueries(Query *parse, Node *jtnode, bool below_outer_join)
|
||||
|
||||
/*
|
||||
* Pull up any FOR UPDATE markers, too. (OffsetVarNodes
|
||||
* already adjusted the marker values, so just list_concat
|
||||
* the list.)
|
||||
* already adjusted the marker values, so just list_concat the
|
||||
* list.)
|
||||
*/
|
||||
parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
|
||||
|
||||
@@ -939,7 +939,7 @@ simplify_jointree(Query *parse, Node *jtnode)
|
||||
* lists. NOTE: we put the pulled-up quals first.
|
||||
*/
|
||||
f->quals = (Node *) list_concat((List *) subf->quals,
|
||||
(List *) f->quals);
|
||||
(List *) f->quals);
|
||||
}
|
||||
else
|
||||
newlist = lappend(newlist, child);
|
||||
@@ -1000,14 +1000,14 @@ simplify_jointree(Query *parse, Node *jtnode)
|
||||
f->fromlist = list_concat(f->fromlist,
|
||||
subf->fromlist);
|
||||
f->quals = (Node *) list_concat((List *) f->quals,
|
||||
(List *) subf->quals);
|
||||
(List *) subf->quals);
|
||||
}
|
||||
else
|
||||
f->fromlist = lappend(f->fromlist, j->rarg);
|
||||
|
||||
/* pulled-up quals first */
|
||||
f->quals = (Node *) list_concat((List *) f->quals,
|
||||
(List *) j->quals);
|
||||
(List *) j->quals);
|
||||
|
||||
return (Node *) f;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.45 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepqual.c,v 1.46 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -58,8 +58,8 @@ canonicalize_qual(Expr *qual)
|
||||
|
||||
/*
|
||||
* Push down NOTs. We do this only in the top-level boolean
|
||||
* expression, without examining arguments of operators/functions.
|
||||
* The main reason for doing this is to expose as much top-level AND/OR
|
||||
* expression, without examining arguments of operators/functions. The
|
||||
* main reason for doing this is to expose as much top-level AND/OR
|
||||
* structure as we can, so there's no point in descending further.
|
||||
*/
|
||||
newqual = find_nots(newqual);
|
||||
@@ -129,7 +129,8 @@ flatten_andors_mutator(Node *node, void *context)
|
||||
* Note: we can destructively concat the subexpression's
|
||||
* arglist because we know the recursive invocation of
|
||||
* flatten_andors will have built a new arglist not shared
|
||||
* with any other expr. Otherwise we'd need a list_copy here.
|
||||
* with any other expr. Otherwise we'd need a list_copy
|
||||
* here.
|
||||
*/
|
||||
if (and_clause(subexpr))
|
||||
out_list = list_concat(out_list,
|
||||
@@ -152,7 +153,8 @@ flatten_andors_mutator(Node *node, void *context)
|
||||
* Note: we can destructively concat the subexpression's
|
||||
* arglist because we know the recursive invocation of
|
||||
* flatten_andors will have built a new arglist not shared
|
||||
* with any other expr. Otherwise we'd need a list_copy here.
|
||||
* with any other expr. Otherwise we'd need a list_copy
|
||||
* here.
|
||||
*/
|
||||
if (or_clause(subexpr))
|
||||
out_list = list_concat(out_list,
|
||||
@@ -192,7 +194,7 @@ pull_ands(List *andlist)
|
||||
*/
|
||||
if (and_clause(subexpr))
|
||||
out_list = list_concat(out_list,
|
||||
pull_ands(((BoolExpr *) subexpr)->args));
|
||||
pull_ands(((BoolExpr *) subexpr)->args));
|
||||
else
|
||||
out_list = lappend(out_list, subexpr);
|
||||
}
|
||||
@@ -224,7 +226,7 @@ pull_ors(List *orlist)
|
||||
*/
|
||||
if (or_clause(subexpr))
|
||||
out_list = list_concat(out_list,
|
||||
pull_ors(((BoolExpr *) subexpr)->args));
|
||||
pull_ors(((BoolExpr *) subexpr)->args));
|
||||
else
|
||||
out_list = lappend(out_list, subexpr);
|
||||
}
|
||||
@@ -236,7 +238,7 @@ pull_ors(List *orlist)
|
||||
* find_nots
|
||||
* Traverse the qualification, looking for NOTs to take care of.
|
||||
* For NOT clauses, apply push_nots() to try to push down the NOT.
|
||||
* For AND and OR clause types, simply recurse. Otherwise stop
|
||||
* For AND and OR clause types, simply recurse. Otherwise stop
|
||||
* recursing (we do not worry about structure below the top AND/OR tree).
|
||||
*
|
||||
* Returns the modified qualification. AND/OR flatness is preserved.
|
||||
@@ -287,8 +289,8 @@ push_nots(Expr *qual)
|
||||
|
||||
/*
|
||||
* Negate an operator clause if possible: (NOT (< A B)) => (> A B)
|
||||
* Otherwise, retain the clause as it is (the NOT can't be pushed
|
||||
* down any farther).
|
||||
* Otherwise, retain the clause as it is (the NOT can't be pushed down
|
||||
* any farther).
|
||||
*/
|
||||
if (is_opclause(qual))
|
||||
{
|
||||
@@ -332,16 +334,16 @@ push_nots(Expr *qual)
|
||||
else if (not_clause((Node *) qual))
|
||||
{
|
||||
/*
|
||||
* Another NOT cancels this NOT, so eliminate the NOT and
|
||||
* stop negating this branch.
|
||||
* Another NOT cancels this NOT, so eliminate the NOT and stop
|
||||
* negating this branch.
|
||||
*/
|
||||
return get_notclausearg(qual);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* We don't know how to negate anything else, place a NOT at
|
||||
* this level.
|
||||
* We don't know how to negate anything else, place a NOT at this
|
||||
* level.
|
||||
*/
|
||||
return make_notclause(qual);
|
||||
}
|
||||
@@ -356,7 +358,7 @@ push_nots(Expr *qual)
|
||||
*
|
||||
* This may seem like a fairly useless activity, but it turns out to be
|
||||
* applicable to many machine-generated queries, and there are also queries
|
||||
* in some of the TPC benchmarks that need it. This was in fact almost the
|
||||
* in some of the TPC benchmarks that need it. This was in fact almost the
|
||||
* sole useful side-effect of the old prepqual code that tried to force
|
||||
* the query into canonical AND-of-ORs form: the canonical equivalent of
|
||||
* ((A AND B) OR (A AND C))
|
||||
@@ -375,7 +377,7 @@ push_nots(Expr *qual)
|
||||
* OR clauses to which the inverse OR distributive law might apply.
|
||||
* Only the top-level AND/OR structure is searched.
|
||||
*
|
||||
* Returns the modified qualification. AND/OR flatness is preserved.
|
||||
* Returns the modified qualification. AND/OR flatness is preserved.
|
||||
*/
|
||||
static Expr *
|
||||
find_duplicate_ors(Expr *qual)
|
||||
@@ -391,6 +393,7 @@ find_duplicate_ors(Expr *qual)
|
||||
/* Recurse */
|
||||
foreach(temp, ((BoolExpr *) qual)->args)
|
||||
orlist = lappend(orlist, find_duplicate_ors(lfirst(temp)));
|
||||
|
||||
/*
|
||||
* Don't need pull_ors() since this routine will never introduce
|
||||
* an OR where there wasn't one before.
|
||||
@@ -433,14 +436,15 @@ process_duplicate_ors(List *orlist)
|
||||
|
||||
if (orlist == NIL)
|
||||
return NULL; /* probably can't happen */
|
||||
if (list_length(orlist) == 1) /* single-expression OR (can this happen?) */
|
||||
if (list_length(orlist) == 1) /* single-expression OR (can this
|
||||
* happen?) */
|
||||
return linitial(orlist);
|
||||
|
||||
/*
|
||||
* Choose the shortest AND clause as the reference list --- obviously,
|
||||
* any subclause not in this clause isn't in all the clauses.
|
||||
* If we find a clause that's not an AND, we can treat it as a
|
||||
* one-element AND clause, which necessarily wins as shortest.
|
||||
* any subclause not in this clause isn't in all the clauses. If we
|
||||
* find a clause that's not an AND, we can treat it as a one-element
|
||||
* AND clause, which necessarily wins as shortest.
|
||||
*/
|
||||
foreach(temp, orlist)
|
||||
{
|
||||
@@ -471,7 +475,7 @@ process_duplicate_ors(List *orlist)
|
||||
|
||||
/*
|
||||
* Check each element of the reference list to see if it's in all the
|
||||
* OR clauses. Build a new list of winning clauses.
|
||||
* OR clauses. Build a new list of winning clauses.
|
||||
*/
|
||||
winners = NIL;
|
||||
foreach(temp, reference)
|
||||
@@ -515,12 +519,13 @@ process_duplicate_ors(List *orlist)
|
||||
/*
|
||||
* Generate new OR list consisting of the remaining sub-clauses.
|
||||
*
|
||||
* If any clause degenerates to empty, then we have a situation like
|
||||
* (A AND B) OR (A), which can be reduced to just A --- that is, the
|
||||
* If any clause degenerates to empty, then we have a situation like (A
|
||||
* AND B) OR (A), which can be reduced to just A --- that is, the
|
||||
* additional conditions in other arms of the OR are irrelevant.
|
||||
*
|
||||
* Note that because we use list_difference, any multiple occurrences of
|
||||
* a winning clause in an AND sub-clause will be removed automatically.
|
||||
* a winning clause in an AND sub-clause will be removed
|
||||
* automatically.
|
||||
*/
|
||||
neworlist = NIL;
|
||||
foreach(temp, orlist)
|
||||
@@ -541,7 +546,7 @@ process_duplicate_ors(List *orlist)
|
||||
}
|
||||
else
|
||||
{
|
||||
neworlist = NIL; /* degenerate case, see above */
|
||||
neworlist = NIL; /* degenerate case, see above */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -551,17 +556,17 @@ process_duplicate_ors(List *orlist)
|
||||
neworlist = lappend(neworlist, clause);
|
||||
else
|
||||
{
|
||||
neworlist = NIL; /* degenerate case, see above */
|
||||
neworlist = NIL; /* degenerate case, see above */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Append reduced OR to the winners list, if it's not degenerate, handling
|
||||
* the special case of one element correctly (can that really happen?).
|
||||
* Also be careful to maintain AND/OR flatness in case we pulled up a
|
||||
* sub-sub-OR-clause.
|
||||
* Append reduced OR to the winners list, if it's not degenerate,
|
||||
* handling the special case of one element correctly (can that really
|
||||
* happen?). Also be careful to maintain AND/OR flatness in case we
|
||||
* pulled up a sub-sub-OR-clause.
|
||||
*/
|
||||
if (neworlist != NIL)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.115 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.116 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -69,7 +69,7 @@ static Node *adjust_inherited_attrs_mutator(Node *node,
|
||||
adjust_inherited_attrs_context *context);
|
||||
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
|
||||
static List *adjust_inherited_tlist(List *tlist,
|
||||
adjust_inherited_attrs_context *context);
|
||||
adjust_inherited_attrs_context *context);
|
||||
|
||||
|
||||
/*
|
||||
@@ -371,7 +371,7 @@ recurse_union_children(Node *setOp, Query *parse,
|
||||
SetOperationStmt *top_union,
|
||||
List *refnames_tlist)
|
||||
{
|
||||
List *child_sortclauses;
|
||||
List *child_sortclauses;
|
||||
|
||||
if (IsA(setOp, SetOperationStmt))
|
||||
{
|
||||
@@ -754,7 +754,7 @@ expand_inherited_rtentry(Query *parse, Index rti, bool dup_parent)
|
||||
if (dup_parent)
|
||||
inhRTIs = NIL;
|
||||
else
|
||||
inhRTIs = list_make1_int(rti); /* include original RTE in result */
|
||||
inhRTIs = list_make1_int(rti); /* include original RTE in result */
|
||||
|
||||
foreach(l, inhOIDs)
|
||||
{
|
||||
@@ -811,8 +811,9 @@ adjust_inherited_attrs(Node *node,
|
||||
}
|
||||
|
||||
/*
|
||||
* We assume that by now the planner has acquired at least AccessShareLock
|
||||
* on both rels, and so we need no additional lock now.
|
||||
* We assume that by now the planner has acquired at least
|
||||
* AccessShareLock on both rels, and so we need no additional lock
|
||||
* now.
|
||||
*/
|
||||
oldrelation = heap_open(old_relid, NoLock);
|
||||
newrelation = heap_open(new_relid, NoLock);
|
||||
@@ -913,21 +914,21 @@ static Node *
|
||||
generate_whole_row(Var *var,
|
||||
adjust_inherited_attrs_context *context)
|
||||
{
|
||||
RowExpr *rowexpr;
|
||||
List *fields = NIL;
|
||||
RowExpr *rowexpr;
|
||||
List *fields = NIL;
|
||||
int oldnatts = context->old_tupdesc->natts;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < oldnatts; i++)
|
||||
{
|
||||
Form_pg_attribute att = context->old_tupdesc->attrs[i];
|
||||
Var *newvar;
|
||||
Var *newvar;
|
||||
|
||||
if (att->attisdropped)
|
||||
{
|
||||
/*
|
||||
* can't use atttypid here, but it doesn't really matter
|
||||
* what type the Const claims to be.
|
||||
* can't use atttypid here, but it doesn't really matter what
|
||||
* type the Const claims to be.
|
||||
*/
|
||||
newvar = (Var *) makeNullConst(INT4OID);
|
||||
}
|
||||
@@ -941,7 +942,7 @@ generate_whole_row(Var *var,
|
||||
}
|
||||
rowexpr = makeNode(RowExpr);
|
||||
rowexpr->args = fields;
|
||||
rowexpr->row_typeid = var->vartype; /* report parent's rowtype */
|
||||
rowexpr->row_typeid = var->vartype; /* report parent's rowtype */
|
||||
rowexpr->row_format = COERCE_IMPLICIT_CAST;
|
||||
|
||||
return (Node *) rowexpr;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.179 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.180 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -66,19 +66,19 @@ static bool contain_volatile_functions_walker(Node *node, void *context);
|
||||
static bool contain_nonstrict_functions_walker(Node *node, void *context);
|
||||
static bool set_coercionform_dontcare_walker(Node *node, void *context);
|
||||
static Node *eval_const_expressions_mutator(Node *node,
|
||||
eval_const_expressions_context *context);
|
||||
static List *simplify_or_arguments(List *args,
|
||||
bool *haveNull, bool *forceTrue);
|
||||
static List *simplify_and_arguments(List *args,
|
||||
bool *haveNull, bool *forceFalse);
|
||||
static Expr *simplify_function(Oid funcid, Oid result_type, List *args,
|
||||
bool allow_inline,
|
||||
eval_const_expressions_context *context);
|
||||
static List *simplify_or_arguments(List *args,
|
||||
bool *haveNull, bool *forceTrue);
|
||||
static List *simplify_and_arguments(List *args,
|
||||
bool *haveNull, bool *forceFalse);
|
||||
static Expr *simplify_function(Oid funcid, Oid result_type, List *args,
|
||||
bool allow_inline,
|
||||
eval_const_expressions_context *context);
|
||||
static Expr *evaluate_function(Oid funcid, Oid result_type, List *args,
|
||||
HeapTuple func_tuple);
|
||||
static Expr *inline_function(Oid funcid, Oid result_type, List *args,
|
||||
HeapTuple func_tuple,
|
||||
eval_const_expressions_context *context);
|
||||
HeapTuple func_tuple,
|
||||
eval_const_expressions_context *context);
|
||||
static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
|
||||
int *usecounts);
|
||||
static Node *substitute_actual_parameters_mutator(Node *node,
|
||||
@@ -717,7 +717,7 @@ contain_volatile_functions_walker(Node *node, void *context)
|
||||
* The idea here is that the caller has verified that the expression contains
|
||||
* one or more Var or Param nodes (as appropriate for the caller's need), and
|
||||
* now wishes to prove that the expression result will be NULL if any of these
|
||||
* inputs is NULL. If we return false, then the proof succeeded.
|
||||
* inputs is NULL. If we return false, then the proof succeeded.
|
||||
*/
|
||||
bool
|
||||
contain_nonstrict_functions(Node *clause)
|
||||
@@ -1164,11 +1164,11 @@ eval_const_expressions_mutator(Node *node,
|
||||
if (paramInfo)
|
||||
{
|
||||
/*
|
||||
* Found it, so return a Const representing the param value.
|
||||
* Note that we don't copy pass-by-ref datatypes, so the
|
||||
* Const will only be valid as long as the bound parameter
|
||||
* list exists. This is okay for intended uses of
|
||||
* estimate_expression_value().
|
||||
* Found it, so return a Const representing the param
|
||||
* value. Note that we don't copy pass-by-ref datatypes,
|
||||
* so the Const will only be valid as long as the bound
|
||||
* parameter list exists. This is okay for intended uses
|
||||
* of estimate_expression_value().
|
||||
*/
|
||||
int16 typLen;
|
||||
bool typByVal;
|
||||
@@ -1381,7 +1381,7 @@ eval_const_expressions_mutator(Node *node,
|
||||
bool forceTrue = false;
|
||||
|
||||
newargs = simplify_or_arguments(args,
|
||||
&haveNull, &forceTrue);
|
||||
&haveNull, &forceTrue);
|
||||
if (forceTrue)
|
||||
return makeBoolConst(true, false);
|
||||
if (haveNull)
|
||||
@@ -1402,7 +1402,7 @@ eval_const_expressions_mutator(Node *node,
|
||||
bool forceFalse = false;
|
||||
|
||||
newargs = simplify_and_arguments(args,
|
||||
&haveNull, &forceFalse);
|
||||
&haveNull, &forceFalse);
|
||||
if (forceFalse)
|
||||
return makeBoolConst(false, false);
|
||||
if (haveNull)
|
||||
@@ -1420,7 +1420,7 @@ eval_const_expressions_mutator(Node *node,
|
||||
Assert(list_length(args) == 1);
|
||||
if (IsA(linitial(args), Const))
|
||||
{
|
||||
Const *const_input = (Const *) linitial(args);
|
||||
Const *const_input = (Const *) linitial(args);
|
||||
|
||||
/* NOT NULL => NULL */
|
||||
if (const_input->constisnull)
|
||||
@@ -1659,9 +1659,9 @@ eval_const_expressions_mutator(Node *node,
|
||||
* it can arise while simplifying functions.) Also, we can
|
||||
* optimize field selection from a RowExpr construct.
|
||||
*
|
||||
* We must however check that the declared type of the field is
|
||||
* still the same as when the FieldSelect was created --- this
|
||||
* can change if someone did ALTER COLUMN TYPE on the rowtype.
|
||||
* We must however check that the declared type of the field is still
|
||||
* the same as when the FieldSelect was created --- this can
|
||||
* change if someone did ALTER COLUMN TYPE on the rowtype.
|
||||
*/
|
||||
FieldSelect *fselect = (FieldSelect *) node;
|
||||
FieldSelect *newfselect;
|
||||
@@ -1684,13 +1684,13 @@ eval_const_expressions_mutator(Node *node,
|
||||
}
|
||||
if (arg && IsA(arg, RowExpr))
|
||||
{
|
||||
RowExpr *rowexpr = (RowExpr *) arg;
|
||||
RowExpr *rowexpr = (RowExpr *) arg;
|
||||
|
||||
if (fselect->fieldnum > 0 &&
|
||||
fselect->fieldnum <= list_length(rowexpr->args))
|
||||
{
|
||||
Node *fld = (Node *) list_nth(rowexpr->args,
|
||||
fselect->fieldnum - 1);
|
||||
Node *fld = (Node *) list_nth(rowexpr->args,
|
||||
fselect->fieldnum - 1);
|
||||
|
||||
if (rowtype_field_matches(rowexpr->row_typeid,
|
||||
fselect->fieldnum,
|
||||
@@ -1746,17 +1746,18 @@ simplify_or_arguments(List *args, bool *haveNull, bool *forceTrue)
|
||||
|
||||
foreach(larg, args)
|
||||
{
|
||||
Node *arg = (Node *) lfirst(larg);
|
||||
Node *arg = (Node *) lfirst(larg);
|
||||
|
||||
if (IsA(arg, Const))
|
||||
{
|
||||
Const *const_input = (Const *) arg;
|
||||
Const *const_input = (Const *) arg;
|
||||
|
||||
if (const_input->constisnull)
|
||||
*haveNull = true;
|
||||
else if (DatumGetBool(const_input->constvalue))
|
||||
{
|
||||
*forceTrue = true;
|
||||
|
||||
/*
|
||||
* Once we detect a TRUE result we can just exit the loop
|
||||
* immediately. However, if we ever add a notion of
|
||||
@@ -1769,13 +1770,11 @@ simplify_or_arguments(List *args, bool *haveNull, bool *forceTrue)
|
||||
else if (or_clause(arg))
|
||||
{
|
||||
newargs = list_concat(newargs,
|
||||
simplify_or_arguments(((BoolExpr *) arg)->args,
|
||||
haveNull, forceTrue));
|
||||
simplify_or_arguments(((BoolExpr *) arg)->args,
|
||||
haveNull, forceTrue));
|
||||
}
|
||||
else
|
||||
{
|
||||
newargs = lappend(newargs, arg);
|
||||
}
|
||||
}
|
||||
|
||||
return newargs;
|
||||
@@ -1807,17 +1806,18 @@ simplify_and_arguments(List *args, bool *haveNull, bool *forceFalse)
|
||||
|
||||
foreach(larg, args)
|
||||
{
|
||||
Node *arg = (Node *) lfirst(larg);
|
||||
Node *arg = (Node *) lfirst(larg);
|
||||
|
||||
if (IsA(arg, Const))
|
||||
{
|
||||
Const *const_input = (Const *) arg;
|
||||
Const *const_input = (Const *) arg;
|
||||
|
||||
if (const_input->constisnull)
|
||||
*haveNull = true;
|
||||
else if (!DatumGetBool(const_input->constvalue))
|
||||
{
|
||||
*forceFalse = true;
|
||||
|
||||
/*
|
||||
* Once we detect a FALSE result we can just exit the loop
|
||||
* immediately. However, if we ever add a notion of
|
||||
@@ -1830,13 +1830,11 @@ simplify_and_arguments(List *args, bool *haveNull, bool *forceFalse)
|
||||
else if (and_clause(arg))
|
||||
{
|
||||
newargs = list_concat(newargs,
|
||||
simplify_and_arguments(((BoolExpr *) arg)->args,
|
||||
haveNull, forceFalse));
|
||||
simplify_and_arguments(((BoolExpr *) arg)->args,
|
||||
haveNull, forceFalse));
|
||||
}
|
||||
else
|
||||
{
|
||||
newargs = lappend(newargs, arg);
|
||||
}
|
||||
}
|
||||
|
||||
return newargs;
|
||||
@@ -2272,7 +2270,7 @@ substitute_actual_parameters_mutator(Node *node,
|
||||
static void
|
||||
sql_inline_error_callback(void *arg)
|
||||
{
|
||||
HeapTuple func_tuple = (HeapTuple) arg;
|
||||
HeapTuple func_tuple = (HeapTuple) arg;
|
||||
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
|
||||
int syntaxerrposition;
|
||||
|
||||
@@ -2586,7 +2584,7 @@ expression_tree_walker(Node *node,
|
||||
return walker(((FieldSelect *) node)->arg, context);
|
||||
case T_FieldStore:
|
||||
{
|
||||
FieldStore *fstore = (FieldStore *) node;
|
||||
FieldStore *fstore = (FieldStore *) node;
|
||||
|
||||
if (walker(fstore->arg, context))
|
||||
return true;
|
||||
@@ -3041,8 +3039,8 @@ expression_tree_mutator(Node *node,
|
||||
break;
|
||||
case T_RowExpr:
|
||||
{
|
||||
RowExpr *rowexpr = (RowExpr *) node;
|
||||
RowExpr *newnode;
|
||||
RowExpr *rowexpr = (RowExpr *) node;
|
||||
RowExpr *newnode;
|
||||
|
||||
FLATCOPY(newnode, rowexpr, RowExpr);
|
||||
MUTATE(newnode->args, rowexpr->args, List *);
|
||||
@@ -3259,9 +3257,7 @@ query_tree_mutator(Query *query,
|
||||
break;
|
||||
case RTE_JOIN:
|
||||
if (!(flags & QTW_IGNORE_JOINALIASES))
|
||||
{
|
||||
MUTATE(newrte->joinaliasvars, rte->joinaliasvars, List *);
|
||||
}
|
||||
break;
|
||||
case RTE_FUNCTION:
|
||||
MUTATE(newrte->funcexpr, rte->funcexpr, Node *);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.109 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.110 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -100,8 +100,9 @@ compare_fuzzy_path_costs(Path *path1, Path *path2, CostSelector criterion)
|
||||
Cost fuzz;
|
||||
|
||||
/*
|
||||
* The fuzz factor is set at one percent of the smaller total_cost, but
|
||||
* not less than 0.01 cost units (just in case total cost is zero).
|
||||
* The fuzz factor is set at one percent of the smaller total_cost,
|
||||
* but not less than 0.01 cost units (just in case total cost is
|
||||
* zero).
|
||||
*
|
||||
* XXX does this percentage need to be user-configurable?
|
||||
*/
|
||||
@@ -278,7 +279,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
|
||||
* possible for more than one old path to be tossed out because
|
||||
* new_path dominates it.
|
||||
*/
|
||||
p1 = list_head(parent_rel->pathlist); /* cannot use foreach here */
|
||||
p1 = list_head(parent_rel->pathlist); /* cannot use foreach here */
|
||||
while (p1 != NULL)
|
||||
{
|
||||
Path *old_path = (Path *) lfirst(p1);
|
||||
@@ -286,9 +287,9 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
|
||||
int costcmp;
|
||||
|
||||
/*
|
||||
* As of Postgres 8.0, we use fuzzy cost comparison to avoid wasting
|
||||
* cycles keeping paths that are really not significantly different
|
||||
* in cost.
|
||||
* As of Postgres 8.0, we use fuzzy cost comparison to avoid
|
||||
* wasting cycles keeping paths that are really not significantly
|
||||
* different in cost.
|
||||
*/
|
||||
costcmp = compare_fuzzy_path_costs(new_path, old_path, TOTAL_COST);
|
||||
|
||||
@@ -298,8 +299,8 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
|
||||
* slower) comparison of pathkeys. If they compare the same,
|
||||
* proceed with the pathkeys comparison. Note: this test relies
|
||||
* on the fact that compare_fuzzy_path_costs will only return 0 if
|
||||
* both costs are effectively equal (and, therefore, there's no need
|
||||
* to call it twice in that case).
|
||||
* both costs are effectively equal (and, therefore, there's no
|
||||
* need to call it twice in that case).
|
||||
*/
|
||||
if (costcmp == 0 ||
|
||||
costcmp == compare_fuzzy_path_costs(new_path, old_path,
|
||||
@@ -321,9 +322,9 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
|
||||
*/
|
||||
if (compare_path_costs(new_path, old_path,
|
||||
TOTAL_COST) < 0)
|
||||
remove_old = true; /* new dominates old */
|
||||
remove_old = true; /* new dominates old */
|
||||
else
|
||||
accept_new = false; /* old equals or dominates
|
||||
accept_new = false; /* old equals or dominates
|
||||
* new */
|
||||
}
|
||||
break;
|
||||
@@ -521,7 +522,7 @@ create_append_path(RelOptInfo *rel, List *subpaths)
|
||||
{
|
||||
Path *subpath = (Path *) lfirst(l);
|
||||
|
||||
if (l == list_head(subpaths)) /* first node? */
|
||||
if (l == list_head(subpaths)) /* first node? */
|
||||
pathnode->path.startup_cost = subpath->startup_cost;
|
||||
pathnode->path.total_cost += subpath->total_cost;
|
||||
}
|
||||
@@ -641,8 +642,8 @@ create_unique_path(Query *root, RelOptInfo *rel, Path *subpath)
|
||||
pathnode->subpath = subpath;
|
||||
|
||||
/*
|
||||
* If the input is a subquery whose output must be unique already,
|
||||
* we don't need to do anything.
|
||||
* If the input is a subquery whose output must be unique already, we
|
||||
* don't need to do anything.
|
||||
*/
|
||||
if (rel->rtekind == RTE_SUBQUERY)
|
||||
{
|
||||
@@ -777,7 +778,7 @@ is_distinct_query(Query *query)
|
||||
|
||||
/*
|
||||
* GROUP BY guarantees uniqueness if all the grouped columns appear in
|
||||
* the output. In our implementation this means checking they are non
|
||||
* the output. In our implementation this means checking they are non
|
||||
* resjunk columns.
|
||||
*/
|
||||
if (query->groupClause)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.95 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.96 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -146,7 +146,7 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel)
|
||||
ChangeVarNodes((Node *) info->indexprs, 1, varno, 0);
|
||||
if (info->indpred && varno != 1)
|
||||
ChangeVarNodes((Node *) info->indpred, 1, varno, 0);
|
||||
info->predOK = false; /* set later in indxpath.c */
|
||||
info->predOK = false; /* set later in indxpath.c */
|
||||
info->unique = index->indisunique;
|
||||
|
||||
/* initialize cached join info to empty */
|
||||
@@ -214,12 +214,12 @@ build_physical_tlist(Query *root, RelOptInfo *rel)
|
||||
}
|
||||
|
||||
tlist = lappend(tlist,
|
||||
create_tl_element(makeVar(varno,
|
||||
attrno,
|
||||
att_tup->atttypid,
|
||||
att_tup->atttypmod,
|
||||
0),
|
||||
attrno));
|
||||
create_tl_element(makeVar(varno,
|
||||
attrno,
|
||||
att_tup->atttypid,
|
||||
att_tup->atttypmod,
|
||||
0),
|
||||
attrno));
|
||||
}
|
||||
|
||||
heap_close(relation, AccessShareLock);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.61 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.62 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -450,9 +450,9 @@ build_joinrel_restrictlist(Query *root,
|
||||
* Collect all the clauses that syntactically belong at this level.
|
||||
*/
|
||||
rlist = list_concat(subbuild_joinrel_restrictlist(joinrel,
|
||||
outer_rel->joininfo),
|
||||
outer_rel->joininfo),
|
||||
subbuild_joinrel_restrictlist(joinrel,
|
||||
inner_rel->joininfo));
|
||||
inner_rel->joininfo));
|
||||
|
||||
/*
|
||||
* Eliminate duplicate and redundant clauses.
|
||||
@@ -500,7 +500,7 @@ subbuild_joinrel_restrictlist(RelOptInfo *joinrel,
|
||||
* but we can use a shallow copy.
|
||||
*/
|
||||
restrictlist = list_concat(restrictlist,
|
||||
list_copy(joininfo->jinfo_restrictinfo));
|
||||
list_copy(joininfo->jinfo_restrictinfo));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.29 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.30 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -22,12 +22,12 @@
|
||||
|
||||
|
||||
static RestrictInfo *make_restrictinfo_internal(Expr *clause,
|
||||
Expr *orclause,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere);
|
||||
Expr *orclause,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere);
|
||||
static Expr *make_sub_restrictinfos(Expr *clause,
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere);
|
||||
bool is_pushed_down,
|
||||
bool valid_everywhere);
|
||||
static RestrictInfo *join_clause_is_redundant(Query *root,
|
||||
RestrictInfo *rinfo,
|
||||
List *reference_list,
|
||||
@@ -104,7 +104,7 @@ make_restrictinfo_from_indexclauses(List *indexclauses,
|
||||
/* Else we need an OR RestrictInfo structure */
|
||||
foreach(orlist, indexclauses)
|
||||
{
|
||||
List *andlist = (List *) lfirst(orlist);
|
||||
List *andlist = (List *) lfirst(orlist);
|
||||
|
||||
/* Create AND subclause with RestrictInfos */
|
||||
withris = lappend(withris, make_ands_explicit(andlist));
|
||||
@@ -113,9 +113,9 @@ make_restrictinfo_from_indexclauses(List *indexclauses,
|
||||
withoutris = lappend(withoutris, make_ands_explicit(andlist));
|
||||
}
|
||||
return list_make1(make_restrictinfo_internal(make_orclause(withoutris),
|
||||
make_orclause(withris),
|
||||
is_pushed_down,
|
||||
valid_everywhere));
|
||||
make_orclause(withris),
|
||||
is_pushed_down,
|
||||
valid_everywhere));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -136,8 +136,8 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
|
||||
restrictinfo->can_join = false; /* may get set below */
|
||||
|
||||
/*
|
||||
* If it's a binary opclause, set up left/right relids info.
|
||||
* In any case set up the total clause relids info.
|
||||
* If it's a binary opclause, set up left/right relids info. In any
|
||||
* case set up the total clause relids info.
|
||||
*/
|
||||
if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
|
||||
{
|
||||
@@ -145,12 +145,12 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
|
||||
restrictinfo->right_relids = pull_varnos(get_rightop(clause));
|
||||
|
||||
restrictinfo->clause_relids = bms_union(restrictinfo->left_relids,
|
||||
restrictinfo->right_relids);
|
||||
restrictinfo->right_relids);
|
||||
|
||||
/*
|
||||
* Does it look like a normal join clause, i.e., a binary operator
|
||||
* relating expressions that come from distinct relations? If so
|
||||
* we might be able to use it in a join algorithm. Note that this
|
||||
* we might be able to use it in a join algorithm. Note that this
|
||||
* is a purely syntactic test that is made regardless of context.
|
||||
*/
|
||||
if (!bms_is_empty(restrictinfo->left_relids) &&
|
||||
@@ -169,10 +169,10 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in all the cacheable fields with "not yet set" markers.
|
||||
* None of these will be computed until/unless needed. Note in
|
||||
* particular that we don't mark a binary opclause as mergejoinable
|
||||
* or hashjoinable here; that happens only if it appears in the right
|
||||
* Fill in all the cacheable fields with "not yet set" markers. None
|
||||
* of these will be computed until/unless needed. Note in particular
|
||||
* that we don't mark a binary opclause as mergejoinable or
|
||||
* hashjoinable here; that happens only if it appears in the right
|
||||
* context (top level of a joinclause list).
|
||||
*/
|
||||
restrictinfo->eval_cost.startup = -1;
|
||||
@@ -322,16 +322,16 @@ remove_redundant_join_clauses(Query *root, List *restrictinfo_list,
|
||||
|
||||
/*
|
||||
* If there are any redundant clauses, we want to eliminate the ones
|
||||
* that are more expensive in favor of the ones that are less so.
|
||||
* Run cost_qual_eval() to ensure the eval_cost fields are set up.
|
||||
* that are more expensive in favor of the ones that are less so. Run
|
||||
* cost_qual_eval() to ensure the eval_cost fields are set up.
|
||||
*/
|
||||
cost_qual_eval(&cost, restrictinfo_list);
|
||||
|
||||
/*
|
||||
* We don't have enough knowledge yet to be able to estimate the number
|
||||
* of times a clause might be evaluated, so it's hard to weight the
|
||||
* startup and per-tuple costs appropriately. For now just weight 'em
|
||||
* the same.
|
||||
* We don't have enough knowledge yet to be able to estimate the
|
||||
* number of times a clause might be evaluated, so it's hard to weight
|
||||
* the startup and per-tuple costs appropriately. For now just weight
|
||||
* 'em the same.
|
||||
*/
|
||||
#define CLAUSECOST(r) ((r)->eval_cost.startup + (r)->eval_cost.per_tuple)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.66 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/tlist.c,v 1.67 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -90,8 +90,8 @@ tlist_member(Node *node, List *targetlist)
|
||||
TargetEntry *
|
||||
create_tl_element(Var *var, int resdomno)
|
||||
{
|
||||
Oid vartype;
|
||||
int32 vartypmod;
|
||||
Oid vartype;
|
||||
int32 vartypmod;
|
||||
|
||||
if (IsA(var, Var))
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.61 2004/08/29 04:12:34 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.62 2004/08/29 05:06:44 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -473,7 +473,7 @@ pull_var_clause_walker(Node *node, pull_var_clause_context *context)
|
||||
* flatten_join_alias_vars
|
||||
* Replace Vars that reference JOIN outputs with references to the original
|
||||
* relation variables instead. This allows quals involving such vars to be
|
||||
* pushed down. Whole-row Vars that reference JOIN relations are expanded
|
||||
* pushed down. Whole-row Vars that reference JOIN relations are expanded
|
||||
* into RowExpr constructs that name the individual output Vars. This
|
||||
* is necessary since we will not scan the JOIN as a base relation, which
|
||||
* is the only way that the executor can directly handle whole-row Vars.
|
||||
@@ -513,10 +513,10 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
if (var->varattno == InvalidAttrNumber)
|
||||
{
|
||||
/* Must expand whole-row reference */
|
||||
RowExpr *rowexpr;
|
||||
List *fields = NIL;
|
||||
RowExpr *rowexpr;
|
||||
List *fields = NIL;
|
||||
AttrNumber attnum;
|
||||
ListCell *l;
|
||||
ListCell *l;
|
||||
|
||||
attnum = 0;
|
||||
foreach(l, rte->joinaliasvars)
|
||||
@@ -528,6 +528,7 @@ flatten_join_alias_vars_mutator(Node *node,
|
||||
var->varno,
|
||||
attnum))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we are expanding an alias carried down from an upper
|
||||
* query, must adjust its varlevelsup fields.
|
||||
|
||||
Reference in New Issue
Block a user