From a635c08fa10fe545d723bcec6eb73bfdca07e2c0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 30 Jan 2007 01:33:36 +0000 Subject: [PATCH] Add support for cross-type hashing in hash index searches and hash joins. 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. --- src/backend/access/hash/hashsearch.c | 26 +++- src/backend/access/hash/hashutil.c | 31 ++++- src/backend/executor/execGrouping.c | 13 +- src/backend/executor/nodeHash.c | 28 ++-- src/backend/executor/nodeHashjoin.c | 3 +- src/backend/executor/nodeSubplan.c | 15 ++- src/backend/optimizer/plan/createplan.c | 13 +- src/backend/utils/cache/lsyscache.c | 168 ++++++++++++++++++------ src/include/access/hash.h | 3 +- src/include/executor/hashjoin.h | 11 +- src/include/executor/nodeHash.h | 3 +- src/include/utils/lsyscache.h | 8 +- 12 files changed, 240 insertions(+), 82 deletions(-) diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c index 5582c036417..52e867e3605 100644 --- a/src/backend/access/hash/hashsearch.c +++ b/src/backend/access/hash/hashsearch.c @@ -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 diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index eadbe7aabe5..afa7c09a53d 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -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. */ diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index f84c1120db2..08391bcc459 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -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]); } } diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index dffe8cb0d30..88d9360e422 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -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; } diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index b03086fb364..4960e2d8c69 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -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)) { diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index c2d4dbea37a..c5c35697c0b 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -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++; } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 36f22c881c8..fdaed3d472e 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -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; diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index c449ad6e742..8946cb73151 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -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; + } } } diff --git a/src/include/access/hash.h b/src/include/access/hash.h index 40c86b74552..baed9fdb4b7 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -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); diff --git a/src/include/executor/hashjoin.h b/src/include/executor/hashjoin.h index ba086407679..19cfb1c473b 100644 --- a/src/include/executor/hashjoin.h +++ b/src/include/executor/hashjoin.h @@ -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 */ diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h index bf7292e8156..7c210bf99a0 100644 --- a/src/include/executor/nodeHash.h +++ b/src/include/executor/nodeHash.h @@ -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, diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 28bb03eca64..8e9bfaa1edc 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -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);