/*------------------------------------------------------------------------- * * hashutil.c * Utility code for Postgres hash implementation. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.42 2005/05/11 01:26:01 neilc Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/genam.h" #include "access/hash.h" #include "access/iqual.h" /* * _hash_checkqual -- does the index tuple satisfy the scan conditions? */ bool _hash_checkqual(IndexScanDesc scan, IndexTuple itup) { return index_keytest(itup, RelationGetDescr(scan->indexRelation), scan->numberOfKeys, scan->keyData); } /* * _hash_formitem -- construct a hash index entry */ HashItem _hash_formitem(IndexTuple itup) { int nbytes_hitem; HashItem hitem; Size tuplen; /* disallow nulls in hash keys */ if (IndexTupleHasNulls(itup)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("hash indexes cannot contain null keys"))); /* * make a copy of the index tuple (XXX do we still need to copy?) * * HashItemData used to have more fields than IndexTupleData, but no * longer... */ tuplen = IndexTupleSize(itup); nbytes_hitem = tuplen + (sizeof(HashItemData) - sizeof(IndexTupleData)); hitem = (HashItem) palloc(nbytes_hitem); memcpy(&(hitem->hash_itup), itup, tuplen); return hitem; } /* * _hash_datum2hashkey -- given a Datum, call the index's hash procedure */ uint32 _hash_datum2hashkey(Relation rel, Datum key) { FmgrInfo *procinfo; /* XXX assumes index has only one attribute */ procinfo = index_getprocinfo(rel, 1, HASHPROC); return DatumGetUInt32(FunctionCall1(procinfo, key)); } /* * _hash_hashkey2bucket -- determine which bucket the hashkey maps to. */ Bucket _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket, uint32 highmask, uint32 lowmask) { Bucket bucket; bucket = hashkey & highmask; if (bucket > maxbucket) bucket = bucket & lowmask; return bucket; } /* * _hash_log2 -- returns ceil(lg2(num)) */ uint32 _hash_log2(uint32 num) { uint32 i, limit; limit = 1; for (i = 0; limit < num; limit <<= 1, i++) ; return i; } /* * _hash_checkpage -- sanity checks on the format of all hash pages */ void _hash_checkpage(Relation rel, Page page, int flags) { Assert(page); /* * When checking the metapage, always verify magic number and version. */ if (flags == LH_META_PAGE) { HashMetaPage metap = (HashMetaPage) page; if (metap->hashm_magic != HASH_MAGIC) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" is not a hash index", RelationGetRelationName(rel)))); if (metap->hashm_version != HASH_VERSION) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("index \"%s\" has wrong hash version", RelationGetRelationName(rel)), errhint("Please REINDEX it."))); } /* * These other checks are for debugging purposes only. */ #ifdef USE_ASSERT_CHECKING Assert(((PageHeader) (page))->pd_lower >= SizeOfPageHeaderData); Assert(((PageHeader) (page))->pd_upper <= (BLCKSZ - MAXALIGN(sizeof(HashPageOpaqueData)))); Assert(((PageHeader) (page))->pd_special == (BLCKSZ - MAXALIGN(sizeof(HashPageOpaqueData)))); Assert(PageGetPageSize(page) == BLCKSZ); if (flags) { HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page); Assert(opaque->hasho_flag & flags); } #endif /* USE_ASSERT_CHECKING */ }