Age Owner TLA Line data Source code
1 : /*
2 : * hashfuncs.c
3 : * Functions to investigate the content of HASH indexes
4 : *
5 : * Copyright (c) 2017-2023, 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 "catalog/pg_am.h"
16 : #include "catalog/pg_type.h"
17 : #include "funcapi.h"
18 : #include "miscadmin.h"
19 : #include "pageinspect.h"
20 : #include "utils/array.h"
21 : #include "utils/builtins.h"
22 : #include "utils/rel.h"
23 :
2257 rhaas 24 CBC 7 : PG_FUNCTION_INFO_V1(hash_page_type);
25 7 : PG_FUNCTION_INFO_V1(hash_page_stats);
26 7 : PG_FUNCTION_INFO_V1(hash_page_items);
27 7 : PG_FUNCTION_INFO_V1(hash_bitmap_info);
28 7 : PG_FUNCTION_INFO_V1(hash_metapage_info);
29 :
30 : #define IS_HASH(r) ((r)->rd_rel->relam == HASH_AM_OID)
31 :
32 : /* ------------------------------------------------
33 : * structure for single hash page statistics
34 : * ------------------------------------------------
35 : */
36 : typedef struct HashPageStat
37 : {
38 : int live_items;
39 : int dead_items;
40 : int page_size;
41 : int free_size;
42 :
43 : /* opaque data */
44 : BlockNumber hasho_prevblkno;
45 : BlockNumber hasho_nextblkno;
46 : Bucket hasho_bucket;
47 : uint16 hasho_flag;
48 : uint16 hasho_page_id;
49 : } HashPageStat;
50 :
51 :
52 : /*
53 : * Verify that the given bytea contains a HASH page, or die in the attempt.
54 : * A pointer to a palloc'd, properly aligned copy of the page is returned.
55 : */
56 : static Page
57 36 : verify_hash_page(bytea *raw_page, int flags)
58 : {
2256 tgl 59 36 : Page page = get_page_from_raw(raw_page);
2195 rhaas 60 32 : int pagetype = LH_UNUSED_PAGE;
61 :
62 : /* Treat new pages as unused. */
63 32 : if (!PageIsNew(page))
64 : {
65 : HashPageOpaque pageopaque;
66 :
67 28 : if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData)))
68 4 : ereport(ERROR,
69 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
70 : errmsg("input page is not a valid %s page", "hash"),
71 : errdetail("Expected special size %d, got %d.",
72 : (int) MAXALIGN(sizeof(HashPageOpaqueData)),
73 : (int) PageGetSpecialSize(page))));
74 :
373 michael 75 24 : pageopaque = HashPageGetOpaque(page);
2195 rhaas 76 24 : if (pageopaque->hasho_page_id != HASHO_PAGE_ID)
2195 rhaas 77 UBC 0 : ereport(ERROR,
78 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
79 : errmsg("input page is not a valid %s page", "hash"),
80 : errdetail("Expected %08x, got %08x.",
81 : HASHO_PAGE_ID, pageopaque->hasho_page_id)));
82 :
2195 rhaas 83 CBC 24 : pagetype = pageopaque->hasho_flag & LH_PAGE_TYPE;
84 : }
85 :
86 : /* Check that page type is sane. */
2257 87 28 : if (pagetype != LH_OVERFLOW_PAGE && pagetype != LH_BUCKET_PAGE &&
2195 88 8 : pagetype != LH_BITMAP_PAGE && pagetype != LH_META_PAGE &&
89 : pagetype != LH_UNUSED_PAGE)
2257 rhaas 90 UBC 0 : ereport(ERROR,
91 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
92 : errmsg("invalid hash page type %08x", pagetype)));
93 :
94 : /* If requested, verify page type. */
2257 rhaas 95 CBC 28 : if (flags != 0 && (pagetype & flags) == 0)
96 : {
97 12 : switch (flags)
98 : {
99 6 : case LH_META_PAGE:
100 6 : ereport(ERROR,
101 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
102 : errmsg("page is not a hash meta page")));
103 : break;
104 6 : case LH_BUCKET_PAGE | LH_OVERFLOW_PAGE:
105 6 : ereport(ERROR,
106 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
107 : errmsg("page is not a hash bucket or overflow page")));
108 : break;
2257 rhaas 109 UBC 0 : case LH_OVERFLOW_PAGE:
110 0 : ereport(ERROR,
111 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
112 : errmsg("page is not a hash overflow page")));
113 : break;
114 0 : default:
115 0 : elog(ERROR,
116 : "hash page of type %08x not in mask %08x",
117 : pagetype, flags);
118 : break;
119 : }
120 : }
121 :
122 : /*
123 : * If it is the metapage, also verify magic number and version.
124 : */
2257 rhaas 125 CBC 16 : if (pagetype == LH_META_PAGE)
126 : {
127 2 : HashMetaPage metap = HashPageGetMeta(page);
128 :
129 2 : if (metap->hashm_magic != HASH_MAGIC)
2257 rhaas 130 UBC 0 : ereport(ERROR,
131 : (errcode(ERRCODE_INDEX_CORRUPTED),
132 : errmsg("invalid magic number for metadata"),
133 : errdetail("Expected 0x%08x, got 0x%08x.",
134 : HASH_MAGIC, metap->hashm_magic)));
135 :
2257 rhaas 136 CBC 2 : if (metap->hashm_version != HASH_VERSION)
2257 rhaas 137 UBC 0 : ereport(ERROR,
138 : (errcode(ERRCODE_INDEX_CORRUPTED),
139 : errmsg("invalid version for metadata"),
140 : errdetail("Expected %d, got %d.",
141 : HASH_VERSION, metap->hashm_version)));
142 : }
143 :
2257 rhaas 144 CBC 16 : return page;
145 : }
146 :
147 : /* -------------------------------------------------
148 : * GetHashPageStatistics()
149 : *
150 : * Collect statistics of single hash page
151 : * -------------------------------------------------
152 : */
153 : static void
2153 bruce 154 4 : GetHashPageStatistics(Page page, HashPageStat *stat)
155 : {
2257 rhaas 156 4 : OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
373 michael 157 4 : HashPageOpaque opaque = HashPageGetOpaque(page);
158 : int off;
159 :
2257 rhaas 160 4 : stat->dead_items = stat->live_items = 0;
161 4 : stat->page_size = PageGetPageSize(page);
162 :
163 : /* hash page opaque data */
164 4 : stat->hasho_prevblkno = opaque->hasho_prevblkno;
165 4 : stat->hasho_nextblkno = opaque->hasho_nextblkno;
166 4 : stat->hasho_bucket = opaque->hasho_bucket;
167 4 : stat->hasho_flag = opaque->hasho_flag;
168 4 : stat->hasho_page_id = opaque->hasho_page_id;
169 :
170 : /* count live and dead tuples, and free space */
171 5 : for (off = FirstOffsetNumber; off <= maxoff; off++)
172 : {
173 1 : ItemId id = PageGetItemId(page, off);
174 :
175 1 : if (!ItemIdIsDead(id))
176 1 : stat->live_items++;
177 : else
2257 rhaas 178 UBC 0 : stat->dead_items++;
179 : }
2257 rhaas 180 CBC 4 : stat->free_size = PageGetFreeSpace(page);
181 4 : }
182 :
183 : /* ---------------------------------------------------
184 : * hash_page_type()
185 : *
186 : * Usage: SELECT hash_page_type(get_raw_page('con_hash_index', 1));
187 : * ---------------------------------------------------
188 : */
189 : Datum
190 9 : hash_page_type(PG_FUNCTION_ARGS)
191 : {
192 9 : bytea *raw_page = PG_GETARG_BYTEA_P(0);
193 : Page page;
194 : HashPageOpaque opaque;
195 : int pagetype;
196 : const char *type;
197 :
198 9 : if (!superuser())
2257 rhaas 199 UBC 0 : ereport(ERROR,
200 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
201 : errmsg("must be superuser to use raw page functions")));
202 :
2257 rhaas 203 CBC 9 : page = verify_hash_page(raw_page, 0);
204 :
2195 205 7 : if (PageIsNew(page))
2257 206 1 : type = "unused";
207 : else
208 : {
373 michael 209 6 : opaque = HashPageGetOpaque(page);
210 :
211 : /* page type (flags) */
2186 tgl 212 6 : pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
213 6 : if (pagetype == LH_META_PAGE)
2195 rhaas 214 1 : type = "metapage";
2186 tgl 215 5 : else if (pagetype == LH_OVERFLOW_PAGE)
2195 rhaas 216 UBC 0 : type = "overflow";
2186 tgl 217 CBC 5 : else if (pagetype == LH_BUCKET_PAGE)
2195 rhaas 218 4 : type = "bucket";
2186 tgl 219 1 : else if (pagetype == LH_BITMAP_PAGE)
2195 rhaas 220 1 : type = "bitmap";
221 : else
2195 rhaas 222 UBC 0 : type = "unused";
223 : }
224 :
2257 rhaas 225 CBC 7 : PG_RETURN_TEXT_P(cstring_to_text(type));
226 : }
227 :
228 : /* ---------------------------------------------------
229 : * hash_page_stats()
230 : *
231 : * Usage: SELECT * FROM hash_page_stats(get_raw_page('con_hash_index', 1));
232 : * ---------------------------------------------------
233 : */
234 : Datum
235 9 : hash_page_stats(PG_FUNCTION_ARGS)
236 : {
237 9 : bytea *raw_page = PG_GETARG_BYTEA_P(0);
238 : Page page;
239 : int j;
240 : Datum values[9];
267 peter 241 GNC 9 : bool nulls[9] = {0};
242 : HashPageStat stat;
243 : HeapTuple tuple;
244 : TupleDesc tupleDesc;
245 :
2257 rhaas 246 CBC 9 : if (!superuser())
2257 rhaas 247 UBC 0 : ereport(ERROR,
248 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
249 : errmsg("must be superuser to use raw page functions")));
250 :
2257 rhaas 251 CBC 9 : page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
252 :
253 : /* keep compiler quiet */
254 4 : stat.hasho_prevblkno = stat.hasho_nextblkno = InvalidBlockNumber;
255 4 : stat.hasho_flag = stat.hasho_page_id = stat.free_size = 0;
256 :
257 4 : GetHashPageStatistics(page, &stat);
258 :
259 : /* Build a tuple descriptor for our result type */
260 4 : if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
2257 rhaas 261 UBC 0 : elog(ERROR, "return type must be a row type");
2257 rhaas 262 CBC 4 : tupleDesc = BlessTupleDesc(tupleDesc);
263 :
264 4 : j = 0;
265 4 : values[j++] = Int32GetDatum(stat.live_items);
266 4 : values[j++] = Int32GetDatum(stat.dead_items);
267 4 : values[j++] = Int32GetDatum(stat.page_size);
268 4 : values[j++] = Int32GetDatum(stat.free_size);
269 4 : values[j++] = Int64GetDatum((int64) stat.hasho_prevblkno);
270 4 : values[j++] = Int64GetDatum((int64) stat.hasho_nextblkno);
271 4 : values[j++] = Int64GetDatum((int64) stat.hasho_bucket);
2257 rhaas 272 GIC 4 : values[j++] = Int32GetDatum((int32) stat.hasho_flag);
2257 rhaas 273 CBC 4 : values[j++] = Int32GetDatum((int32) stat.hasho_page_id);
274 :
275 4 : tuple = heap_form_tuple(tupleDesc, values, nulls);
276 :
2257 rhaas 277 GIC 4 : PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
278 : }
279 :
280 : /*
281 : * cross-call data structure for SRF
282 : */
283 : struct user_args
284 : {
285 : Page page;
286 : OffsetNumber offset;
287 : };
288 :
289 : /*-------------------------------------------------------
290 : * hash_page_items()
291 : *
292 : * Get IndexTupleData set in a hash page
293 : *
294 : * Usage: SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1));
295 : *-------------------------------------------------------
2257 rhaas 296 ECB : */
297 : Datum
2257 rhaas 298 CBC 10 : hash_page_items(PG_FUNCTION_ARGS)
299 : {
2257 rhaas 300 GIC 10 : bytea *raw_page = PG_GETARG_BYTEA_P(0);
301 : Page page;
2257 rhaas 302 ECB : Datum result;
303 : Datum values[3];
267 peter 304 GNC 10 : bool nulls[3] = {0};
305 : uint32 hashkey;
306 : HeapTuple tuple;
307 : FuncCallContext *fctx;
308 : MemoryContext mctx;
2257 rhaas 309 ECB : struct user_args *uargs;
2257 rhaas 310 EUB :
2257 rhaas 311 GIC 10 : if (!superuser())
2257 rhaas 312 UIC 0 : ereport(ERROR,
313 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1165 alvherre 314 ECB : errmsg("must be superuser to use raw page functions")));
315 :
2257 rhaas 316 GIC 10 : if (SRF_IS_FIRSTCALL())
317 : {
2257 rhaas 318 ECB : TupleDesc tupleDesc;
319 :
2257 rhaas 320 CBC 9 : fctx = SRF_FIRSTCALL_INIT();
321 :
322 9 : mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
323 :
1899 324 9 : page = verify_hash_page(raw_page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
325 :
2257 326 4 : uargs = palloc(sizeof(struct user_args));
327 :
328 4 : uargs->page = page;
329 :
330 4 : uargs->offset = FirstOffsetNumber;
331 :
2257 rhaas 332 GIC 4 : fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
2257 rhaas 333 ECB :
2257 rhaas 334 EUB : /* Build a tuple descriptor for our result type */
2257 rhaas 335 CBC 4 : if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
2257 rhaas 336 UIC 0 : elog(ERROR, "return type must be a row type");
2257 rhaas 337 CBC 4 : tupleDesc = BlessTupleDesc(tupleDesc);
338 :
339 4 : fctx->attinmeta = TupleDescGetAttInMetadata(tupleDesc);
340 :
341 4 : fctx->user_fctx = uargs;
342 :
2257 rhaas 343 GIC 4 : MemoryContextSwitchTo(mctx);
2257 rhaas 344 ECB : }
345 :
2257 rhaas 346 GIC 5 : fctx = SRF_PERCALL_SETUP();
2257 rhaas 347 CBC 5 : uargs = fctx->user_fctx;
348 :
2257 rhaas 349 GIC 5 : if (fctx->call_cntr < fctx->max_calls)
350 : {
351 : ItemId id;
352 : IndexTuple itup;
2257 rhaas 353 ECB : int j;
354 :
2257 rhaas 355 CBC 1 : id = PageGetItemId(uargs->page, uargs->offset);
2257 rhaas 356 EUB :
2257 rhaas 357 GIC 1 : if (!ItemIdIsValid(id))
2257 rhaas 358 LBC 0 : elog(ERROR, "invalid ItemId");
359 :
2257 rhaas 360 CBC 1 : itup = (IndexTuple) PageGetItem(uargs->page, id);
2257 rhaas 361 ECB :
2257 rhaas 362 CBC 1 : j = 0;
2256 363 1 : values[j++] = Int32GetDatum((int32) uargs->offset);
2257 rhaas 364 GIC 1 : values[j++] = PointerGetDatum(&itup->t_tid);
2257 rhaas 365 ECB :
2257 rhaas 366 CBC 1 : hashkey = _hash_get_indextuple_hashkey(itup);
2256 rhaas 367 GIC 1 : values[j] = Int64GetDatum((int64) hashkey);
2257 rhaas 368 ECB :
2257 rhaas 369 GIC 1 : tuple = heap_form_tuple(fctx->attinmeta->tupdesc, values, nulls);
2257 rhaas 370 CBC 1 : result = HeapTupleGetDatum(tuple);
371 :
2257 rhaas 372 GIC 1 : uargs->offset = uargs->offset + 1;
2257 rhaas 373 ECB :
2257 rhaas 374 GIC 1 : SRF_RETURN_NEXT(fctx, result);
375 : }
376 :
1119 tgl 377 4 : SRF_RETURN_DONE(fctx);
378 : }
379 :
380 : /* ------------------------------------------------
381 : * hash_bitmap_info()
382 : *
383 : * Get bitmap information for a particular overflow page
384 : *
2257 rhaas 385 ECB : * Usage: SELECT * FROM hash_bitmap_info('con_hash_index'::regclass, 5);
386 : * ------------------------------------------------
387 : */
388 : Datum
2257 rhaas 389 GIC 9 : hash_bitmap_info(PG_FUNCTION_ARGS)
390 : {
391 9 : Oid indexRelid = PG_GETARG_OID(0);
810 peter 392 9 : int64 ovflblkno = PG_GETARG_INT64(1);
393 : HashMetaPage metap;
2250 rhaas 394 ECB : Buffer metabuf,
395 : mapbuf;
396 : BlockNumber bitmapblkno;
397 : Page mappage;
2257 rhaas 398 GIC 9 : bool bit = false;
399 : TupleDesc tupleDesc;
400 : Relation indexRel;
401 : uint32 ovflbitno;
402 : int32 bitmappage,
403 : bitmapbit;
2257 rhaas 404 ECB : HeapTuple tuple;
405 : int i,
406 : j;
407 : Datum values[3];
267 peter 408 GNC 9 : bool nulls[3] = {0};
409 : uint32 *freep;
410 :
2257 rhaas 411 GIC 9 : if (!superuser())
2257 rhaas 412 LBC 0 : ereport(ERROR,
413 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1165 alvherre 414 ECB : errmsg("must be superuser to use raw page functions")));
2257 rhaas 415 :
2257 rhaas 416 GIC 9 : indexRel = index_open(indexRelid, AccessShareLock);
417 :
418 9 : if (!IS_HASH(indexRel))
389 michael 419 1 : ereport(ERROR,
389 michael 420 ECB : (errcode(ERRCODE_WRONG_OBJECT_TYPE),
389 michael 421 EUB : errmsg("\"%s\" is not a %s index",
422 : RelationGetRelationName(indexRel), "hash")));
423 :
2257 rhaas 424 GIC 8 : if (RELATION_IS_OTHER_TEMP(indexRel))
2257 rhaas 425 LBC 0 : ereport(ERROR,
2257 rhaas 426 ECB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
427 : errmsg("cannot access temporary tables of other sessions")));
428 :
810 peter 429 GIC 8 : if (ovflblkno < 0 || ovflblkno > MaxBlockNumber)
810 peter 430 CBC 1 : ereport(ERROR,
810 peter 431 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
432 : errmsg("invalid block number")));
433 :
2257 tgl 434 GIC 7 : if (ovflblkno >= RelationGetNumberOfBlocks(indexRel))
rhaas 435 1 : ereport(ERROR,
436 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
810 peter 437 ECB : errmsg("block number %lld is out of range for relation \"%s\"",
438 : (long long int) ovflblkno, RelationGetRelationName(indexRel))));
439 :
440 : /* Read the metapage so we can determine which bitmap page to use */
2257 rhaas 441 GIC 6 : metabuf = _hash_getbuf(indexRel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
442 6 : metap = HashPageGetMeta(BufferGetPage(metabuf));
443 :
2250 rhaas 444 ECB : /*
445 : * Reject attempt to read the bit for a metapage or bitmap page; this is
446 : * only meaningful for overflow pages.
447 : */
2250 rhaas 448 GIC 6 : if (ovflblkno == 0)
2250 rhaas 449 CBC 1 : ereport(ERROR,
2250 rhaas 450 ECB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
451 : errmsg("invalid overflow block number %u",
452 : (BlockNumber) ovflblkno)));
2250 rhaas 453 GIC 9 : for (i = 0; i < metap->hashm_nmaps; i++)
454 5 : if (metap->hashm_mapp[i] == ovflblkno)
455 1 : ereport(ERROR,
456 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
457 : errmsg("invalid overflow block number %u",
458 : (BlockNumber) ovflblkno)));
459 :
2250 rhaas 460 ECB : /*
461 : * Identify overflow bit number. This will error out for primary bucket
2250 rhaas 462 EUB : * pages, and we've already rejected the metapage and bitmap pages above.
463 : */
2257 tgl 464 GIC 4 : ovflbitno = _hash_ovflblkno_to_bitno(metap, (BlockNumber) ovflblkno);
2257 rhaas 465 EUB :
2257 rhaas 466 UBC 0 : bitmappage = ovflbitno >> BMPG_SHIFT(metap);
2257 rhaas 467 UIC 0 : bitmapbit = ovflbitno & BMPG_MASK(metap);
468 :
469 0 : if (bitmappage >= metap->hashm_nmaps)
470 0 : ereport(ERROR,
2257 rhaas 471 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
472 : errmsg("invalid overflow block number %u",
2250 473 : (BlockNumber) ovflblkno)));
474 :
2257 rhaas 475 UIC 0 : bitmapblkno = metap->hashm_mapp[bitmappage];
2257 rhaas 476 EUB :
2257 rhaas 477 UBC 0 : _hash_relbuf(indexRel, metabuf);
2257 rhaas 478 EUB :
479 : /* Check the status of bitmap bit for overflow page */
2250 rhaas 480 UBC 0 : mapbuf = _hash_getbuf(indexRel, bitmapblkno, HASH_READ, LH_BITMAP_PAGE);
2250 rhaas 481 UIC 0 : mappage = BufferGetPage(mapbuf);
2250 rhaas 482 UBC 0 : freep = HashPageGetBitmap(mappage);
2250 rhaas 483 EUB :
2250 rhaas 484 UIC 0 : bit = ISSET(freep, bitmapbit) != 0;
485 :
2250 rhaas 486 UBC 0 : _hash_relbuf(indexRel, mapbuf);
2257 487 0 : index_close(indexRel, AccessShareLock);
2257 rhaas 488 EUB :
489 : /* Build a tuple descriptor for our result type */
2257 rhaas 490 UBC 0 : if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
491 0 : elog(ERROR, "return type must be a row type");
492 0 : tupleDesc = BlessTupleDesc(tupleDesc);
2257 rhaas 493 EUB :
2257 rhaas 494 UIC 0 : j = 0;
2256 rhaas 495 UBC 0 : values[j++] = Int64GetDatum((int64) bitmapblkno);
2257 rhaas 496 UIC 0 : values[j++] = Int32GetDatum(bitmapbit);
497 0 : values[j++] = BoolGetDatum(bit);
498 :
499 0 : tuple = heap_form_tuple(tupleDesc, values, nulls);
500 :
501 0 : PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
502 : }
503 :
504 : /* ------------------------------------------------
505 : * hash_metapage_info()
506 : *
2257 rhaas 507 ECB : * Get the meta-page information for a hash index
508 : *
509 : * Usage: SELECT * FROM hash_metapage_info(get_raw_page('con_hash_index', 0))
510 : * ------------------------------------------------
511 : */
512 : Datum
2257 rhaas 513 GIC 9 : hash_metapage_info(PG_FUNCTION_ARGS)
514 : {
515 9 : bytea *raw_page = PG_GETARG_BYTEA_P(0);
516 : Page page;
2257 rhaas 517 ECB : HashMetaPageData *metad;
518 : TupleDesc tupleDesc;
519 : HeapTuple tuple;
520 : int i,
521 : j;
2257 rhaas 522 EUB : Datum values[16];
267 peter 523 GNC 9 : bool nulls[16] = {0};
524 : Datum spares[HASH_MAX_SPLITPOINTS];
525 : Datum mapp[HASH_MAX_BITMAPS];
2257 rhaas 526 ECB :
2257 rhaas 527 GIC 9 : if (!superuser())
2257 rhaas 528 UIC 0 : ereport(ERROR,
2257 rhaas 529 ECB : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1165 alvherre 530 EUB : errmsg("must be superuser to use raw page functions")));
2257 rhaas 531 ECB :
2257 rhaas 532 GIC 9 : page = verify_hash_page(raw_page, LH_META_PAGE);
2257 rhaas 533 ECB :
534 : /* Build a tuple descriptor for our result type */
2257 rhaas 535 CBC 1 : if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
2257 rhaas 536 LBC 0 : elog(ERROR, "return type must be a row type");
2257 rhaas 537 CBC 1 : tupleDesc = BlessTupleDesc(tupleDesc);
2257 rhaas 538 ECB :
2257 rhaas 539 CBC 1 : metad = HashPageGetMeta(page);
2257 rhaas 540 ECB :
2257 rhaas 541 CBC 1 : j = 0;
2256 542 1 : values[j++] = Int64GetDatum((int64) metad->hashm_magic);
543 1 : values[j++] = Int64GetDatum((int64) metad->hashm_version);
2257 544 1 : values[j++] = Float8GetDatum(metad->hashm_ntuples);
2256 545 1 : values[j++] = Int32GetDatum((int32) metad->hashm_ffactor);
546 1 : values[j++] = Int32GetDatum((int32) metad->hashm_bsize);
547 1 : values[j++] = Int32GetDatum((int32) metad->hashm_bmsize);
2256 rhaas 548 GIC 1 : values[j++] = Int32GetDatum((int32) metad->hashm_bmshift);
2256 rhaas 549 CBC 1 : values[j++] = Int64GetDatum((int64) metad->hashm_maxbucket);
550 1 : values[j++] = Int64GetDatum((int64) metad->hashm_highmask);
551 1 : values[j++] = Int64GetDatum((int64) metad->hashm_lowmask);
2256 rhaas 552 GIC 1 : values[j++] = Int64GetDatum((int64) metad->hashm_ovflpoint);
2256 rhaas 553 CBC 1 : values[j++] = Int64GetDatum((int64) metad->hashm_firstfree);
554 1 : values[j++] = Int64GetDatum((int64) metad->hashm_nmaps);
555 1 : values[j++] = ObjectIdGetDatum((Oid) metad->hashm_procid);
556 :
2257 557 99 : for (i = 0; i < HASH_MAX_SPLITPOINTS; i++)
2237 rhaas 558 GIC 98 : spares[i] = Int64GetDatum((int64) metad->hashm_spares[i]);
282 peter 559 GNC 1 : values[j++] = PointerGetDatum(construct_array_builtin(spares, HASH_MAX_SPLITPOINTS, INT8OID));
560 :
2257 rhaas 561 GIC 1025 : for (i = 0; i < HASH_MAX_BITMAPS; i++)
2256 562 1024 : mapp[i] = Int64GetDatum((int64) metad->hashm_mapp[i]);
282 peter 563 GNC 1 : values[j++] = PointerGetDatum(construct_array_builtin(mapp, HASH_MAX_BITMAPS, INT8OID));
564 :
2257 rhaas 565 GIC 1 : tuple = heap_form_tuple(tupleDesc, values, nulls);
566 :
567 1 : PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
568 : }
|