1 : /*-------------------------------------------------------------------------
2 : *
3 : * hashutil.c
4 : * Utility code for Postgres hash implementation.
5 : *
6 : * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * $PostgreSQL: pgsql/src/backend/access/hash/hashutil.c,v 1.52 2007/05/03 16:45:58 tgl Exp $
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/genam.h"
18 : #include "access/hash.h"
19 : #include "access/reloptions.h"
20 : #include "executor/execdebug.h"
21 : #include "utils/lsyscache.h"
22 :
23 :
24 : /*
25 : * _hash_checkqual -- does the index tuple satisfy the scan conditions?
26 : */
27 : bool
28 : _hash_checkqual(IndexScanDesc scan, IndexTuple itup)
29 4173 : {
30 4173 : TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
31 4173 : ScanKey key = scan->keyData;
32 4173 : int scanKeySize = scan->numberOfKeys;
33 :
34 : IncrIndexProcessed();
35 :
36 8366 : while (scanKeySize > 0)
37 : {
38 : Datum datum;
39 : bool isNull;
40 : Datum test;
41 :
42 4173 : datum = index_getattr(itup,
43 : key->sk_attno,
44 : tupdesc,
45 : &isNull);
46 :
47 : /* assume sk_func is strict */
48 4173 : if (isNull)
49 0 : return false;
50 4173 : if (key->sk_flags & SK_ISNULL)
51 0 : return false;
52 :
53 4173 : test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
54 :
55 4173 : if (!DatumGetBool(test))
56 4153 : return false;
57 :
58 20 : key++;
59 20 : scanKeySize--;
60 : }
61 :
62 20 : return true;
63 : }
64 :
65 : /*
66 : * _hash_datum2hashkey -- given a Datum, call the index's hash procedure
67 : *
68 : * The Datum is assumed to be of the index's column type, so we can use the
69 : * "primary" hash procedure that's tracked for us by the generic index code.
70 : */
71 : uint32
72 : _hash_datum2hashkey(Relation rel, Datum key)
73 95055 : {
74 : FmgrInfo *procinfo;
75 :
76 : /* XXX assumes index has only one attribute */
77 95055 : procinfo = index_getprocinfo(rel, 1, HASHPROC);
78 :
79 95055 : return DatumGetUInt32(FunctionCall1(procinfo, key));
80 : }
81 :
82 : /*
83 : * _hash_datum2hashkey_type -- given a Datum of a specified type,
84 : * hash it in a fashion compatible with this index
85 : *
86 : * This is much more expensive than _hash_datum2hashkey, so use it only in
87 : * cross-type situations.
88 : */
89 : uint32
90 : _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype)
91 0 : {
92 : RegProcedure hash_proc;
93 :
94 : /* XXX assumes index has only one attribute */
95 0 : hash_proc = get_opfamily_proc(rel->rd_opfamily[0],
96 : keytype,
97 : keytype,
98 : HASHPROC);
99 0 : if (!RegProcedureIsValid(hash_proc))
100 0 : elog(ERROR, "missing support function %d(%u,%u) for index \"%s\"",
101 : HASHPROC, keytype, keytype,
102 : RelationGetRelationName(rel));
103 :
104 0 : return DatumGetUInt32(OidFunctionCall1(hash_proc, key));
105 : }
106 :
107 : /*
108 : * _hash_hashkey2bucket -- determine which bucket the hashkey maps to.
109 : */
110 : Bucket
111 : _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
112 : uint32 highmask, uint32 lowmask)
113 95055 : {
114 : Bucket bucket;
115 :
116 95055 : bucket = hashkey & highmask;
117 95055 : if (bucket > maxbucket)
118 10279 : bucket = bucket & lowmask;
119 :
120 95055 : return bucket;
121 : }
122 :
123 : /*
124 : * _hash_log2 -- returns ceil(lg2(num))
125 : */
126 : uint32
127 : _hash_log2(uint32 num)
128 38006 : {
129 : uint32 i,
130 : limit;
131 :
132 38006 : limit = 1;
133 38006 : for (i = 0; limit < num; limit <<= 1, i++)
134 : ;
135 38006 : return i;
136 : }
137 :
138 : /*
139 : * _hash_checkpage -- sanity checks on the format of all hash pages
140 : *
141 : * If flags is not zero, it is a bitwise OR of the acceptable values of
142 : * hasho_flag.
143 : */
144 : void
145 : _hash_checkpage(Relation rel, Buffer buf, int flags)
146 127581 : {
147 127581 : Page page = BufferGetPage(buf);
148 :
149 : /*
150 : * ReadBuffer verifies that every newly-read page passes
151 : * PageHeaderIsValid, which means it either contains a reasonably sane
152 : * page header or is all-zero. We have to defend against the all-zero
153 : * case, however.
154 : */
155 127581 : if (PageIsNew(page))
156 0 : ereport(ERROR,
157 : (errcode(ERRCODE_INDEX_CORRUPTED),
158 : errmsg("index \"%s\" contains unexpected zero page at block %u",
159 : RelationGetRelationName(rel),
160 : BufferGetBlockNumber(buf)),
161 : errhint("Please REINDEX it.")));
162 :
163 : /*
164 : * Additionally check that the special area looks sane.
165 : */
166 127581 : if (((PageHeader) (page))->pd_special !=
167 : (BLCKSZ - MAXALIGN(sizeof(HashPageOpaqueData))))
168 0 : ereport(ERROR,
169 : (errcode(ERRCODE_INDEX_CORRUPTED),
170 : errmsg("index \"%s\" contains corrupted page at block %u",
171 : RelationGetRelationName(rel),
172 : BufferGetBlockNumber(buf)),
173 : errhint("Please REINDEX it.")));
174 :
175 127581 : if (flags)
176 : {
177 127581 : HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page);
178 :
179 127581 : if ((opaque->hasho_flag & flags) == 0)
180 0 : ereport(ERROR,
181 : (errcode(ERRCODE_INDEX_CORRUPTED),
182 : errmsg("index \"%s\" contains corrupted page at block %u",
183 : RelationGetRelationName(rel),
184 : BufferGetBlockNumber(buf)),
185 : errhint("Please REINDEX it.")));
186 : }
187 :
188 : /*
189 : * When checking the metapage, also verify magic number and version.
190 : */
191 127581 : if (flags == LH_META_PAGE)
192 : {
193 40516 : HashMetaPage metap = (HashMetaPage) page;
194 :
195 40516 : if (metap->hashm_magic != HASH_MAGIC)
196 0 : ereport(ERROR,
197 : (errcode(ERRCODE_INDEX_CORRUPTED),
198 : errmsg("index \"%s\" is not a hash index",
199 : RelationGetRelationName(rel))));
200 :
201 40516 : if (metap->hashm_version != HASH_VERSION)
202 0 : ereport(ERROR,
203 : (errcode(ERRCODE_INDEX_CORRUPTED),
204 : errmsg("index \"%s\" has wrong hash version",
205 : RelationGetRelationName(rel)),
206 : errhint("Please REINDEX it.")));
207 : }
208 127581 : }
209 :
210 : Datum
211 : hashoptions(PG_FUNCTION_ARGS)
212 0 : {
213 0 : Datum reloptions = PG_GETARG_DATUM(0);
214 0 : bool validate = PG_GETARG_BOOL(1);
215 : bytea *result;
216 :
217 0 : result = default_reloptions(reloptions, validate,
218 : HASH_MIN_FILLFACTOR,
219 : HASH_DEFAULT_FILLFACTOR);
220 0 : if (result)
221 0 : PG_RETURN_BYTEA_P(result);
222 0 : PG_RETURN_NULL();
223 : }
|