mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
pgindent run for 8.3.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.165 2007/09/26 18:51:50 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.166 2007/11/15 21:14:35 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -43,7 +43,7 @@ join_search_hook_type join_search_hook = NULL;
|
||||
|
||||
static void set_base_rel_pathlists(PlannerInfo *root);
|
||||
static void set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
Index rti, RangeTblEntry *rte);
|
||||
Index rti, RangeTblEntry *rte);
|
||||
static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
RangeTblEntry *rte);
|
||||
static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
@ -312,10 +312,10 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
|
||||
/*
|
||||
* We have to copy the parent's targetlist and quals to the child,
|
||||
* with appropriate substitution of variables. However, only the
|
||||
* with appropriate substitution of variables. However, only the
|
||||
* baserestrictinfo quals are needed before we can check for
|
||||
* constraint exclusion; so do that first and then check to see
|
||||
* if we can disregard this child.
|
||||
* constraint exclusion; so do that first and then check to see if we
|
||||
* can disregard this child.
|
||||
*/
|
||||
childrel->baserestrictinfo = (List *)
|
||||
adjust_appendrel_attrs((Node *) rel->baserestrictinfo,
|
||||
@ -325,8 +325,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
{
|
||||
/*
|
||||
* This child need not be scanned, so we can omit it from the
|
||||
* appendrel. Mark it with a dummy cheapest-path though, in
|
||||
* case best_appendrel_indexscan() looks at it later.
|
||||
* appendrel. Mark it with a dummy cheapest-path though, in case
|
||||
* best_appendrel_indexscan() looks at it later.
|
||||
*/
|
||||
set_dummy_rel_pathlist(childrel);
|
||||
continue;
|
||||
@ -709,7 +709,7 @@ make_rel_from_joinlist(PlannerInfo *root, List *joinlist)
|
||||
* needed for these paths need have been instantiated.
|
||||
*
|
||||
* Note to plugin authors: the functions invoked during standard_join_search()
|
||||
* modify root->join_rel_list and root->join_rel_hash. If you want to do more
|
||||
* modify root->join_rel_list and root->join_rel_hash. If you want to do more
|
||||
* than one join-order search, you'll probably need to save and restore the
|
||||
* original states of those data structures. See geqo_eval() for an example.
|
||||
*/
|
||||
|
@ -54,7 +54,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.187 2007/10/24 18:37:08 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.188 2007/11/15 21:14:35 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -112,12 +112,12 @@ typedef struct
|
||||
{
|
||||
PlannerInfo *root;
|
||||
QualCost total;
|
||||
} cost_qual_eval_context;
|
||||
} cost_qual_eval_context;
|
||||
|
||||
static MergeScanSelCache *cached_scansel(PlannerInfo *root,
|
||||
RestrictInfo *rinfo,
|
||||
PathKey *pathkey);
|
||||
static bool cost_qual_eval_walker(Node *node, cost_qual_eval_context *context);
|
||||
RestrictInfo *rinfo,
|
||||
PathKey * pathkey);
|
||||
static bool cost_qual_eval_walker(Node *node, cost_qual_eval_context * context);
|
||||
static Selectivity approx_selectivity(PlannerInfo *root, List *quals,
|
||||
JoinType jointype);
|
||||
static Selectivity join_in_selectivity(JoinPath *path, PlannerInfo *root);
|
||||
@ -303,15 +303,14 @@ cost_index(IndexPath *path, PlannerInfo *root,
|
||||
max_IO_cost = (pages_fetched * random_page_cost) / num_scans;
|
||||
|
||||
/*
|
||||
* In the perfectly correlated case, the number of pages touched
|
||||
* by each scan is selectivity * table_size, and we can use the
|
||||
* Mackert and Lohman formula at the page level to estimate how
|
||||
* much work is saved by caching across scans. We still assume
|
||||
* all the fetches are random, though, which is an overestimate
|
||||
* that's hard to correct for without double-counting the cache
|
||||
* effects. (But in most cases where such a plan is actually
|
||||
* interesting, only one page would get fetched per scan anyway,
|
||||
* so it shouldn't matter much.)
|
||||
* In the perfectly correlated case, the number of pages touched by
|
||||
* each scan is selectivity * table_size, and we can use the Mackert
|
||||
* and Lohman formula at the page level to estimate how much work is
|
||||
* saved by caching across scans. We still assume all the fetches are
|
||||
* random, though, which is an overestimate that's hard to correct for
|
||||
* without double-counting the cache effects. (But in most cases
|
||||
* where such a plan is actually interesting, only one page would get
|
||||
* fetched per scan anyway, so it shouldn't matter much.)
|
||||
*/
|
||||
pages_fetched = ceil(indexSelectivity * (double) baserel->pages);
|
||||
|
||||
@ -344,8 +343,8 @@ cost_index(IndexPath *path, PlannerInfo *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* Now interpolate based on estimated index order correlation to get
|
||||
* total disk I/O cost for main table accesses.
|
||||
* Now interpolate based on estimated index order correlation to get total
|
||||
* disk I/O cost for main table accesses.
|
||||
*/
|
||||
csquared = indexCorrelation * indexCorrelation;
|
||||
|
||||
@ -643,11 +642,12 @@ cost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec)
|
||||
{
|
||||
*cost = ((IndexPath *) path)->indextotalcost;
|
||||
*selec = ((IndexPath *) path)->indexselectivity;
|
||||
|
||||
/*
|
||||
* Charge a small amount per retrieved tuple to reflect the costs of
|
||||
* manipulating the bitmap. This is mostly to make sure that a bitmap
|
||||
* scan doesn't look to be the same cost as an indexscan to retrieve
|
||||
* a single tuple.
|
||||
* scan doesn't look to be the same cost as an indexscan to retrieve a
|
||||
* single tuple.
|
||||
*/
|
||||
*cost += 0.1 * cpu_operator_cost * ((IndexPath *) path)->rows;
|
||||
}
|
||||
@ -806,7 +806,7 @@ cost_tidscan(Path *path, PlannerInfo *root,
|
||||
|
||||
/*
|
||||
* We must force TID scan for WHERE CURRENT OF, because only nodeTidscan.c
|
||||
* understands how to do it correctly. Therefore, honor enable_tidscan
|
||||
* understands how to do it correctly. Therefore, honor enable_tidscan
|
||||
* only when CURRENT OF isn't present. Also note that cost_qual_eval
|
||||
* counts a CurrentOfExpr as having startup cost disable_cost, which we
|
||||
* subtract off here; that's to prevent other plan types such as seqscan
|
||||
@ -1043,10 +1043,10 @@ cost_sort(Path *path, PlannerInfo *root,
|
||||
else if (tuples > 2 * output_tuples || input_bytes > work_mem_bytes)
|
||||
{
|
||||
/*
|
||||
* We'll use a bounded heap-sort keeping just K tuples in memory,
|
||||
* for a total number of tuple comparisons of N log2 K; but the
|
||||
* constant factor is a bit higher than for quicksort. Tweak it
|
||||
* so that the cost curve is continuous at the crossover point.
|
||||
* We'll use a bounded heap-sort keeping just K tuples in memory, for
|
||||
* a total number of tuple comparisons of N log2 K; but the constant
|
||||
* factor is a bit higher than for quicksort. Tweak it so that the
|
||||
* cost curve is continuous at the crossover point.
|
||||
*/
|
||||
startup_cost += 2.0 * cpu_operator_cost * tuples * LOG2(2.0 * output_tuples);
|
||||
}
|
||||
@ -1454,8 +1454,8 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
|
||||
RestrictInfo *firstclause = (RestrictInfo *) linitial(mergeclauses);
|
||||
List *opathkeys;
|
||||
List *ipathkeys;
|
||||
PathKey *opathkey;
|
||||
PathKey *ipathkey;
|
||||
PathKey *opathkey;
|
||||
PathKey *ipathkey;
|
||||
MergeScanSelCache *cache;
|
||||
|
||||
/* Get the input pathkeys to determine the sort-order details */
|
||||
@ -1593,7 +1593,7 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
|
||||
* run mergejoinscansel() with caching
|
||||
*/
|
||||
static MergeScanSelCache *
|
||||
cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey *pathkey)
|
||||
cached_scansel(PlannerInfo *root, RestrictInfo *rinfo, PathKey * pathkey)
|
||||
{
|
||||
MergeScanSelCache *cache;
|
||||
ListCell *lc;
|
||||
@ -1787,8 +1787,8 @@ cost_hashjoin(HashPath *path, PlannerInfo *root)
|
||||
* If inner relation is too big then we will need to "batch" the join,
|
||||
* which implies writing and reading most of the tuples to disk an extra
|
||||
* time. Charge seq_page_cost per page, since the I/O should be nice and
|
||||
* sequential. Writing the inner rel counts as startup cost,
|
||||
* all the rest as run cost.
|
||||
* sequential. Writing the inner rel counts as startup cost, all the rest
|
||||
* as run cost.
|
||||
*/
|
||||
if (numbatches > 1)
|
||||
{
|
||||
@ -1891,16 +1891,16 @@ cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
|
||||
}
|
||||
|
||||
static bool
|
||||
cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
cost_qual_eval_walker(Node *node, cost_qual_eval_context * context)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* RestrictInfo nodes contain an eval_cost field reserved for this
|
||||
* routine's use, so that it's not necessary to evaluate the qual
|
||||
* clause's cost more than once. If the clause's cost hasn't been
|
||||
* computed yet, the field's startup value will contain -1.
|
||||
* routine's use, so that it's not necessary to evaluate the qual clause's
|
||||
* cost more than once. If the clause's cost hasn't been computed yet,
|
||||
* the field's startup value will contain -1.
|
||||
*/
|
||||
if (IsA(node, RestrictInfo))
|
||||
{
|
||||
@ -1913,14 +1913,16 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
locContext.root = context->root;
|
||||
locContext.total.startup = 0;
|
||||
locContext.total.per_tuple = 0;
|
||||
|
||||
/*
|
||||
* For an OR clause, recurse into the marked-up tree so that
|
||||
* we set the eval_cost for contained RestrictInfos too.
|
||||
* For an OR clause, recurse into the marked-up tree so that we
|
||||
* set the eval_cost for contained RestrictInfos too.
|
||||
*/
|
||||
if (rinfo->orclause)
|
||||
cost_qual_eval_walker((Node *) rinfo->orclause, &locContext);
|
||||
else
|
||||
cost_qual_eval_walker((Node *) rinfo->clause, &locContext);
|
||||
|
||||
/*
|
||||
* If the RestrictInfo is marked pseudoconstant, it will be tested
|
||||
* only once, so treat its cost as all startup cost.
|
||||
@ -1941,8 +1943,8 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
|
||||
/*
|
||||
* For each operator or function node in the given tree, we charge the
|
||||
* estimated execution cost given by pg_proc.procost (remember to
|
||||
* multiply this by cpu_operator_cost).
|
||||
* estimated execution cost given by pg_proc.procost (remember to multiply
|
||||
* this by cpu_operator_cost).
|
||||
*
|
||||
* Vars and Consts are charged zero, and so are boolean operators (AND,
|
||||
* OR, NOT). Simplistic, but a lot better than no model at all.
|
||||
@ -1951,7 +1953,7 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
* evaluation of AND/OR? Probably *not*, because that would make the
|
||||
* results depend on the clause ordering, and we are not in any position
|
||||
* to expect that the current ordering of the clauses is the one that's
|
||||
* going to end up being used. (Is it worth applying order_qual_clauses
|
||||
* going to end up being used. (Is it worth applying order_qual_clauses
|
||||
* much earlier in the planning process to fix this?)
|
||||
*/
|
||||
if (IsA(node, FuncExpr))
|
||||
@ -1984,9 +1986,9 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
{
|
||||
CoerceViaIO *iocoerce = (CoerceViaIO *) node;
|
||||
Oid iofunc;
|
||||
Oid typioparam;
|
||||
bool typisvarlena;
|
||||
Oid iofunc;
|
||||
Oid typioparam;
|
||||
bool typisvarlena;
|
||||
|
||||
/* check the result type's input function */
|
||||
getTypeInputInfo(iocoerce->resulttype,
|
||||
@ -2014,7 +2016,7 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
|
||||
foreach(lc, rcexpr->opnos)
|
||||
{
|
||||
Oid opid = lfirst_oid(lc);
|
||||
Oid opid = lfirst_oid(lc);
|
||||
|
||||
context->total.per_tuple += get_func_cost(get_opcode(opid)) *
|
||||
cpu_operator_cost;
|
||||
@ -2069,7 +2071,7 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
{
|
||||
/*
|
||||
* Otherwise we will be rescanning the subplan output on each
|
||||
* evaluation. We need to estimate how much of the output we will
|
||||
* evaluation. We need to estimate how much of the output we will
|
||||
* actually need to scan. NOTE: this logic should agree with
|
||||
* get_initplan_cost, below, and with the estimates used by
|
||||
* make_subplan() in plan/subselect.c.
|
||||
@ -2266,9 +2268,9 @@ set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
|
||||
* double-counting them because they were not considered in estimating the
|
||||
* sizes of the component rels.
|
||||
*
|
||||
* For an outer join, we have to distinguish the selectivity of the
|
||||
* join's own clauses (JOIN/ON conditions) from any clauses that were
|
||||
* "pushed down". For inner joins we just count them all as joinclauses.
|
||||
* For an outer join, we have to distinguish the selectivity of the join's
|
||||
* own clauses (JOIN/ON conditions) from any clauses that were "pushed
|
||||
* down". For inner joins we just count them all as joinclauses.
|
||||
*/
|
||||
if (IS_OUTER_JOIN(jointype))
|
||||
{
|
||||
@ -2316,7 +2318,7 @@ set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
|
||||
*
|
||||
* If we are doing an outer join, take that into account: the joinqual
|
||||
* selectivity has to be clamped using the knowledge that the output must
|
||||
* be at least as large as the non-nullable input. However, any
|
||||
* be at least as large as the non-nullable input. However, any
|
||||
* pushed-down quals are applied after the outer join, so their
|
||||
* selectivity applies fully.
|
||||
*
|
||||
@ -2515,7 +2517,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
|
||||
if (rel->relid > 0)
|
||||
rel_reloid = getrelid(rel->relid, root->parse->rtable);
|
||||
else
|
||||
rel_reloid = InvalidOid; /* probably can't happen */
|
||||
rel_reloid = InvalidOid; /* probably can't happen */
|
||||
|
||||
foreach(tllist, rel->reltargetlist)
|
||||
{
|
||||
|
@ -10,7 +10,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.4 2007/11/08 21:49:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.5 2007/11/15 21:14:35 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -26,37 +26,37 @@
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
|
||||
static EquivalenceMember *add_eq_member(EquivalenceClass *ec,
|
||||
Expr *expr, Relids relids,
|
||||
bool is_child, Oid datatype);
|
||||
static EquivalenceMember *add_eq_member(EquivalenceClass * ec,
|
||||
Expr *expr, Relids relids,
|
||||
bool is_child, Oid datatype);
|
||||
static void generate_base_implied_equalities_const(PlannerInfo *root,
|
||||
EquivalenceClass *ec);
|
||||
EquivalenceClass * ec);
|
||||
static void generate_base_implied_equalities_no_const(PlannerInfo *root,
|
||||
EquivalenceClass *ec);
|
||||
EquivalenceClass * ec);
|
||||
static void generate_base_implied_equalities_broken(PlannerInfo *root,
|
||||
EquivalenceClass *ec);
|
||||
EquivalenceClass * ec);
|
||||
static List *generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
EquivalenceClass *ec,
|
||||
EquivalenceClass * ec,
|
||||
RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel);
|
||||
static List *generate_join_implied_equalities_broken(PlannerInfo *root,
|
||||
EquivalenceClass *ec,
|
||||
EquivalenceClass * ec,
|
||||
RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel);
|
||||
static Oid select_equality_operator(EquivalenceClass *ec,
|
||||
Oid lefttype, Oid righttype);
|
||||
static Oid select_equality_operator(EquivalenceClass * ec,
|
||||
Oid lefttype, Oid righttype);
|
||||
static RestrictInfo *create_join_clause(PlannerInfo *root,
|
||||
EquivalenceClass *ec, Oid opno,
|
||||
EquivalenceMember *leftem,
|
||||
EquivalenceMember *rightem,
|
||||
EquivalenceClass *parent_ec);
|
||||
EquivalenceClass * ec, Oid opno,
|
||||
EquivalenceMember * leftem,
|
||||
EquivalenceMember * rightem,
|
||||
EquivalenceClass * parent_ec);
|
||||
static void reconsider_outer_join_clause(PlannerInfo *root,
|
||||
RestrictInfo *rinfo,
|
||||
bool outer_on_left);
|
||||
RestrictInfo *rinfo,
|
||||
bool outer_on_left);
|
||||
static void reconsider_full_join_clause(PlannerInfo *root,
|
||||
RestrictInfo *rinfo);
|
||||
RestrictInfo *rinfo);
|
||||
|
||||
|
||||
/*
|
||||
@ -70,7 +70,7 @@ static void reconsider_full_join_clause(PlannerInfo *root,
|
||||
*
|
||||
* If below_outer_join is true, then the clause was found below the nullable
|
||||
* side of an outer join, so its sides might validly be both NULL rather than
|
||||
* strictly equal. We can still deduce equalities in such cases, but we take
|
||||
* strictly equal. We can still deduce equalities in such cases, but we take
|
||||
* care to mark an EquivalenceClass if it came from any such clauses. Also,
|
||||
* we have to check that both sides are either pseudo-constants or strict
|
||||
* functions of Vars, else they might not both go to NULL above the outer
|
||||
@ -127,37 +127,37 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
|
||||
}
|
||||
|
||||
/*
|
||||
* We use the declared input types of the operator, not exprType() of
|
||||
* the inputs, as the nominal datatypes for opfamily lookup. This
|
||||
* presumes that btree operators are always registered with amoplefttype
|
||||
* and amoprighttype equal to their declared input types. We will need
|
||||
* this info anyway to build EquivalenceMember nodes, and by extracting
|
||||
* it now we can use type comparisons to short-circuit some equal() tests.
|
||||
* We use the declared input types of the operator, not exprType() of the
|
||||
* inputs, as the nominal datatypes for opfamily lookup. This presumes
|
||||
* that btree operators are always registered with amoplefttype and
|
||||
* amoprighttype equal to their declared input types. We will need this
|
||||
* info anyway to build EquivalenceMember nodes, and by extracting it now
|
||||
* we can use type comparisons to short-circuit some equal() tests.
|
||||
*/
|
||||
op_input_types(opno, &item1_type, &item2_type);
|
||||
|
||||
opfamilies = restrictinfo->mergeopfamilies;
|
||||
|
||||
/*
|
||||
* Sweep through the existing EquivalenceClasses looking for matches
|
||||
* to item1 and item2. These are the possible outcomes:
|
||||
* Sweep through the existing EquivalenceClasses looking for matches to
|
||||
* item1 and item2. These are the possible outcomes:
|
||||
*
|
||||
* 1. We find both in the same EC. The equivalence is already known,
|
||||
* so there's nothing to do.
|
||||
* 1. We find both in the same EC. The equivalence is already known, so
|
||||
* there's nothing to do.
|
||||
*
|
||||
* 2. We find both in different ECs. Merge the two ECs together.
|
||||
*
|
||||
* 3. We find just one. Add the other to its EC.
|
||||
*
|
||||
* 4. We find neither. Make a new, two-entry EC.
|
||||
* 4. We find neither. Make a new, two-entry EC.
|
||||
*
|
||||
* Note: since all ECs are built through this process, it's impossible
|
||||
* that we'd match an item in more than one existing EC. It is possible
|
||||
* to match more than once within an EC, if someone fed us something silly
|
||||
* like "WHERE X=X". (However, we can't simply discard such clauses,
|
||||
* since they should fail when X is null; so we will build a 2-member
|
||||
* EC to ensure the correct restriction clause gets generated. Hence
|
||||
* there is no shortcut here for item1 and item2 equal.)
|
||||
* since they should fail when X is null; so we will build a 2-member EC
|
||||
* to ensure the correct restriction clause gets generated. Hence there
|
||||
* is no shortcut here for item1 and item2 equal.)
|
||||
*/
|
||||
ec1 = ec2 = NULL;
|
||||
em1 = em2 = NULL;
|
||||
@ -182,11 +182,11 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
|
||||
{
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
|
||||
|
||||
Assert(!cur_em->em_is_child); /* no children yet */
|
||||
Assert(!cur_em->em_is_child); /* no children yet */
|
||||
|
||||
/*
|
||||
* If below an outer join, don't match constants: they're not
|
||||
* as constant as they look.
|
||||
* If below an outer join, don't match constants: they're not as
|
||||
* constant as they look.
|
||||
*/
|
||||
if ((below_outer_join || cur_ec->ec_below_outer_join) &&
|
||||
cur_em->em_is_const)
|
||||
@ -234,11 +234,11 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
|
||||
}
|
||||
|
||||
/*
|
||||
* Case 2: need to merge ec1 and ec2. We add ec2's items to ec1,
|
||||
* then set ec2's ec_merged link to point to ec1 and remove ec2
|
||||
* from the eq_classes list. We cannot simply delete ec2 because
|
||||
* that could leave dangling pointers in existing PathKeys. We
|
||||
* leave it behind with a link so that the merged EC can be found.
|
||||
* Case 2: need to merge ec1 and ec2. We add ec2's items to ec1, then
|
||||
* set ec2's ec_merged link to point to ec1 and remove ec2 from the
|
||||
* eq_classes list. We cannot simply delete ec2 because that could
|
||||
* leave dangling pointers in existing PathKeys. We leave it behind
|
||||
* with a link so that the merged EC can be found.
|
||||
*/
|
||||
ec1->ec_members = list_concat(ec1->ec_members, ec2->ec_members);
|
||||
ec1->ec_sources = list_concat(ec1->ec_sources, ec2->ec_sources);
|
||||
@ -313,7 +313,7 @@ process_equivalence(PlannerInfo *root, RestrictInfo *restrictinfo,
|
||||
* add_eq_member - build a new EquivalenceMember and add it to an EC
|
||||
*/
|
||||
static EquivalenceMember *
|
||||
add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
|
||||
add_eq_member(EquivalenceClass * ec, Expr *expr, Relids relids,
|
||||
bool is_child, Oid datatype)
|
||||
{
|
||||
EquivalenceMember *em = makeNode(EquivalenceMember);
|
||||
@ -327,10 +327,10 @@ add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
|
||||
if (bms_is_empty(relids))
|
||||
{
|
||||
/*
|
||||
* No Vars, assume it's a pseudoconstant. This is correct for
|
||||
* entries generated from process_equivalence(), because a WHERE
|
||||
* clause can't contain aggregates or SRFs, and non-volatility was
|
||||
* checked before process_equivalence() ever got called. But
|
||||
* No Vars, assume it's a pseudoconstant. This is correct for entries
|
||||
* generated from process_equivalence(), because a WHERE clause can't
|
||||
* contain aggregates or SRFs, and non-volatility was checked before
|
||||
* process_equivalence() ever got called. But
|
||||
* get_eclass_for_sort_expr() has to work harder. We put the tests
|
||||
* there not here to save cycles in the equivalence case.
|
||||
*/
|
||||
@ -399,8 +399,8 @@ get_eclass_for_sort_expr(PlannerInfo *root,
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
|
||||
|
||||
/*
|
||||
* If below an outer join, don't match constants: they're not
|
||||
* as constant as they look.
|
||||
* If below an outer join, don't match constants: they're not as
|
||||
* constant as they look.
|
||||
*/
|
||||
if (cur_ec->ec_below_outer_join &&
|
||||
cur_em->em_is_const)
|
||||
@ -408,15 +408,15 @@ get_eclass_for_sort_expr(PlannerInfo *root,
|
||||
|
||||
if (expr_datatype == cur_em->em_datatype &&
|
||||
equal(expr, cur_em->em_expr))
|
||||
return cur_ec; /* Match! */
|
||||
return cur_ec; /* Match! */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* No match, so build a new single-member EC
|
||||
*
|
||||
* Here, we must be sure that we construct the EC in the right context.
|
||||
* We can assume, however, that the passed expr is long-lived.
|
||||
* Here, we must be sure that we construct the EC in the right context. We
|
||||
* can assume, however, that the passed expr is long-lived.
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(root->planner_cxt);
|
||||
|
||||
@ -437,8 +437,8 @@ get_eclass_for_sort_expr(PlannerInfo *root,
|
||||
|
||||
/*
|
||||
* add_eq_member doesn't check for volatile functions, set-returning
|
||||
* functions, or aggregates, but such could appear in sort expressions;
|
||||
* so we have to check whether its const-marking was correct.
|
||||
* functions, or aggregates, but such could appear in sort expressions; so
|
||||
* we have to check whether its const-marking was correct.
|
||||
*/
|
||||
if (newec->ec_has_const)
|
||||
{
|
||||
@ -466,7 +466,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
|
||||
*
|
||||
* When an EC contains pseudoconstants, our strategy is to generate
|
||||
* "member = const1" clauses where const1 is the first constant member, for
|
||||
* every other member (including other constants). If we are able to do this
|
||||
* every other member (including other constants). If we are able to do this
|
||||
* then we don't need any "var = var" comparisons because we've successfully
|
||||
* constrained all the vars at their points of creation. If we fail to
|
||||
* generate any of these clauses due to lack of cross-type operators, we fall
|
||||
@ -491,7 +491,7 @@ get_eclass_for_sort_expr(PlannerInfo *root,
|
||||
* "WHERE a.x = b.y AND b.y = a.z", the scheme breaks down if we cannot
|
||||
* generate "a.x = a.z" as a restriction clause for A.) In this case we mark
|
||||
* the EC "ec_broken" and fall back to regurgitating its original source
|
||||
* RestrictInfos at appropriate times. We do not try to retract any derived
|
||||
* RestrictInfos at appropriate times. We do not try to retract any derived
|
||||
* clauses already generated from the broken EC, so the resulting plan could
|
||||
* be poor due to bad selectivity estimates caused by redundant clauses. But
|
||||
* the correct solution to that is to fix the opfamilies ...
|
||||
@ -517,8 +517,8 @@ generate_base_implied_equalities(PlannerInfo *root)
|
||||
{
|
||||
EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc);
|
||||
|
||||
Assert(ec->ec_merged == NULL); /* else shouldn't be in list */
|
||||
Assert(!ec->ec_broken); /* not yet anyway... */
|
||||
Assert(ec->ec_merged == NULL); /* else shouldn't be in list */
|
||||
Assert(!ec->ec_broken); /* not yet anyway... */
|
||||
|
||||
/* Single-member ECs won't generate any deductions */
|
||||
if (list_length(ec->ec_members) <= 1)
|
||||
@ -535,9 +535,8 @@ generate_base_implied_equalities(PlannerInfo *root)
|
||||
}
|
||||
|
||||
/*
|
||||
* This is also a handy place to mark base rels (which should all
|
||||
* exist by now) with flags showing whether they have pending eclass
|
||||
* joins.
|
||||
* This is also a handy place to mark base rels (which should all exist by
|
||||
* now) with flags showing whether they have pending eclass joins.
|
||||
*/
|
||||
for (rti = 1; rti < root->simple_rel_array_size; rti++)
|
||||
{
|
||||
@ -555,7 +554,7 @@ generate_base_implied_equalities(PlannerInfo *root)
|
||||
*/
|
||||
static void
|
||||
generate_base_implied_equalities_const(PlannerInfo *root,
|
||||
EquivalenceClass *ec)
|
||||
EquivalenceClass * ec)
|
||||
{
|
||||
EquivalenceMember *const_em = NULL;
|
||||
ListCell *lc;
|
||||
@ -579,7 +578,7 @@ generate_base_implied_equalities_const(PlannerInfo *root,
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc);
|
||||
Oid eq_op;
|
||||
|
||||
Assert(!cur_em->em_is_child); /* no children yet */
|
||||
Assert(!cur_em->em_is_child); /* no children yet */
|
||||
if (cur_em == const_em)
|
||||
continue;
|
||||
eq_op = select_equality_operator(ec,
|
||||
@ -604,7 +603,7 @@ generate_base_implied_equalities_const(PlannerInfo *root,
|
||||
*/
|
||||
static void
|
||||
generate_base_implied_equalities_no_const(PlannerInfo *root,
|
||||
EquivalenceClass *ec)
|
||||
EquivalenceClass * ec)
|
||||
{
|
||||
EquivalenceMember **prev_ems;
|
||||
ListCell *lc;
|
||||
@ -613,9 +612,10 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
|
||||
* We scan the EC members once and track the last-seen member for each
|
||||
* base relation. When we see another member of the same base relation,
|
||||
* we generate "prev_mem = cur_mem". This results in the minimum number
|
||||
* of derived clauses, but it's possible that it will fail when a different
|
||||
* ordering would succeed. XXX FIXME: use a UNION-FIND algorithm similar
|
||||
* to the way we build merged ECs. (Use a list-of-lists for each rel.)
|
||||
* of derived clauses, but it's possible that it will fail when a
|
||||
* different ordering would succeed. XXX FIXME: use a UNION-FIND
|
||||
* algorithm similar to the way we build merged ECs. (Use a list-of-lists
|
||||
* for each rel.)
|
||||
*/
|
||||
prev_ems = (EquivalenceMember **)
|
||||
palloc0(root->simple_rel_array_size * sizeof(EquivalenceMember *));
|
||||
@ -625,7 +625,7 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc);
|
||||
int relid;
|
||||
|
||||
Assert(!cur_em->em_is_child); /* no children yet */
|
||||
Assert(!cur_em->em_is_child); /* no children yet */
|
||||
if (bms_membership(cur_em->em_relids) != BMS_SINGLETON)
|
||||
continue;
|
||||
relid = bms_singleton_member(cur_em->em_relids);
|
||||
@ -657,12 +657,12 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
|
||||
pfree(prev_ems);
|
||||
|
||||
/*
|
||||
* We also have to make sure that all the Vars used in the member
|
||||
* clauses will be available at any join node we might try to reference
|
||||
* them at. For the moment we force all the Vars to be available at
|
||||
* all join nodes for this eclass. Perhaps this could be improved by
|
||||
* doing some pre-analysis of which members we prefer to join, but it's
|
||||
* no worse than what happened in the pre-8.3 code.
|
||||
* We also have to make sure that all the Vars used in the member clauses
|
||||
* will be available at any join node we might try to reference them at.
|
||||
* For the moment we force all the Vars to be available at all join nodes
|
||||
* for this eclass. Perhaps this could be improved by doing some
|
||||
* pre-analysis of which members we prefer to join, but it's no worse than
|
||||
* what happened in the pre-8.3 code.
|
||||
*/
|
||||
foreach(lc, ec->ec_members)
|
||||
{
|
||||
@ -685,7 +685,7 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
|
||||
*/
|
||||
static void
|
||||
generate_base_implied_equalities_broken(PlannerInfo *root,
|
||||
EquivalenceClass *ec)
|
||||
EquivalenceClass * ec)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
@ -720,7 +720,7 @@ generate_base_implied_equalities_broken(PlannerInfo *root,
|
||||
* we consider different join paths, we avoid generating multiple copies:
|
||||
* whenever we select a particular pair of EquivalenceMembers to join,
|
||||
* we check to see if the pair matches any original clause (in ec_sources)
|
||||
* or previously-built clause (in ec_derives). This saves memory and allows
|
||||
* or previously-built clause (in ec_derives). This saves memory and allows
|
||||
* re-use of information cached in RestrictInfos.
|
||||
*/
|
||||
List *
|
||||
@ -735,7 +735,7 @@ generate_join_implied_equalities(PlannerInfo *root,
|
||||
foreach(lc, root->eq_classes)
|
||||
{
|
||||
EquivalenceClass *ec = (EquivalenceClass *) lfirst(lc);
|
||||
List *sublist = NIL;
|
||||
List *sublist = NIL;
|
||||
|
||||
/* ECs containing consts do not need any further enforcement */
|
||||
if (ec->ec_has_const)
|
||||
@ -775,7 +775,7 @@ generate_join_implied_equalities(PlannerInfo *root,
|
||||
*/
|
||||
static List *
|
||||
generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
EquivalenceClass *ec,
|
||||
EquivalenceClass * ec,
|
||||
RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel)
|
||||
@ -787,13 +787,13 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
ListCell *lc1;
|
||||
|
||||
/*
|
||||
* First, scan the EC to identify member values that are computable
|
||||
* at the outer rel, at the inner rel, or at this relation but not in
|
||||
* either input rel. The outer-rel members should already be enforced
|
||||
* equal, likewise for the inner-rel members. We'll need to create
|
||||
* clauses to enforce that any newly computable members are all equal
|
||||
* to each other as well as to at least one input member, plus enforce
|
||||
* at least one outer-rel member equal to at least one inner-rel member.
|
||||
* First, scan the EC to identify member values that are computable at the
|
||||
* outer rel, at the inner rel, or at this relation but not in either
|
||||
* input rel. The outer-rel members should already be enforced equal,
|
||||
* likewise for the inner-rel members. We'll need to create clauses to
|
||||
* enforce that any newly computable members are all equal to each other
|
||||
* as well as to at least one input member, plus enforce at least one
|
||||
* outer-rel member equal to at least one inner-rel member.
|
||||
*/
|
||||
foreach(lc1, ec->ec_members)
|
||||
{
|
||||
@ -813,20 +813,20 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* First, select the joinclause if needed. We can equate any one outer
|
||||
* First, select the joinclause if needed. We can equate any one outer
|
||||
* member to any one inner member, but we have to find a datatype
|
||||
* combination for which an opfamily member operator exists. If we
|
||||
* have choices, we prefer simple Var members (possibly with RelabelType)
|
||||
* since these are (a) cheapest to compute at runtime and (b) most likely
|
||||
* to have useful statistics. Also, if enable_hashjoin is on, we prefer
|
||||
* combination for which an opfamily member operator exists. If we have
|
||||
* choices, we prefer simple Var members (possibly with RelabelType) since
|
||||
* these are (a) cheapest to compute at runtime and (b) most likely to
|
||||
* have useful statistics. Also, if enable_hashjoin is on, we prefer
|
||||
* operators that are also hashjoinable.
|
||||
*/
|
||||
if (outer_members && inner_members)
|
||||
{
|
||||
EquivalenceMember *best_outer_em = NULL;
|
||||
EquivalenceMember *best_inner_em = NULL;
|
||||
Oid best_eq_op = InvalidOid;
|
||||
int best_score = -1;
|
||||
Oid best_eq_op = InvalidOid;
|
||||
int best_score = -1;
|
||||
RestrictInfo *rinfo;
|
||||
|
||||
foreach(lc1, outer_members)
|
||||
@ -837,8 +837,8 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
foreach(lc2, inner_members)
|
||||
{
|
||||
EquivalenceMember *inner_em = (EquivalenceMember *) lfirst(lc2);
|
||||
Oid eq_op;
|
||||
int score;
|
||||
Oid eq_op;
|
||||
int score;
|
||||
|
||||
eq_op = select_equality_operator(ec,
|
||||
outer_em->em_datatype,
|
||||
@ -863,11 +863,11 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
best_eq_op = eq_op;
|
||||
best_score = score;
|
||||
if (best_score == 3)
|
||||
break; /* no need to look further */
|
||||
break; /* no need to look further */
|
||||
}
|
||||
}
|
||||
if (best_score == 3)
|
||||
break; /* no need to look further */
|
||||
break; /* no need to look further */
|
||||
}
|
||||
if (best_score < 0)
|
||||
{
|
||||
@ -892,8 +892,8 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
* Vars from both sides of the join. We have to equate all of these to
|
||||
* each other as well as to at least one old member (if any).
|
||||
*
|
||||
* XXX as in generate_base_implied_equalities_no_const, we could be a
|
||||
* lot smarter here to avoid unnecessary failures in cross-type situations.
|
||||
* XXX as in generate_base_implied_equalities_no_const, we could be a lot
|
||||
* smarter here to avoid unnecessary failures in cross-type situations.
|
||||
* For now, use the same left-to-right method used there.
|
||||
*/
|
||||
if (new_members)
|
||||
@ -944,7 +944,7 @@ generate_join_implied_equalities_normal(PlannerInfo *root,
|
||||
*/
|
||||
static List *
|
||||
generate_join_implied_equalities_broken(PlannerInfo *root,
|
||||
EquivalenceClass *ec,
|
||||
EquivalenceClass * ec,
|
||||
RelOptInfo *joinrel,
|
||||
RelOptInfo *outer_rel,
|
||||
RelOptInfo *inner_rel)
|
||||
@ -957,7 +957,7 @@ generate_join_implied_equalities_broken(PlannerInfo *root,
|
||||
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(lc);
|
||||
|
||||
if (bms_is_subset(restrictinfo->required_relids, joinrel->relids) &&
|
||||
!bms_is_subset(restrictinfo->required_relids, outer_rel->relids) &&
|
||||
!bms_is_subset(restrictinfo->required_relids, outer_rel->relids) &&
|
||||
!bms_is_subset(restrictinfo->required_relids, inner_rel->relids))
|
||||
result = lappend(result, restrictinfo);
|
||||
}
|
||||
@ -973,14 +973,14 @@ generate_join_implied_equalities_broken(PlannerInfo *root,
|
||||
* Returns InvalidOid if no operator can be found for this datatype combination
|
||||
*/
|
||||
static Oid
|
||||
select_equality_operator(EquivalenceClass *ec, Oid lefttype, Oid righttype)
|
||||
select_equality_operator(EquivalenceClass * ec, Oid lefttype, Oid righttype)
|
||||
{
|
||||
ListCell *lc;
|
||||
|
||||
foreach(lc, ec->ec_opfamilies)
|
||||
{
|
||||
Oid opfamily = lfirst_oid(lc);
|
||||
Oid opno;
|
||||
Oid opfamily = lfirst_oid(lc);
|
||||
Oid opno;
|
||||
|
||||
opno = get_opfamily_member(opfamily, lefttype, righttype,
|
||||
BTEqualStrategyNumber);
|
||||
@ -1003,10 +1003,10 @@ select_equality_operator(EquivalenceClass *ec, Oid lefttype, Oid righttype)
|
||||
*/
|
||||
static RestrictInfo *
|
||||
create_join_clause(PlannerInfo *root,
|
||||
EquivalenceClass *ec, Oid opno,
|
||||
EquivalenceMember *leftem,
|
||||
EquivalenceMember *rightem,
|
||||
EquivalenceClass *parent_ec)
|
||||
EquivalenceClass * ec, Oid opno,
|
||||
EquivalenceMember * leftem,
|
||||
EquivalenceMember * rightem,
|
||||
EquivalenceClass * parent_ec)
|
||||
{
|
||||
RestrictInfo *rinfo;
|
||||
ListCell *lc;
|
||||
@ -1014,8 +1014,8 @@ create_join_clause(PlannerInfo *root,
|
||||
|
||||
/*
|
||||
* Search to see if we already built a RestrictInfo for this pair of
|
||||
* EquivalenceMembers. We can use either original source clauses or
|
||||
* previously-derived clauses. The check on opno is probably redundant,
|
||||
* EquivalenceMembers. We can use either original source clauses or
|
||||
* previously-derived clauses. The check on opno is probably redundant,
|
||||
* but be safe ...
|
||||
*/
|
||||
foreach(lc, ec->ec_sources)
|
||||
@ -1039,8 +1039,8 @@ create_join_clause(PlannerInfo *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* Not there, so build it, in planner context so we can re-use it.
|
||||
* (Not important in normal planning, but definitely so in GEQO.)
|
||||
* Not there, so build it, in planner context so we can re-use it. (Not
|
||||
* important in normal planning, but definitely so in GEQO.)
|
||||
*/
|
||||
oldcontext = MemoryContextSwitchTo(root->planner_cxt);
|
||||
|
||||
@ -1216,10 +1216,9 @@ reconsider_outer_join_clause(PlannerInfo *root, RestrictInfo *rinfo,
|
||||
continue; /* no match, so ignore this EC */
|
||||
|
||||
/*
|
||||
* Yes it does! Try to generate a clause INNERVAR = CONSTANT for
|
||||
* each CONSTANT in the EC. Note that we must succeed with at
|
||||
* least one constant before we can decide to throw away the
|
||||
* outer-join clause.
|
||||
* Yes it does! Try to generate a clause INNERVAR = CONSTANT for each
|
||||
* CONSTANT in the EC. Note that we must succeed with at least one
|
||||
* constant before we can decide to throw away the outer-join clause.
|
||||
*/
|
||||
match = false;
|
||||
foreach(lc2, cur_ec->ec_members)
|
||||
@ -1300,15 +1299,15 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
|
||||
/*
|
||||
* Does it contain a COALESCE(leftvar, rightvar) construct?
|
||||
*
|
||||
* We can assume the COALESCE() inputs are in the same order as
|
||||
* the join clause, since both were automatically generated in the
|
||||
* cases we care about.
|
||||
* We can assume the COALESCE() inputs are in the same order as the
|
||||
* join clause, since both were automatically generated in the cases
|
||||
* we care about.
|
||||
*
|
||||
* XXX currently this may fail to match in cross-type cases
|
||||
* because the COALESCE will contain typecast operations while the
|
||||
* join clause may not (if there is a cross-type mergejoin
|
||||
* operator available for the two column types). Is it OK to strip
|
||||
* implicit coercions from the COALESCE arguments?
|
||||
* XXX currently this may fail to match in cross-type cases because
|
||||
* the COALESCE will contain typecast operations while the join clause
|
||||
* may not (if there is a cross-type mergejoin operator available for
|
||||
* the two column types). Is it OK to strip implicit coercions from
|
||||
* the COALESCE arguments?
|
||||
*/
|
||||
match = false;
|
||||
foreach(lc2, cur_ec->ec_members)
|
||||
@ -1337,9 +1336,9 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
|
||||
|
||||
/*
|
||||
* Yes it does! Try to generate clauses LEFTVAR = CONSTANT and
|
||||
* RIGHTVAR = CONSTANT for each CONSTANT in the EC. Note that we
|
||||
* must succeed with at least one constant for each var before
|
||||
* we can decide to throw away the outer-join clause.
|
||||
* RIGHTVAR = CONSTANT for each CONSTANT in the EC. Note that we must
|
||||
* succeed with at least one constant for each var before we can
|
||||
* decide to throw away the outer-join clause.
|
||||
*/
|
||||
matchleft = matchright = false;
|
||||
foreach(lc2, cur_ec->ec_members)
|
||||
@ -1378,16 +1377,17 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo)
|
||||
|
||||
/*
|
||||
* If we were able to equate both vars to constants, we're done, and
|
||||
* we can throw away the full-join clause as redundant. Moreover,
|
||||
* we can remove the COALESCE entry from the EC, since the added
|
||||
* restrictions ensure it will always have the expected value.
|
||||
* (We don't bother trying to update ec_relids or ec_sources.)
|
||||
* we can throw away the full-join clause as redundant. Moreover, we
|
||||
* can remove the COALESCE entry from the EC, since the added
|
||||
* restrictions ensure it will always have the expected value. (We
|
||||
* don't bother trying to update ec_relids or ec_sources.)
|
||||
*/
|
||||
if (matchleft && matchright)
|
||||
{
|
||||
cur_ec->ec_members = list_delete_ptr(cur_ec->ec_members, coal_em);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, fall out of the search loop, since we know the COALESCE
|
||||
* appears in at most one EC (XXX might stop being true if we allow
|
||||
@ -1489,8 +1489,8 @@ add_child_rel_equivalences(PlannerInfo *root,
|
||||
if (bms_equal(cur_em->em_relids, parent_rel->relids))
|
||||
{
|
||||
/* Yes, generate transformed child version */
|
||||
Expr *child_expr;
|
||||
|
||||
Expr *child_expr;
|
||||
|
||||
child_expr = (Expr *)
|
||||
adjust_appendrel_attrs((Node *) cur_em->em_expr,
|
||||
appinfo);
|
||||
@ -1528,8 +1528,8 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
continue;
|
||||
|
||||
/*
|
||||
* No point in searching if rel not mentioned in eclass (but we
|
||||
* can't tell that for a child rel).
|
||||
* No point in searching if rel not mentioned in eclass (but we can't
|
||||
* tell that for a child rel).
|
||||
*/
|
||||
if (!is_child_rel &&
|
||||
!bms_is_subset(rel->relids, cur_ec->ec_relids))
|
||||
@ -1543,7 +1543,7 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
{
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
|
||||
EquivalenceMember *best_outer_em = NULL;
|
||||
Oid best_eq_op = InvalidOid;
|
||||
Oid best_eq_op = InvalidOid;
|
||||
ListCell *lc3;
|
||||
|
||||
if (!bms_equal(cur_em->em_relids, rel->relids) ||
|
||||
@ -1552,14 +1552,14 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
|
||||
/*
|
||||
* Found one, so try to generate a join clause. This is like
|
||||
* generate_join_implied_equalities_normal, except simpler
|
||||
* since our only preference item is to pick a Var on the
|
||||
* outer side. We only need one join clause per index col.
|
||||
* generate_join_implied_equalities_normal, except simpler since
|
||||
* our only preference item is to pick a Var on the outer side.
|
||||
* We only need one join clause per index col.
|
||||
*/
|
||||
foreach(lc3, cur_ec->ec_members)
|
||||
{
|
||||
EquivalenceMember *outer_em = (EquivalenceMember *) lfirst(lc3);
|
||||
Oid eq_op;
|
||||
Oid eq_op;
|
||||
|
||||
if (!bms_is_subset(outer_em->em_relids, outer_relids))
|
||||
continue;
|
||||
@ -1573,7 +1573,7 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
if (IsA(outer_em->em_expr, Var) ||
|
||||
(IsA(outer_em->em_expr, RelabelType) &&
|
||||
IsA(((RelabelType *) outer_em->em_expr)->arg, Var)))
|
||||
break; /* no need to look further */
|
||||
break; /* no need to look further */
|
||||
}
|
||||
|
||||
if (best_outer_em)
|
||||
@ -1587,9 +1587,10 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
cur_ec);
|
||||
|
||||
result = lappend(result, rinfo);
|
||||
|
||||
/*
|
||||
* Note: we keep scanning here because we want to provide
|
||||
* a clause for every possible indexcol.
|
||||
* Note: we keep scanning here because we want to provide a
|
||||
* clause for every possible indexcol.
|
||||
*/
|
||||
}
|
||||
}
|
||||
@ -1605,7 +1606,7 @@ find_eclass_clauses_for_index_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
* a joinclause between the two given relations.
|
||||
*
|
||||
* This is essentially a very cut-down version of
|
||||
* generate_join_implied_equalities(). Note it's OK to occasionally say "yes"
|
||||
* generate_join_implied_equalities(). Note it's OK to occasionally say "yes"
|
||||
* incorrectly. Hence we don't bother with details like whether the lack of a
|
||||
* cross-type operator might prevent the clause from actually being generated.
|
||||
*/
|
||||
@ -1647,7 +1648,7 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
|
||||
|
||||
if (cur_em->em_is_child)
|
||||
continue; /* ignore children here */
|
||||
continue; /* ignore children here */
|
||||
if (bms_is_subset(cur_em->em_relids, rel1->relids))
|
||||
{
|
||||
has_rel1 = true;
|
||||
@ -1715,7 +1716,7 @@ has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
|
||||
EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2);
|
||||
|
||||
if (cur_em->em_is_child)
|
||||
continue; /* ignore children here */
|
||||
continue; /* ignore children here */
|
||||
if (bms_is_subset(cur_em->em_relids, rel1->relids))
|
||||
{
|
||||
has_rel1 = true;
|
||||
@ -1744,12 +1745,12 @@ has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
|
||||
* against the specified relation.
|
||||
*
|
||||
* This is just a heuristic test and doesn't have to be exact; it's better
|
||||
* to say "yes" incorrectly than "no". Hence we don't bother with details
|
||||
* to say "yes" incorrectly than "no". Hence we don't bother with details
|
||||
* like whether the lack of a cross-type operator might prevent the clause
|
||||
* from actually being generated.
|
||||
*/
|
||||
bool
|
||||
eclass_useful_for_merging(EquivalenceClass *eclass,
|
||||
eclass_useful_for_merging(EquivalenceClass * eclass,
|
||||
RelOptInfo *rel)
|
||||
{
|
||||
ListCell *lc;
|
||||
@ -1757,16 +1758,16 @@ eclass_useful_for_merging(EquivalenceClass *eclass,
|
||||
Assert(!eclass->ec_merged);
|
||||
|
||||
/*
|
||||
* Won't generate joinclauses if const or single-member (the latter
|
||||
* test covers the volatile case too)
|
||||
* Won't generate joinclauses if const or single-member (the latter test
|
||||
* covers the volatile case too)
|
||||
*/
|
||||
if (eclass->ec_has_const || list_length(eclass->ec_members) <= 1)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Note we don't test ec_broken; if we did, we'd need a separate code
|
||||
* path to look through ec_sources. Checking the members anyway is OK
|
||||
* as a possibly-overoptimistic heuristic.
|
||||
* Note we don't test ec_broken; if we did, we'd need a separate code path
|
||||
* to look through ec_sources. Checking the members anyway is OK as a
|
||||
* possibly-overoptimistic heuristic.
|
||||
*/
|
||||
|
||||
/* If rel already includes all members of eclass, no point in searching */
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.223 2007/11/07 22:37:24 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.224 2007/11/15 21:14:35 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -39,7 +39,7 @@
|
||||
/*
|
||||
* DoneMatchingIndexKeys() - MACRO
|
||||
*/
|
||||
#define DoneMatchingIndexKeys(families) (families[0] == InvalidOid)
|
||||
#define DoneMatchingIndexKeys(families) (families[0] == InvalidOid)
|
||||
|
||||
#define IsBooleanOpfamily(opfamily) \
|
||||
((opfamily) == BOOL_BTREE_FAM_OID || (opfamily) == BOOL_HASH_FAM_OID)
|
||||
@ -52,7 +52,7 @@ typedef struct
|
||||
List *quals; /* the WHERE clauses it uses */
|
||||
List *preds; /* predicates of its partial index(es) */
|
||||
Bitmapset *clauseids; /* quals+preds represented as a bitmapset */
|
||||
} PathClauseUsage;
|
||||
} PathClauseUsage;
|
||||
|
||||
|
||||
static List *find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
|
||||
@ -70,7 +70,7 @@ static Cost bitmap_scan_cost_est(PlannerInfo *root, RelOptInfo *rel,
|
||||
static Cost bitmap_and_cost_est(PlannerInfo *root, RelOptInfo *rel,
|
||||
List *paths, RelOptInfo *outer_rel);
|
||||
static PathClauseUsage *classify_index_clause_usage(Path *path,
|
||||
List **clauselist);
|
||||
List **clauselist);
|
||||
static void find_indexpath_quals(Path *bitmapqual, List **quals, List **preds);
|
||||
static int find_list_position(Node *node, List **nodelist);
|
||||
static bool match_clause_to_indexcol(IndexOptInfo *index,
|
||||
@ -382,8 +382,8 @@ find_usable_indexes(PlannerInfo *root, RelOptInfo *rel,
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. If the index is ordered, a backwards scan might be
|
||||
* interesting. Again, this is only interesting at top level.
|
||||
* 4. If the index is ordered, a backwards scan might be interesting.
|
||||
* Again, this is only interesting at top level.
|
||||
*/
|
||||
if (index_is_ordered && possibly_useful_pathkeys &&
|
||||
istoplevel && outer_rel == NULL)
|
||||
@ -581,7 +581,8 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
List *clauselist;
|
||||
List *bestpaths = NIL;
|
||||
Cost bestcost = 0;
|
||||
int i, j;
|
||||
int i,
|
||||
j;
|
||||
ListCell *l;
|
||||
|
||||
Assert(npaths > 0); /* else caller error */
|
||||
@ -592,40 +593,39 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
* In theory we should consider every nonempty subset of the given paths.
|
||||
* In practice that seems like overkill, given the crude nature of the
|
||||
* estimates, not to mention the possible effects of higher-level AND and
|
||||
* OR clauses. Moreover, it's completely impractical if there are a large
|
||||
* OR clauses. Moreover, it's completely impractical if there are a large
|
||||
* number of paths, since the work would grow as O(2^N).
|
||||
*
|
||||
* As a heuristic, we first check for paths using exactly the same
|
||||
* sets of WHERE clauses + index predicate conditions, and reject all
|
||||
* but the cheapest-to-scan in any such group. This primarily gets rid
|
||||
* of indexes that include the interesting columns but also irrelevant
|
||||
* columns. (In situations where the DBA has gone overboard on creating
|
||||
* variant indexes, this can make for a very large reduction in the number
|
||||
* of paths considered further.)
|
||||
* As a heuristic, we first check for paths using exactly the same sets of
|
||||
* WHERE clauses + index predicate conditions, and reject all but the
|
||||
* cheapest-to-scan in any such group. This primarily gets rid of indexes
|
||||
* that include the interesting columns but also irrelevant columns. (In
|
||||
* situations where the DBA has gone overboard on creating variant
|
||||
* indexes, this can make for a very large reduction in the number of
|
||||
* paths considered further.)
|
||||
*
|
||||
* We then sort the surviving paths with the cheapest-to-scan first,
|
||||
* and for each path, consider using that path alone as the basis for
|
||||
* a bitmap scan. Then we consider bitmap AND scans formed from that
|
||||
* path plus each subsequent (higher-cost) path, adding on a subsequent
|
||||
* path if it results in a reduction in the estimated total scan cost.
|
||||
* This means we consider about O(N^2) rather than O(2^N) path
|
||||
* combinations, which is quite tolerable, especially given than N is
|
||||
* usually reasonably small because of the prefiltering step. The
|
||||
* cheapest of these is returned.
|
||||
* We then sort the surviving paths with the cheapest-to-scan first, and
|
||||
* for each path, consider using that path alone as the basis for a bitmap
|
||||
* scan. Then we consider bitmap AND scans formed from that path plus
|
||||
* each subsequent (higher-cost) path, adding on a subsequent path if it
|
||||
* results in a reduction in the estimated total scan cost. This means we
|
||||
* consider about O(N^2) rather than O(2^N) path combinations, which is
|
||||
* quite tolerable, especially given than N is usually reasonably small
|
||||
* because of the prefiltering step. The cheapest of these is returned.
|
||||
*
|
||||
* We will only consider AND combinations in which no two indexes use
|
||||
* the same WHERE clause. This is a bit of a kluge: it's needed because
|
||||
* We will only consider AND combinations in which no two indexes use the
|
||||
* same WHERE clause. This is a bit of a kluge: it's needed because
|
||||
* costsize.c and clausesel.c aren't very smart about redundant clauses.
|
||||
* They will usually double-count the redundant clauses, producing a
|
||||
* too-small selectivity that makes a redundant AND step look like it
|
||||
* reduces the total cost. Perhaps someday that code will be smarter and
|
||||
* reduces the total cost. Perhaps someday that code will be smarter and
|
||||
* we can remove this limitation. (But note that this also defends
|
||||
* against flat-out duplicate input paths, which can happen because
|
||||
* best_inner_indexscan will find the same OR join clauses that
|
||||
* create_or_index_quals has pulled OR restriction clauses out of.)
|
||||
*
|
||||
* For the same reason, we reject AND combinations in which an index
|
||||
* predicate clause duplicates another clause. Here we find it necessary
|
||||
* predicate clause duplicates another clause. Here we find it necessary
|
||||
* to be even stricter: we'll reject a partial index if any of its
|
||||
* predicate clauses are implied by the set of WHERE clauses and predicate
|
||||
* clauses used so far. This covers cases such as a condition "x = 42"
|
||||
@ -639,9 +639,9 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
*/
|
||||
|
||||
/*
|
||||
* Extract clause usage info and detect any paths that use exactly
|
||||
* the same set of clauses; keep only the cheapest-to-scan of any such
|
||||
* groups. The surviving paths are put into an array for qsort'ing.
|
||||
* Extract clause usage info and detect any paths that use exactly the
|
||||
* same set of clauses; keep only the cheapest-to-scan of any such groups.
|
||||
* The surviving paths are put into an array for qsort'ing.
|
||||
*/
|
||||
pathinfoarray = (PathClauseUsage **)
|
||||
palloc(npaths * sizeof(PathClauseUsage *));
|
||||
@ -649,7 +649,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
npaths = 0;
|
||||
foreach(l, paths)
|
||||
{
|
||||
Path *ipath = (Path *) lfirst(l);
|
||||
Path *ipath = (Path *) lfirst(l);
|
||||
|
||||
pathinfo = classify_index_clause_usage(ipath, &clauselist);
|
||||
for (i = 0; i < npaths; i++)
|
||||
@ -686,9 +686,9 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
path_usage_comparator);
|
||||
|
||||
/*
|
||||
* For each surviving index, consider it as an "AND group leader", and
|
||||
* see whether adding on any of the later indexes results in an AND path
|
||||
* with cheaper total cost than before. Then take the cheapest AND group.
|
||||
* For each surviving index, consider it as an "AND group leader", and see
|
||||
* whether adding on any of the later indexes results in an AND path with
|
||||
* cheaper total cost than before. Then take the cheapest AND group.
|
||||
*/
|
||||
for (i = 0; i < npaths; i++)
|
||||
{
|
||||
@ -705,17 +705,17 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
clauseidsofar = bms_copy(pathinfo->clauseids);
|
||||
lastcell = list_head(paths); /* for quick deletions */
|
||||
|
||||
for (j = i+1; j < npaths; j++)
|
||||
for (j = i + 1; j < npaths; j++)
|
||||
{
|
||||
Cost newcost;
|
||||
|
||||
pathinfo = pathinfoarray[j];
|
||||
/* Check for redundancy */
|
||||
if (bms_overlap(pathinfo->clauseids, clauseidsofar))
|
||||
continue; /* consider it redundant */
|
||||
continue; /* consider it redundant */
|
||||
if (pathinfo->preds)
|
||||
{
|
||||
bool redundant = false;
|
||||
bool redundant = false;
|
||||
|
||||
/* we check each predicate clause separately */
|
||||
foreach(l, pathinfo->preds)
|
||||
@ -725,7 +725,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
if (predicate_implied_by(list_make1(np), qualsofar))
|
||||
{
|
||||
redundant = true;
|
||||
break; /* out of inner foreach loop */
|
||||
break; /* out of inner foreach loop */
|
||||
}
|
||||
}
|
||||
if (redundant)
|
||||
@ -766,7 +766,7 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
}
|
||||
|
||||
if (list_length(bestpaths) == 1)
|
||||
return (Path *) linitial(bestpaths); /* no need for AND */
|
||||
return (Path *) linitial(bestpaths); /* no need for AND */
|
||||
return (Path *) create_bitmap_and_path(root, rel, bestpaths);
|
||||
}
|
||||
|
||||
@ -774,8 +774,8 @@ choose_bitmap_and(PlannerInfo *root, RelOptInfo *rel,
|
||||
static int
|
||||
path_usage_comparator(const void *a, const void *b)
|
||||
{
|
||||
PathClauseUsage *pa = *(PathClauseUsage *const *) a;
|
||||
PathClauseUsage *pb = *(PathClauseUsage *const *) b;
|
||||
PathClauseUsage *pa = *(PathClauseUsage * const *) a;
|
||||
PathClauseUsage *pb = *(PathClauseUsage * const *) b;
|
||||
Cost acost;
|
||||
Cost bcost;
|
||||
Selectivity aselec;
|
||||
@ -872,14 +872,14 @@ classify_index_clause_usage(Path *path, List **clauselist)
|
||||
clauseids = NULL;
|
||||
foreach(lc, result->quals)
|
||||
{
|
||||
Node *node = (Node *) lfirst(lc);
|
||||
Node *node = (Node *) lfirst(lc);
|
||||
|
||||
clauseids = bms_add_member(clauseids,
|
||||
find_list_position(node, clauselist));
|
||||
}
|
||||
foreach(lc, result->preds)
|
||||
{
|
||||
Node *node = (Node *) lfirst(lc);
|
||||
Node *node = (Node *) lfirst(lc);
|
||||
|
||||
clauseids = bms_add_member(clauseids,
|
||||
find_list_position(node, clauselist));
|
||||
@ -944,7 +944,7 @@ find_indexpath_quals(Path *bitmapqual, List **quals, List **preds)
|
||||
/*
|
||||
* find_list_position
|
||||
* Return the given node's position (counting from 0) in the given
|
||||
* list of nodes. If it's not equal() to any existing list member,
|
||||
* list of nodes. If it's not equal() to any existing list member,
|
||||
* add it at the end, and return that position.
|
||||
*/
|
||||
static int
|
||||
@ -956,7 +956,7 @@ find_list_position(Node *node, List **nodelist)
|
||||
i = 0;
|
||||
foreach(lc, *nodelist)
|
||||
{
|
||||
Node *oldnode = (Node *) lfirst(lc);
|
||||
Node *oldnode = (Node *) lfirst(lc);
|
||||
|
||||
if (equal(node, oldnode))
|
||||
return i;
|
||||
@ -1218,7 +1218,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
|
||||
}
|
||||
else if (index->amsearchnulls && IsA(clause, NullTest))
|
||||
{
|
||||
NullTest *nt = (NullTest *) clause;
|
||||
NullTest *nt = (NullTest *) clause;
|
||||
|
||||
if (nt->nulltesttype == IS_NULL &&
|
||||
match_index_to_operand((Node *) nt->arg, indexcol, index))
|
||||
@ -1315,12 +1315,12 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
|
||||
/*
|
||||
* We could do the matching on the basis of insisting that the opfamily
|
||||
* shown in the RowCompareExpr be the same as the index column's opfamily,
|
||||
* but that could fail in the presence of reverse-sort opfamilies: it'd
|
||||
* be a matter of chance whether RowCompareExpr had picked the forward
|
||||
* or reverse-sort family. So look only at the operator, and match
|
||||
* if it is a member of the index's opfamily (after commutation, if the
|
||||
* indexkey is on the right). We'll worry later about whether any
|
||||
* additional operators are matchable to the index.
|
||||
* but that could fail in the presence of reverse-sort opfamilies: it'd be
|
||||
* a matter of chance whether RowCompareExpr had picked the forward or
|
||||
* reverse-sort family. So look only at the operator, and match if it is
|
||||
* a member of the index's opfamily (after commutation, if the indexkey is
|
||||
* on the right). We'll worry later about whether any additional
|
||||
* operators are matchable to the index.
|
||||
*/
|
||||
leftop = (Node *) linitial(clause->largs);
|
||||
rightop = (Node *) linitial(clause->rargs);
|
||||
@ -1421,8 +1421,8 @@ indexable_outerrelids(PlannerInfo *root, RelOptInfo *rel)
|
||||
}
|
||||
|
||||
/*
|
||||
* We also have to look through the query's EquivalenceClasses to see
|
||||
* if any of them could generate indexable join conditions for this rel.
|
||||
* We also have to look through the query's EquivalenceClasses to see if
|
||||
* any of them could generate indexable join conditions for this rel.
|
||||
*/
|
||||
if (rel->has_eclass_joins)
|
||||
{
|
||||
@ -1434,8 +1434,8 @@ indexable_outerrelids(PlannerInfo *root, RelOptInfo *rel)
|
||||
ListCell *lc2;
|
||||
|
||||
/*
|
||||
* Won't generate joinclauses if const or single-member (the latter
|
||||
* test covers the volatile case too)
|
||||
* Won't generate joinclauses if const or single-member (the
|
||||
* latter test covers the volatile case too)
|
||||
*/
|
||||
if (cur_ec->ec_has_const || list_length(cur_ec->ec_members) <= 1)
|
||||
continue;
|
||||
@ -1569,7 +1569,7 @@ matches_any_index(RestrictInfo *rinfo, RelOptInfo *rel, Relids outer_relids)
|
||||
* This is also exported for use by find_eclass_clauses_for_index_join.
|
||||
*/
|
||||
bool
|
||||
eclass_matches_any_index(EquivalenceClass *ec, EquivalenceMember *em,
|
||||
eclass_matches_any_index(EquivalenceClass * ec, EquivalenceMember * em,
|
||||
RelOptInfo *rel)
|
||||
{
|
||||
ListCell *l;
|
||||
@ -1831,14 +1831,14 @@ find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
|
||||
|
||||
/*
|
||||
* Also check to see if any EquivalenceClasses can produce a relevant
|
||||
* joinclause. Since all such clauses are effectively pushed-down,
|
||||
* this doesn't apply to outer joins.
|
||||
* joinclause. Since all such clauses are effectively pushed-down, this
|
||||
* doesn't apply to outer joins.
|
||||
*/
|
||||
if (!isouterjoin && rel->has_eclass_joins)
|
||||
clause_list = list_concat(clause_list,
|
||||
find_eclass_clauses_for_index_join(root,
|
||||
rel,
|
||||
outer_relids));
|
||||
outer_relids));
|
||||
|
||||
/* If no join clause was matched then forget it, per comments above */
|
||||
if (clause_list == NIL)
|
||||
@ -2150,9 +2150,9 @@ match_special_index_operator(Expr *clause, Oid opfamily,
|
||||
* want to apply. (A hash index, for example, will not support ">=".)
|
||||
* Currently, only btree supports the operators we need.
|
||||
*
|
||||
* We insist on the opfamily being the specific one we expect, else we'd do
|
||||
* the wrong thing if someone were to make a reverse-sort opfamily with the
|
||||
* same operators.
|
||||
* We insist on the opfamily being the specific one we expect, else we'd
|
||||
* do the wrong thing if someone were to make a reverse-sort opfamily with
|
||||
* the same operators.
|
||||
*/
|
||||
switch (expr_op)
|
||||
{
|
||||
@ -2260,7 +2260,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
|
||||
{
|
||||
resultquals = list_concat(resultquals,
|
||||
expand_indexqual_opclause(rinfo,
|
||||
curFamily));
|
||||
curFamily));
|
||||
}
|
||||
else if (IsA(clause, ScalarArrayOpExpr))
|
||||
{
|
||||
@ -2602,9 +2602,9 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
|
||||
righttypes_cell = list_head(righttypes);
|
||||
foreach(opfamilies_cell, opfamilies)
|
||||
{
|
||||
Oid opfam = lfirst_oid(opfamilies_cell);
|
||||
Oid lefttype = lfirst_oid(lefttypes_cell);
|
||||
Oid righttype = lfirst_oid(righttypes_cell);
|
||||
Oid opfam = lfirst_oid(opfamilies_cell);
|
||||
Oid lefttype = lfirst_oid(lefttypes_cell);
|
||||
Oid righttype = lfirst_oid(righttypes_cell);
|
||||
|
||||
expr_op = get_opfamily_member(opfam, lefttype, righttype,
|
||||
op_strategy);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.112 2007/05/22 01:40:33 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.113 2007/11/15 21:14:35 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -200,7 +200,7 @@ sort_inner_and_outer(PlannerInfo *root,
|
||||
*
|
||||
* Actually, it's not quite true that every mergeclause ordering will
|
||||
* generate a different path order, because some of the clauses may be
|
||||
* partially redundant (refer to the same EquivalenceClasses). Therefore,
|
||||
* partially redundant (refer to the same EquivalenceClasses). Therefore,
|
||||
* what we do is convert the mergeclause list to a list of canonical
|
||||
* pathkeys, and then consider different orderings of the pathkeys.
|
||||
*
|
||||
@ -237,7 +237,7 @@ sort_inner_and_outer(PlannerInfo *root,
|
||||
list_delete_ptr(list_copy(all_pathkeys),
|
||||
front_pathkey));
|
||||
else
|
||||
outerkeys = all_pathkeys; /* no work at first one... */
|
||||
outerkeys = all_pathkeys; /* no work at first one... */
|
||||
|
||||
/* Sort the mergeclauses into the corresponding ordering */
|
||||
cur_mergeclauses = find_mergeclauses_for_pathkeys(root,
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.88 2007/10/26 18:10:50 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/joinrels.c,v 1.89 2007/11/15 21:14:36 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -346,8 +346,8 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
||||
ListCell *l;
|
||||
|
||||
/*
|
||||
* Ensure *jointype_p is set on failure return. This is just to
|
||||
* suppress uninitialized-variable warnings from overly anal compilers.
|
||||
* Ensure *jointype_p is set on failure return. This is just to suppress
|
||||
* uninitialized-variable warnings from overly anal compilers.
|
||||
*/
|
||||
*jointype_p = JOIN_INNER;
|
||||
|
||||
@ -398,14 +398,14 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
||||
bms_is_subset(ojinfo->min_righthand, rel2->relids))
|
||||
{
|
||||
if (jointype != JOIN_INNER)
|
||||
return false; /* invalid join path */
|
||||
return false; /* invalid join path */
|
||||
jointype = ojinfo->is_full_join ? JOIN_FULL : JOIN_LEFT;
|
||||
}
|
||||
else if (bms_is_subset(ojinfo->min_lefthand, rel2->relids) &&
|
||||
bms_is_subset(ojinfo->min_righthand, rel1->relids))
|
||||
{
|
||||
if (jointype != JOIN_INNER)
|
||||
return false; /* invalid join path */
|
||||
return false; /* invalid join path */
|
||||
jointype = ojinfo->is_full_join ? JOIN_FULL : JOIN_RIGHT;
|
||||
}
|
||||
else
|
||||
@ -520,7 +520,7 @@ join_is_legal(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
||||
else if (bms_equal(ininfo->righthand, rel2->relids))
|
||||
jointype = JOIN_UNIQUE_INNER;
|
||||
else
|
||||
return false; /* invalid join path */
|
||||
return false; /* invalid join path */
|
||||
}
|
||||
|
||||
/* Join is valid */
|
||||
@ -666,9 +666,9 @@ have_join_order_restriction(PlannerInfo *root,
|
||||
ListCell *l;
|
||||
|
||||
/*
|
||||
* It's possible that the rels correspond to the left and right sides
|
||||
* of a degenerate outer join, that is, one with no joinclause mentioning
|
||||
* the non-nullable side; in which case we should force the join to occur.
|
||||
* It's possible that the rels correspond to the left and right sides of a
|
||||
* degenerate outer join, that is, one with no joinclause mentioning the
|
||||
* non-nullable side; in which case we should force the join to occur.
|
||||
*
|
||||
* Also, the two rels could represent a clauseless join that has to be
|
||||
* completed to build up the LHS or RHS of an outer join.
|
||||
@ -696,9 +696,9 @@ have_join_order_restriction(PlannerInfo *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* Might we need to join these rels to complete the RHS? We have
|
||||
* to use "overlap" tests since either rel might include a lower OJ
|
||||
* that has been proven to commute with this one.
|
||||
* Might we need to join these rels to complete the RHS? We have to
|
||||
* use "overlap" tests since either rel might include a lower OJ that
|
||||
* has been proven to commute with this one.
|
||||
*/
|
||||
if (bms_overlap(ojinfo->min_righthand, rel1->relids) &&
|
||||
bms_overlap(ojinfo->min_righthand, rel2->relids))
|
||||
@ -761,13 +761,13 @@ have_join_order_restriction(PlannerInfo *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* We do not force the join to occur if either input rel can legally
|
||||
* be joined to anything else using joinclauses. This essentially
|
||||
* means that clauseless bushy joins are put off as long as possible.
|
||||
* The reason is that when there is a join order restriction high up
|
||||
* in the join tree (that is, with many rels inside the LHS or RHS),
|
||||
* we would otherwise expend lots of effort considering very stupid
|
||||
* join combinations within its LHS or RHS.
|
||||
* We do not force the join to occur if either input rel can legally be
|
||||
* joined to anything else using joinclauses. This essentially means that
|
||||
* clauseless bushy joins are put off as long as possible. The reason is
|
||||
* that when there is a join order restriction high up in the join tree
|
||||
* (that is, with many rels inside the LHS or RHS), we would otherwise
|
||||
* expend lots of effort considering very stupid join combinations within
|
||||
* its LHS or RHS.
|
||||
*/
|
||||
if (result)
|
||||
{
|
||||
@ -787,7 +787,7 @@ have_join_order_restriction(PlannerInfo *root,
|
||||
*
|
||||
* Essentially, this tests whether have_join_order_restriction() could
|
||||
* succeed with this rel and some other one. It's OK if we sometimes
|
||||
* say "true" incorrectly. (Therefore, we don't bother with the relatively
|
||||
* say "true" incorrectly. (Therefore, we don't bother with the relatively
|
||||
* expensive has_legal_joinclause test.)
|
||||
*/
|
||||
static bool
|
||||
|
@ -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.89 2007/11/08 21:49:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.90 2007/11/15 21:14:36 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -37,12 +37,12 @@
|
||||
#define MUST_BE_REDUNDANT(eclass) \
|
||||
((eclass)->ec_has_const && !(eclass)->ec_below_outer_join)
|
||||
|
||||
static PathKey *makePathKey(EquivalenceClass *eclass, Oid opfamily,
|
||||
int strategy, bool nulls_first);
|
||||
static PathKey *makePathKey(EquivalenceClass * eclass, Oid opfamily,
|
||||
int strategy, bool nulls_first);
|
||||
static PathKey *make_canonical_pathkey(PlannerInfo *root,
|
||||
EquivalenceClass *eclass, Oid opfamily,
|
||||
EquivalenceClass * eclass, Oid opfamily,
|
||||
int strategy, bool nulls_first);
|
||||
static bool pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys);
|
||||
static bool pathkey_is_redundant(PathKey * new_pathkey, List *pathkeys);
|
||||
static PathKey *make_pathkey_from_sortinfo(PlannerInfo *root,
|
||||
Expr *expr, Oid ordering_op,
|
||||
bool nulls_first,
|
||||
@ -50,7 +50,7 @@ static PathKey *make_pathkey_from_sortinfo(PlannerInfo *root,
|
||||
bool canonicalize);
|
||||
static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel,
|
||||
AttrNumber varattno);
|
||||
static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey);
|
||||
static bool right_merge_direction(PlannerInfo *root, PathKey * pathkey);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
@ -65,10 +65,10 @@ static bool right_merge_direction(PlannerInfo *root, PathKey *pathkey);
|
||||
* convenience routine to build the specified node.
|
||||
*/
|
||||
static PathKey *
|
||||
makePathKey(EquivalenceClass *eclass, Oid opfamily,
|
||||
makePathKey(EquivalenceClass * eclass, Oid opfamily,
|
||||
int strategy, bool nulls_first)
|
||||
{
|
||||
PathKey *pk = makeNode(PathKey);
|
||||
PathKey *pk = makeNode(PathKey);
|
||||
|
||||
pk->pk_eclass = eclass;
|
||||
pk->pk_opfamily = opfamily;
|
||||
@ -89,10 +89,10 @@ makePathKey(EquivalenceClass *eclass, Oid opfamily,
|
||||
*/
|
||||
static PathKey *
|
||||
make_canonical_pathkey(PlannerInfo *root,
|
||||
EquivalenceClass *eclass, Oid opfamily,
|
||||
EquivalenceClass * eclass, Oid opfamily,
|
||||
int strategy, bool nulls_first)
|
||||
{
|
||||
PathKey *pk;
|
||||
PathKey *pk;
|
||||
ListCell *lc;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
@ -155,7 +155,7 @@ make_canonical_pathkey(PlannerInfo *root,
|
||||
* pointer comparison is enough to decide whether canonical ECs are the same.
|
||||
*/
|
||||
static bool
|
||||
pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys)
|
||||
pathkey_is_redundant(PathKey * new_pathkey, List *pathkeys)
|
||||
{
|
||||
EquivalenceClass *new_ec = new_pathkey->pk_eclass;
|
||||
ListCell *lc;
|
||||
@ -170,7 +170,7 @@ pathkey_is_redundant(PathKey *new_pathkey, List *pathkeys)
|
||||
/* If same EC already used in list, then redundant */
|
||||
foreach(lc, pathkeys)
|
||||
{
|
||||
PathKey *old_pathkey = (PathKey *) lfirst(lc);
|
||||
PathKey *old_pathkey = (PathKey *) lfirst(lc);
|
||||
|
||||
/* Assert we've been given canonical pathkeys */
|
||||
Assert(!old_pathkey->pk_eclass->ec_merged);
|
||||
@ -197,9 +197,9 @@ canonicalize_pathkeys(PlannerInfo *root, List *pathkeys)
|
||||
|
||||
foreach(l, pathkeys)
|
||||
{
|
||||
PathKey *pathkey = (PathKey *) lfirst(l);
|
||||
PathKey *pathkey = (PathKey *) lfirst(l);
|
||||
EquivalenceClass *eclass;
|
||||
PathKey *cpathkey;
|
||||
PathKey *cpathkey;
|
||||
|
||||
/* Find the canonical (merged) EquivalenceClass */
|
||||
eclass = pathkey->pk_eclass;
|
||||
@ -255,13 +255,13 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
|
||||
EquivalenceClass *eclass;
|
||||
|
||||
/*
|
||||
* An ordering operator fully determines the behavior of its opfamily,
|
||||
* so could only meaningfully appear in one family --- or perhaps two
|
||||
* if one builds a reverse-sort opfamily, but there's not much point in
|
||||
* that anymore. But EquivalenceClasses need to contain opfamily lists
|
||||
* based on the family membership of equality operators, which could
|
||||
* easily be bigger. So, look up the equality operator that goes with
|
||||
* the ordering operator (this should be unique) and get its membership.
|
||||
* An ordering operator fully determines the behavior of its opfamily, so
|
||||
* could only meaningfully appear in one family --- or perhaps two if one
|
||||
* builds a reverse-sort opfamily, but there's not much point in that
|
||||
* anymore. But EquivalenceClasses need to contain opfamily lists based
|
||||
* on the family membership of equality operators, which could easily be
|
||||
* bigger. So, look up the equality operator that goes with the ordering
|
||||
* operator (this should be unique) and get its membership.
|
||||
*/
|
||||
|
||||
/* Find the operator in pg_amop --- failure shouldn't happen */
|
||||
@ -284,15 +284,15 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
|
||||
|
||||
/*
|
||||
* When dealing with binary-compatible opclasses, we have to ensure that
|
||||
* the exposed type of the expression tree matches the declared input
|
||||
* type of the opclass, except when that is a polymorphic type
|
||||
* (compare the behavior of parse_coerce.c). This ensures that we can
|
||||
* correctly match the indexkey or sortclause expression to other
|
||||
* expressions we find in the query, because arguments of ordinary
|
||||
* operator expressions will be cast that way. (We have to do this
|
||||
* for indexkeys because they are represented without any explicit
|
||||
* relabel in pg_index, and for sort clauses because the parser is
|
||||
* likewise cavalier about putting relabels on them.)
|
||||
* the exposed type of the expression tree matches the declared input type
|
||||
* of the opclass, except when that is a polymorphic type (compare the
|
||||
* behavior of parse_coerce.c). This ensures that we can correctly match
|
||||
* the indexkey or sortclause expression to other expressions we find in
|
||||
* the query, because arguments of ordinary operator expressions will be
|
||||
* cast that way. (We have to do this for indexkeys because they are
|
||||
* represented without any explicit relabel in pg_index, and for sort
|
||||
* clauses because the parser is likewise cavalier about putting relabels
|
||||
* on them.)
|
||||
*/
|
||||
if (exprType((Node *) expr) != opcintype &&
|
||||
!IsPolymorphicType(opcintype))
|
||||
@ -341,8 +341,8 @@ compare_pathkeys(List *keys1, List *keys2)
|
||||
|
||||
forboth(key1, keys1, key2, keys2)
|
||||
{
|
||||
PathKey *pathkey1 = (PathKey *) lfirst(key1);
|
||||
PathKey *pathkey2 = (PathKey *) lfirst(key2);
|
||||
PathKey *pathkey1 = (PathKey *) lfirst(key1);
|
||||
PathKey *pathkey2 = (PathKey *) lfirst(key2);
|
||||
|
||||
/*
|
||||
* XXX would like to check that we've been given canonicalized input,
|
||||
@ -495,7 +495,7 @@ build_index_pathkeys(PlannerInfo *root,
|
||||
bool nulls_first;
|
||||
int ikey;
|
||||
Expr *indexkey;
|
||||
PathKey *cpathkey;
|
||||
PathKey *cpathkey;
|
||||
|
||||
if (ScanDirectionIsBackward(scandir))
|
||||
{
|
||||
@ -601,9 +601,9 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
|
||||
foreach(i, subquery_pathkeys)
|
||||
{
|
||||
PathKey *sub_pathkey = (PathKey *) lfirst(i);
|
||||
PathKey *sub_pathkey = (PathKey *) lfirst(i);
|
||||
EquivalenceClass *sub_eclass = sub_pathkey->pk_eclass;
|
||||
PathKey *best_pathkey = NULL;
|
||||
PathKey *best_pathkey = NULL;
|
||||
|
||||
if (sub_eclass->ec_has_volatile)
|
||||
{
|
||||
@ -614,7 +614,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
*/
|
||||
TargetEntry *tle;
|
||||
|
||||
if (sub_eclass->ec_sortref == 0) /* can't happen */
|
||||
if (sub_eclass->ec_sortref == 0) /* can't happen */
|
||||
elog(ERROR, "volatile EquivalenceClass has no sortref");
|
||||
tle = get_sortgroupref_tle(sub_eclass->ec_sortref, sub_tlist);
|
||||
Assert(tle);
|
||||
@ -653,11 +653,11 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
/*
|
||||
* Otherwise, the sub_pathkey's EquivalenceClass could contain
|
||||
* multiple elements (representing knowledge that multiple items
|
||||
* are effectively equal). Each element might match none, one, or
|
||||
* more of the output columns that are visible to the outer
|
||||
* query. This means we may have multiple possible representations
|
||||
* of the sub_pathkey in the context of the outer query. Ideally
|
||||
* we would generate them all and put them all into an EC of the
|
||||
* are effectively equal). Each element might match none, one, or
|
||||
* more of the output columns that are visible to the outer query.
|
||||
* This means we may have multiple possible representations of the
|
||||
* sub_pathkey in the context of the outer query. Ideally we
|
||||
* would generate them all and put them all into an EC of the
|
||||
* outer query, thereby propagating equality knowledge up to the
|
||||
* outer query. Right now we cannot do so, because the outer
|
||||
* query's EquivalenceClasses are already frozen when this is
|
||||
@ -680,7 +680,8 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
* We handle two cases: the sub_pathkey key can be either an
|
||||
* exact match for a targetlist entry, or it could match after
|
||||
* stripping RelabelType nodes. (We need that case since
|
||||
* make_pathkey_from_sortinfo could add or remove RelabelType.)
|
||||
* make_pathkey_from_sortinfo could add or remove
|
||||
* RelabelType.)
|
||||
*/
|
||||
sub_stripped = sub_expr;
|
||||
while (sub_stripped && IsA(sub_stripped, RelabelType))
|
||||
@ -691,7 +692,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
TargetEntry *tle = (TargetEntry *) lfirst(k);
|
||||
Expr *outer_expr;
|
||||
EquivalenceClass *outer_ec;
|
||||
PathKey *outer_pk;
|
||||
PathKey *outer_pk;
|
||||
int score;
|
||||
|
||||
/* resjunk items aren't visible to outer query */
|
||||
@ -729,7 +730,7 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
exprType((Node *) sub_expr))
|
||||
outer_expr = (Expr *)
|
||||
makeRelabelType(outer_expr,
|
||||
exprType((Node *) sub_expr),
|
||||
exprType((Node *) sub_expr),
|
||||
-1,
|
||||
COERCE_DONTCARE);
|
||||
}
|
||||
@ -740,14 +741,14 @@ convert_subquery_pathkeys(PlannerInfo *root, RelOptInfo *rel,
|
||||
/* Found a representation for this sub_pathkey */
|
||||
outer_ec = get_eclass_for_sort_expr(root,
|
||||
outer_expr,
|
||||
sub_member->em_datatype,
|
||||
sub_eclass->ec_opfamilies,
|
||||
sub_member->em_datatype,
|
||||
sub_eclass->ec_opfamilies,
|
||||
0);
|
||||
outer_pk = make_canonical_pathkey(root,
|
||||
outer_ec,
|
||||
sub_pathkey->pk_opfamily,
|
||||
sub_pathkey->pk_strategy,
|
||||
sub_pathkey->pk_nulls_first);
|
||||
sub_pathkey->pk_opfamily,
|
||||
sub_pathkey->pk_strategy,
|
||||
sub_pathkey->pk_nulls_first);
|
||||
/* score = # of equivalence peers */
|
||||
score = list_length(outer_ec->ec_members) - 1;
|
||||
/* +1 if it matches the proper query_pathkeys item */
|
||||
@ -854,7 +855,7 @@ make_pathkeys_for_sortclauses(PlannerInfo *root,
|
||||
{
|
||||
SortClause *sortcl = (SortClause *) lfirst(l);
|
||||
Expr *sortkey;
|
||||
PathKey *pathkey;
|
||||
PathKey *pathkey;
|
||||
|
||||
sortkey = (Expr *) get_sortgroupclause_expr(sortcl, tlist);
|
||||
pathkey = make_pathkey_from_sortinfo(root,
|
||||
@ -961,7 +962,7 @@ find_mergeclauses_for_pathkeys(PlannerInfo *root,
|
||||
|
||||
foreach(i, pathkeys)
|
||||
{
|
||||
PathKey *pathkey = (PathKey *) lfirst(i);
|
||||
PathKey *pathkey = (PathKey *) lfirst(i);
|
||||
EquivalenceClass *pathkey_ec = pathkey->pk_eclass;
|
||||
List *matched_restrictinfos = NIL;
|
||||
ListCell *j;
|
||||
@ -1042,7 +1043,7 @@ find_mergeclauses_for_pathkeys(PlannerInfo *root,
|
||||
* Returns a pathkeys list that can be applied to the outer relation.
|
||||
*
|
||||
* Since we assume here that a sort is required, there is no particular use
|
||||
* in matching any available ordering of the outerrel. (joinpath.c has an
|
||||
* in matching any available ordering of the outerrel. (joinpath.c has an
|
||||
* entirely separate code path for considering sort-free mergejoins.) Rather,
|
||||
* it's interesting to try to match the requested query_pathkeys so that a
|
||||
* second output sort may be avoided; and failing that, we try to list "more
|
||||
@ -1117,16 +1118,15 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out if we have all the ECs mentioned in query_pathkeys; if so
|
||||
* we can generate a sort order that's also useful for final output.
|
||||
* There is no percentage in a partial match, though, so we have to
|
||||
* have 'em all.
|
||||
* Find out if we have all the ECs mentioned in query_pathkeys; if so we
|
||||
* can generate a sort order that's also useful for final output. There is
|
||||
* no percentage in a partial match, though, so we have to have 'em all.
|
||||
*/
|
||||
if (root->query_pathkeys)
|
||||
{
|
||||
foreach(lc, root->query_pathkeys)
|
||||
{
|
||||
PathKey *query_pathkey = (PathKey *) lfirst(lc);
|
||||
PathKey *query_pathkey = (PathKey *) lfirst(lc);
|
||||
EquivalenceClass *query_ec = query_pathkey->pk_eclass;
|
||||
|
||||
for (j = 0; j < necs; j++)
|
||||
@ -1145,7 +1145,7 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
|
||||
/* mark their ECs as already-emitted */
|
||||
foreach(lc, root->query_pathkeys)
|
||||
{
|
||||
PathKey *query_pathkey = (PathKey *) lfirst(lc);
|
||||
PathKey *query_pathkey = (PathKey *) lfirst(lc);
|
||||
EquivalenceClass *query_ec = query_pathkey->pk_eclass;
|
||||
|
||||
for (j = 0; j < necs; j++)
|
||||
@ -1161,16 +1161,16 @@ select_outer_pathkeys_for_merge(PlannerInfo *root,
|
||||
}
|
||||
|
||||
/*
|
||||
* Add remaining ECs to the list in popularity order, using a default
|
||||
* sort ordering. (We could use qsort() here, but the list length is
|
||||
* usually so small it's not worth it.)
|
||||
* Add remaining ECs to the list in popularity order, using a default sort
|
||||
* ordering. (We could use qsort() here, but the list length is usually
|
||||
* so small it's not worth it.)
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
int best_j;
|
||||
int best_score;
|
||||
int best_j;
|
||||
int best_score;
|
||||
EquivalenceClass *ec;
|
||||
PathKey *pathkey;
|
||||
PathKey *pathkey;
|
||||
|
||||
best_j = 0;
|
||||
best_score = scores[0];
|
||||
@ -1230,7 +1230,7 @@ make_inner_pathkeys_for_merge(PlannerInfo *root,
|
||||
{
|
||||
List *pathkeys = NIL;
|
||||
EquivalenceClass *lastoeclass;
|
||||
PathKey *opathkey;
|
||||
PathKey *opathkey;
|
||||
ListCell *lc;
|
||||
ListCell *lop;
|
||||
|
||||
@ -1243,7 +1243,7 @@ make_inner_pathkeys_for_merge(PlannerInfo *root,
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
|
||||
EquivalenceClass *oeclass;
|
||||
EquivalenceClass *ieclass;
|
||||
PathKey *pathkey;
|
||||
PathKey *pathkey;
|
||||
|
||||
cache_mergeclause_eclasses(root, rinfo);
|
||||
|
||||
@ -1332,7 +1332,7 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys)
|
||||
|
||||
foreach(i, pathkeys)
|
||||
{
|
||||
PathKey *pathkey = (PathKey *) lfirst(i);
|
||||
PathKey *pathkey = (PathKey *) lfirst(i);
|
||||
bool matched = false;
|
||||
ListCell *j;
|
||||
|
||||
@ -1392,23 +1392,23 @@ pathkeys_useful_for_merging(PlannerInfo *root, RelOptInfo *rel, List *pathkeys)
|
||||
* for merging its target column.
|
||||
*/
|
||||
static bool
|
||||
right_merge_direction(PlannerInfo *root, PathKey *pathkey)
|
||||
right_merge_direction(PlannerInfo *root, PathKey * pathkey)
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, root->query_pathkeys)
|
||||
{
|
||||
PathKey *query_pathkey = (PathKey *) lfirst(l);
|
||||
PathKey *query_pathkey = (PathKey *) lfirst(l);
|
||||
|
||||
if (pathkey->pk_eclass == query_pathkey->pk_eclass &&
|
||||
pathkey->pk_opfamily == query_pathkey->pk_opfamily)
|
||||
{
|
||||
/*
|
||||
* Found a matching query sort column. Prefer this pathkey's
|
||||
* Found a matching query sort column. Prefer this pathkey's
|
||||
* direction iff it matches. Note that we ignore pk_nulls_first,
|
||||
* which means that a sort might be needed anyway ... but we
|
||||
* still want to prefer only one of the two possible directions,
|
||||
* and we might as well use this one.
|
||||
* which means that a sort might be needed anyway ... but we still
|
||||
* want to prefer only one of the two possible directions, and we
|
||||
* might as well use this one.
|
||||
*/
|
||||
return (pathkey->pk_strategy == query_pathkey->pk_strategy);
|
||||
}
|
||||
@ -1480,13 +1480,13 @@ truncate_useless_pathkeys(PlannerInfo *root,
|
||||
* useful according to truncate_useless_pathkeys().
|
||||
*
|
||||
* This is a cheap test that lets us skip building pathkeys at all in very
|
||||
* simple queries. It's OK to err in the direction of returning "true" when
|
||||
* simple queries. It's OK to err in the direction of returning "true" when
|
||||
* there really aren't any usable pathkeys, but erring in the other direction
|
||||
* is bad --- so keep this in sync with the routines above!
|
||||
*
|
||||
* We could make the test more complex, for example checking to see if any of
|
||||
* the joinclauses are really mergejoinable, but that likely wouldn't win
|
||||
* often enough to repay the extra cycles. Queries with neither a join nor
|
||||
* often enough to repay the extra cycles. Queries with neither a join nor
|
||||
* a sort are reasonably common, though, so this much work seems worthwhile.
|
||||
*/
|
||||
bool
|
||||
|
Reference in New Issue
Block a user