00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/hash.h"
00018 #include "access/reloptions.h"
00019 #include "access/relscan.h"
00020 #include "utils/lsyscache.h"
00021 #include "utils/rel.h"
00022
00023
00024
00025
00026
00027 bool
00028 _hash_checkqual(IndexScanDesc scan, IndexTuple itup)
00029 {
00030
00031
00032
00033
00034
00035
00036 #ifdef NOT_USED
00037 TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
00038 ScanKey key = scan->keyData;
00039 int scanKeySize = scan->numberOfKeys;
00040
00041 while (scanKeySize > 0)
00042 {
00043 Datum datum;
00044 bool isNull;
00045 Datum test;
00046
00047 datum = index_getattr(itup,
00048 key->sk_attno,
00049 tupdesc,
00050 &isNull);
00051
00052
00053 if (isNull)
00054 return false;
00055 if (key->sk_flags & SK_ISNULL)
00056 return false;
00057
00058 test = FunctionCall2Coll(&key->sk_func, key->sk_collation,
00059 datum, key->sk_argument);
00060
00061 if (!DatumGetBool(test))
00062 return false;
00063
00064 key++;
00065 scanKeySize--;
00066 }
00067 #endif
00068
00069 return true;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078 uint32
00079 _hash_datum2hashkey(Relation rel, Datum key)
00080 {
00081 FmgrInfo *procinfo;
00082 Oid collation;
00083
00084
00085 procinfo = index_getprocinfo(rel, 1, HASHPROC);
00086 collation = rel->rd_indcollation[0];
00087
00088 return DatumGetUInt32(FunctionCall1Coll(procinfo, collation, key));
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098 uint32
00099 _hash_datum2hashkey_type(Relation rel, Datum key, Oid keytype)
00100 {
00101 RegProcedure hash_proc;
00102 Oid collation;
00103
00104
00105 hash_proc = get_opfamily_proc(rel->rd_opfamily[0],
00106 keytype,
00107 keytype,
00108 HASHPROC);
00109 if (!RegProcedureIsValid(hash_proc))
00110 elog(ERROR, "missing support function %d(%u,%u) for index \"%s\"",
00111 HASHPROC, keytype, keytype,
00112 RelationGetRelationName(rel));
00113 collation = rel->rd_indcollation[0];
00114
00115 return DatumGetUInt32(OidFunctionCall1Coll(hash_proc, collation, key));
00116 }
00117
00118
00119
00120
00121 Bucket
00122 _hash_hashkey2bucket(uint32 hashkey, uint32 maxbucket,
00123 uint32 highmask, uint32 lowmask)
00124 {
00125 Bucket bucket;
00126
00127 bucket = hashkey & highmask;
00128 if (bucket > maxbucket)
00129 bucket = bucket & lowmask;
00130
00131 return bucket;
00132 }
00133
00134
00135
00136
00137 uint32
00138 _hash_log2(uint32 num)
00139 {
00140 uint32 i,
00141 limit;
00142
00143 limit = 1;
00144 for (i = 0; limit < num; limit <<= 1, i++)
00145 ;
00146 return i;
00147 }
00148
00149
00150
00151
00152
00153
00154
00155 void
00156 _hash_checkpage(Relation rel, Buffer buf, int flags)
00157 {
00158 Page page = BufferGetPage(buf);
00159
00160
00161
00162
00163
00164
00165
00166 if (PageIsNew(page))
00167 ereport(ERROR,
00168 (errcode(ERRCODE_INDEX_CORRUPTED),
00169 errmsg("index \"%s\" contains unexpected zero page at block %u",
00170 RelationGetRelationName(rel),
00171 BufferGetBlockNumber(buf)),
00172 errhint("Please REINDEX it.")));
00173
00174
00175
00176
00177 if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
00178 ereport(ERROR,
00179 (errcode(ERRCODE_INDEX_CORRUPTED),
00180 errmsg("index \"%s\" contains corrupted page at block %u",
00181 RelationGetRelationName(rel),
00182 BufferGetBlockNumber(buf)),
00183 errhint("Please REINDEX it.")));
00184
00185 if (flags)
00186 {
00187 HashPageOpaque opaque = (HashPageOpaque) PageGetSpecialPointer(page);
00188
00189 if ((opaque->hasho_flag & flags) == 0)
00190 ereport(ERROR,
00191 (errcode(ERRCODE_INDEX_CORRUPTED),
00192 errmsg("index \"%s\" contains corrupted page at block %u",
00193 RelationGetRelationName(rel),
00194 BufferGetBlockNumber(buf)),
00195 errhint("Please REINDEX it.")));
00196 }
00197
00198
00199
00200
00201 if (flags == LH_META_PAGE)
00202 {
00203 HashMetaPage metap = HashPageGetMeta(page);
00204
00205 if (metap->hashm_magic != HASH_MAGIC)
00206 ereport(ERROR,
00207 (errcode(ERRCODE_INDEX_CORRUPTED),
00208 errmsg("index \"%s\" is not a hash index",
00209 RelationGetRelationName(rel))));
00210
00211 if (metap->hashm_version != HASH_VERSION)
00212 ereport(ERROR,
00213 (errcode(ERRCODE_INDEX_CORRUPTED),
00214 errmsg("index \"%s\" has wrong hash version",
00215 RelationGetRelationName(rel)),
00216 errhint("Please REINDEX it.")));
00217 }
00218 }
00219
00220 Datum
00221 hashoptions(PG_FUNCTION_ARGS)
00222 {
00223 Datum reloptions = PG_GETARG_DATUM(0);
00224 bool validate = PG_GETARG_BOOL(1);
00225 bytea *result;
00226
00227 result = default_reloptions(reloptions, validate, RELOPT_KIND_HASH);
00228
00229 if (result)
00230 PG_RETURN_BYTEA_P(result);
00231 PG_RETURN_NULL();
00232 }
00233
00234
00235
00236
00237 uint32
00238 _hash_get_indextuple_hashkey(IndexTuple itup)
00239 {
00240 char *attp;
00241
00242
00243
00244
00245
00246 attp = (char *) itup + IndexInfoFindDataOffset(itup->t_info);
00247 return *((uint32 *) attp);
00248 }
00249
00250
00251
00252
00253 IndexTuple
00254 _hash_form_tuple(Relation index, Datum *values, bool *isnull)
00255 {
00256 IndexTuple itup;
00257 uint32 hashkey;
00258 Datum hashkeydatum;
00259 TupleDesc hashdesc;
00260
00261 if (isnull[0])
00262 hashkeydatum = (Datum) 0;
00263 else
00264 {
00265 hashkey = _hash_datum2hashkey(index, values[0]);
00266 hashkeydatum = UInt32GetDatum(hashkey);
00267 }
00268 hashdesc = RelationGetDescr(index);
00269 Assert(hashdesc->natts == 1);
00270 itup = index_form_tuple(hashdesc, &hashkeydatum, isnull);
00271 return itup;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286 OffsetNumber
00287 _hash_binsearch(Page page, uint32 hash_value)
00288 {
00289 OffsetNumber upper;
00290 OffsetNumber lower;
00291
00292
00293 upper = PageGetMaxOffsetNumber(page) + 1;
00294 lower = FirstOffsetNumber;
00295
00296 while (upper > lower)
00297 {
00298 OffsetNumber off;
00299 IndexTuple itup;
00300 uint32 hashkey;
00301
00302 off = (upper + lower) / 2;
00303 Assert(OffsetNumberIsValid(off));
00304
00305 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
00306 hashkey = _hash_get_indextuple_hashkey(itup);
00307 if (hashkey < hash_value)
00308 lower = off + 1;
00309 else
00310 upper = off;
00311 }
00312
00313 return lower;
00314 }
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 OffsetNumber
00325 _hash_binsearch_last(Page page, uint32 hash_value)
00326 {
00327 OffsetNumber upper;
00328 OffsetNumber lower;
00329
00330
00331 upper = PageGetMaxOffsetNumber(page);
00332 lower = FirstOffsetNumber - 1;
00333
00334 while (upper > lower)
00335 {
00336 IndexTuple itup;
00337 OffsetNumber off;
00338 uint32 hashkey;
00339
00340 off = (upper + lower + 1) / 2;
00341 Assert(OffsetNumberIsValid(off));
00342
00343 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
00344 hashkey = _hash_get_indextuple_hashkey(itup);
00345 if (hashkey > hash_value)
00346 upper = off - 1;
00347 else
00348 lower = off;
00349 }
00350
00351 return lower;
00352 }