|
27 | 27 |
|
28 | 28 | #include "postgres.h"
|
29 | 29 |
|
| 30 | +#include "access/gin_private.h" |
30 | 31 | #include "access/heapam.h"
|
| 32 | +#include "access/htup_details.h" |
31 | 33 | #include "access/nbtree.h"
|
32 | 34 | #include "catalog/namespace.h"
|
33 | 35 | #include "funcapi.h"
|
|
39 | 41 |
|
40 | 42 | extern Datum pgstatindex(PG_FUNCTION_ARGS);
|
41 | 43 | extern Datum pg_relpages(PG_FUNCTION_ARGS);
|
| 44 | +extern Datum pgstatginindex(PG_FUNCTION_ARGS); |
42 | 45 |
|
43 | 46 | PG_FUNCTION_INFO_V1(pgstatindex);
|
44 | 47 | PG_FUNCTION_INFO_V1(pg_relpages);
|
| 48 | +PG_FUNCTION_INFO_V1(pgstatginindex); |
45 | 49 |
|
46 | 50 | #define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
|
47 | 51 | #define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID)
|
| 52 | +#define IS_GIN(r) ((r)->rd_rel->relam == GIN_AM_OID) |
48 | 53 |
|
49 | 54 | #define CHECK_PAGE_OFFSET_RANGE(pg, offnum) { \
|
50 | 55 | if ( !(FirstOffsetNumber <= (offnum) && \
|
@@ -79,6 +84,19 @@ typedef struct BTIndexStat
|
79 | 84 | uint64 fragments;
|
80 | 85 | } BTIndexStat;
|
81 | 86 |
|
| 87 | +/* ------------------------------------------------ |
| 88 | + * A structure for a whole GIN index statistics |
| 89 | + * used by pgstatginindex(). |
| 90 | + * ------------------------------------------------ |
| 91 | + */ |
| 92 | +typedef struct GinIndexStat |
| 93 | +{ |
| 94 | + int32 version; |
| 95 | + |
| 96 | + BlockNumber pending_pages; |
| 97 | + int64 pending_tuples; |
| 98 | +} GinIndexStat; |
| 99 | + |
82 | 100 | /* ------------------------------------------------------
|
83 | 101 | * pgstatindex()
|
84 | 102 | *
|
@@ -292,3 +310,79 @@ pg_relpages(PG_FUNCTION_ARGS)
|
292 | 310 |
|
293 | 311 | PG_RETURN_INT64(relpages);
|
294 | 312 | }
|
| 313 | + |
| 314 | +/* ------------------------------------------------------ |
| 315 | + * pgstatginindex() |
| 316 | + * |
| 317 | + * Usage: SELECT * FROM pgstatginindex('ginindex'); |
| 318 | + * ------------------------------------------------------ |
| 319 | + */ |
| 320 | +Datum |
| 321 | +pgstatginindex(PG_FUNCTION_ARGS) |
| 322 | +{ |
| 323 | + Oid relid = PG_GETARG_OID(0); |
| 324 | + Relation rel; |
| 325 | + Buffer buffer; |
| 326 | + Page page; |
| 327 | + GinMetaPageData *metadata; |
| 328 | + GinIndexStat stats; |
| 329 | + HeapTuple tuple; |
| 330 | + TupleDesc tupleDesc; |
| 331 | + Datum values[3]; |
| 332 | + bool nulls[3] = {false, false, false}; |
| 333 | + Datum result; |
| 334 | + |
| 335 | + if (!superuser()) |
| 336 | + ereport(ERROR, |
| 337 | + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 338 | + (errmsg("must be superuser to use pgstattuple functions")))); |
| 339 | + |
| 340 | + rel = relation_open(relid, AccessShareLock); |
| 341 | + |
| 342 | + if (!IS_INDEX(rel) || !IS_GIN(rel)) |
| 343 | + elog(ERROR, "relation \"%s\" is not a GIN index", |
| 344 | + RelationGetRelationName(rel)); |
| 345 | + |
| 346 | + /* |
| 347 | + * Reject attempts to read non-local temporary relations; we would be |
| 348 | + * likely to get wrong data since we have no visibility into the owning |
| 349 | + * session's local buffers. |
| 350 | + */ |
| 351 | + if (RELATION_IS_OTHER_TEMP(rel)) |
| 352 | + ereport(ERROR, |
| 353 | + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
| 354 | + errmsg("cannot access temporary indexes of other sessions"))); |
| 355 | + |
| 356 | + /* |
| 357 | + * Read metapage |
| 358 | + */ |
| 359 | + buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO); |
| 360 | + LockBuffer(buffer, GIN_SHARE); |
| 361 | + page = BufferGetPage(buffer); |
| 362 | + metadata = GinPageGetMeta(page); |
| 363 | + |
| 364 | + stats.version = metadata->ginVersion; |
| 365 | + stats.pending_pages = metadata->nPendingPages; |
| 366 | + stats.pending_tuples = metadata->nPendingHeapTuples; |
| 367 | + |
| 368 | + UnlockReleaseBuffer(buffer); |
| 369 | + relation_close(rel, AccessShareLock); |
| 370 | + |
| 371 | + /* |
| 372 | + * Build a tuple descriptor for our result type |
| 373 | + */ |
| 374 | + if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) |
| 375 | + elog(ERROR, "return type must be a row type"); |
| 376 | + |
| 377 | + values[0] = Int32GetDatum(stats.version); |
| 378 | + values[1] = UInt32GetDatum(stats.pending_pages); |
| 379 | + values[2] = Int64GetDatum(stats.pending_tuples); |
| 380 | + |
| 381 | + /* |
| 382 | + * Build and return the tuple |
| 383 | + */ |
| 384 | + tuple = heap_form_tuple(tupleDesc, values, nulls); |
| 385 | + result = HeapTupleGetDatum(tuple); |
| 386 | + |
| 387 | + PG_RETURN_DATUM(result); |
| 388 | +} |
0 commit comments