mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Revise hash join and hash aggregation code to use the same datatype-
specific hash functions used by hash indexes, rather than the old not-datatype-aware ComputeHashFunc routine. This makes it safe to do hash joining on several datatypes that previously couldn't use hashing. The sets of datatypes that are hash indexable and hash joinable are now exactly the same, whereas before each had some that weren't in the other.
This commit is contained in:
78
src/backend/utils/cache/catcache.c
vendored
78
src/backend/utils/cache/catcache.c
vendored
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.103 2003/05/27 17:49:46 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.104 2003/06/22 22:04:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -81,22 +81,6 @@
|
||||
/* Cache management header --- pointer is NULL until created */
|
||||
static CatCacheHeader *CacheHdr = NULL;
|
||||
|
||||
/*
|
||||
* EQPROC is used in CatalogCacheInitializeCache to find the equality
|
||||
* functions for system types that are used as cache key fields.
|
||||
* See also GetCCHashFunc, which should support the same set of types.
|
||||
*
|
||||
* XXX this should be replaced by catalog lookups,
|
||||
* but that seems to pose considerable risk of circularity...
|
||||
*/
|
||||
static const Oid eqproc[] = {
|
||||
F_BOOLEQ, InvalidOid, F_CHAREQ, F_NAMEEQ, InvalidOid,
|
||||
F_INT2EQ, F_INT2VECTOREQ, F_INT4EQ, F_OIDEQ, F_TEXTEQ,
|
||||
F_OIDEQ, InvalidOid, InvalidOid, InvalidOid, F_OIDVECTOREQ
|
||||
};
|
||||
|
||||
#define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-BOOLOID]
|
||||
|
||||
|
||||
static uint32 CatalogCacheComputeHashValue(CatCache *cache, int nkeys,
|
||||
ScanKey cur_skey);
|
||||
@ -119,24 +103,46 @@ static HeapTuple build_dummy_tuple(CatCache *cache, int nkeys, ScanKey skeys);
|
||||
* internal support functions
|
||||
*/
|
||||
|
||||
static PGFunction
|
||||
GetCCHashFunc(Oid keytype)
|
||||
/*
|
||||
* Look up the hash and equality functions for system types that are used
|
||||
* as cache key fields.
|
||||
*
|
||||
* XXX this should be replaced by catalog lookups,
|
||||
* but that seems to pose considerable risk of circularity...
|
||||
*/
|
||||
static void
|
||||
GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc)
|
||||
{
|
||||
switch (keytype)
|
||||
{
|
||||
case BOOLOID:
|
||||
*hashfunc = hashchar;
|
||||
*eqfunc = F_BOOLEQ;
|
||||
break;
|
||||
case CHAROID:
|
||||
return hashchar;
|
||||
*hashfunc = hashchar;
|
||||
*eqfunc = F_CHAREQ;
|
||||
break;
|
||||
case NAMEOID:
|
||||
return hashname;
|
||||
*hashfunc = hashname;
|
||||
*eqfunc = F_NAMEEQ;
|
||||
break;
|
||||
case INT2OID:
|
||||
return hashint2;
|
||||
*hashfunc = hashint2;
|
||||
*eqfunc = F_INT2EQ;
|
||||
break;
|
||||
case INT2VECTOROID:
|
||||
return hashint2vector;
|
||||
*hashfunc = hashint2vector;
|
||||
*eqfunc = F_INT2VECTOREQ;
|
||||
break;
|
||||
case INT4OID:
|
||||
return hashint4;
|
||||
*hashfunc = hashint4;
|
||||
*eqfunc = F_INT4EQ;
|
||||
break;
|
||||
case TEXTOID:
|
||||
return hashvarlena;
|
||||
*hashfunc = hashtext;
|
||||
*eqfunc = F_TEXTEQ;
|
||||
break;
|
||||
case OIDOID:
|
||||
case REGPROCOID:
|
||||
case REGPROCEDUREOID:
|
||||
@ -144,13 +150,17 @@ GetCCHashFunc(Oid keytype)
|
||||
case REGOPERATOROID:
|
||||
case REGCLASSOID:
|
||||
case REGTYPEOID:
|
||||
return hashoid;
|
||||
*hashfunc = hashoid;
|
||||
*eqfunc = F_OIDEQ;
|
||||
break;
|
||||
case OIDVECTOROID:
|
||||
return hashoidvector;
|
||||
*hashfunc = hashoidvector;
|
||||
*eqfunc = F_OIDVECTOREQ;
|
||||
break;
|
||||
default:
|
||||
elog(FATAL, "GetCCHashFunc: type %u unsupported as catcache key",
|
||||
elog(FATAL, "GetCCHashEqFuncs: type %u unsupported as catcache key",
|
||||
keytype);
|
||||
return (PGFunction) NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -941,16 +951,16 @@ CatalogCacheInitializeCache(CatCache *cache)
|
||||
keytype = OIDOID;
|
||||
}
|
||||
|
||||
cache->cc_hashfunc[i] = GetCCHashFunc(keytype);
|
||||
GetCCHashEqFuncs(keytype,
|
||||
&cache->cc_hashfunc[i],
|
||||
&cache->cc_skey[i].sk_procedure);
|
||||
|
||||
cache->cc_isname[i] = (keytype == NAMEOID);
|
||||
|
||||
/*
|
||||
* If GetCCHashFunc liked the type, safe to index into eqproc[]
|
||||
* Do equality-function lookup (we assume this won't need a catalog
|
||||
* lookup for any supported type)
|
||||
*/
|
||||
cache->cc_skey[i].sk_procedure = EQPROC(keytype);
|
||||
|
||||
/* Do function lookup */
|
||||
fmgr_info_cxt(cache->cc_skey[i].sk_procedure,
|
||||
&cache->cc_skey[i].sk_func,
|
||||
CacheMemoryContext);
|
||||
|
96
src/backend/utils/cache/lsyscache.c
vendored
96
src/backend/utils/cache/lsyscache.c
vendored
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.95 2003/05/26 00:11:27 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.96 2003/06/22 22:04:54 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Eventually, the index information should go through here, too.
|
||||
@ -16,8 +16,10 @@
|
||||
#include "postgres.h"
|
||||
#include "miscadmin.h"
|
||||
|
||||
#include "access/hash.h"
|
||||
#include "access/tupmacs.h"
|
||||
#include "catalog/pg_amop.h"
|
||||
#include "catalog/pg_amproc.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
@ -28,6 +30,7 @@
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "utils/array.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/catcache.h"
|
||||
#include "utils/datum.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
@ -106,6 +109,72 @@ get_opclass_member(Oid opclass, int16 strategy)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_op_hash_function
|
||||
* Get the OID of the datatype-specific hash function associated with
|
||||
* a hashable equality operator.
|
||||
*
|
||||
* Returns InvalidOid if no hash function can be found. (This indicates
|
||||
* that the operator should not have been marked oprcanhash.)
|
||||
*/
|
||||
Oid
|
||||
get_op_hash_function(Oid opno)
|
||||
{
|
||||
CatCList *catlist;
|
||||
int i;
|
||||
HeapTuple tuple;
|
||||
Oid opclass = InvalidOid;
|
||||
|
||||
/*
|
||||
* Search pg_amop to see if the target operator is registered as the "="
|
||||
* operator of any hash opclass. If the operator is registered in
|
||||
* multiple opclasses, assume we can use the associated hash function
|
||||
* from any one.
|
||||
*/
|
||||
catlist = SearchSysCacheList(AMOPOPID, 1,
|
||||
ObjectIdGetDatum(opno),
|
||||
0, 0, 0);
|
||||
|
||||
for (i = 0; i < catlist->n_members; i++)
|
||||
{
|
||||
Form_pg_amop aform;
|
||||
|
||||
tuple = &catlist->members[i]->tuple;
|
||||
aform = (Form_pg_amop) GETSTRUCT(tuple);
|
||||
|
||||
if (aform->amopstrategy == HTEqualStrategyNumber &&
|
||||
opclass_is_hash(aform->amopclaid))
|
||||
{
|
||||
opclass = aform->amopclaid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseSysCacheList(catlist);
|
||||
|
||||
if (OidIsValid(opclass))
|
||||
{
|
||||
/* Found a suitable opclass, get its hash support function */
|
||||
tuple = SearchSysCache(AMPROCNUM,
|
||||
ObjectIdGetDatum(opclass),
|
||||
Int16GetDatum(HASHPROC),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
Form_pg_amproc aform = (Form_pg_amproc) GETSTRUCT(tuple);
|
||||
RegProcedure result;
|
||||
|
||||
result = aform->amproc;
|
||||
ReleaseSysCache(tuple);
|
||||
Assert(RegProcedureIsValid(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/* Didn't find a match... */
|
||||
return InvalidOid;
|
||||
}
|
||||
|
||||
|
||||
/* ---------- ATTRIBUTE CACHES ---------- */
|
||||
|
||||
@ -284,6 +353,31 @@ opclass_is_btree(Oid opclass)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* opclass_is_hash
|
||||
*
|
||||
* Returns TRUE iff the specified opclass is associated with the
|
||||
* hash index access method.
|
||||
*/
|
||||
bool
|
||||
opclass_is_hash(Oid opclass)
|
||||
{
|
||||
HeapTuple tp;
|
||||
Form_pg_opclass cla_tup;
|
||||
bool result;
|
||||
|
||||
tp = SearchSysCache(CLAOID,
|
||||
ObjectIdGetDatum(opclass),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tp))
|
||||
elog(ERROR, "cache lookup failed for opclass %u", opclass);
|
||||
cla_tup = (Form_pg_opclass) GETSTRUCT(tp);
|
||||
|
||||
result = (cla_tup->opcamid == HASH_AM_OID);
|
||||
ReleaseSysCache(tp);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ---------- OPERATOR CACHE ---------- */
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user