PostgreSQL Source Code git master
Loading...
Searching...
No Matches
hashfuncs.c
Go to the documentation of this file.
1/*
2 * hashfuncs.c
3 * Functions to investigate the content of HASH indexes
4 *
5 * Copyright (c) 2017-2026, PostgreSQL Global Development Group
6 *
7 * IDENTIFICATION
8 * contrib/pageinspect/hashfuncs.c
9 */
10
11#include "postgres.h"
12
13#include "access/hash.h"
14#include "access/htup_details.h"
15#include "access/relation.h"
16#include "catalog/pg_am.h"
17#include "catalog/pg_type.h"
18#include "funcapi.h"
19#include "miscadmin.h"
20#include "pageinspect.h"
21#include "utils/array.h"
22#include "utils/builtins.h"
23#include "utils/rel.h"
24
30
31#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
32#define IS_HASH(r) ((r)->rd_rel->relam == HASH_AM_OID)
33
34/* ------------------------------------------------
35 * structure for single hash page statistics
36 * ------------------------------------------------
37 */
52
53
54/*
55 * Verify that the given bytea contains a HASH page, or die in the attempt.
56 * A pointer to a palloc'd, properly aligned copy of the page is returned.
57 */
58static Page
60{
63
64 /* Treat new pages as unused. */
65 if (!PageIsNew(page))
66 {
68
72 errmsg("input page is not a valid %s page", "hash"),
73 errdetail("Expected special size %d, got %d.",
74 (int) MAXALIGN(sizeof(HashPageOpaqueData)),
75 (int) PageGetSpecialSize(page))));
76
78 if (pageopaque->hasho_page_id != HASHO_PAGE_ID)
81 errmsg("input page is not a valid %s page", "hash"),
82 errdetail("Expected %08x, got %08x.",
83 HASHO_PAGE_ID, pageopaque->hasho_page_id)));
84
85 pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
86 }
87
88 /* Check that page type is sane. */
94 errmsg("invalid hash page type %08x", pagetype)));
95
96 /* If requested, verify page type. */
97 if (flags != 0 && (pagetype & flags) == 0)
98 {
99 switch (flags)
100 {
101 case LH_META_PAGE:
104 errmsg("page is not a hash meta page")));
105 break;
109 errmsg("page is not a hash bucket or overflow page")));
110 break;
111 case LH_OVERFLOW_PAGE:
114 errmsg("page is not a hash overflow page")));
115 break;
116 default:
117 elog(ERROR,
118 "hash page of type %08x not in mask %08x",
119 pagetype, flags);
120 break;
121 }
122 }
123
124 /*
125 * If it is the metapage, also verify magic number and version.
126 */
127 if (pagetype == LH_META_PAGE)
128 {
130
131 if (metap->hashm_magic != HASH_MAGIC)
134 errmsg("invalid magic number for metadata"),
135 errdetail("Expected 0x%08x, got 0x%08x.",
136 HASH_MAGIC, metap->hashm_magic)));
137
138 if (metap->hashm_version != HASH_VERSION)
141 errmsg("invalid version for metadata"),
142 errdetail("Expected %d, got %d.",
143 HASH_VERSION, metap->hashm_version)));
144 }
145
146 return page;
147}
148
149/* -------------------------------------------------
150 * GetHashPageStatistics()
151 *
152 * Collect statistics of single hash page
153 * -------------------------------------------------
154 */
155static void
157{
159 HashPageOpaque opaque = HashPageGetOpaque(page);
160 int off;
161
162 stat->dead_items = stat->live_items = 0;
163 stat->page_size = PageGetPageSize(page);
164
165 /* hash page opaque data */
166 stat->hasho_prevblkno = opaque->hasho_prevblkno;
167 stat->hasho_nextblkno = opaque->hasho_nextblkno;
168 stat->hasho_bucket = opaque->hasho_bucket;
169 stat->hasho_flag = opaque->hasho_flag;
170 stat->hasho_page_id = opaque->hasho_page_id;
171
172 /* count live and dead tuples, and free space */
173 for (off = FirstOffsetNumber; off <= maxoff; off++)
174 {
175 ItemId id = PageGetItemId(page, off);
176
177 if (!ItemIdIsDead(id))
178 stat->live_items++;
179 else
180 stat->dead_items++;
181 }
182 stat->free_size = PageGetFreeSpace(page);
183}
184
185/* ---------------------------------------------------
186 * hash_page_type()
187 *
188 * Usage: SELECT hash_page_type(get_raw_page('con_hash_index', 1));
189 * ---------------------------------------------------
190 */
191Datum
193{
195 Page page;
196 HashPageOpaque opaque;
197 int pagetype;
198 const char *type;
199
200 if (!superuser())
203 errmsg("must be superuser to use raw page functions")));
204
205 page = verify_hash_page(raw_page, 0);
206
207 if (PageIsNew(page))
208 type = "unused";
209 else
210 {
211 opaque = HashPageGetOpaque(page);
212
213 /* page type (flags) */
214 pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
215 if (pagetype == LH_META_PAGE)
216 type = "metapage";
217 else if (pagetype == LH_OVERFLOW_PAGE)
218 type = "overflow";
219 else if (pagetype == LH_BUCKET_PAGE)
220 type = "bucket";
221 else if (pagetype == LH_BITMAP_PAGE)
222 type = "bitmap";
223 else
224 type = "unused";
225 }
226
228}
229
230/* ---------------------------------------------------
231 * hash_page_stats()
232 *
233 * Usage: SELECT * FROM hash_page_stats(get_raw_page('con_hash_index', 1));
234 * ---------------------------------------------------
235 */
236Datum
238{
240 Page page;
241 int j;
242 Datum values[9];
243 bool nulls[9] = {0};
245 HeapTuple tuple;
247
248 if (!superuser())
251 errmsg("must be superuser to use raw page functions")));
252
254
255 /* keep compiler quiet */
256 stat.hasho_prevblkno = stat.hasho_nextblkno = InvalidBlockNumber;
257 stat.hasho_flag = stat.hasho_page_id = stat.free_size = 0;
258
260
261 /* Build a tuple descriptor for our result type */
263 elog(ERROR, "return type must be a row type");
265
266 j = 0;
267 values[j++] = Int32GetDatum(stat.live_items);
268 values[j++] = Int32GetDatum(stat.dead_items);
269 values[j++] = Int32GetDatum(stat.page_size);
270 values[j++] = Int32GetDatum(stat.free_size);
271 values[j++] = Int64GetDatum((int64) stat.hasho_prevblkno);
272 values[j++] = Int64GetDatum((int64) stat.hasho_nextblkno);
273 values[j++] = Int64GetDatum((int64) stat.hasho_bucket);
274 values[j++] = Int32GetDatum((int32) stat.hasho_flag);
275 values[j++] = Int32GetDatum((int32) stat.hasho_page_id);
276
277 tuple = heap_form_tuple(tupleDesc, values, nulls);
278
280}
281
282/*
283 * cross-call data structure for SRF
284 */
290
291/*-------------------------------------------------------
292 * hash_page_items()
293 *
294 * Get IndexTupleData set in a hash page
295 *
296 * Usage: SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1));
297 *-------------------------------------------------------
298 */
299Datum
301{
303 Page page;
304 Datum result;
305 Datum values[3];
306 bool nulls[3] = {0};
308 HeapTuple tuple;
311 struct user_args *uargs;
312
313 if (!superuser())
316 errmsg("must be superuser to use raw page functions")));
317
318 if (SRF_IS_FIRSTCALL())
319 {
321
323
324 mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
325
327
328 uargs = palloc_object(struct user_args);
329
330 uargs->page = page;
331
332 uargs->offset = FirstOffsetNumber;
333
334 fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
335
336 /* Build a tuple descriptor for our result type */
338 elog(ERROR, "return type must be a row type");
340
342
343 fctx->user_fctx = uargs;
344
346 }
347
349 uargs = fctx->user_fctx;
350
351 if (fctx->call_cntr < fctx->max_calls)
352 {
353 ItemId id;
354 IndexTuple itup;
355 int j;
356
357 id = PageGetItemId(uargs->page, uargs->offset);
358
359 if (!ItemIdIsValid(id))
360 elog(ERROR, "invalid ItemId");
361
362 itup = (IndexTuple) PageGetItem(uargs->page, id);
363
364 j = 0;
365 values[j++] = Int32GetDatum((int32) uargs->offset);
366 values[j++] = PointerGetDatum(&itup->t_tid);
367
370
371 tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
372 result = HeapTupleGetDatum(tuple);
373
374 uargs->offset = uargs->offset + 1;
375
376 SRF_RETURN_NEXT(fctx, result);
377 }
378
380}
381
382/* ------------------------------------------------
383 * hash_bitmap_info()
384 *
385 * Get bitmap information for a particular overflow page
386 *
387 * Usage: SELECT * FROM hash_bitmap_info('con_hash_index'::regclass, 5);
388 * ------------------------------------------------
389 */
390Datum
392{
397 mapbuf;
400 bool bit = false;
402 Relation indexRel;
405 bitmapbit;
406 HeapTuple tuple;
407 int i,
408 j;
409 Datum values[3];
410 bool nulls[3] = {0};
411 uint32 *freep;
412
413 if (!superuser())
416 errmsg("must be superuser to use raw page functions")));
417
418 /*
419 * This uses relation_open() and not index_open(). The latter allows
420 * partitioned indexes, and these are forbidden here.
421 */
423
424 if (!IS_INDEX(indexRel) || !IS_HASH(indexRel))
427 errmsg("\"%s\" is not a %s index",
428 RelationGetRelationName(indexRel), "hash")));
429
430 if (RELATION_IS_OTHER_TEMP(indexRel))
433 errmsg("cannot access temporary tables of other sessions")));
434
438 errmsg("invalid block number")));
439
440 if (ovflblkno >= RelationGetNumberOfBlocks(indexRel))
443 errmsg("block number %" PRId64 " is out of range for relation \"%s\"",
445
446 /* Read the metapage so we can determine which bitmap page to use */
449
450 /*
451 * Reject attempt to read the bit for a metapage or bitmap page; this is
452 * only meaningful for overflow pages.
453 */
454 if (ovflblkno == 0)
457 errmsg("invalid overflow block number %u",
459 for (i = 0; i < metap->hashm_nmaps; i++)
460 if (metap->hashm_mapp[i] == ovflblkno)
463 errmsg("invalid overflow block number %u",
465
466 /*
467 * Identify overflow bit number. This will error out for primary bucket
468 * pages, and we've already rejected the metapage and bitmap pages above.
469 */
471
474
475 if (bitmappage >= metap->hashm_nmaps)
478 errmsg("invalid overflow block number %u",
480
481 bitmapblkno = metap->hashm_mapp[bitmappage];
482
483 _hash_relbuf(indexRel, metabuf);
484
485 /* Check the status of bitmap bit for overflow page */
489
490 bit = ISSET(freep, bitmapbit) != 0;
491
492 _hash_relbuf(indexRel, mapbuf);
494
495 /* Build a tuple descriptor for our result type */
497 elog(ERROR, "return type must be a row type");
499
500 j = 0;
503 values[j++] = BoolGetDatum(bit);
504
505 tuple = heap_form_tuple(tupleDesc, values, nulls);
506
508}
509
510/* ------------------------------------------------
511 * hash_metapage_info()
512 *
513 * Get the meta-page information for a hash index
514 *
515 * Usage: SELECT * FROM hash_metapage_info(get_raw_page('con_hash_index', 0))
516 * ------------------------------------------------
517 */
518Datum
520{
522 Page page;
525 HeapTuple tuple;
526 int i,
527 j;
528 Datum values[16];
529 bool nulls[16] = {0};
532
533 if (!superuser())
536 errmsg("must be superuser to use raw page functions")));
537
539
540 /* Build a tuple descriptor for our result type */
542 elog(ERROR, "return type must be a row type");
544
546
547 j = 0;
548 values[j++] = Int64GetDatum((int64) metad->hashm_magic);
549 values[j++] = Int64GetDatum((int64) metad->hashm_version);
550 values[j++] = Float8GetDatum(metad->hashm_ntuples);
551 values[j++] = Int32GetDatum((int32) metad->hashm_ffactor);
552 values[j++] = Int32GetDatum((int32) metad->hashm_bsize);
553 values[j++] = Int32GetDatum((int32) metad->hashm_bmsize);
554 values[j++] = Int32GetDatum((int32) metad->hashm_bmshift);
555 values[j++] = Int64GetDatum((int64) metad->hashm_maxbucket);
556 values[j++] = Int64GetDatum((int64) metad->hashm_highmask);
557 values[j++] = Int64GetDatum((int64) metad->hashm_lowmask);
558 values[j++] = Int64GetDatum((int64) metad->hashm_ovflpoint);
559 values[j++] = Int64GetDatum((int64) metad->hashm_firstfree);
560 values[j++] = Int64GetDatum((int64) metad->hashm_nmaps);
561 values[j++] = ObjectIdGetDatum((Oid) metad->hashm_procid);
562
563 for (i = 0; i < HASH_MAX_SPLITPOINTS; i++)
564 spares[i] = Int64GetDatum((int64) metad->hashm_spares[i]);
566
567 for (i = 0; i < HASH_MAX_BITMAPS; i++)
568 mapp[i] = Int64GetDatum((int64) metad->hashm_mapp[i]);
570
571 tuple = heap_form_tuple(tupleDesc, values, nulls);
572
574}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
#define MaxBlockNumber
Definition block.h:35
static Datum values[MAXATTR]
Definition bootstrap.c:155
int Buffer
Definition buf.h:23
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:466
Size PageGetFreeSpace(const PageData *page)
Definition bufpage.c:906
static uint16 PageGetSpecialSize(const PageData *page)
Definition bufpage.h:316
static Size PageGetPageSize(const PageData *page)
Definition bufpage.h:276
static bool PageIsNew(const PageData *page)
Definition bufpage.h:233
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:243
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:353
PageData * Page
Definition bufpage.h:81
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:371
#define MAXALIGN(LEN)
Definition c.h:826
int64_t int64
Definition c.h:543
int32_t int32
Definition c.h:542
uint16_t uint16
Definition c.h:545
uint32_t uint32
Definition c.h:546
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
#define palloc_object(type)
Definition fe_memutils.h:74
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_GETARG_INT64(n)
Definition fmgr.h:284
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_GETARG_BYTEA_P(n)
Definition fmgr.h:336
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
#define HashPageGetOpaque(page)
Definition hash.h:88
#define LH_BUCKET_PAGE
Definition hash.h:55
#define HASH_MAX_BITMAPS
Definition hash.h:230
#define BMPG_MASK(metap)
Definition hash.h:314
#define HASH_VERSION
Definition hash.h:201
#define HASH_MAX_SPLITPOINTS
Definition hash.h:239
#define LH_UNUSED_PAGE
Definition hash.h:53
#define HashPageGetBitmap(page)
Definition hash.h:316
#define LH_META_PAGE
Definition hash.h:57
#define HASHO_PAGE_ID
Definition hash.h:101
#define ISSET(A, N)
Definition hash.h:334
#define HashPageGetMeta(page)
Definition hash.h:323
#define HASH_READ
Definition hash.h:339
#define HASH_METAPAGE
Definition hash.h:198
#define LH_PAGE_TYPE
Definition hash.h:63
uint32 Bucket
Definition hash.h:35
#define LH_BITMAP_PAGE
Definition hash.h:56
#define BMPG_SHIFT(metap)
Definition hash.h:313
#define HASH_MAGIC
Definition hash.h:200
#define LH_OVERFLOW_PAGE
Definition hash.h:54
#define IS_HASH(r)
Definition hashfuncs.c:32
Datum hash_bitmap_info(PG_FUNCTION_ARGS)
Definition hashfuncs.c:391
Datum hash_page_stats(PG_FUNCTION_ARGS)
Definition hashfuncs.c:237
Datum hash_page_type(PG_FUNCTION_ARGS)
Definition hashfuncs.c:192
#define IS_INDEX(r)
Definition hashfuncs.c:31
Datum hash_metapage_info(PG_FUNCTION_ARGS)
Definition hashfuncs.c:519
static Page verify_hash_page(bytea *raw_page, int flags)
Definition hashfuncs.c:59
static void GetHashPageStatistics(Page page, HashPageStat *stat)
Definition hashfuncs.c:156
Datum hash_page_items(PG_FUNCTION_ARGS)
Definition hashfuncs.c:300
uint32 _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno)
Definition hashovfl.c:62
void _hash_relbuf(Relation rel, Buffer buf)
Definition hashpage.c:266
Buffer _hash_getbuf(Relation rel, BlockNumber blkno, int access, int flags)
Definition hashpage.c:70
uint32 _hash_get_indextuple_hashkey(IndexTuple itup)
Definition hashutil.c:291
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1117
int j
Definition isn.c:78
int i
Definition isn.c:77
#define ItemIdIsDead(itemId)
Definition itemid.h:113
#define ItemIdIsValid(itemId)
Definition itemid.h:86
IndexTupleData * IndexTuple
Definition itup.h:53
#define AccessShareLock
Definition lockdefs.h:36
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
Page get_page_from_raw(bytea *raw_page)
Definition rawpage.c:218
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static Datum Int64GetDatum(int64 X)
Definition postgres.h:423
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
uint64_t Datum
Definition postgres.h:70
static Datum Float8GetDatum(float8 X)
Definition postgres.h:512
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222
unsigned int Oid
static int fb(int x)
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RELATION_IS_OTHER_TEMP(relation)
Definition rel.h:667
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:47
BlockNumber hasho_nextblkno
Definition hash.h:80
uint16 hasho_flag
Definition hash.h:82
BlockNumber hasho_prevblkno
Definition hash.h:79
uint16 hasho_page_id
Definition hash.h:83
Bucket hasho_bucket
Definition hash.h:81
BlockNumber hasho_prevblkno
Definition hashfuncs.c:46
uint16 hasho_page_id
Definition hashfuncs.c:50
Bucket hasho_bucket
Definition hashfuncs.c:48
uint16 hasho_flag
Definition hashfuncs.c:49
BlockNumber hasho_nextblkno
Definition hashfuncs.c:47
ItemPointerData t_tid
Definition itup.h:37
OffsetNumber offset
Definition hashfuncs.c:288
Page page
Definition hashfuncs.c:287
Definition c.h:706
bool superuser(void)
Definition superuser.c:46
Datum bit(PG_FUNCTION_ARGS)
Definition varbit.c:391
text * cstring_to_text(const char *s)
Definition varlena.c:181
const char * type
#define stat
Definition win32_port.h:74