|
|
@ -11,7 +11,7 @@ |
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California |
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California |
|
|
|
* |
|
|
|
* |
|
|
|
* IDENTIFICATION |
|
|
|
* IDENTIFICATION |
|
|
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.69 2005/07/02 23:00:40 tgl Exp $ |
|
|
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.70 2005/07/03 18:26:32 tgl Exp $ |
|
|
|
* |
|
|
|
* |
|
|
|
*------------------------------------------------------------------------- |
|
|
|
*------------------------------------------------------------------------- |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -35,6 +35,10 @@ static PathKeyItem *makePathKeyItem(Node *key, Oid sortop, bool checkType); |
|
|
|
static void generate_outer_join_implications(PlannerInfo *root, |
|
|
|
static void generate_outer_join_implications(PlannerInfo *root, |
|
|
|
List *equi_key_set, |
|
|
|
List *equi_key_set, |
|
|
|
Relids *relids); |
|
|
|
Relids *relids); |
|
|
|
|
|
|
|
static void sub_generate_join_implications(PlannerInfo *root, |
|
|
|
|
|
|
|
List *equi_key_set, Relids *relids, |
|
|
|
|
|
|
|
Node *item1, Oid sortop1, |
|
|
|
|
|
|
|
Relids item1_relids); |
|
|
|
static void process_implied_const_eq(PlannerInfo *root, |
|
|
|
static void process_implied_const_eq(PlannerInfo *root, |
|
|
|
List *equi_key_set, Relids *relids, |
|
|
|
List *equi_key_set, Relids *relids, |
|
|
|
Node *item1, Oid sortop1, |
|
|
|
Node *item1, Oid sortop1, |
|
|
@ -250,65 +254,65 @@ generate_implied_equalities(PlannerInfo *root) |
|
|
|
i1++; |
|
|
|
i1++; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* If we have constant(s) and outer joins, try to propagate the |
|
|
|
|
|
|
|
* constants through outer-join quals. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (have_consts && root->hasOuterJoins) |
|
|
|
|
|
|
|
generate_outer_join_implications(root, curset, relids); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* A set containing only two items cannot imply any equalities |
|
|
|
|
|
|
|
* beyond the one that created the set, so we can skip it. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (nitems < 3) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Match each item in the set with all that appear after it (it's |
|
|
|
* Match each item in the set with all that appear after it (it's |
|
|
|
* sufficient to generate A=B, need not process B=A too). |
|
|
|
* sufficient to generate A=B, need not process B=A too). |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* A set containing only two items cannot imply any equalities |
|
|
|
|
|
|
|
* beyond the one that created the set, so we can skip this |
|
|
|
|
|
|
|
* processing in that case. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
i1 = 0; |
|
|
|
if (nitems >= 3) |
|
|
|
foreach(ptr1, curset) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
PathKeyItem *item1 = (PathKeyItem *) lfirst(ptr1); |
|
|
|
i1 = 0; |
|
|
|
bool i1_is_variable = !bms_is_empty(relids[i1]); |
|
|
|
foreach(ptr1, curset) |
|
|
|
ListCell *ptr2; |
|
|
|
|
|
|
|
int i2 = i1 + 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for_each_cell(ptr2, lnext(ptr1)) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
PathKeyItem *item2 = (PathKeyItem *) lfirst(ptr2); |
|
|
|
PathKeyItem *item1 = (PathKeyItem *) lfirst(ptr1); |
|
|
|
bool i2_is_variable = !bms_is_empty(relids[i2]); |
|
|
|
bool i1_is_variable = !bms_is_empty(relids[i1]); |
|
|
|
|
|
|
|
ListCell *ptr2; |
|
|
|
|
|
|
|
int i2 = i1 + 1; |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
for_each_cell(ptr2, lnext(ptr1)) |
|
|
|
* If it's "const = const" then just ignore it altogether. |
|
|
|
|
|
|
|
* There is no place in the restrictinfo structure to |
|
|
|
|
|
|
|
* store it. (If the two consts are in fact unequal, then |
|
|
|
|
|
|
|
* propagating the comparison to Vars will cause us to |
|
|
|
|
|
|
|
* produce zero rows out, as expected.) |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (i1_is_variable || i2_is_variable) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
PathKeyItem *item2 = (PathKeyItem *) lfirst(ptr2); |
|
|
|
|
|
|
|
bool i2_is_variable = !bms_is_empty(relids[i2]); |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Tell process_implied_equality to delete the clause, |
|
|
|
* If it's "const = const" then just ignore it altogether. |
|
|
|
* not add it, if it's "var = var" and we have |
|
|
|
* There is no place in the restrictinfo structure to |
|
|
|
* constants present in the list. |
|
|
|
* store it. (If the two consts are in fact unequal, then |
|
|
|
|
|
|
|
* propagating the comparison to Vars will cause us to |
|
|
|
|
|
|
|
* produce zero rows out, as expected.) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
bool delete_it = (have_consts && |
|
|
|
if (i1_is_variable || i2_is_variable) |
|
|
|
i1_is_variable && |
|
|
|
{ |
|
|
|
i2_is_variable); |
|
|
|
/*
|
|
|
|
|
|
|
|
* Tell process_implied_equality to delete the clause, |
|
|
|
process_implied_equality(root, |
|
|
|
* not add it, if it's "var = var" and we have |
|
|
|
item1->key, item2->key, |
|
|
|
* constants present in the list. |
|
|
|
item1->sortop, item2->sortop, |
|
|
|
*/ |
|
|
|
relids[i1], relids[i2], |
|
|
|
bool delete_it = (have_consts && |
|
|
|
delete_it); |
|
|
|
i1_is_variable && |
|
|
|
|
|
|
|
i2_is_variable); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
process_implied_equality(root, |
|
|
|
|
|
|
|
item1->key, item2->key, |
|
|
|
|
|
|
|
item1->sortop, item2->sortop, |
|
|
|
|
|
|
|
relids[i1], relids[i2], |
|
|
|
|
|
|
|
delete_it); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
i2++; |
|
|
|
} |
|
|
|
} |
|
|
|
i2++; |
|
|
|
i1++; |
|
|
|
} |
|
|
|
} |
|
|
|
i1++; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* If we have constant(s) and outer joins, try to propagate the |
|
|
|
|
|
|
|
* constants through outer-join quals. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (have_consts && root->hasOuterJoins) |
|
|
|
|
|
|
|
generate_outer_join_implications(root, curset, relids); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -362,118 +366,154 @@ generate_outer_join_implications(PlannerInfo *root, |
|
|
|
List *equi_key_set, |
|
|
|
List *equi_key_set, |
|
|
|
Relids *relids) |
|
|
|
Relids *relids) |
|
|
|
{ |
|
|
|
{ |
|
|
|
ListCell *l1; |
|
|
|
ListCell *l; |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
|
|
|
|
|
|
|
|
/* Examine each mergejoinable outer-join clause with OUTERVAR on left */ |
|
|
|
/* Process each non-constant element of equi_key_set */ |
|
|
|
foreach(l1, root->left_join_clauses) |
|
|
|
foreach(l, equi_key_set) |
|
|
|
{ |
|
|
|
{ |
|
|
|
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1); |
|
|
|
PathKeyItem *item1 = (PathKeyItem *) lfirst(l); |
|
|
|
Node *leftop = get_leftop(rinfo->clause); |
|
|
|
|
|
|
|
Node *rightop = get_rightop(rinfo->clause); |
|
|
|
|
|
|
|
ListCell *l2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Scan to see if it matches any element of equi_key_set */ |
|
|
|
if (!bms_is_empty(relids[i])) |
|
|
|
foreach(l2, equi_key_set) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
PathKeyItem *item1 = (PathKeyItem *) lfirst(l2); |
|
|
|
sub_generate_join_implications(root, equi_key_set, relids, |
|
|
|
|
|
|
|
item1->key, |
|
|
|
|
|
|
|
item1->sortop, |
|
|
|
|
|
|
|
relids[i]); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
i++; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (equal(leftop, item1->key) && |
|
|
|
/*
|
|
|
|
rinfo->left_sortop == item1->sortop) |
|
|
|
* sub_generate_join_implications |
|
|
|
{ |
|
|
|
* Propagate a constant equality through outer join clauses. |
|
|
|
/*
|
|
|
|
* |
|
|
|
* Yes, so find constant member(s) of set and generate |
|
|
|
* The item described by item1/sortop1/item1_relids has been determined |
|
|
|
* implied INNERVAR = CONSTANT |
|
|
|
* to be equal to the constant(s) listed in equi_key_set. Recursively |
|
|
|
*/ |
|
|
|
* trace out the implications of this. |
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
|
* |
|
|
|
rightop, |
|
|
|
* equi_key_set and relids are as for generate_outer_join_implications. |
|
|
|
rinfo->right_sortop, |
|
|
|
*/ |
|
|
|
rinfo->right_relids, |
|
|
|
static void |
|
|
|
false); |
|
|
|
sub_generate_join_implications(PlannerInfo *root, |
|
|
|
/*
|
|
|
|
List *equi_key_set, Relids *relids, |
|
|
|
* We can remove the explicit outer join qual, too, |
|
|
|
Node *item1, Oid sortop1, Relids item1_relids) |
|
|
|
* since we now have tests forcing each of its sides |
|
|
|
|
|
|
|
* to the same value. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
process_implied_equality(root, |
|
|
|
|
|
|
|
leftop, |
|
|
|
|
|
|
|
rightop, |
|
|
|
|
|
|
|
rinfo->left_sortop, |
|
|
|
|
|
|
|
rinfo->right_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids, |
|
|
|
|
|
|
|
rinfo->right_relids, |
|
|
|
|
|
|
|
true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* No need to match against remaining set members */ |
|
|
|
{ |
|
|
|
break; |
|
|
|
ListCell *l; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Examine each mergejoinable outer-join clause with OUTERVAR on left, |
|
|
|
|
|
|
|
* looking for an OUTERVAR identical to item1 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
foreach(l, root->left_join_clauses) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); |
|
|
|
|
|
|
|
Node *leftop = get_leftop(rinfo->clause); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (equal(leftop, item1) && rinfo->left_sortop == sortop1) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Match, so find constant member(s) of set and generate |
|
|
|
|
|
|
|
* implied INNERVAR = CONSTANT |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
Node *rightop = get_rightop(rinfo->clause); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
|
|
|
|
|
rightop, |
|
|
|
|
|
|
|
rinfo->right_sortop, |
|
|
|
|
|
|
|
rinfo->right_relids, |
|
|
|
|
|
|
|
false); |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* We can remove explicit tests of this outer-join qual, too, |
|
|
|
|
|
|
|
* since we now have tests forcing each of its sides |
|
|
|
|
|
|
|
* to the same value. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
process_implied_equality(root, |
|
|
|
|
|
|
|
leftop, rightop, |
|
|
|
|
|
|
|
rinfo->left_sortop, rinfo->right_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids, rinfo->right_relids, |
|
|
|
|
|
|
|
true); |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* And recurse to see if we can deduce anything from |
|
|
|
|
|
|
|
* INNERVAR = CONSTANT |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
sub_generate_join_implications(root, equi_key_set, relids, |
|
|
|
|
|
|
|
rightop, |
|
|
|
|
|
|
|
rinfo->right_sortop, |
|
|
|
|
|
|
|
rinfo->right_relids); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Examine each mergejoinable outer-join clause with OUTERVAR on right */ |
|
|
|
/* The same, looking at clauses with OUTERVAR on right */ |
|
|
|
foreach(l1, root->right_join_clauses) |
|
|
|
foreach(l, root->right_join_clauses) |
|
|
|
{ |
|
|
|
{ |
|
|
|
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1); |
|
|
|
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); |
|
|
|
Node *leftop = get_leftop(rinfo->clause); |
|
|
|
|
|
|
|
Node *rightop = get_rightop(rinfo->clause); |
|
|
|
Node *rightop = get_rightop(rinfo->clause); |
|
|
|
ListCell *l2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Scan to see if it matches any element of equi_key_set */ |
|
|
|
if (equal(rightop, item1) && rinfo->right_sortop == sortop1) |
|
|
|
foreach(l2, equi_key_set) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
PathKeyItem *item1 = (PathKeyItem *) lfirst(l2); |
|
|
|
/*
|
|
|
|
|
|
|
|
* Match, so find constant member(s) of set and generate |
|
|
|
if (equal(rightop, item1->key) && |
|
|
|
* implied INNERVAR = CONSTANT |
|
|
|
rinfo->right_sortop == item1->sortop) |
|
|
|
*/ |
|
|
|
{ |
|
|
|
Node *leftop = get_leftop(rinfo->clause); |
|
|
|
/*
|
|
|
|
|
|
|
|
* Yes, so find constant member(s) of set and generate |
|
|
|
|
|
|
|
* implied INNERVAR = CONSTANT |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
|
|
|
|
|
leftop, |
|
|
|
|
|
|
|
rinfo->left_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids, |
|
|
|
|
|
|
|
false); |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* We can remove the explicit outer join qual, too, |
|
|
|
|
|
|
|
* since we now have tests forcing each of its sides |
|
|
|
|
|
|
|
* to the same value. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
process_implied_equality(root, |
|
|
|
|
|
|
|
leftop, |
|
|
|
|
|
|
|
rightop, |
|
|
|
|
|
|
|
rinfo->left_sortop, |
|
|
|
|
|
|
|
rinfo->right_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids, |
|
|
|
|
|
|
|
rinfo->right_relids, |
|
|
|
|
|
|
|
true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* No need to match against remaining set members */ |
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
|
break; |
|
|
|
leftop, |
|
|
|
} |
|
|
|
rinfo->left_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids, |
|
|
|
|
|
|
|
false); |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* We can remove explicit tests of this outer-join qual, too, |
|
|
|
|
|
|
|
* since we now have tests forcing each of its sides |
|
|
|
|
|
|
|
* to the same value. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
process_implied_equality(root, |
|
|
|
|
|
|
|
leftop, rightop, |
|
|
|
|
|
|
|
rinfo->left_sortop, rinfo->right_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids, rinfo->right_relids, |
|
|
|
|
|
|
|
true); |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* And recurse to see if we can deduce anything from |
|
|
|
|
|
|
|
* INNERVAR = CONSTANT |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
sub_generate_join_implications(root, equi_key_set, relids, |
|
|
|
|
|
|
|
leftop, |
|
|
|
|
|
|
|
rinfo->left_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Examine each mergejoinable full-join clause */ |
|
|
|
/*
|
|
|
|
foreach(l1, root->full_join_clauses) |
|
|
|
* Only COALESCE(x,y) items can possibly match full joins |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (IsA(item1, CoalesceExpr)) |
|
|
|
{ |
|
|
|
{ |
|
|
|
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1); |
|
|
|
CoalesceExpr *cexpr = (CoalesceExpr *) item1; |
|
|
|
Node *leftop = get_leftop(rinfo->clause); |
|
|
|
Node *cfirst; |
|
|
|
Node *rightop = get_rightop(rinfo->clause); |
|
|
|
Node *csecond; |
|
|
|
int i1 = 0; |
|
|
|
|
|
|
|
ListCell *l2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Scan to see if it matches any element of equi_key_set */ |
|
|
|
if (list_length(cexpr->args) != 2) |
|
|
|
foreach(l2, equi_key_set) |
|
|
|
return; |
|
|
|
|
|
|
|
cfirst = (Node *) linitial(cexpr->args); |
|
|
|
|
|
|
|
csecond = (Node *) lsecond(cexpr->args); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Examine each mergejoinable full-join clause, looking for a |
|
|
|
|
|
|
|
* clause of the form "x = y" matching the COALESCE(x,y) expression |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
foreach(l, root->full_join_clauses) |
|
|
|
{ |
|
|
|
{ |
|
|
|
PathKeyItem *item1 = (PathKeyItem *) lfirst(l2); |
|
|
|
RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); |
|
|
|
CoalesceExpr *cexpr = (CoalesceExpr *) item1->key; |
|
|
|
Node *leftop = get_leftop(rinfo->clause); |
|
|
|
|
|
|
|
Node *rightop = get_rightop(rinfo->clause); |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Try to match a pathkey containing a COALESCE() expression |
|
|
|
* We can assume the COALESCE() inputs are in the same order |
|
|
|
* to the join clause. We can assume the COALESCE() inputs |
|
|
|
* as the join clause, since both were automatically generated |
|
|
|
* are in the same order as the join clause, since both were |
|
|
|
* in the cases we care about. |
|
|
|
* automatically generated in the cases we care about. |
|
|
|
|
|
|
|
* |
|
|
|
* |
|
|
|
* XXX currently this may fail to match in cross-type cases |
|
|
|
* XXX currently this may fail to match in cross-type cases |
|
|
|
* because the COALESCE will contain typecast operations while |
|
|
|
* because the COALESCE will contain typecast operations while |
|
|
@ -482,15 +522,13 @@ generate_outer_join_implications(PlannerInfo *root, |
|
|
|
* Is it OK to strip implicit coercions from the COALESCE |
|
|
|
* Is it OK to strip implicit coercions from the COALESCE |
|
|
|
* arguments? What of the sortops in such cases? |
|
|
|
* arguments? What of the sortops in such cases? |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (IsA(cexpr, CoalesceExpr) && |
|
|
|
if (equal(leftop, cfirst) && |
|
|
|
list_length(cexpr->args) == 2 && |
|
|
|
equal(rightop, csecond) && |
|
|
|
equal(leftop, (Node *) linitial(cexpr->args)) && |
|
|
|
rinfo->left_sortop == sortop1 && |
|
|
|
equal(rightop, (Node *) lsecond(cexpr->args)) && |
|
|
|
rinfo->right_sortop == sortop1) |
|
|
|
rinfo->left_sortop == item1->sortop && |
|
|
|
|
|
|
|
rinfo->right_sortop == item1->sortop) |
|
|
|
|
|
|
|
{ |
|
|
|
{ |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Yes, so find constant member(s) of set and generate |
|
|
|
* Match, so find constant member(s) of set and generate |
|
|
|
* implied LEFTVAR = CONSTANT |
|
|
|
* implied LEFTVAR = CONSTANT |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
@ -506,28 +544,37 @@ generate_outer_join_implications(PlannerInfo *root, |
|
|
|
false); |
|
|
|
false); |
|
|
|
/* ... and remove COALESCE() = CONSTANT */ |
|
|
|
/* ... and remove COALESCE() = CONSTANT */ |
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
|
process_implied_const_eq(root, equi_key_set, relids, |
|
|
|
item1->key, |
|
|
|
item1, |
|
|
|
item1->sortop, |
|
|
|
sortop1, |
|
|
|
relids[i1], |
|
|
|
item1_relids, |
|
|
|
true); |
|
|
|
true); |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* We can remove the explicit outer join qual, too, |
|
|
|
* We can remove explicit tests of this outer-join qual, too, |
|
|
|
* since we now have tests forcing each of its sides |
|
|
|
* since we now have tests forcing each of its sides |
|
|
|
* to the same value. |
|
|
|
* to the same value. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
process_implied_equality(root, |
|
|
|
process_implied_equality(root, |
|
|
|
leftop, |
|
|
|
leftop, rightop, |
|
|
|
rightop, |
|
|
|
|
|
|
|
rinfo->left_sortop, |
|
|
|
rinfo->left_sortop, |
|
|
|
rinfo->right_sortop, |
|
|
|
rinfo->right_sortop, |
|
|
|
rinfo->left_relids, |
|
|
|
rinfo->left_relids, |
|
|
|
rinfo->right_relids, |
|
|
|
rinfo->right_relids, |
|
|
|
true); |
|
|
|
true); |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* And recurse to see if we can deduce anything from |
|
|
|
|
|
|
|
* LEFTVAR = CONSTANT |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
sub_generate_join_implications(root, equi_key_set, relids, |
|
|
|
|
|
|
|
leftop, |
|
|
|
|
|
|
|
rinfo->left_sortop, |
|
|
|
|
|
|
|
rinfo->left_relids); |
|
|
|
|
|
|
|
/* ... and RIGHTVAR = CONSTANT */ |
|
|
|
|
|
|
|
sub_generate_join_implications(root, equi_key_set, relids, |
|
|
|
|
|
|
|
rightop, |
|
|
|
|
|
|
|
rinfo->right_sortop, |
|
|
|
|
|
|
|
rinfo->right_relids); |
|
|
|
|
|
|
|
|
|
|
|
/* No need to match against remaining set members */ |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
i1++; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -537,10 +584,8 @@ generate_outer_join_implications(PlannerInfo *root, |
|
|
|
* Apply process_implied_equality with the given item and each |
|
|
|
* Apply process_implied_equality with the given item and each |
|
|
|
* pseudoconstant member of equi_key_set. |
|
|
|
* pseudoconstant member of equi_key_set. |
|
|
|
* |
|
|
|
* |
|
|
|
* This is just a subroutine to save some cruft in |
|
|
|
* equi_key_set and relids are as for generate_outer_join_implications, |
|
|
|
* generate_outer_join_implications. equi_key_set and relids are as in |
|
|
|
* the other parameters as for process_implied_equality. |
|
|
|
* generate_outer_join_implications, the other parameters as for |
|
|
|
|
|
|
|
* process_implied_equality. |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
static void |
|
|
|
static void |
|
|
|
process_implied_const_eq(PlannerInfo *root, List *equi_key_set, Relids *relids, |
|
|
|
process_implied_const_eq(PlannerInfo *root, List *equi_key_set, Relids *relids, |
|
|
|