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.
This commit is contained in:
parent
e8cd6f14a2
commit
a635c08fa1
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
Relation rel = scan->indexRelation;
|
||||||
HashScanOpaque so = (HashScanOpaque) scan->opaque;
|
HashScanOpaque so = (HashScanOpaque) scan->opaque;
|
||||||
|
ScanKey cur;
|
||||||
uint32 hashkey;
|
uint32 hashkey;
|
||||||
Bucket bucket;
|
Bucket bucket;
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
@ -143,18 +144,37 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
|
|||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("hash indexes do not support whole-index scans")));
|
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
|
* If the constant in the index qual is NULL, assume it cannot match any
|
||||||
* items in the index.
|
* items in the index.
|
||||||
*/
|
*/
|
||||||
if (scan->keyData[0].sk_flags & SK_ISNULL)
|
if (cur->sk_flags & SK_ISNULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay to compute the hash key. We want to do this before acquiring any
|
* 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.
|
* 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
|
* Acquire shared split lock so we can compute the target bucket safely
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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/hash.h"
|
||||||
#include "access/reloptions.h"
|
#include "access/reloptions.h"
|
||||||
#include "executor/execdebug.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
|
* _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
|
uint32
|
||||||
_hash_datum2hashkey(Relation rel, Datum key)
|
_hash_datum2hashkey(Relation rel, Datum key)
|
||||||
@ -75,6 +79,31 @@ _hash_datum2hashkey(Relation rel, Datum key)
|
|||||||
return DatumGetUInt32(FunctionCall1(procinfo, 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.
|
* _hash_hashkey2bucket -- determine which bucket the hashkey maps to.
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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_opr = eqOperators[i];
|
||||||
Oid eq_function;
|
Oid eq_function;
|
||||||
Oid hash_function;
|
Oid left_hash_function;
|
||||||
|
Oid right_hash_function;
|
||||||
|
|
||||||
eq_function = get_opcode(eq_opr);
|
eq_function = get_opcode(eq_opr);
|
||||||
hash_function = get_op_hash_function(eq_opr);
|
if (!get_op_hash_functions(eq_opr,
|
||||||
if (!OidIsValid(hash_function)) /* should not happen */
|
&left_hash_function, &right_hash_function))
|
||||||
elog(ERROR, "could not find hash function for hash operator %u",
|
elog(ERROR, "could not find hash function for hash operator %u",
|
||||||
eq_opr);
|
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(eq_function, &(*eqFunctions)[i]);
|
||||||
fmgr_info(hash_function, &(*hashFunctions)[i]);
|
fmgr_info(right_hash_function, &(*hashFunctions)[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
break;
|
||||||
/* We have to compute the hash value */
|
/* We have to compute the hash value */
|
||||||
econtext->ecxt_innertuple = slot;
|
econtext->ecxt_innertuple = slot;
|
||||||
if (ExecHashGetHashValue(hashtable, econtext, hashkeys, false,
|
if (ExecHashGetHashValue(hashtable, econtext, hashkeys, false, false,
|
||||||
&hashvalue))
|
&hashvalue))
|
||||||
{
|
{
|
||||||
ExecHashTableInsert(hashtable, slot, hashvalue);
|
ExecHashTableInsert(hashtable, slot, hashvalue);
|
||||||
@ -267,19 +267,23 @@ ExecHashTableCreate(Hash *node, List *hashOperators)
|
|||||||
* Also remember whether the join operators are strict.
|
* Also remember whether the join operators are strict.
|
||||||
*/
|
*/
|
||||||
nkeys = list_length(hashOperators);
|
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));
|
hashtable->hashStrict = (bool *) palloc(nkeys * sizeof(bool));
|
||||||
i = 0;
|
i = 0;
|
||||||
foreach(ho, hashOperators)
|
foreach(ho, hashOperators)
|
||||||
{
|
{
|
||||||
Oid hashop = lfirst_oid(ho);
|
Oid hashop = lfirst_oid(ho);
|
||||||
Oid hashfn;
|
Oid left_hashfn;
|
||||||
|
Oid right_hashfn;
|
||||||
|
|
||||||
hashfn = get_op_hash_function(hashop);
|
if (!get_op_hash_functions(hashop, &left_hashfn, &right_hashfn))
|
||||||
if (!OidIsValid(hashfn))
|
|
||||||
elog(ERROR, "could not find hash function for hash operator %u",
|
elog(ERROR, "could not find hash function for hash operator %u",
|
||||||
hashop);
|
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);
|
hashtable->hashStrict[i] = op_strict(hashop);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -674,10 +678,12 @@ bool
|
|||||||
ExecHashGetHashValue(HashJoinTable hashtable,
|
ExecHashGetHashValue(HashJoinTable hashtable,
|
||||||
ExprContext *econtext,
|
ExprContext *econtext,
|
||||||
List *hashkeys,
|
List *hashkeys,
|
||||||
|
bool outer_tuple,
|
||||||
bool keep_nulls,
|
bool keep_nulls,
|
||||||
uint32 *hashvalue)
|
uint32 *hashvalue)
|
||||||
{
|
{
|
||||||
uint32 hashkey = 0;
|
uint32 hashkey = 0;
|
||||||
|
FmgrInfo *hashfunctions;
|
||||||
ListCell *hk;
|
ListCell *hk;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
@ -690,6 +696,11 @@ ExecHashGetHashValue(HashJoinTable hashtable,
|
|||||||
|
|
||||||
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
|
||||||
|
|
||||||
|
if (outer_tuple)
|
||||||
|
hashfunctions = hashtable->outer_hashfunctions;
|
||||||
|
else
|
||||||
|
hashfunctions = hashtable->inner_hashfunctions;
|
||||||
|
|
||||||
foreach(hk, hashkeys)
|
foreach(hk, hashkeys)
|
||||||
{
|
{
|
||||||
ExprState *keyexpr = (ExprState *) lfirst(hk);
|
ExprState *keyexpr = (ExprState *) lfirst(hk);
|
||||||
@ -728,8 +739,7 @@ ExecHashGetHashValue(HashJoinTable hashtable,
|
|||||||
/* Compute the hash function */
|
/* Compute the hash function */
|
||||||
uint32 hkey;
|
uint32 hkey;
|
||||||
|
|
||||||
hkey = DatumGetUInt32(FunctionCall1(&hashtable->hashfunctions[i],
|
hkey = DatumGetUInt32(FunctionCall1(&hashfunctions[i], keyval));
|
||||||
keyval));
|
|
||||||
hashkey ^= hkey;
|
hashkey ^= hkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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;
|
econtext->ecxt_outertuple = slot;
|
||||||
if (ExecHashGetHashValue(hashtable, econtext,
|
if (ExecHashGetHashValue(hashtable, econtext,
|
||||||
hjstate->hj_OuterHashKeys,
|
hjstate->hj_OuterHashKeys,
|
||||||
|
true, /* outer tuple */
|
||||||
(hjstate->js.jointype == JOIN_LEFT),
|
(hjstate->js.jointype == JOIN_LEFT),
|
||||||
hashvalue))
|
hashvalue))
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/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;
|
Expr *expr;
|
||||||
TargetEntry *tle;
|
TargetEntry *tle;
|
||||||
GenericExprState *tlestate;
|
GenericExprState *tlestate;
|
||||||
Oid hashfn;
|
Oid left_hashfn;
|
||||||
|
Oid right_hashfn;
|
||||||
|
|
||||||
Assert(IsA(fstate, FuncExprState));
|
Assert(IsA(fstate, FuncExprState));
|
||||||
Assert(IsA(opexpr, OpExpr));
|
Assert(IsA(opexpr, OpExpr));
|
||||||
@ -830,12 +831,14 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
|
|||||||
fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]);
|
fmgr_info(opexpr->opfuncid, &node->eqfunctions[i - 1]);
|
||||||
node->eqfunctions[i - 1].fn_expr = (Node *) opexpr;
|
node->eqfunctions[i - 1].fn_expr = (Node *) opexpr;
|
||||||
|
|
||||||
/* Lookup the associated hash function */
|
/* Lookup the associated hash functions */
|
||||||
hashfn = get_op_hash_function(opexpr->opno);
|
if (!get_op_hash_functions(opexpr->opno,
|
||||||
if (!OidIsValid(hashfn))
|
&left_hashfn, &right_hashfn))
|
||||||
elog(ERROR, "could not find hash function for hash operator %u",
|
elog(ERROR, "could not find hash function for hash operator %u",
|
||||||
opexpr->opno);
|
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++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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);
|
numGroups = (long) Min(best_path->rows, (double) LONG_MAX);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the (presumed hashable) equality operators for the Agg node
|
* Get the hashable equality operators for the Agg node to use.
|
||||||
* to use. Normally these are the same as the IN clause operators,
|
* Normally these are the same as the IN clause operators, but if
|
||||||
* but if those are cross-type operators then the equality operators
|
* those are cross-type operators then the equality operators are
|
||||||
* are the ones for the IN clause operators' RHS datatype.
|
* the ones for the IN clause operators' RHS datatype.
|
||||||
*/
|
*/
|
||||||
groupOperators = (Oid *) palloc(numGroupCols * sizeof(Oid));
|
groupOperators = (Oid *) palloc(numGroupCols * sizeof(Oid));
|
||||||
groupColPos = 0;
|
groupColPos = 0;
|
||||||
@ -728,8 +728,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
|
|||||||
Oid in_oper = lfirst_oid(l);
|
Oid in_oper = lfirst_oid(l);
|
||||||
Oid eq_oper;
|
Oid eq_oper;
|
||||||
|
|
||||||
eq_oper = get_compatible_hash_operator(in_oper, false);
|
if (!get_compatible_hash_operators(in_oper, NULL, &eq_oper))
|
||||||
if (!OidIsValid(eq_oper)) /* shouldn't happen */
|
|
||||||
elog(ERROR, "could not find compatible hash operator for operator %u",
|
elog(ERROR, "could not find compatible hash operator for operator %u",
|
||||||
in_oper);
|
in_oper);
|
||||||
groupOperators[groupColPos++] = eq_oper;
|
groupOperators[groupColPos++] = eq_oper;
|
||||||
|
168
src/backend/utils/cache/lsyscache.c
vendored
168
src/backend/utils/cache/lsyscache.c
vendored
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/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
|
* NOTES
|
||||||
* Eventually, the index information should go through here, too.
|
* Eventually, the index information should go through here, too.
|
||||||
@ -389,23 +389,34 @@ get_mergejoin_opfamilies(Oid opno)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get_compatible_hash_operator
|
* get_compatible_hash_operators
|
||||||
* Get the OID of a hash equality operator compatible with the given
|
* Get the OID(s) of hash equality operator(s) compatible with the given
|
||||||
* operator, but operating on its LHS or RHS datatype as specified.
|
* operator, but operating on its LHS and/or RHS datatype.
|
||||||
*
|
*
|
||||||
* If the given operator is not cross-type, the result should be the same
|
* An operator for the LHS type is sought and returned into *lhs_opno if
|
||||||
* operator, but in cross-type situations it is different.
|
* 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
|
* If the given operator is not cross-type, the results should be the same
|
||||||
* that the operator should not have been marked oprcanhash.)
|
* 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
|
bool
|
||||||
get_compatible_hash_operator(Oid opno, bool use_lhs_type)
|
get_compatible_hash_operators(Oid opno,
|
||||||
|
Oid *lhs_opno, Oid *rhs_opno)
|
||||||
{
|
{
|
||||||
Oid result = InvalidOid;
|
bool result = false;
|
||||||
CatCList *catlist;
|
CatCList *catlist;
|
||||||
int i;
|
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 "="
|
* Search pg_amop to see if the target operator is registered as the "="
|
||||||
* operator of any hash opfamily. If the operator is registered in
|
* 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 &&
|
if (aform->amopmethod == HASH_AM_OID &&
|
||||||
aform->amopstrategy == HTEqualStrategyNumber)
|
aform->amopstrategy == HTEqualStrategyNumber)
|
||||||
{
|
{
|
||||||
/* Found a suitable opfamily, get matching single-type operator */
|
|
||||||
Oid typid;
|
|
||||||
|
|
||||||
/* No extra lookup needed if given operator is single-type */
|
/* No extra lookup needed if given operator is single-type */
|
||||||
if (aform->amoplefttype == aform->amoprighttype)
|
if (aform->amoplefttype == aform->amoprighttype)
|
||||||
{
|
{
|
||||||
result = opno;
|
if (lhs_opno)
|
||||||
|
*lhs_opno = opno;
|
||||||
|
if (rhs_opno)
|
||||||
|
*rhs_opno = opno;
|
||||||
|
result = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
typid = use_lhs_type ? aform->amoplefttype : aform->amoprighttype;
|
/*
|
||||||
result = get_opfamily_member(aform->amopfamily,
|
* Get the matching single-type operator(s). Failure probably
|
||||||
typid, typid,
|
* shouldn't happen --- it implies a bogus opfamily --- but
|
||||||
HTEqualStrategyNumber);
|
* continue looking if so.
|
||||||
if (OidIsValid(result))
|
*/
|
||||||
|
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;
|
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_op_hash_functions
|
||||||
* Get the OID of the datatype-specific hash function associated with
|
* Get the OID(s) of hash support function(s) compatible with the given
|
||||||
* a hashable equality operator.
|
* 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
|
* A function for the LHS type is sought and returned into *lhs_procno if
|
||||||
* datatypes.
|
* 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
|
* If the given operator is not cross-type, the results should be the same
|
||||||
* that the operator should not have been marked oprcanhash.)
|
* 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
|
bool
|
||||||
get_op_hash_function(Oid opno)
|
get_op_hash_functions(Oid opno,
|
||||||
|
RegProcedure *lhs_procno, RegProcedure *rhs_procno)
|
||||||
{
|
{
|
||||||
Oid result = InvalidOid;
|
bool result = false;
|
||||||
CatCList *catlist;
|
CatCList *catlist;
|
||||||
int i;
|
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 "="
|
* Search pg_amop to see if the target operator is registered as the "="
|
||||||
* operator of any hash opfamily. If the operator is registered in
|
* operator of any hash opfamily. If the operator is registered in
|
||||||
* multiple opfamilies, assume we can use the associated hash function from
|
* multiple opfamilies, assume we can use any one.
|
||||||
* any one.
|
|
||||||
*/
|
*/
|
||||||
catlist = SearchSysCacheList(AMOPOPID, 1,
|
catlist = SearchSysCacheList(AMOPOPID, 1,
|
||||||
ObjectIdGetDatum(opno),
|
ObjectIdGetDatum(opno),
|
||||||
@ -483,12 +535,50 @@ get_op_hash_function(Oid opno)
|
|||||||
if (aform->amopmethod == HASH_AM_OID &&
|
if (aform->amopmethod == HASH_AM_OID &&
|
||||||
aform->amopstrategy == HTEqualStrategyNumber)
|
aform->amopstrategy == HTEqualStrategyNumber)
|
||||||
{
|
{
|
||||||
/* Found a suitable opfamily, get matching hash support function */
|
/*
|
||||||
result = get_opfamily_proc(aform->amopfamily,
|
* Get the matching support function(s). Failure probably
|
||||||
aform->amoplefttype,
|
* shouldn't happen --- it implies a bogus opfamily --- but
|
||||||
aform->amoprighttype,
|
* continue looking if so.
|
||||||
HASHPROC);
|
*/
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* NOTES
|
||||||
* modeled after Margo Seltzer's hash implementation for unix.
|
* 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 */
|
/* hashutil.c */
|
||||||
extern bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup);
|
extern bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup);
|
||||||
extern uint32 _hash_datum2hashkey(Relation rel, Datum key);
|
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,
|
extern Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
|
||||||
uint32 highmask, uint32 lowmask);
|
uint32 highmask, uint32 lowmask);
|
||||||
extern uint32 _hash_log2(uint32 num);
|
extern uint32 _hash_log2(uint32 num);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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
|
* Info about the datatype-specific hash functions for the datatypes being
|
||||||
* hashed. We assume that the inner and outer sides of each hashclause
|
* hashed. These are arrays of the same length as the number of hash join
|
||||||
* are the same type, or at least share the same hash function. This is an
|
* clauses (hash keys).
|
||||||
* array of the same length as the number of 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? */
|
bool *hashStrict; /* is each hash join operator strict? */
|
||||||
|
|
||||||
Size spaceUsed; /* memory space currently used by tuples */
|
Size spaceUsed; /* memory space currently used by tuples */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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,
|
extern bool ExecHashGetHashValue(HashJoinTable hashtable,
|
||||||
ExprContext *econtext,
|
ExprContext *econtext,
|
||||||
List *hashkeys,
|
List *hashkeys,
|
||||||
|
bool outer_tuple,
|
||||||
bool keep_nulls,
|
bool keep_nulls,
|
||||||
uint32 *hashvalue);
|
uint32 *hashvalue);
|
||||||
extern void ExecHashGetBucketAndBatch(HashJoinTable hashtable,
|
extern void ExecHashGetBucketAndBatch(HashJoinTable hashtable,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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_equality_op_for_ordering_op(Oid opno);
|
||||||
extern Oid get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type);
|
extern Oid get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type);
|
||||||
extern List *get_mergejoin_opfamilies(Oid opno);
|
extern List *get_mergejoin_opfamilies(Oid opno);
|
||||||
extern Oid get_compatible_hash_operator(Oid opno, bool use_lhs_type);
|
extern bool get_compatible_hash_operators(Oid opno,
|
||||||
extern Oid get_op_hash_function(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,
|
extern void get_op_btree_interpretation(Oid opno,
|
||||||
List **opfamilies, List **opstrats);
|
List **opfamilies, List **opstrats);
|
||||||
extern bool ops_in_same_btree_opfamily(Oid opno1, Oid opno2);
|
extern bool ops_in_same_btree_opfamily(Oid opno1, Oid opno2);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user