mirror of
https://github.com/postgres/postgres.git
synced 2025-11-13 16:22:44 +03:00
Allow merge and hash joins to occur on arbitrary expressions (anything not
containing a volatile function), rather than only on 'Var = Var' clauses as before. This makes it practical to do flatten_join_alias_vars at the start of planning, which in turn eliminates a bunch of klugery inside the planner to deal with alias vars. As a free side effect, we now detect implied equality of non-Var expressions; for example in SELECT ... WHERE a.x = b.y and b.y = 42 we will deduce a.x = 42 and use that as a restriction qual on a. Also, we can remove the restriction introduced 12/5/02 to prevent pullup of subqueries whose targetlists contain sublinks. Still TODO: make statistical estimation routines in selfuncs.c and costsize.c smarter about expressions that are more complex than plain Vars. The need for this is considerably greater now that we have to be able to estimate the suitability of merge and hash join techniques on such expressions.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.54 2002/12/12 15:49:28 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.55 2003/01/15 19:35:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -266,12 +266,12 @@ addRangeClause(RangeQueryClause **rqlist, Node *clause,
|
||||
|
||||
if (varonleft)
|
||||
{
|
||||
var = (Node *) get_leftop((Expr *) clause);
|
||||
var = get_leftop((Expr *) clause);
|
||||
is_lobound = !isLTsel; /* x < something is high bound */
|
||||
}
|
||||
else
|
||||
{
|
||||
var = (Node *) get_rightop((Expr *) clause);
|
||||
var = get_rightop((Expr *) clause);
|
||||
is_lobound = isLTsel; /* something < x is low bound */
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.99 2003/01/12 22:35:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.100 2003/01/15 19:35:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -752,7 +752,6 @@ cost_mergejoin(Path *path, Query *root,
|
||||
Cost cpu_per_tuple;
|
||||
QualCost restrict_qual_cost;
|
||||
RestrictInfo *firstclause;
|
||||
Var *leftvar;
|
||||
double outer_rows,
|
||||
inner_rows;
|
||||
double ntuples;
|
||||
@@ -779,9 +778,7 @@ cost_mergejoin(Path *path, Query *root,
|
||||
&firstclause->left_mergescansel,
|
||||
&firstclause->right_mergescansel);
|
||||
|
||||
leftvar = get_leftop(firstclause->clause);
|
||||
Assert(IsA(leftvar, Var));
|
||||
if (VARISRELMEMBER(leftvar->varno, outer_path->parent))
|
||||
if (is_subseti(firstclause->left_relids, outer_path->parent->relids))
|
||||
{
|
||||
/* left side of clause is outer */
|
||||
outerscansel = firstclause->left_mergescansel;
|
||||
@@ -935,14 +932,9 @@ cost_hashjoin(Path *path, Query *root,
|
||||
foreach(hcl, hashclauses)
|
||||
{
|
||||
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(hcl);
|
||||
Var *left,
|
||||
*right;
|
||||
Selectivity thisbucketsize;
|
||||
|
||||
Assert(IsA(restrictinfo, RestrictInfo));
|
||||
/* these must be OK, since check_hashjoinable accepted the clause */
|
||||
left = get_leftop(restrictinfo->clause);
|
||||
right = get_rightop(restrictinfo->clause);
|
||||
|
||||
/*
|
||||
* First we have to figure out which side of the hashjoin clause is the
|
||||
@@ -952,27 +944,30 @@ cost_hashjoin(Path *path, Query *root,
|
||||
* a large query, we cache the bucketsize estimate in the RestrictInfo
|
||||
* node to avoid repeated lookups of statistics.
|
||||
*/
|
||||
if (VARISRELMEMBER(right->varno, inner_path->parent))
|
||||
if (is_subseti(restrictinfo->right_relids, inner_path->parent->relids))
|
||||
{
|
||||
/* righthand side is inner */
|
||||
thisbucketsize = restrictinfo->right_bucketsize;
|
||||
if (thisbucketsize < 0)
|
||||
{
|
||||
/* not cached yet */
|
||||
thisbucketsize = estimate_hash_bucketsize(root, right,
|
||||
thisbucketsize = estimate_hash_bucketsize(root,
|
||||
(Var *) get_rightop(restrictinfo->clause),
|
||||
virtualbuckets);
|
||||
restrictinfo->right_bucketsize = thisbucketsize;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert(VARISRELMEMBER(left->varno, inner_path->parent));
|
||||
Assert(is_subseti(restrictinfo->left_relids,
|
||||
inner_path->parent->relids));
|
||||
/* lefthand side is inner */
|
||||
thisbucketsize = restrictinfo->left_bucketsize;
|
||||
if (thisbucketsize < 0)
|
||||
{
|
||||
/* not cached yet */
|
||||
thisbucketsize = estimate_hash_bucketsize(root, left,
|
||||
thisbucketsize = estimate_hash_bucketsize(root,
|
||||
(Var *) get_leftop(restrictinfo->clause),
|
||||
virtualbuckets);
|
||||
restrictinfo->left_bucketsize = thisbucketsize;
|
||||
}
|
||||
@@ -1088,7 +1083,7 @@ estimate_hash_bucketsize(Query *root, Var *var, int nbuckets)
|
||||
* Lookup info about var's relation and attribute; if none available,
|
||||
* return default estimate.
|
||||
*/
|
||||
if (!IsA(var, Var))
|
||||
if (var == NULL || !IsA(var, Var))
|
||||
return 0.1;
|
||||
|
||||
relid = getrelid(var->varno, root->rtable);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.130 2002/12/16 21:30:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.131 2003/01/15 19:35:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -85,15 +85,15 @@ static Relids indexable_outerrelids(RelOptInfo *rel, IndexOptInfo *index);
|
||||
static Path *make_innerjoin_index_path(Query *root,
|
||||
RelOptInfo *rel, IndexOptInfo *index,
|
||||
List *clausegroup);
|
||||
static bool match_index_to_operand(int indexkey, Var *operand,
|
||||
static bool match_index_to_operand(int indexkey, Node *operand,
|
||||
RelOptInfo *rel, IndexOptInfo *index);
|
||||
static bool function_index_operand(Expr *funcOpnd, RelOptInfo *rel,
|
||||
IndexOptInfo *index);
|
||||
static bool match_special_index_operator(Expr *clause, Oid opclass,
|
||||
bool indexkey_on_left);
|
||||
static List *prefix_quals(Var *leftop, Oid expr_op,
|
||||
static List *prefix_quals(Node *leftop, Oid expr_op,
|
||||
Const *prefix, Pattern_Prefix_Status pstatus);
|
||||
static List *network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop);
|
||||
static List *network_prefix_quals(Node *leftop, Oid expr_op, Datum rightop);
|
||||
static Oid find_operator(const char *opname, Oid datatype);
|
||||
static Datum string_to_datum(const char *str, Oid datatype);
|
||||
static Const *string_to_const(const char *str, Oid datatype);
|
||||
@@ -713,7 +713,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
Oid opclass,
|
||||
Expr *clause)
|
||||
{
|
||||
Var *leftop,
|
||||
Node *leftop,
|
||||
*rightop;
|
||||
|
||||
/* Clause must be a binary opclause. */
|
||||
@@ -730,7 +730,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
* Anything that is a "pseudo constant" expression will do.
|
||||
*/
|
||||
if (match_index_to_operand(indexkey, leftop, rel, index) &&
|
||||
is_pseudo_constant_clause((Node *) rightop))
|
||||
is_pseudo_constant_clause(rightop))
|
||||
{
|
||||
if (is_indexable_operator(clause, opclass, true))
|
||||
return true;
|
||||
@@ -745,7 +745,7 @@ match_clause_to_indexkey(RelOptInfo *rel,
|
||||
}
|
||||
|
||||
if (match_index_to_operand(indexkey, rightop, rel, index) &&
|
||||
is_pseudo_constant_clause((Node *) leftop))
|
||||
is_pseudo_constant_clause(leftop))
|
||||
{
|
||||
if (is_indexable_operator(clause, opclass, false))
|
||||
return true;
|
||||
@@ -801,7 +801,7 @@ match_join_clause_to_indexkey(RelOptInfo *rel,
|
||||
Oid opclass,
|
||||
Expr *clause)
|
||||
{
|
||||
Var *leftop,
|
||||
Node *leftop,
|
||||
*rightop;
|
||||
|
||||
/* Clause must be a binary opclause. */
|
||||
@@ -820,12 +820,12 @@ match_join_clause_to_indexkey(RelOptInfo *rel,
|
||||
*/
|
||||
if (match_index_to_operand(indexkey, leftop, rel, index))
|
||||
{
|
||||
List *othervarnos = pull_varnos((Node *) rightop);
|
||||
List *othervarnos = pull_varnos(rightop);
|
||||
bool isIndexable;
|
||||
|
||||
isIndexable =
|
||||
!intMember(lfirsti(rel->relids), othervarnos) &&
|
||||
!contain_volatile_functions((Node *) rightop) &&
|
||||
!contain_volatile_functions(rightop) &&
|
||||
is_indexable_operator(clause, opclass, true);
|
||||
freeList(othervarnos);
|
||||
return isIndexable;
|
||||
@@ -833,12 +833,12 @@ match_join_clause_to_indexkey(RelOptInfo *rel,
|
||||
|
||||
if (match_index_to_operand(indexkey, rightop, rel, index))
|
||||
{
|
||||
List *othervarnos = pull_varnos((Node *) leftop);
|
||||
List *othervarnos = pull_varnos(leftop);
|
||||
bool isIndexable;
|
||||
|
||||
isIndexable =
|
||||
!intMember(lfirsti(rel->relids), othervarnos) &&
|
||||
!contain_volatile_functions((Node *) leftop) &&
|
||||
!contain_volatile_functions(leftop) &&
|
||||
is_indexable_operator(clause, opclass, false);
|
||||
freeList(othervarnos);
|
||||
return isIndexable;
|
||||
@@ -1622,7 +1622,7 @@ make_innerjoin_index_path(Query *root,
|
||||
*/
|
||||
static bool
|
||||
match_index_to_operand(int indexkey,
|
||||
Var *operand,
|
||||
Node *operand,
|
||||
RelOptInfo *rel,
|
||||
IndexOptInfo *index)
|
||||
{
|
||||
@@ -1633,7 +1633,7 @@ match_index_to_operand(int indexkey,
|
||||
* eval_const_expressions() will have simplified if more than one.
|
||||
*/
|
||||
if (operand && IsA(operand, RelabelType))
|
||||
operand = (Var *) ((RelabelType *) operand)->arg;
|
||||
operand = (Node *) ((RelabelType *) operand)->arg;
|
||||
|
||||
if (index->indproc == InvalidOid)
|
||||
{
|
||||
@@ -1641,8 +1641,8 @@ match_index_to_operand(int indexkey,
|
||||
* Simple index.
|
||||
*/
|
||||
if (operand && IsA(operand, Var) &&
|
||||
lfirsti(rel->relids) == operand->varno &&
|
||||
indexkey == operand->varattno)
|
||||
lfirsti(rel->relids) == ((Var *) operand)->varno &&
|
||||
indexkey == ((Var *) operand)->varattno)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@@ -1764,7 +1764,7 @@ match_special_index_operator(Expr *clause, Oid opclass,
|
||||
bool indexkey_on_left)
|
||||
{
|
||||
bool isIndexable = false;
|
||||
Var *leftop,
|
||||
Node *leftop,
|
||||
*rightop;
|
||||
Oid expr_op;
|
||||
Const *patt = NULL;
|
||||
@@ -1944,8 +1944,8 @@ expand_indexqual_conditions(List *indexquals)
|
||||
Expr *clause = (Expr *) lfirst(q);
|
||||
|
||||
/* we know these will succeed */
|
||||
Var *leftop = get_leftop(clause);
|
||||
Var *rightop = get_rightop(clause);
|
||||
Node *leftop = get_leftop(clause);
|
||||
Node *rightop = get_rightop(clause);
|
||||
Oid expr_op = ((OpExpr *) clause)->opno;
|
||||
Const *patt = (Const *) rightop;
|
||||
Const *prefix = NULL;
|
||||
@@ -2033,7 +2033,7 @@ expand_indexqual_conditions(List *indexquals)
|
||||
* operators.
|
||||
*/
|
||||
static List *
|
||||
prefix_quals(Var *leftop, Oid expr_op,
|
||||
prefix_quals(Node *leftop, Oid expr_op,
|
||||
Const *prefix_const, Pattern_Prefix_Status pstatus)
|
||||
{
|
||||
List *result;
|
||||
@@ -2143,7 +2143,7 @@ prefix_quals(Var *leftop, Oid expr_op,
|
||||
* operator.
|
||||
*/
|
||||
static List *
|
||||
network_prefix_quals(Var *leftop, Oid expr_op, Datum rightop)
|
||||
network_prefix_quals(Node *leftop, Oid expr_op, Datum rightop)
|
||||
{
|
||||
bool is_eq;
|
||||
char *opr1name;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.74 2002/11/30 05:21:02 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.75 2003/01/15 19:35:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -774,10 +774,9 @@ hash_inner_and_outer(Query *root,
|
||||
foreach(i, restrictlist)
|
||||
{
|
||||
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
|
||||
Var *left,
|
||||
*right;
|
||||
|
||||
if (restrictinfo->hashjoinoperator == InvalidOid)
|
||||
if (restrictinfo->left_relids == NIL ||
|
||||
restrictinfo->hashjoinoperator == InvalidOid)
|
||||
continue; /* not hashjoinable */
|
||||
|
||||
/*
|
||||
@@ -787,26 +786,16 @@ hash_inner_and_outer(Query *root,
|
||||
if (isouterjoin && restrictinfo->ispusheddown)
|
||||
continue;
|
||||
|
||||
/* these must be OK, since check_hashjoinable accepted the clause */
|
||||
left = get_leftop(restrictinfo->clause);
|
||||
right = get_rightop(restrictinfo->clause);
|
||||
|
||||
/*
|
||||
* Check if clause is usable with these input rels.
|
||||
*
|
||||
* Since we currently accept only var-op-var clauses as hashjoinable,
|
||||
* we need only check the membership of the vars to determine whether
|
||||
* a particular clause can be used with this pair of sub-relations.
|
||||
* This code would need to be upgraded if we wanted to allow
|
||||
* more-complex expressions in hash joins.
|
||||
*/
|
||||
if (VARISRELMEMBER(left->varno, outerrel) &&
|
||||
VARISRELMEMBER(right->varno, innerrel))
|
||||
if (is_subseti(restrictinfo->left_relids, outerrel->relids) &&
|
||||
is_subseti(restrictinfo->right_relids, innerrel->relids))
|
||||
{
|
||||
/* righthand side is inner */
|
||||
}
|
||||
else if (VARISRELMEMBER(left->varno, innerrel) &&
|
||||
VARISRELMEMBER(right->varno, outerrel))
|
||||
else if (is_subseti(restrictinfo->left_relids, innerrel->relids) &&
|
||||
is_subseti(restrictinfo->right_relids, outerrel->relids))
|
||||
{
|
||||
/* lefthand side is inner */
|
||||
}
|
||||
@@ -874,9 +863,6 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
|
||||
foreach(i, restrictlist)
|
||||
{
|
||||
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
|
||||
Expr *clause;
|
||||
Var *left,
|
||||
*right;
|
||||
|
||||
/*
|
||||
* If processing an outer join, only use its own join clauses in
|
||||
@@ -896,11 +882,13 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
|
||||
switch (jointype)
|
||||
{
|
||||
case JOIN_RIGHT:
|
||||
if (restrictinfo->mergejoinoperator == InvalidOid)
|
||||
if (restrictinfo->left_relids == NIL ||
|
||||
restrictinfo->mergejoinoperator == InvalidOid)
|
||||
return NIL; /* not mergejoinable */
|
||||
break;
|
||||
case JOIN_FULL:
|
||||
if (restrictinfo->mergejoinoperator == InvalidOid)
|
||||
if (restrictinfo->left_relids == NIL ||
|
||||
restrictinfo->mergejoinoperator == InvalidOid)
|
||||
elog(ERROR, "FULL JOIN is only supported with mergejoinable join conditions");
|
||||
break;
|
||||
default:
|
||||
@@ -909,19 +897,27 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
|
||||
}
|
||||
}
|
||||
|
||||
if (restrictinfo->mergejoinoperator == InvalidOid)
|
||||
if (restrictinfo->left_relids == NIL ||
|
||||
restrictinfo->mergejoinoperator == InvalidOid)
|
||||
continue; /* not mergejoinable */
|
||||
|
||||
clause = restrictinfo->clause;
|
||||
/* these must be OK, since check_mergejoinable accepted the clause */
|
||||
left = get_leftop(clause);
|
||||
right = get_rightop(clause);
|
||||
/*
|
||||
* Check if clause is usable with these input rels.
|
||||
*/
|
||||
if (is_subseti(restrictinfo->left_relids, outerrel->relids) &&
|
||||
is_subseti(restrictinfo->right_relids, innerrel->relids))
|
||||
{
|
||||
/* righthand side is inner */
|
||||
}
|
||||
else if (is_subseti(restrictinfo->left_relids, innerrel->relids) &&
|
||||
is_subseti(restrictinfo->right_relids, outerrel->relids))
|
||||
{
|
||||
/* lefthand side is inner */
|
||||
}
|
||||
else
|
||||
continue; /* no good for these input relations */
|
||||
|
||||
if ((VARISRELMEMBER(left->varno, outerrel) &&
|
||||
VARISRELMEMBER(right->varno, innerrel)) ||
|
||||
(VARISRELMEMBER(left->varno, innerrel) &&
|
||||
VARISRELMEMBER(right->varno, outerrel)))
|
||||
result_list = lcons(restrictinfo, result_list);
|
||||
result_list = lcons(restrictinfo, result_list);
|
||||
}
|
||||
|
||||
return result_list;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.43 2002/12/17 01:18:22 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.44 2003/01/15 19:35:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -53,27 +53,23 @@ makePathKeyItem(Node *key, Oid sortop)
|
||||
* The given clause has a mergejoinable operator, so its two sides
|
||||
* can be considered equal after restriction clause application; in
|
||||
* particular, any pathkey mentioning one side (with the correct sortop)
|
||||
* can be expanded to include the other as well. Record the vars and
|
||||
* can be expanded to include the other as well. Record the exprs and
|
||||
* associated sortops in the query's equi_key_list for future use.
|
||||
*
|
||||
* The query's equi_key_list field points to a list of sublists of PathKeyItem
|
||||
* nodes, where each sublist is a set of two or more vars+sortops that have
|
||||
* nodes, where each sublist is a set of two or more exprs+sortops that have
|
||||
* been identified as logically equivalent (and, therefore, we may consider
|
||||
* any two in a set to be equal). As described above, we will subsequently
|
||||
* use direct pointers to one of these sublists to represent any pathkey
|
||||
* that involves an equijoined variable.
|
||||
*
|
||||
* This code would actually work fine with expressions more complex than
|
||||
* a single Var, but currently it won't see any because check_mergejoinable
|
||||
* won't accept such clauses as mergejoinable.
|
||||
*/
|
||||
void
|
||||
add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
|
||||
{
|
||||
Expr *clause = restrictinfo->clause;
|
||||
PathKeyItem *item1 = makePathKeyItem((Node *) get_leftop(clause),
|
||||
PathKeyItem *item1 = makePathKeyItem(get_leftop(clause),
|
||||
restrictinfo->left_sortop);
|
||||
PathKeyItem *item2 = makePathKeyItem((Node *) get_rightop(clause),
|
||||
PathKeyItem *item2 = makePathKeyItem(get_rightop(clause),
|
||||
restrictinfo->right_sortop);
|
||||
List *newset,
|
||||
*cursetlink;
|
||||
@@ -717,13 +713,13 @@ cache_mergeclause_pathkeys(Query *root, RestrictInfo *restrictinfo)
|
||||
|
||||
if (restrictinfo->left_pathkey == NIL)
|
||||
{
|
||||
key = (Node *) get_leftop(restrictinfo->clause);
|
||||
key = get_leftop(restrictinfo->clause);
|
||||
item = makePathKeyItem(key, restrictinfo->left_sortop);
|
||||
restrictinfo->left_pathkey = make_canonical_pathkey(root, item);
|
||||
}
|
||||
if (restrictinfo->right_pathkey == NIL)
|
||||
{
|
||||
key = (Node *) get_rightop(restrictinfo->clause);
|
||||
key = get_rightop(restrictinfo->clause);
|
||||
item = makePathKeyItem(key, restrictinfo->right_sortop);
|
||||
restrictinfo->right_pathkey = make_canonical_pathkey(root, item);
|
||||
}
|
||||
@@ -852,32 +848,24 @@ make_pathkeys_for_mergeclauses(Query *root,
|
||||
foreach(i, mergeclauses)
|
||||
{
|
||||
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(i);
|
||||
Node *key;
|
||||
List *pathkey;
|
||||
|
||||
cache_mergeclause_pathkeys(root, restrictinfo);
|
||||
|
||||
key = (Node *) get_leftop(restrictinfo->clause);
|
||||
if (IsA(key, Var) &&
|
||||
VARISRELMEMBER(((Var *) key)->varno, rel))
|
||||
if (is_subseti(restrictinfo->left_relids, rel->relids))
|
||||
{
|
||||
/* Rel is left side of mergeclause */
|
||||
pathkey = restrictinfo->left_pathkey;
|
||||
}
|
||||
else if (is_subseti(restrictinfo->right_relids, rel->relids))
|
||||
{
|
||||
/* Rel is right side of mergeclause */
|
||||
pathkey = restrictinfo->right_pathkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = (Node *) get_rightop(restrictinfo->clause);
|
||||
if (IsA(key, Var) &&
|
||||
VARISRELMEMBER(((Var *) key)->varno, rel))
|
||||
{
|
||||
/* Rel is right side of mergeclause */
|
||||
pathkey = restrictinfo->right_pathkey;
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "make_pathkeys_for_mergeclauses: can't identify which side of mergeclause to use");
|
||||
pathkey = NIL; /* keep compiler quiet */
|
||||
}
|
||||
elog(ERROR, "make_pathkeys_for_mergeclauses: can't identify which side of mergeclause to use");
|
||||
pathkey = NIL; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user