diff --git a/contrib/pageinspect/expected/hash.out b/contrib/pageinspect/expected/hash.out index 7eb1537b29..8ed60bccc0 100644 --- a/contrib/pageinspect/expected/hash.out +++ b/contrib/pageinspect/expected/hash.out @@ -30,23 +30,17 @@ hash_page_type | bitmap SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6)); ERROR: block number 6 is out of range for relation "test_hash_a_idx" SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000008. +ERROR: invalid overflow block number 0 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 1 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 2); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 2 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 3); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 3 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000002. +ERROR: invalid overflow block number 4 SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5); -ERROR: page is not an overflow page -DETAIL: Expected 00000001, got 00000004. +ERROR: invalid overflow block number 5 SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 0)); diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index 08663c109d..88c807af5b 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -380,21 +380,22 @@ hash_bitmap_info(PG_FUNCTION_ARGS) Oid indexRelid = PG_GETARG_OID(0); uint64 ovflblkno = PG_GETARG_INT64(1); HashMetaPage metap; - Buffer buf, - metabuf; + Buffer metabuf, + mapbuf; BlockNumber bitmapblkno; - Page page; + Page mappage; bool bit = false; - HashPageOpaque opaque; TupleDesc tupleDesc; Relation indexRel; uint32 ovflbitno; int32 bitmappage, bitmapbit; HeapTuple tuple; - int j; + int i, + j; Datum values[3]; bool nulls[3]; + uint32 *freep; if (!superuser()) ereport(ERROR, @@ -418,30 +419,30 @@ hash_bitmap_info(PG_FUNCTION_ARGS) errmsg("block number " UINT64_FORMAT " is out of range for relation \"%s\"", ovflblkno, RelationGetRelationName(indexRel)))); - buf = ReadBufferExtended(indexRel, MAIN_FORKNUM, (BlockNumber) ovflblkno, - RBM_NORMAL, NULL); - LockBuffer(buf, BUFFER_LOCK_SHARE); - _hash_checkpage(indexRel, buf, LH_PAGE_TYPE); - page = BufferGetPage(buf); - opaque = (HashPageOpaque) PageGetSpecialPointer(page); - - if (opaque->hasho_flag != LH_OVERFLOW_PAGE) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("page is not an overflow page"), - errdetail("Expected %08x, got %08x.", - LH_OVERFLOW_PAGE, opaque->hasho_flag))); - - if (BlockNumberIsValid(opaque->hasho_prevblkno)) - bit = true; - - UnlockReleaseBuffer(buf); - /* Read the metapage so we can determine which bitmap page to use */ metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE); metap = HashPageGetMeta(BufferGetPage(metabuf)); - /* Identify overflow bit number */ + /* + * Reject attempt to read the bit for a metapage or bitmap page; this is + * only meaningful for overflow pages. + */ + if (ovflblkno == 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid overflow block number %u", + (BlockNumber) ovflblkno))); + for (i = 0; i < metap->hashm_nmaps; i++) + if (metap->hashm_mapp[i] == ovflblkno) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid overflow block number %u", + (BlockNumber) ovflblkno))); + + /* + * Identify overflow bit number. This will error out for primary bucket + * pages, and we've already rejected the metapage and bitmap pages above. + */ ovflbitno = _hash_ovflblkno_to_bitno(metap, (BlockNumber) ovflblkno); bitmappage = ovflbitno >> BMPG_SHIFT(metap); @@ -450,12 +451,21 @@ hash_bitmap_info(PG_FUNCTION_ARGS) if (bitmappage >= metap->hashm_nmaps) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid overflow bit number %u", ovflbitno))); + errmsg("invalid overflow block number %u", + (BlockNumber) ovflblkno))); bitmapblkno = metap->hashm_mapp[bitmappage]; _hash_relbuf(indexRel, metabuf); + /* Check the status of bitmap bit for overflow page */ + mapbuf = _hash_getbuf(indexRel, bitmapblkno, HASH_READ, LH_BITMAP_PAGE); + mappage = BufferGetPage(mapbuf); + freep = HashPageGetBitmap(mappage); + + bit = ISSET(freep, bitmapbit) != 0; + + _hash_relbuf(indexRel, mapbuf); index_close(indexRel, AccessShareLock); /* Build a tuple descriptor for our result type */ diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c index 753c8a6a13..3334089329 100644 --- a/src/backend/access/hash/hashovfl.c +++ b/src/backend/access/hash/hashovfl.c @@ -69,11 +69,20 @@ _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno) if (ovflblkno <= (BlockNumber) (1 << i)) break; /* oops */ bitnum = ovflblkno - (1 << i); - if (bitnum <= metap->hashm_spares[i]) + + /* + * bitnum has to be greater than number of overflow page added in + * previous split point. The overflow page at this splitnum (i) if any + * should start from ((2 ^ i) + metap->hashm_spares[i - 1] + 1). + */ + if (bitnum > metap->hashm_spares[i - 1] && + bitnum <= metap->hashm_spares[i]) return bitnum - 1; /* -1 to convert 1-based to 0-based */ } - elog(ERROR, "invalid overflow block number %u", ovflblkno); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid overflow block number %u", ovflblkno))); return 0; /* keep compiler quiet */ }