1 /*-------------------------------------------------------------------------
4 * Target list, qualification, joininfo initialization routines
6 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.65 2001/10/25 05:49:33 momjian Exp $
13 *-------------------------------------------------------------------------
17 #include <sys/types.h>
19 #include "catalog/pg_operator.h"
20 #include "catalog/pg_type.h"
21 #include "nodes/makefuncs.h"
22 #include "optimizer/clauses.h"
23 #include "optimizer/cost.h"
24 #include "optimizer/joininfo.h"
25 #include "optimizer/pathnode.h"
26 #include "optimizer/paths.h"
27 #include "optimizer/planmain.h"
28 #include "optimizer/tlist.h"
29 #include "optimizer/var.h"
30 #include "parser/parsetree.h"
31 #include "parser/parse_expr.h"
32 #include "parser/parse_oper.h"
33 #include "parser/parse_type.h"
34 #include "utils/lsyscache.h"
35 #include "utils/syscache.h"
38 static void mark_baserels_for_outer_join(Query *root, Relids rels,
40 static void distribute_qual_to_rels(Query *root, Node *clause,
45 static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
47 static void add_vars_to_targetlist(Query *root, List *vars);
48 static bool qual_is_redundant(Query *root, RestrictInfo *restrictinfo,
50 static void check_mergejoinable(RestrictInfo *restrictinfo);
51 static void check_hashjoinable(RestrictInfo *restrictinfo);
54 /*****************************************************************************
58 *****************************************************************************/
61 * build_base_rel_tlists
62 * Creates rel nodes for every relation mentioned in the target list
63 * 'tlist' (if a node hasn't already been created) and adds them to
64 * root->base_rel_list. Creates targetlist entries for each var seen
65 * in 'tlist' and adds them to the tlist of the appropriate rel node.
68 build_base_rel_tlists(Query *root, List *tlist)
70 List *tlist_vars = pull_var_clause((Node *) tlist, false);
72 add_vars_to_targetlist(root, tlist_vars);
77 * add_vars_to_targetlist
78 * For each variable appearing in the list, add it to the relation's
79 * targetlist if not already present. Corresponding base rel nodes
80 * will be created if not already present.
83 add_vars_to_targetlist(Query *root, List *vars)
89 Var *var = (Var *) lfirst(temp);
90 RelOptInfo *rel = build_base_rel(root, var->varno);
92 add_var_to_tlist(rel, var);
97 * add_missing_rels_to_query
99 * If we have a relation listed in the join tree that does not appear
100 * in the target list nor qualifications, we must add it to the base
101 * relation list so that it can be processed. For instance,
102 * select count(*) from foo;
103 * would fail to scan foo if this routine were not called. More subtly,
104 * select f.x from foo f, foo f2
105 * is a join of f and f2. Note that if we have
106 * select foo.x from foo f
107 * this also gets turned into a join (between foo as foo and foo as f).
109 * Returns a list of all the base relations (RelOptInfo nodes) that appear
110 * in the join tree. This list can be used for cross-checking in the
111 * reverse direction, ie, that we have a join tree entry for every
112 * relation used in the query.
116 add_missing_rels_to_query(Query *root, Node *jtnode)
122 if (IsA(jtnode, RangeTblRef))
124 int varno = ((RangeTblRef *) jtnode)->rtindex;
126 /* This call to build_base_rel does the primary work... */
127 RelOptInfo *rel = build_base_rel(root, varno);
129 result = makeList1(rel);
131 else if (IsA(jtnode, FromExpr))
133 FromExpr *f = (FromExpr *) jtnode;
136 foreach(l, f->fromlist)
138 result = nconc(result,
139 add_missing_rels_to_query(root, lfirst(l)));
142 else if (IsA(jtnode, JoinExpr))
144 JoinExpr *j = (JoinExpr *) jtnode;
146 result = add_missing_rels_to_query(root, j->larg);
147 result = nconc(result,
148 add_missing_rels_to_query(root, j->rarg));
151 elog(ERROR, "add_missing_rels_to_query: unexpected node type %d",
157 /*****************************************************************************
161 *****************************************************************************/
165 * distribute_quals_to_rels
166 * Recursively scan the query's join tree for WHERE and JOIN/ON qual
167 * clauses, and add these to the appropriate RestrictInfo and JoinInfo
168 * lists belonging to base RelOptInfos. New base rel entries are created
169 * as needed. Also, base RelOptInfos are marked with outerjoinset
170 * information, to aid in proper positioning of qual clauses that appear
173 * NOTE: when dealing with inner joins, it is appropriate to let a qual clause
174 * be evaluated at the lowest level where all the variables it mentions are
175 * available. However, we cannot push a qual down into the nullable side(s)
176 * of an outer join since the qual might eliminate matching rows and cause a
177 * NULL row to be incorrectly emitted by the join. Therefore, rels appearing
178 * within the nullable side(s) of an outer join are marked with
179 * outerjoinset = list of Relids used at the outer join node.
180 * This list will be added to the list of rels referenced by quals using such
181 * a rel, thereby forcing them up the join tree to the right level.
183 * To ease the calculation of these values, distribute_quals_to_rels() returns
184 * the list of Relids involved in its own level of join. This is just an
185 * internal convenience; no outside callers pay attention to the result.
188 distribute_quals_to_rels(Query *root, Node *jtnode)
194 if (IsA(jtnode, RangeTblRef))
196 int varno = ((RangeTblRef *) jtnode)->rtindex;
198 /* No quals to deal with, just return correct result */
199 result = makeListi1(varno);
201 else if (IsA(jtnode, FromExpr))
203 FromExpr *f = (FromExpr *) jtnode;
208 * First, recurse to handle child joins.
210 * Note: we assume it's impossible to see same RT index from more
211 * than one subtree, so nconc() is OK rather than set_unioni().
213 foreach(l, f->fromlist)
215 result = nconc(result,
216 distribute_quals_to_rels(root, lfirst(l)));
220 * Now process the top-level quals. These are always marked as
221 * "pushed down", since they clearly didn't come from a JOIN expr.
223 foreach(qual, (List *) f->quals)
224 distribute_qual_to_rels(root, (Node *) lfirst(qual),
225 true, false, false, result);
227 else if (IsA(jtnode, JoinExpr))
229 JoinExpr *j = (JoinExpr *) jtnode;
236 * Order of operations here is subtle and critical. First we
237 * recurse to handle sub-JOINs. Their join quals will be placed
238 * without regard for whether this level is an outer join, which
239 * is correct. Then, if we are an outer join, we mark baserels
240 * contained within the nullable side(s) with our own rel list;
241 * this will restrict placement of subsequent quals using those
242 * rels, including our own quals and quals above us in the join
243 * tree. Finally we place our own join quals.
245 leftids = distribute_quals_to_rels(root, j->larg);
246 rightids = distribute_quals_to_rels(root, j->rarg);
248 result = nconc(listCopy(leftids), rightids);
254 /* Inner join adds no restrictions for quals */
257 mark_baserels_for_outer_join(root, rightids, result);
261 mark_baserels_for_outer_join(root, result, result);
265 mark_baserels_for_outer_join(root, leftids, result);
271 * This is where we fail if upper levels of planner
272 * haven't rewritten UNION JOIN as an Append ...
274 elog(ERROR, "UNION JOIN is not implemented yet");
278 "distribute_quals_to_rels: unsupported join type %d",
283 foreach(qual, (List *) j->quals)
284 distribute_qual_to_rels(root, (Node *) lfirst(qual),
285 false, isouterjoin, false, result);
288 elog(ERROR, "distribute_quals_to_rels: unexpected node type %d",
294 * mark_baserels_for_outer_join
295 * Mark all base rels listed in 'rels' as having the given outerjoinset.
298 mark_baserels_for_outer_join(Query *root, Relids rels, Relids outerrels)
304 int relno = lfirsti(relid);
305 RelOptInfo *rel = build_base_rel(root, relno);
308 * Since we do this bottom-up, any outer-rels previously marked
309 * should be within the new outer join set.
311 Assert(is_subseti(rel->outerjoinset, outerrels));
314 * Presently the executor cannot support FOR UPDATE marking of
315 * rels appearing on the nullable side of an outer join. (It's
316 * somewhat unclear what that would mean, anyway: what should we
317 * mark when a result row is generated from no element of the
318 * nullable relation?) So, complain if target rel is FOR UPDATE.
319 * It's sufficient to make this check once per rel, so do it only
320 * if rel wasn't already known nullable.
322 if (rel->outerjoinset == NIL)
324 if (intMember(relno, root->rowMarks))
325 elog(ERROR, "SELECT FOR UPDATE cannot be applied to the nullable side of an OUTER JOIN");
328 rel->outerjoinset = outerrels;
333 * distribute_qual_to_rels
334 * Add clause information to either the 'RestrictInfo' or 'JoinInfo' field
335 * (depending on whether the clause is a join) of each base relation
336 * mentioned in the clause. A RestrictInfo node is created and added to
337 * the appropriate list for each rel. Also, if the clause uses a
338 * mergejoinable operator and is not an outer-join qual, enter the left-
339 * and right-side expressions into the query's lists of equijoined vars.
341 * 'clause': the qual clause to be distributed
342 * 'ispusheddown': if TRUE, force the clause to be marked 'ispusheddown'
343 * (this indicates the clause came from a FromExpr, not a JoinExpr)
344 * 'isouterjoin': TRUE if the qual came from an OUTER JOIN's ON-clause
345 * 'isdeduced': TRUE if the qual came from implied-equality deduction
346 * 'qualscope': list of baserels the qual's syntactic scope covers
348 * 'qualscope' identifies what level of JOIN the qual came from. For a top
349 * level qual (WHERE qual), qualscope lists all baserel ids and in addition
350 * 'ispusheddown' will be TRUE.
353 distribute_qual_to_rels(Query *root, Node *clause,
359 RestrictInfo *restrictinfo = makeNode(RestrictInfo);
362 bool can_be_equijoin;
364 restrictinfo->clause = (Expr *) clause;
365 restrictinfo->subclauseindices = NIL;
366 restrictinfo->eval_cost = -1; /* not computed until needed */
367 restrictinfo->this_selec = -1; /* not computed until needed */
368 restrictinfo->mergejoinoperator = InvalidOid;
369 restrictinfo->left_sortop = InvalidOid;
370 restrictinfo->right_sortop = InvalidOid;
371 restrictinfo->left_pathkey = NIL; /* not computable yet */
372 restrictinfo->right_pathkey = NIL;
373 restrictinfo->hashjoinoperator = InvalidOid;
374 restrictinfo->left_bucketsize = -1; /* not computed until needed */
375 restrictinfo->right_bucketsize = -1;
378 * Retrieve all relids and vars contained within the clause.
380 clause_get_relids_vars(clause, &relids, &vars);
383 * Cross-check: clause should contain no relids not within its scope.
384 * Otherwise the parser messed up.
386 if (!is_subseti(relids, qualscope))
387 elog(ERROR, "JOIN qualification may not refer to other relations");
390 * If the clause is variable-free, we force it to be evaluated at its
391 * original syntactic level. Note that this should not happen for
392 * top-level clauses, because query_planner() special-cases them. But
393 * it will happen for variable-free JOIN/ON clauses. We don't have to
394 * be real smart about such a case, we just have to be correct.
400 * For an outer-join qual, pretend that the clause references all rels
401 * appearing within its syntactic scope, even if it really doesn't.
402 * This ensures that the clause will be evaluated exactly at the level
403 * of joining corresponding to the outer join.
405 * For a non-outer-join qual, we can evaluate the qual as soon as (1) we
406 * have all the rels it mentions, and (2) we are at or above any outer
407 * joins that can null any of these rels and are below the syntactic
408 * location of the given qual. To enforce the latter, scan the base
409 * rels listed in relids, and merge their outer-join lists into the
410 * clause's own reference list. At the time we are called, the
411 * outerjoinset list of each baserel will show exactly those outer
412 * joins that are below the qual in the join tree.
414 * If the qual came from implied-equality deduction, we can evaluate the
415 * qual at its natural semantic level.
420 Assert(sameseti(relids, qualscope));
421 can_be_equijoin = true;
423 else if (isouterjoin)
426 can_be_equijoin = false;
430 Relids newrelids = relids;
434 * We rely on set_unioni to be nondestructive of its input
437 can_be_equijoin = true;
438 foreach(relid, relids)
440 RelOptInfo *rel = build_base_rel(root, lfirsti(relid));
442 if (rel->outerjoinset &&
443 !is_subseti(rel->outerjoinset, relids))
445 newrelids = set_unioni(newrelids, rel->outerjoinset);
448 * Because application of the qual will be delayed by
449 * outer join, we mustn't assume its vars are equal
452 can_be_equijoin = false;
456 /* Should still be a subset of current scope ... */
457 Assert(is_subseti(relids, qualscope));
461 * Mark the qual as "pushed down" if it can be applied at a level
462 * below its original syntactic level. This allows us to distinguish
463 * original JOIN/ON quals from higher-level quals pushed down to the
464 * same joinrel. A qual originating from WHERE is always considered
467 restrictinfo->ispusheddown = ispusheddown || !sameseti(relids,
470 if (length(relids) == 1)
473 * There is only one relation participating in 'clause', so
474 * 'clause' is a restriction clause for that relation.
476 RelOptInfo *rel = build_base_rel(root, lfirsti(relids));
479 * Check for a "mergejoinable" clause even though it's not a join
480 * clause. This is so that we can recognize that "a.x = a.y"
481 * makes x and y eligible to be considered equal, even when they
482 * belong to the same rel. Without this, we would not recognize
483 * that "a.x = a.y AND a.x = b.z AND a.y = c.q" allows us to
484 * consider z and q equal after their rels are joined.
487 check_mergejoinable(restrictinfo);
490 * If the clause was deduced from implied equality, check to see
491 * whether it is redundant with restriction clauses we already
492 * have for this rel. Note we cannot apply this check to
493 * user-written clauses, since we haven't found the canonical
494 * pathkey sets yet while processing user clauses. (NB: no
495 * comparable check is done in the join-clause case; redundancy
496 * will be detected when the join clause is moved into a join
497 * rel's restriction list.)
500 !qual_is_redundant(root, restrictinfo, rel->baserestrictinfo))
502 /* Add clause to rel's restriction list */
503 rel->baserestrictinfo = lappend(rel->baserestrictinfo,
507 else if (relids != NIL)
510 * 'clause' is a join clause, since there is more than one rel in
511 * the relid list. Set additional RestrictInfo fields for
514 * We don't bother setting the merge/hashjoin info if we're not going
515 * to need it. We do want to know about mergejoinable ops in any
516 * potential equijoin clause (see later in this routine), and we
517 * ignore enable_mergejoin if isouterjoin is true, because
518 * mergejoin is the only implementation we have for full and right
521 if (enable_mergejoin || isouterjoin || can_be_equijoin)
522 check_mergejoinable(restrictinfo);
524 check_hashjoinable(restrictinfo);
527 * Add clause to the join lists of all the relevant relations.
529 add_join_info_to_rels(root, restrictinfo, relids);
532 * Add vars used in the join clause to targetlists of their
533 * relations, so that they will be emitted by the plan nodes that
534 * scan those relations (else they won't be available at the join
537 add_vars_to_targetlist(root, vars);
542 * 'clause' references no rels, and therefore we have no place to
543 * attach it. Shouldn't get here if callers are working properly.
545 elog(ERROR, "distribute_qual_to_rels: can't cope with variable-free clause");
549 * If the clause has a mergejoinable operator, and is not an
550 * outer-join qualification nor bubbled up due to an outer join, then
551 * the two sides represent equivalent PathKeyItems for path keys: any
552 * path that is sorted by one side will also be sorted by the other
553 * (as soon as the two rels are joined, that is). Record the key
554 * equivalence for future use. (We can skip this for a deduced
555 * clause, since the keys are already known equivalent in that case.)
557 if (can_be_equijoin && restrictinfo->mergejoinoperator != InvalidOid &&
559 add_equijoined_keys(root, restrictinfo);
563 * add_join_info_to_rels
564 * For every relation participating in a join clause, add 'restrictinfo' to
565 * the appropriate joininfo list (creating a new list and adding it to the
566 * appropriate rel node if necessary).
568 * 'restrictinfo' describes the join clause
569 * 'join_relids' is the list of relations participating in the join clause
572 add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
577 /* For every relid, find the joininfo, and add the proper join entries */
578 foreach(join_relid, join_relids)
580 int cur_relid = lfirsti(join_relid);
581 Relids unjoined_relids = NIL;
585 /* Get the relids not equal to the current relid */
586 foreach(otherrel, join_relids)
588 if (lfirsti(otherrel) != cur_relid)
589 unjoined_relids = lappendi(unjoined_relids, lfirsti(otherrel));
593 * Find or make the joininfo node for this combination of rels,
594 * and add the restrictinfo node to it.
596 joininfo = find_joininfo_node(build_base_rel(root, cur_relid),
598 joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
604 * process_implied_equality
605 * Check to see whether we already have a restrictinfo item that says
606 * item1 = item2, and create one if not. This is a consequence of
607 * transitivity of mergejoin equality: if we have mergejoinable
608 * clauses A = B and B = C, we can deduce A = C (where = is an
609 * appropriate mergejoinable operator).
612 process_implied_equality(Query *root, Node *item1, Node *item2,
613 Oid sortop1, Oid sortop2)
622 Operator eq_operator;
623 Form_pg_operator pgopform;
627 * Currently, since check_mergejoinable only accepts Var = Var
628 * clauses, we should only see Var nodes here. Would have to work a
629 * little harder to locate the right rel(s) if more-general mergejoin
630 * clauses were accepted.
632 Assert(IsA(item1, Var));
633 irel1 = ((Var *) item1)->varno;
634 Assert(IsA(item2, Var));
635 irel2 = ((Var *) item2)->varno;
638 * If both vars belong to same rel, we need to look at that rel's
639 * baserestrictinfo list. If different rels, each will have a
640 * joininfo node for the other, and we can scan either list.
642 * All baserel entries should already exist at this point, so use
643 * find_base_rel not build_base_rel.
645 rel1 = find_base_rel(root, irel1);
647 restrictlist = rel1->baserestrictinfo;
650 JoinInfo *joininfo = find_joininfo_node(rel1,
653 restrictlist = joininfo->jinfo_restrictinfo;
657 * Scan to see if equality is already known.
659 foreach(itm, restrictlist)
661 RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(itm);
665 if (restrictinfo->mergejoinoperator == InvalidOid)
666 continue; /* ignore non-mergejoinable clauses */
667 /* We now know the restrictinfo clause is a binary opclause */
668 left = (Node *) get_leftop(restrictinfo->clause);
669 right = (Node *) get_rightop(restrictinfo->clause);
670 if ((equal(item1, left) && equal(item2, right)) ||
671 (equal(item2, left) && equal(item1, right)))
672 return; /* found a matching clause */
676 * This equality is new information, so construct a clause
677 * representing it to add to the query data structures.
679 ltype = exprType(item1);
680 rtype = exprType(item2);
681 eq_operator = compatible_oper("=", ltype, rtype, true);
682 if (!HeapTupleIsValid(eq_operator))
685 * Would it be safe to just not add the equality to the query if
686 * we have no suitable equality operator for the combination of
687 * datatypes? NO, because sortkey selection may screw up anyway.
689 elog(ERROR, "Unable to identify an equality operator for types '%s' and '%s'",
690 typeidTypeName(ltype), typeidTypeName(rtype));
692 pgopform = (Form_pg_operator) GETSTRUCT(eq_operator);
695 * Let's just make sure this appears to be a compatible operator.
697 if (pgopform->oprlsortop != sortop1 ||
698 pgopform->oprrsortop != sortop2 ||
699 pgopform->oprresult != BOOLOID)
700 elog(ERROR, "Equality operator for types '%s' and '%s' should be mergejoinable, but isn't",
701 typeidTypeName(ltype), typeidTypeName(rtype));
703 clause = makeNode(Expr);
704 clause->typeOid = BOOLOID;
705 clause->opType = OP_EXPR;
706 clause->oper = (Node *) makeOper(oprid(eq_operator), /* opno */
707 InvalidOid, /* opid */
708 BOOLOID); /* operator result type */
709 clause->args = makeList2(item1, item2);
711 ReleaseSysCache(eq_operator);
714 * Note: we mark the qual "pushed down" to ensure that it can never be
715 * taken for an original JOIN/ON clause.
717 distribute_qual_to_rels(root, (Node *) clause,
719 pull_varnos((Node *) clause));
724 * Detect whether an implied-equality qual that turns out to be a
725 * restriction clause for a single base relation is redundant with
726 * already-known restriction clauses for that rel. This occurs with,
728 * SELECT * FROM tab WHERE f1 = f2 AND f2 = f3;
729 * We need to suppress the redundant condition to avoid computing
730 * too-small selectivity, not to mention wasting time at execution.
733 qual_is_redundant(Query *root,
734 RestrictInfo *restrictinfo,
745 * Set cached pathkeys. NB: it is okay to do this now because this
746 * routine is only invoked while we are generating implied equalities.
747 * Therefore, the equi_key_list is already complete and so we can
748 * correctly determine canonical pathkeys.
750 cache_mergeclause_pathkeys(root, restrictinfo);
751 /* If different, say "not redundant" (should never happen) */
752 if (restrictinfo->left_pathkey != restrictinfo->right_pathkey)
756 * Scan existing quals to find those referencing same pathkeys.
757 * Usually there will be few, if any, so build a list of just the
761 foreach(olditem, restrictlist)
763 RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
765 if (oldrinfo->mergejoinoperator != InvalidOid)
767 cache_mergeclause_pathkeys(root, oldrinfo);
768 if (restrictinfo->left_pathkey == oldrinfo->left_pathkey &&
769 restrictinfo->right_pathkey == oldrinfo->right_pathkey)
770 oldquals = lcons(oldrinfo, oldquals);
777 * Now, we want to develop a list of Vars that are known equal to the
778 * left side of the new qual. We traverse the old-quals list
779 * repeatedly to transitively expand the Vars list. If at any point
780 * we find we can reach the right-side Var of the new qual, we are
781 * done. We give up when we can't expand the equalvars list any more.
783 newleft = (Node *) get_leftop(restrictinfo->clause);
784 newright = (Node *) get_rightop(restrictinfo->clause);
785 equalvars = makeList1(newleft);
789 foreach(olditem, oldquals)
791 RestrictInfo *oldrinfo = (RestrictInfo *) lfirst(olditem);
792 Node *oldleft = (Node *) get_leftop(oldrinfo->clause);
793 Node *oldright = (Node *) get_rightop(oldrinfo->clause);
796 if (member(oldleft, equalvars))
798 else if (member(oldright, equalvars))
802 if (equal(newguy, newright))
803 return true; /* we proved new clause is redundant */
804 equalvars = lcons(newguy, equalvars);
808 * Remove this qual from list, since we don't need it anymore.
809 * Note this doesn't break the foreach() loop, since lremove
810 * doesn't touch the next-link of the removed cons cell.
812 oldquals = lremove(oldrinfo, oldquals);
816 return false; /* it's not redundant */
820 /*****************************************************************************
822 * CHECKS FOR MERGEJOINABLE AND HASHJOINABLE CLAUSES
824 *****************************************************************************/
827 * check_mergejoinable
828 * If the restrictinfo's clause is mergejoinable, set the mergejoin
829 * info fields in the restrictinfo.
831 * Currently, we support mergejoin for binary opclauses where
832 * both operands are simple Vars and the operator is a mergejoinable
836 check_mergejoinable(RestrictInfo *restrictinfo)
838 Expr *clause = restrictinfo->clause;
845 if (!is_opclause((Node *) clause))
848 left = get_leftop(clause);
849 right = get_rightop(clause);
851 /* caution: is_opclause accepts more than I do, so check it */
853 return; /* unary opclauses need not apply */
854 if (!IsA(left, Var) ||!IsA(right, Var))
857 opno = ((Oper *) clause->oper)->opno;
859 if (op_mergejoinable(opno,
865 restrictinfo->mergejoinoperator = opno;
866 restrictinfo->left_sortop = leftOp;
867 restrictinfo->right_sortop = rightOp;
873 * If the restrictinfo's clause is hashjoinable, set the hashjoin
874 * info fields in the restrictinfo.
876 * Currently, we support hashjoin for binary opclauses where
877 * both operands are simple Vars and the operator is a hashjoinable
881 check_hashjoinable(RestrictInfo *restrictinfo)
883 Expr *clause = restrictinfo->clause;
888 if (!is_opclause((Node *) clause))
891 left = get_leftop(clause);
892 right = get_rightop(clause);
894 /* caution: is_opclause accepts more than I do, so check it */
896 return; /* unary opclauses need not apply */
897 if (!IsA(left, Var) ||!IsA(right, Var))
900 opno = ((Oper *) clause->oper)->opno;
902 if (op_hashjoinable(opno,
905 restrictinfo->hashjoinoperator = opno;