summaryrefslogtreecommitdiff
path: root/src/backend/access/hash/hashutil.c
blob: 304ae236cbf8ecf765b84fb751049a73529dabef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*-------------------------------------------------------------------------
 *
 * btutils.c
 *	  Utility code for Postgres btree implementation.
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  $Header: /cvsroot/pgsql/src/backend/access/hash/hashutil.c,v 1.15 1999/02/13 23:14:21 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */

#include <postgres.h>

#include <access/hash.h>
#include <fmgr.h>
#include <utils/memutils.h>
#include <access/iqual.h>

#ifndef HAVE_MEMMOVE
#include <regex/utils.h>
#else
#include <string.h>
#endif

ScanKey
_hash_mkscankey(Relation rel, IndexTuple itup, HashMetaPage metap)
{
	ScanKey		skey;
	TupleDesc	itupdesc;
	int			natts;
	AttrNumber	i;
	Datum		arg;
	RegProcedure proc;
	bool		null;

	natts = rel->rd_rel->relnatts;
	itupdesc = RelationGetDescr(rel);

	skey = (ScanKey) palloc(natts * sizeof(ScanKeyData));

	for (i = 0; i < natts; i++)
	{
		arg = index_getattr(itup, i + 1, itupdesc, &null);
		proc = metap->hashm_procid;
		ScanKeyEntryInitialize(&skey[i],
							   0x0, (AttrNumber) (i + 1), proc, arg);
	}

	return skey;
}

void
_hash_freeskey(ScanKey skey)
{
	pfree(skey);
}


bool
_hash_checkqual(IndexScanDesc scan, IndexTuple itup)
{
	if (scan->numberOfKeys > 0)
		return (index_keytest(itup,
							  RelationGetDescr(scan->relation),
							  scan->numberOfKeys, scan->keyData));
	else
		return true;
}

HashItem
_hash_formitem(IndexTuple itup)
{
	int			nbytes_hitem;
	HashItem	hitem;
	Size		tuplen;

	/* disallow nulls in hash keys */
	if (itup->t_info & INDEX_NULL_MASK)
		elog(ERROR, "hash indices cannot include null keys");

	/* make a copy of the index tuple with room for the sequence number */
	tuplen = IndexTupleSize(itup);
	nbytes_hitem = tuplen +
		(sizeof(HashItemData) - sizeof(IndexTupleData));

	hitem = (HashItem) palloc(nbytes_hitem);
	memmove((char *) &(hitem->hash_itup), (char *) itup, tuplen);

	return hitem;
}

Bucket
_hash_call(Relation rel, HashMetaPage metap, Datum key)
{
	uint32		n;
	Bucket		bucket;
	RegProcedure proc;

	proc = metap->hashm_procid;
	n = (uint32) fmgr(proc, key);
	bucket = n & metap->hashm_highmask;
	if (bucket > metap->hashm_maxbucket)
		bucket = bucket & metap->hashm_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 = limit << 1, i++)
		;
	return i;
}

/*
 * _hash_checkpage -- sanity checks on the format of all hash pages
 */
void
_hash_checkpage(Page page, int flags)
{
	HashPageOpaque opaque;

	Assert(page);
	Assert(((PageHeader) (page))->pd_lower >= (sizeof(PageHeaderData) - sizeof(ItemIdData)));
#if 1
	Assert(((PageHeader) (page))->pd_upper <=
		   (BLCKSZ - DOUBLEALIGN(sizeof(HashPageOpaqueData))));
	Assert(((PageHeader) (page))->pd_special ==
		   (BLCKSZ - DOUBLEALIGN(sizeof(HashPageOpaqueData))));
	Assert(((PageHeader) (page))->pd_opaque.od_pagesize == BLCKSZ);
#endif
	if (flags)
	{
		opaque = (HashPageOpaque) PageGetSpecialPointer(page);
		Assert(opaque->hasho_flag & flags);
	}
}