Add support for cross-type hashing in hash index searches and hash joins.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 Jan 2007 01:33:36 +0000 (01:33 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 Jan 2007 01:33:36 +0000 (01:33 +0000)
Hashing for aggregation purposes still needs work, so it's not time to
mark any cross-type operators as hashable for general use, but these cases
work if the operators are so marked by hand in the system catalogs.

12 files changed:
src/backend/access/hash/hashsearch.c
src/backend/access/hash/hashutil.c
src/backend/executor/execGrouping.c
src/backend/executor/nodeHash.c
src/backend/executor/nodeHashjoin.c
src/backend/executor/nodeSubplan.c
src/backend/optimizer/plan/createplan.c
src/backend/utils/cache/lsyscache.c
src/include/access/hash.h
src/include/executor/hashjoin.h
src/include/executor/nodeHash.h
src/include/utils/lsyscache.h

index 5582c03641737ba549198f6cd59f022bf98fb77b..52e867e36057f98dffce79f1cba81ebca9944c19 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.47 2007/01/20 18:43:35 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.48 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -115,6 +115,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
 {
        Relation        rel = scan->indexRelation;
        HashScanOpaque so = (HashScanOpaque) scan->opaque;
+       ScanKey         cur;
        uint32          hashkey;
        Bucket          bucket;
        BlockNumber blkno;
@@ -143,18 +144,37 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("hash indexes do not support whole-index scans")));
 
+       /* There may be more than one index qual, but we hash only the first */
+       cur = &scan->keyData[0];
+
+       /* We support only single-column hash indexes */
+       Assert(cur->sk_attno == 1);
+       /* And there's only one operator strategy, too */
+       Assert(cur->sk_strategy == HTEqualStrategyNumber);
+
        /*
         * If the constant in the index qual is NULL, assume it cannot match any
         * items in the index.
         */
-       if (scan->keyData[0].sk_flags & SK_ISNULL)
+       if (cur->sk_flags & SK_ISNULL)
                return false;
 
        /*
         * Okay to compute the hash key.  We want to do this before acquiring any
         * locks, in case a user-defined hash function happens to be slow.
+        *
+        * If scankey operator is not a cross-type comparison, we can use the
+        * cached hash function; otherwise gotta look it up in the catalogs.
+        *
+        * We support the convention that sk_subtype == InvalidOid means the
+        * opclass input type; this is a hack to simplify life for ScanKeyInit().
         */
-       hashkey = _hash_datum2hashkey(rel, scan->keyData[0].sk_argument);
+       if (cur->sk_subtype == rel->rd_opcintype[0] ||
+               cur->sk_subtype == InvalidOid)
+               hashkey = _hash_datum2hashkey(rel, cur->sk_argument);
+       else
+               hashkey = _hash_datum2hashkey_type(rel, cur->sk_argument,
+                                                                                  cur->sk_subtype);
 
        /*
         * Acquire shared split lock so we can compute the target bucket safely
index eadbe7aabe54d3f2dc00c91ff02a2e22cbdaf623..afa7c09a53df4aca111dd03b6e2a69bfd3eb6ca8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.50 2007/01/05 22:19:22 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.51 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,6 +18,7 @@
 #include "access/hash.h"
 #include "access/reloptions.h"
 #include "executor/execdebug.h"
+#include "utils/lsyscache.h"
 
 
 /*
@@ -63,6 +64,9 @@ _hash_checkqual(IndexScanDesc scan, IndexTuple itup)
 
 /*
  * _hash_datum2hashkey -- given a Datum, call the index's hash procedure
+ *
+ * The Datum is assumed to be of the index's column type, so we can use the
+ * "primary" hash procedure that's tracked for us by the generic index code.
  */
 uint32
 _hash_datum2hashkey(Relation rel, Datum key)
@@ -75,6 +79,31 @@ _hash_datum2hashkey(Relation rel, Datum key)
        return DatumGetUInt32(FunctionCall1(procinfo, key));
 }
 
+/*
+ * _hash_datum2hashkey_type -- given a Datum of a specified type,
+ *                     hash it in a fashion compatible with this index
+ *
+ * This is much more expensive than _hash_datum2hashkey, so use it only in
+ * cross-type situations.
+ */
+uint32
+_hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype)
+{
+       RegProcedure hash_proc;
+
+       /* XXX assumes index has only one attribute */
+       hash_proc = get_opfamily_proc(rel->rd_opfamily[0],
+                                                                 keytype,
+                                                                 keytype,
+                                                                 HASHPROC);
+       if (!RegProcedureIsValid(hash_proc))
+               elog(ERROR, "missing support function %d(%u,%u) for index \"%s\"",
+                        HASHPROC, keytype, keytype,
+                        RelationGetRelationName(rel));
+
+       return DatumGetUInt32(OidFunctionCall1(hash_proc, key));
+}
+
 /*
  * _hash_hashkey2bucket -- determine which bucket the hashkey maps to.
  */
index f84c1120db23683ddcf73644cb2551a1b7c95205..08391bcc45946937033a48f49711dd95e328c0e6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execGrouping.c,v 1.23 2007/01/10 18:06:02 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execGrouping.c,v 1.24 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -224,15 +224,18 @@ execTuplesHashPrepare(int numCols,
        {
                Oid                     eq_opr = eqOperators[i];
                Oid                     eq_function;
-               Oid                     hash_function;
+               Oid                     left_hash_function;
+               Oid                     right_hash_function;
 
                eq_function = get_opcode(eq_opr);
-               hash_function = get_op_hash_function(eq_opr);
-               if (!OidIsValid(hash_function)) /* should not happen */
+               if (!get_op_hash_functions(eq_opr,
+                                                                  &left_hash_function, &right_hash_function))
                        elog(ERROR, "could not find hash function for hash operator %u",
                                 eq_opr);
+               /* For the moment, we're not supporting cross-type cases here */
+               Assert(left_hash_function == right_hash_function);
                fmgr_info(eq_function, &(*eqFunctions)[i]);
-               fmgr_info(hash_function, &(*hashFunctions)[i]);
+               fmgr_info(right_hash_function, &(*hashFunctions)[i]);
        }
 }
 
index dffe8cb0d30bd786eb5a5d169e3c412d5e5685f3..88d9360e422ea41ff4a31b735ea29d06189ee4db 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.109 2007/01/28 23:21:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeHash.c,v 1.110 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -94,7 +94,7 @@ MultiExecHash(HashState *node)
                        break;
                /* We have to compute the hash value */
                econtext->ecxt_innertuple = slot;
-               if (ExecHashGetHashValue(hashtable, econtext, hashkeys, false,
+               if (ExecHashGetHashValue(hashtable, econtext, hashkeys, false, false,
                                                                 &hashvalue))
                {
                        ExecHashTableInsert(hashtable, slot, hashvalue);
@@ -267,19 +267,23 @@ ExecHashTableCreate(Hash *node, List *hashOperators)
         * Also remember whether the join operators are strict.
         */
        nkeys = list_length(hashOperators);
-       hashtable->hashfunctions = (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
+       hashtable->outer_hashfunctions =
+               (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
+       hashtable->inner_hashfunctions =
+               (FmgrInfo *) palloc(nkeys * sizeof(FmgrInfo));
        hashtable->hashStrict = (bool *) palloc(nkeys * sizeof(bool));
        i = 0;
        foreach(ho, hashOperators)
        {
                Oid                     hashop = lfirst_oid(ho);
-               Oid                     hashfn;
+               Oid                     left_hashfn;
+               Oid                     right_hashfn;
 
-               hashfn = get_op_hash_function(hashop);
-               if (!OidIsValid(hashfn))
+               if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
                        elog(ERROR, "could not find hash function for hash operator %u",
                                 hashop);
-               fmgr_info(hashfn, &hashtable->hashfunctions[i]);
+               fmgr_info(left_hashfn, &hashtable->outer_hashfunctions[i]);
+               fmgr_info(right_hashfn, &hashtable->inner_hashfunctions[i]);
                hashtable->hashStrict[i] = op_strict(hashop);
                i++;
        }
@@ -674,10 +678,12 @@ bool
 ExecHashGetHashValue(HashJoinTable hashtable,
                                         ExprContext *econtext,
                                         List *hashkeys,
+                                        bool outer_tuple,
                                         bool keep_nulls,
                                         uint32 *hashvalue)
 {
        uint32          hashkey = 0;
+       FmgrInfo   *hashfunctions;
        ListCell   *hk;
        int                     i = 0;
        MemoryContext oldContext;
@@ -690,6 +696,11 @@ ExecHashGetHashValue(HashJoinTable hashtable,
 
        oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 
+       if (outer_tuple)
+               hashfunctions = hashtable->outer_hashfunctions;
+       else
+               hashfunctions = hashtable->inner_hashfunctions;
+
        foreach(hk, hashkeys)
        {
                ExprState  *keyexpr = (ExprState *) lfirst(hk);
@@ -728,8 +739,7 @@ ExecHashGetHashValue(HashJoinTable hashtable,
                        /* Compute the hash function */
                        uint32          hkey;
 
-                       hkey = DatumGetUInt32(FunctionCall1(&hashtable->hashfunctions[i],
-                                                                                               keyval));
+                       hkey = DatumGetUInt32(FunctionCall1(&hashfunctions[i], keyval));
                        hashkey ^= hkey;
                }
 
index b03086fb364a17356873cdb2652ce47bce506fd8..4960e2d8c697e5a7f86b69dec5e42aec76c9342b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.87 2007/01/28 23:21:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeHashjoin.c,v 1.88 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -569,6 +569,7 @@ ExecHashJoinOuterGetTuple(PlanState *outerNode,
                        econtext->ecxt_outertuple = slot;
                        if (ExecHashGetHashValue(hashtable, econtext,
                                                                         hjstate->hj_OuterHashKeys,
+                                                                        true, /* outer tuple */
                                                                         (hjstate->js.jointype == JOIN_LEFT),
                                                                         hashvalue))
                        {
index c2d4dbea37a926465c002afaa4bc68ffcb8a267f..c5c35697c0b08ab6a6dc22d78e116c38e8a72e6c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.82 2007/01/05 22:19:28 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.83 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -792,7 +792,8 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
                        Expr       *expr;
                        TargetEntry *tle;
                        GenericExprState *tlestate;
-                       Oid                     hashfn;
+                       Oid                     left_hashfn;
+                       Oid                     right_hashfn;
 
                        Assert(IsA(fstate, FuncExprState));
                        Assert(IsA(opexpr, OpExpr));
@@ -830,12 +831,14 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
                        fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]);
                        node->eqfunctions[i - 1].fn_expr = (Node *) opexpr;
 
-                       /* Lookup the associated hash function */
-                       hashfn = get_op_hash_function(opexpr->opno);
-                       if (!OidIsValid(hashfn))
+                       /* Lookup the associated hash functions */
+                       if (!get_op_hash_functions(opexpr->opno,
+                                                                          &left_hashfn, &right_hashfn))
                                elog(ERROR, "could not find hash function for hash operator %u",
                                         opexpr->opno);
-                       fmgr_info(hashfn, &node->hashfunctions[i - 1]);
+                       /* For the moment, not supporting cross-type cases */
+                       Assert(left_hashfn == right_hashfn);
+                       fmgr_info(right_hashfn, &node->hashfunctions[i - 1]);
 
                        i++;
                }
index 36f22c881c86779f9457e4395589119219aae9ae..fdaed3d472ed3908aafe8b1cf5f4e4db3abae25e 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.223 2007/01/22 01:35:20 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.224 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -716,10 +716,10 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
                numGroups = (long) Min(best_path->rows, (double) LONG_MAX);
 
                /*
-                * Get the (presumed hashable) equality operators for the Agg node
-                * to use.  Normally these are the same as the IN clause operators,
-                * but if those are cross-type operators then the equality operators
-                * are the ones for the IN clause operators' RHS datatype.
+                * Get the hashable equality operators for the Agg node to use.
+                * Normally these are the same as the IN clause operators, but if
+                * those are cross-type operators then the equality operators are
+                * the ones for the IN clause operators' RHS datatype.
                 */
                groupOperators = (Oid *) palloc(numGroupCols * sizeof(Oid));
                groupColPos = 0;
@@ -728,8 +728,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
                        Oid                     in_oper = lfirst_oid(l);
                        Oid                     eq_oper;
 
-                       eq_oper = get_compatible_hash_operator(in_oper, false);
-                       if (!OidIsValid(eq_oper))               /* shouldn't happen */
+                       if (!get_compatible_hash_operators(in_oper, NULL, &eq_oper))
                                elog(ERROR, "could not find compatible hash operator for operator %u",
                                         in_oper);
                        groupOperators[groupColPos++] = eq_oper;
index c449ad6e74220b93dbabfb0acff342a379464f19..8946cb73151fcedab2f7741f0a7a9f9f825b5280 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.146 2007/01/22 01:35:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.147 2007/01/30 01:33:36 tgl Exp $
  *
  * NOTES
  *       Eventually, the index information should go through here, too.
@@ -389,23 +389,34 @@ get_mergejoin_opfamilies(Oid opno)
 }
 
 /*
- * get_compatible_hash_operator
- *             Get the OID of a hash equality operator compatible with the given
- *             operator, but operating on its LHS or RHS datatype as specified.
+ * get_compatible_hash_operators
+ *             Get the OID(s) of hash equality operator(s) compatible with the given
+ *             operator, but operating on its LHS and/or RHS datatype.
  *
- * If the given operator is not cross-type, the result should be the same
- * operator, but in cross-type situations it is different.
+ * An operator for the LHS type is sought and returned into *lhs_opno if
+ * lhs_opno isn't NULL.  Similarly, an operator for the RHS type is sought
+ * and returned into *rhs_opno if rhs_opno isn't NULL.
  *
- * Returns InvalidOid if no compatible operator can be found.  (This indicates
- * that the operator should not have been marked oprcanhash.)
+ * If the given operator is not cross-type, the results should be the same
+ * operator, but in cross-type situations they will be different.
+ *
+ * Returns true if able to find the requested operator(s), false if not.
+ * (This indicates that the operator should not have been marked oprcanhash.)
  */
-Oid
-get_compatible_hash_operator(Oid opno, bool use_lhs_type)
+bool
+get_compatible_hash_operators(Oid opno,
+                                                         Oid *lhs_opno, Oid *rhs_opno)
 {
-       Oid                     result = InvalidOid;
+       bool            result = false;
        CatCList   *catlist;
        int                     i;
 
+       /* Ensure output args are initialized on failure */
+       if (lhs_opno)
+               *lhs_opno = InvalidOid;
+       if (rhs_opno)
+               *rhs_opno = InvalidOid;
+
        /*
         * Search pg_amop to see if the target operator is registered as the "="
         * operator of any hash opfamily.  If the operator is registered in
@@ -423,22 +434,53 @@ get_compatible_hash_operator(Oid opno, bool use_lhs_type)
                if (aform->amopmethod == HASH_AM_OID &&
                        aform->amopstrategy == HTEqualStrategyNumber)
                {
-                       /* Found a suitable opfamily, get matching single-type operator */
-                       Oid             typid;
-
                        /* No extra lookup needed if given operator is single-type */
                        if (aform->amoplefttype == aform->amoprighttype)
                        {
-                               result = opno;
+                               if (lhs_opno)
+                                       *lhs_opno = opno;
+                               if (rhs_opno)
+                                       *rhs_opno = opno;
+                               result = true;
                                break;
                        }
-                       typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
-                       result = get_opfamily_member(aform->amopfamily,
-                                                                                typid, typid,
-                                                                                HTEqualStrategyNumber);
-                       if (OidIsValid(result))
+                       /*
+                        * Get the matching single-type operator(s).  Failure probably
+                        * shouldn't happen --- it implies a bogus opfamily --- but
+                        * continue looking if so.
+                        */
+                       if (lhs_opno)
+                       {
+                               *lhs_opno = get_opfamily_member(aform->amopfamily,
+                                                                                               aform->amoplefttype,
+                                                                                               aform->amoplefttype,
+                                                                                               HTEqualStrategyNumber);
+                               if (!OidIsValid(*lhs_opno))
+                                       continue;
+                               /* Matching LHS found, done if caller doesn't want RHS */
+                               if (!rhs_opno)
+                               {
+                                       result = true;
+                                       break;
+                               }
+                       }
+                       if (rhs_opno)
+                       {
+                               *rhs_opno = get_opfamily_member(aform->amopfamily,
+                                                                                               aform->amoprighttype,
+                                                                                               aform->amoprighttype,
+                                                                                               HTEqualStrategyNumber);
+                               if (!OidIsValid(*rhs_opno))
+                               {
+                                       /* Forget any LHS operator from this opfamily */
+                                       if (lhs_opno)
+                                               *lhs_opno = InvalidOid;
+                                       continue;
+                               }
+                               /* Matching RHS found, so done */
+                               result = true;
                                break;
-                       /* failure probably shouldn't happen, but keep looking if so */
+                       }
                }
        }
 
@@ -448,28 +490,38 @@ get_compatible_hash_operator(Oid opno, bool use_lhs_type)
 }
 
 /*
- * get_op_hash_function
- *             Get the OID of the datatype-specific hash function associated with
- *             a hashable equality operator.
+ * get_op_hash_functions
+ *             Get the OID(s) of hash support function(s) compatible with the given
+ *             operator, operating on its LHS and/or RHS datatype as required.
  *
- * XXX API needs to be generalized for the case of different left and right
- * datatypes.
+ * A function for the LHS type is sought and returned into *lhs_procno if
+ * lhs_procno isn't NULL.  Similarly, a function for the RHS type is sought
+ * and returned into *rhs_procno if rhs_procno isn't NULL.
  *
- * Returns InvalidOid if no hash function can be found.  (This indicates
- * that the operator should not have been marked oprcanhash.)
+ * If the given operator is not cross-type, the results should be the same
+ * function, but in cross-type situations they will be different.
+ *
+ * Returns true if able to find the requested function(s), false if not.
+ * (This indicates that the operator should not have been marked oprcanhash.)
  */
-Oid
-get_op_hash_function(Oid opno)
+bool
+get_op_hash_functions(Oid opno,
+                                         RegProcedure *lhs_procno, RegProcedure *rhs_procno)
 {
-       Oid                     result = InvalidOid;
+       bool            result = false;
        CatCList   *catlist;
        int                     i;
 
+       /* Ensure output args are initialized on failure */
+       if (lhs_procno)
+               *lhs_procno = InvalidOid;
+       if (rhs_procno)
+               *rhs_procno = InvalidOid;
+
        /*
         * Search pg_amop to see if the target operator is registered as the "="
         * operator of any hash opfamily.  If the operator is registered in
-        * multiple opfamilies, assume we can use the associated hash function from
-        * any one.
+        * multiple opfamilies, assume we can use any one.
         */
        catlist = SearchSysCacheList(AMOPOPID, 1,
                                                                 ObjectIdGetDatum(opno),
@@ -483,12 +535,50 @@ get_op_hash_function(Oid opno)
                if (aform->amopmethod == HASH_AM_OID &&
                        aform->amopstrategy == HTEqualStrategyNumber)
                {
-                       /* Found a suitable opfamily, get matching hash support function */
-                       result = get_opfamily_proc(aform->amopfamily,
-                                                                          aform->amoplefttype,
-                                                                          aform->amoprighttype,
-                                                                          HASHPROC);
-                       break;
+                       /*
+                        * Get the matching support function(s).  Failure probably
+                        * shouldn't happen --- it implies a bogus opfamily --- but
+                        * continue looking if so.
+                        */
+                       if (lhs_procno)
+                       {
+                               *lhs_procno = get_opfamily_proc(aform->amopfamily,
+                                                                                               aform->amoplefttype,
+                                                                                               aform->amoplefttype,
+                                                                                               HASHPROC);
+                               if (!OidIsValid(*lhs_procno))
+                                       continue;
+                               /* Matching LHS found, done if caller doesn't want RHS */
+                               if (!rhs_procno)
+                               {
+                                       result = true;
+                                       break;
+                               }
+                               /* Only one lookup needed if given operator is single-type */
+                               if (aform->amoplefttype == aform->amoprighttype)
+                               {
+                                       *rhs_procno = *lhs_procno;
+                                       result = true;
+                                       break;
+                               }
+                       }
+                       if (rhs_procno)
+                       {
+                               *rhs_procno = get_opfamily_proc(aform->amopfamily,
+                                                                                               aform->amoprighttype,
+                                                                                               aform->amoprighttype,
+                                                                                               HASHPROC);
+                               if (!OidIsValid(*rhs_procno))
+                               {
+                                       /* Forget any LHS function from this opfamily */
+                                       if (lhs_procno)
+                                               *lhs_procno = InvalidOid;
+                                       continue;
+                               }
+                               /* Matching RHS found, so done */
+                               result = true;
+                               break;
+                       }
                }
        }
 
index 40c86b745520247607b2bd0240a57a62c447551e..baed9fdb4b74bb270a9f7cb8a8acfbe76bd00fe8 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.75 2007/01/20 18:43:35 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/access/hash.h,v 1.76 2007/01/30 01:33:36 tgl Exp $
  *
  * NOTES
  *             modeled after Margo Seltzer's hash implementation for unix.
@@ -308,6 +308,7 @@ extern bool _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir);
 /* hashutil.c */
 extern bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup);
 extern uint32 _hash_datum2hashkey(Relation rel, Datum key);
+extern uint32 _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype);
 extern Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
                                         uint32 highmask, uint32 lowmask);
 extern uint32 _hash_log2(uint32 num);
index ba08640767998ca1a11c2682d8e5d9ac820cb37a..19cfb1c473b90eaf90e52de9f3967b2a123ac3cd 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/hashjoin.h,v 1.43 2007/01/28 23:21:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/hashjoin.h,v 1.44 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -102,12 +102,11 @@ typedef struct HashJoinTableData
 
        /*
         * Info about the datatype-specific hash functions for the datatypes being
-        * hashed.      We assume that the inner and outer sides of each hashclause
-        * are the same type, or at least share the same hash function. This is an
-        * array of the same length as the number of hash keys.
+        * hashed. These are arrays of the same length as the number of hash join
+        * clauses (hash keys).
         */
-       FmgrInfo   *hashfunctions;      /* lookup data for hash functions */
-
+       FmgrInfo   *outer_hashfunctions;        /* lookup data for hash functions */
+       FmgrInfo   *inner_hashfunctions;        /* lookup data for hash functions */
        bool       *hashStrict;         /* is each hash join operator strict? */
 
        Size            spaceUsed;              /* memory space currently used by tuples */
index bf7292e8156e89233abb892a0aa23ffe50ebdb21..7c210bf99a0adc566233117268733ac86481c9c5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.43 2007/01/28 23:21:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/nodeHash.h,v 1.44 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,6 +31,7 @@ extern void ExecHashTableInsert(HashJoinTable hashtable,
 extern bool ExecHashGetHashValue(HashJoinTable hashtable,
                                         ExprContext *econtext,
                                         List *hashkeys,
+                                        bool outer_tuple,
                                         bool keep_nulls,
                                         uint32 *hashvalue);
 extern void ExecHashGetBucketAndBatch(HashJoinTable hashtable,
index 28bb03eca64bdc3b0410a01f05add897b0ab50fe..8e9bfaa1edc5df55b381bfefd9550b83341fe5e5 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.115 2007/01/22 01:35:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.116 2007/01/30 01:33:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,8 +42,10 @@ extern bool get_compare_function_for_ordering_op(Oid opno,
 extern Oid     get_equality_op_for_ordering_op(Oid opno);
 extern Oid     get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type);
 extern List *get_mergejoin_opfamilies(Oid opno);
-extern Oid     get_compatible_hash_operator(Oid opno, bool use_lhs_type);
-extern Oid     get_op_hash_function(Oid opno);
+extern bool get_compatible_hash_operators(Oid opno,
+                                                                                 Oid *lhs_opno, Oid *rhs_opno);
+extern bool get_op_hash_functions(Oid opno,
+                                         RegProcedure *lhs_procno, RegProcedure *rhs_procno);
 extern void get_op_btree_interpretation(Oid opno,
                                                        List **opfamilies, List **opstrats);
 extern bool ops_in_same_btree_opfamily(Oid opno1, Oid opno2);