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