LCOV - differential code coverage report
Current view: top level - contrib/pgstattuple - pgstatindex.c (source / functions) Coverage Total Hit UIC UBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 68.6 % 229 157 3 69 6 1 150 3 5 2
Current Date: 2023-04-08 17:13:01 Functions: 80.8 % 26 21 5 1 1 19 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (240..) days: 68.6 % 229 157 3 69 6 1 150 3 5
Legend: Lines: hit not hit Function coverage date bins:
(240..) days: 77.8 % 27 21 5 1 1 19 1

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*
                                  2                 :  * contrib/pgstattuple/pgstatindex.c
                                  3                 :  *
                                  4                 :  *
                                  5                 :  * pgstatindex
                                  6                 :  *
                                  7                 :  * Copyright (c) 2006 Satoshi Nagayasu <nagayasus@nttdata.co.jp>
                                  8                 :  *
                                  9                 :  * Permission to use, copy, modify, and distribute this software and
                                 10                 :  * its documentation for any purpose, without fee, and without a
                                 11                 :  * written agreement is hereby granted, provided that the above
                                 12                 :  * copyright notice and this paragraph and the following two
                                 13                 :  * paragraphs appear in all copies.
                                 14                 :  *
                                 15                 :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
                                 16                 :  * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
                                 17                 :  * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
                                 18                 :  * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
                                 19                 :  * OF THE POSSIBILITY OF SUCH DAMAGE.
                                 20                 :  *
                                 21                 :  * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
                                 22                 :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                                 23                 :  * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
                                 24                 :  * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
                                 25                 :  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
                                 26                 :  */
                                 27                 : 
                                 28                 : #include "postgres.h"
                                 29                 : 
                                 30                 : #include "access/gin_private.h"
                                 31                 : #include "access/hash.h"
                                 32                 : #include "access/htup_details.h"
                                 33                 : #include "access/nbtree.h"
                                 34                 : #include "access/relation.h"
                                 35                 : #include "access/table.h"
                                 36                 : #include "catalog/namespace.h"
                                 37                 : #include "catalog/pg_am.h"
                                 38                 : #include "funcapi.h"
                                 39                 : #include "miscadmin.h"
                                 40                 : #include "storage/bufmgr.h"
                                 41                 : #include "storage/lmgr.h"
                                 42                 : #include "utils/builtins.h"
                                 43                 : #include "utils/rel.h"
                                 44                 : #include "utils/varlena.h"
                                 45                 : 
                                 46                 : 
                                 47                 : /*
                                 48                 :  * Because of backward-compatibility issue, we have decided to have
                                 49                 :  * two types of interfaces, with regclass-type input arg and text-type
                                 50                 :  * input arg, for each function.
                                 51                 :  *
                                 52                 :  * Those functions which have text-type input arg will be deprecated
                                 53                 :  * in the future release.
                                 54                 :  */
 5705 tgl                        55 CBC           1 : PG_FUNCTION_INFO_V1(pgstatindex);
 3551 fujii                      56               1 : PG_FUNCTION_INFO_V1(pgstatindexbyid);
 5705 tgl                        57               1 : PG_FUNCTION_INFO_V1(pg_relpages);
 3551 fujii                      58               1 : PG_FUNCTION_INFO_V1(pg_relpagesbyid);
 3777 heikki.linnakangas         59               1 : PG_FUNCTION_INFO_V1(pgstatginindex);
 2256 rhaas                      60               2 : PG_FUNCTION_INFO_V1(pgstathashindex);
                                 61                 : 
 2383 sfrost                     62               2 : PG_FUNCTION_INFO_V1(pgstatindex_v1_5);
                                 63               2 : PG_FUNCTION_INFO_V1(pgstatindexbyid_v1_5);
                                 64               2 : PG_FUNCTION_INFO_V1(pg_relpages_v1_5);
                                 65               2 : PG_FUNCTION_INFO_V1(pg_relpagesbyid_v1_5);
                                 66               2 : PG_FUNCTION_INFO_V1(pgstatginindex_v1_5);
                                 67                 : 
                                 68                 : Datum       pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo);
                                 69                 : 
                                 70                 : #define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
                                 71                 : #define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID)
                                 72                 : #define IS_GIN(r) ((r)->rd_rel->relam == GIN_AM_OID)
                                 73                 : #define IS_HASH(r) ((r)->rd_rel->relam == HASH_AM_OID)
                                 74                 : 
                                 75                 : /* ------------------------------------------------
                                 76                 :  * A structure for a whole btree index statistics
                                 77                 :  * used by pgstatindex().
                                 78                 :  * ------------------------------------------------
                                 79                 :  */
                                 80                 : typedef struct BTIndexStat
                                 81                 : {
                                 82                 :     uint32      version;
                                 83                 :     uint32      level;
                                 84                 :     BlockNumber root_blkno;
                                 85                 : 
                                 86                 :     uint64      internal_pages;
                                 87                 :     uint64      leaf_pages;
                                 88                 :     uint64      empty_pages;
                                 89                 :     uint64      deleted_pages;
                                 90                 : 
                                 91                 :     uint64      max_avail;
                                 92                 :     uint64      free_space;
                                 93                 : 
                                 94                 :     uint64      fragments;
                                 95                 : } BTIndexStat;
                                 96                 : 
                                 97                 : /* ------------------------------------------------
                                 98                 :  * A structure for a whole GIN index statistics
                                 99                 :  * used by pgstatginindex().
                                100                 :  * ------------------------------------------------
                                101                 :  */
                                102                 : typedef struct GinIndexStat
                                103                 : {
                                104                 :     int32       version;
                                105                 : 
                                106                 :     BlockNumber pending_pages;
                                107                 :     int64       pending_tuples;
                                108                 : } GinIndexStat;
                                109                 : 
                                110                 : /* ------------------------------------------------
                                111                 :  * A structure for a whole HASH index statistics
                                112                 :  * used by pgstathashindex().
                                113                 :  * ------------------------------------------------
                                114                 :  */
                                115                 : typedef struct HashIndexStat
                                116                 : {
                                117                 :     int32       version;
                                118                 :     int32       space_per_page;
                                119                 : 
                                120                 :     BlockNumber bucket_pages;
                                121                 :     BlockNumber overflow_pages;
                                122                 :     BlockNumber bitmap_pages;
                                123                 :     BlockNumber unused_pages;
                                124                 : 
                                125                 :     int64       live_items;
                                126                 :     int64       dead_items;
                                127                 :     uint64      free_space;
                                128                 : } HashIndexStat;
                                129                 : 
                                130                 : static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo);
                                131                 : static int64 pg_relpages_impl(Relation rel);
                                132                 : static void GetHashPageStats(Page page, HashIndexStat *stats);
                                133                 : 
                                134                 : /* ------------------------------------------------------
                                135                 :  * pgstatindex()
                                136                 :  *
                                137                 :  * Usage: SELECT * FROM pgstatindex('t1_pkey');
                                138                 :  *
                                139                 :  * The superuser() check here must be kept as the library might be upgraded
                                140                 :  * without the extension being upgraded, meaning that in pre-1.5 installations
                                141                 :  * these functions could be called by any user.
                                142                 :  * ------------------------------------------------------
                                143                 :  */
                                144                 : Datum
 6063 bruce                     145 UBC           0 : pgstatindex(PG_FUNCTION_ARGS)
                                146                 : {
 2219 noah                      147               0 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                148                 :     Relation    rel;
                                149                 :     RangeVar   *relrv;
                                150                 : 
 5705 tgl                       151               0 :     if (!superuser())
                                152               0 :         ereport(ERROR,
                                153                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                154                 :                  errmsg("must be superuser to use pgstattuple functions")));
                                155                 : 
 6063 bruce                     156               0 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                157               0 :     rel = relation_openrv(relrv, AccessShareLock);
                                158                 : 
 3551 fujii                     159               0 :     PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
                                160                 : }
                                161                 : 
                                162                 : /*
                                163                 :  * As of pgstattuple version 1.5, we no longer need to check if the user
                                164                 :  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
                                165                 :  * Users can then grant access to it based on their policies.
                                166                 :  *
                                167                 :  * Otherwise identical to pgstatindex (above).
                                168                 :  */
                                169                 : Datum
 2383 sfrost                    170 CBC          10 : pgstatindex_v1_5(PG_FUNCTION_ARGS)
                                171                 : {
 2219 noah                      172              10 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                173                 :     Relation    rel;
                                174                 :     RangeVar   *relrv;
                                175                 : 
 2383 sfrost                    176              10 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                177              10 :     rel = relation_openrv(relrv, AccessShareLock);
                                178                 : 
                                179              10 :     PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
                                180                 : }
                                181                 : 
                                182                 : /*
                                183                 :  * The superuser() check here must be kept as the library might be upgraded
                                184                 :  * without the extension being upgraded, meaning that in pre-1.5 installations
                                185                 :  * these functions could be called by any user.
                                186                 :  */
                                187                 : Datum
 3551 fujii                     188 UBC           0 : pgstatindexbyid(PG_FUNCTION_ARGS)
                                189                 : {
                                190               0 :     Oid         relid = PG_GETARG_OID(0);
                                191                 :     Relation    rel;
                                192                 : 
                                193               0 :     if (!superuser())
                                194               0 :         ereport(ERROR,
                                195                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                196                 :                  errmsg("must be superuser to use pgstattuple functions")));
                                197                 : 
                                198               0 :     rel = relation_open(relid, AccessShareLock);
                                199                 : 
                                200               0 :     PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
                                201                 : }
                                202                 : 
                                203                 : /* No need for superuser checks in v1.5, see above */
                                204                 : Datum
 2383 sfrost                    205 CBC           1 : pgstatindexbyid_v1_5(PG_FUNCTION_ARGS)
                                206                 : {
                                207               1 :     Oid         relid = PG_GETARG_OID(0);
                                208                 :     Relation    rel;
                                209                 : 
                                210               1 :     rel = relation_open(relid, AccessShareLock);
                                211                 : 
                                212               1 :     PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
                                213                 : }
                                214                 : 
                                215                 : static Datum
 3551 fujii                     216              11 : pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
                                217                 : {
                                218                 :     Datum       result;
                                219                 :     BlockNumber nblocks;
                                220                 :     BlockNumber blkno;
                                221                 :     BTIndexStat indexStat;
                                222              11 :     BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
                                223                 : 
 6063 bruce                     224              11 :     if (!IS_INDEX(rel) || !IS_BTREE(rel))
 2222 sfrost                    225               6 :         ereport(ERROR,
                                226                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                227                 :                  errmsg("relation \"%s\" is not a btree index",
                                228                 :                         RelationGetRelationName(rel))));
                                229                 : 
                                230                 :     /*
                                231                 :      * Reject attempts to read non-local temporary relations; we would be
                                232                 :      * likely to get wrong data since we have no visibility into the owning
                                233                 :      * session's local buffers.
                                234                 :      */
 5122 tgl                       235               5 :     if (RELATION_IS_OTHER_TEMP(rel))
 5122 tgl                       236 UBC           0 :         ereport(ERROR,
                                237                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                238                 :                  errmsg("cannot access temporary tables of other sessions")));
                                239                 : 
                                240                 :     /*
                                241                 :      * Read metapage
                                242                 :      */
                                243                 :     {
 4044 rhaas                     244 CBC           5 :         Buffer      buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy);
 2545 kgrittn                   245               5 :         Page        page = BufferGetPage(buffer);
 6063 bruce                     246               5 :         BTMetaPageData *metad = BTPageGetMeta(page);
                                247                 : 
                                248               5 :         indexStat.version = metad->btm_version;
                                249               5 :         indexStat.level = metad->btm_level;
 5497 tgl                       250               5 :         indexStat.root_blkno = metad->btm_root;
                                251                 : 
 6063 bruce                     252               5 :         ReleaseBuffer(buffer);
                                253                 :     }
                                254                 : 
                                255                 :     /* -- init counters -- */
                                256               5 :     indexStat.internal_pages = 0;
 5497 tgl                       257               5 :     indexStat.leaf_pages = 0;
 6063 bruce                     258               5 :     indexStat.empty_pages = 0;
                                259               5 :     indexStat.deleted_pages = 0;
                                260                 : 
                                261               5 :     indexStat.max_avail = 0;
                                262               5 :     indexStat.free_space = 0;
                                263                 : 
 5497 tgl                       264               5 :     indexStat.fragments = 0;
                                265                 : 
                                266                 :     /*
                                267                 :      * Scan all blocks except the metapage
                                268                 :      */
                                269               5 :     nblocks = RelationGetNumberOfBlocks(rel);
                                270                 : 
 6063 bruce                     271               5 :     for (blkno = 1; blkno < nblocks; blkno++)
                                272                 :     {
                                273                 :         Buffer      buffer;
                                274                 :         Page        page;
                                275                 :         BTPageOpaque opaque;
                                276                 : 
 4203 rhaas                     277 UBC           0 :         CHECK_FOR_INTERRUPTS();
                                278                 : 
                                279                 :         /* Read and lock buffer */
 3955 bruce                     280               0 :         buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
 5806                           281               0 :         LockBuffer(buffer, BUFFER_LOCK_SHARE);
                                282                 : 
 2545 kgrittn                   283               0 :         page = BufferGetPage(buffer);
  373 michael                   284               0 :         opaque = BTPageGetOpaque(page);
                                285                 : 
                                286                 :         /*
                                287                 :          * Determine page type, and update totals.
                                288                 :          *
                                289                 :          * Note that we arbitrarily bucket deleted pages together without
                                290                 :          * considering if they're leaf pages or internal pages.
                                291                 :          */
 2607 tgl                       292               0 :         if (P_ISDELETED(opaque))
                                293               0 :             indexStat.deleted_pages++;
                                294               0 :         else if (P_IGNORE(opaque))
                                295               0 :             indexStat.empty_pages++;    /* this is the "half dead" state */
                                296               0 :         else if (P_ISLEAF(opaque))
                                297                 :         {
                                298                 :             int         max_avail;
                                299                 : 
 5624 bruce                     300               0 :             max_avail = BLCKSZ - (BLCKSZ - ((PageHeader) page)->pd_special + SizeOfPageHeaderData);
 5806                           301               0 :             indexStat.max_avail += max_avail;
                                302               0 :             indexStat.free_space += PageGetFreeSpace(page);
                                303                 : 
                                304               0 :             indexStat.leaf_pages++;
                                305                 : 
                                306                 :             /*
                                307                 :              * If the next leaf is on an earlier block, it means a
                                308                 :              * fragmentation.
                                309                 :              */
                                310               0 :             if (opaque->btpo_next != P_NONE && opaque->btpo_next < blkno)
                                311               0 :                 indexStat.fragments++;
                                312                 :         }
                                313                 :         else
                                314               0 :             indexStat.internal_pages++;
                                315                 : 
                                316                 :         /* Unlock and release buffer */
                                317               0 :         LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 6063                           318               0 :         ReleaseBuffer(buffer);
                                319                 :     }
                                320                 : 
 6063 bruce                     321 CBC           5 :     relation_close(rel, AccessShareLock);
                                322                 : 
                                323                 :     /*----------------------------
                                324                 :      * Build a result tuple
                                325                 :      *----------------------------
                                326                 :      */
                                327                 :     {
                                328                 :         TupleDesc   tupleDesc;
                                329                 :         int         j;
                                330                 :         char       *values[10];
                                331                 :         HeapTuple   tuple;
                                332                 : 
                                333                 :         /* Build a tuple descriptor for our result type */
 5705 tgl                       334               5 :         if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 5705 tgl                       335 UBC           0 :             elog(ERROR, "return type must be a row type");
                                336                 : 
 6063 bruce                     337 CBC           5 :         j = 0;
 3380 peter_e                   338               5 :         values[j++] = psprintf("%d", indexStat.version);
                                339               5 :         values[j++] = psprintf("%d", indexStat.level);
                                340              10 :         values[j++] = psprintf(INT64_FORMAT,
                                341                 :                                (1 + /* include the metapage in index_size */
 3260 bruce                     342               5 :                                 indexStat.leaf_pages +
                                343               5 :                                 indexStat.internal_pages +
                                344               5 :                                 indexStat.deleted_pages +
                                345               5 :                                 indexStat.empty_pages) * BLCKSZ);
 3380 peter_e                   346               5 :         values[j++] = psprintf("%u", indexStat.root_blkno);
                                347               5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.internal_pages);
                                348               5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.leaf_pages);
                                349               5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.empty_pages);
                                350               5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.deleted_pages);
 4246 tgl                       351               5 :         if (indexStat.max_avail > 0)
 3380 peter_e                   352 UBC           0 :             values[j++] = psprintf("%.2f",
 3260 bruce                     353               0 :                                    100.0 - (double) indexStat.free_space / (double) indexStat.max_avail * 100.0);
                                354                 :         else
 3380 peter_e                   355 CBC           5 :             values[j++] = pstrdup("NaN");
 4246 tgl                       356               5 :         if (indexStat.leaf_pages > 0)
 3380 peter_e                   357 UBC           0 :             values[j++] = psprintf("%.2f",
 3260 bruce                     358               0 :                                    (double) indexStat.fragments / (double) indexStat.leaf_pages * 100.0);
                                359                 :         else
 3380 peter_e                   360 CBC           5 :             values[j++] = pstrdup("NaN");
                                361                 : 
 6063 bruce                     362               5 :         tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
                                363                 :                                        values);
                                364                 : 
 5705 tgl                       365               5 :         result = HeapTupleGetDatum(tuple);
                                366                 :     }
                                367                 : 
 3551 fujii                     368               5 :     return result;
                                369                 : }
                                370                 : 
                                371                 : /* --------------------------------------------------------
                                372                 :  * pg_relpages()
                                373                 :  *
                                374                 :  * Get the number of pages of the table/index.
                                375                 :  *
                                376                 :  * Usage: SELECT pg_relpages('t1');
                                377                 :  *        SELECT pg_relpages('t1_pkey');
                                378                 :  *
                                379                 :  * Must keep superuser() check, see above.
                                380                 :  * --------------------------------------------------------
                                381                 :  */
                                382                 : Datum
 6063 bruce                     383 UBC           0 : pg_relpages(PG_FUNCTION_ARGS)
                                384                 : {
 2219 noah                      385               0 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                386                 :     Relation    rel;
                                387                 :     RangeVar   *relrv;
                                388                 : 
 5705 tgl                       389               0 :     if (!superuser())
                                390               0 :         ereport(ERROR,
                                391                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                392                 :                  errmsg("must be superuser to use pgstattuple functions")));
                                393                 : 
 6063 bruce                     394               0 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                395               0 :     rel = relation_openrv(relrv, AccessShareLock);
                                396                 : 
  640 peter                     397               0 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                398                 : }
                                399                 : 
                                400                 : /* No need for superuser checks in v1.5, see above */
                                401                 : Datum
 2383 sfrost                    402 CBC           9 : pg_relpages_v1_5(PG_FUNCTION_ARGS)
                                403                 : {
 2219 noah                      404               9 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                405                 :     Relation    rel;
                                406                 :     RangeVar   *relrv;
                                407                 : 
 2383 sfrost                    408               9 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                409               9 :     rel = relation_openrv(relrv, AccessShareLock);
                                410                 : 
  640 peter                     411               9 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                412                 : }
                                413                 : 
                                414                 : /* Must keep superuser() check, see above. */
                                415                 : Datum
 3551 fujii                     416 UBC           0 : pg_relpagesbyid(PG_FUNCTION_ARGS)
                                417                 : {
                                418               0 :     Oid         relid = PG_GETARG_OID(0);
                                419                 :     Relation    rel;
                                420                 : 
                                421               0 :     if (!superuser())
                                422               0 :         ereport(ERROR,
                                423                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                424                 :                  errmsg("must be superuser to use pgstattuple functions")));
                                425                 : 
                                426               0 :     rel = relation_open(relid, AccessShareLock);
                                427                 : 
  640 peter                     428               0 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                429                 : }
                                430                 : 
                                431                 : /* No need for superuser checks in v1.5, see above */
                                432                 : Datum
 2383 sfrost                    433 CBC           3 : pg_relpagesbyid_v1_5(PG_FUNCTION_ARGS)
                                434                 : {
                                435               3 :     Oid         relid = PG_GETARG_OID(0);
                                436                 :     Relation    rel;
                                437                 : 
                                438               3 :     rel = relation_open(relid, AccessShareLock);
                                439                 : 
  640 peter                     440               3 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                441                 : }
                                442                 : 
                                443                 : static int64
                                444              12 : pg_relpages_impl(Relation rel)
                                445                 : {
                                446                 :     int64       relpages;
                                447                 : 
                                448              12 :     if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
                                449               3 :         ereport(ERROR,
                                450                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                451                 :                  errmsg("cannot get page count of relation \"%s\"",
                                452                 :                         RelationGetRelationName(rel)),
                                453                 :                  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
                                454                 : 
                                455                 :     /* note: this will work OK on non-local temp tables */
                                456                 : 
 2383 sfrost                    457               9 :     relpages = RelationGetNumberOfBlocks(rel);
                                458                 : 
                                459               9 :     relation_close(rel, AccessShareLock);
                                460                 : 
  640 peter                     461               9 :     return relpages;
                                462                 : }
                                463                 : 
                                464                 : /* ------------------------------------------------------
                                465                 :  * pgstatginindex()
                                466                 :  *
                                467                 :  * Usage: SELECT * FROM pgstatginindex('ginindex');
                                468                 :  *
                                469                 :  * Must keep superuser() check, see above.
                                470                 :  * ------------------------------------------------------
                                471                 :  */
                                472                 : Datum
 3777 heikki.linnakangas        473 UBC           0 : pgstatginindex(PG_FUNCTION_ARGS)
                                474                 : {
                                475               0 :     Oid         relid = PG_GETARG_OID(0);
                                476                 : 
 2383 sfrost                    477               0 :     if (!superuser())
                                478               0 :         ereport(ERROR,
                                479                 :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                480                 :                  errmsg("must be superuser to use pgstattuple functions")));
                                481                 : 
                                482               0 :     PG_RETURN_DATUM(pgstatginindex_internal(relid, fcinfo));
                                483                 : }
                                484                 : 
                                485                 : /* No need for superuser checks in v1.5, see above */
                                486                 : Datum
 2383 sfrost                    487 CBC           7 : pgstatginindex_v1_5(PG_FUNCTION_ARGS)
                                488                 : {
                                489               7 :     Oid         relid = PG_GETARG_OID(0);
                                490                 : 
                                491               7 :     PG_RETURN_DATUM(pgstatginindex_internal(relid, fcinfo));
                                492                 : }
                                493                 : 
                                494                 : Datum
                                495               7 : pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
                                496                 : {
                                497                 :     Relation    rel;
                                498                 :     Buffer      buffer;
                                499                 :     Page        page;
                                500                 :     GinMetaPageData *metadata;
                                501                 :     GinIndexStat stats;
                                502                 :     HeapTuple   tuple;
                                503                 :     TupleDesc   tupleDesc;
                                504                 :     Datum       values[3];
 3777 heikki.linnakangas        505               7 :     bool        nulls[3] = {false, false, false};
                                506                 :     Datum       result;
                                507                 : 
                                508               7 :     rel = relation_open(relid, AccessShareLock);
                                509                 : 
                                510               7 :     if (!IS_INDEX(rel) || !IS_GIN(rel))
 2222 sfrost                    511               6 :         ereport(ERROR,
                                512                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                513                 :                  errmsg("relation \"%s\" is not a GIN index",
                                514                 :                         RelationGetRelationName(rel))));
                                515                 : 
                                516                 :     /*
                                517                 :      * Reject attempts to read non-local temporary relations; we would be
                                518                 :      * likely to get wrong data since we have no visibility into the owning
                                519                 :      * session's local buffers.
                                520                 :      */
 3777 heikki.linnakangas        521               1 :     if (RELATION_IS_OTHER_TEMP(rel))
 3777 heikki.linnakangas        522 UBC           0 :         ereport(ERROR,
                                523                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                524                 :                  errmsg("cannot access temporary indexes of other sessions")));
                                525                 : 
                                526                 :     /*
                                527                 :      * Read metapage
                                528                 :      */
 3777 heikki.linnakangas        529 CBC           1 :     buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO);
                                530               1 :     LockBuffer(buffer, GIN_SHARE);
 2545 kgrittn                   531               1 :     page = BufferGetPage(buffer);
 3777 heikki.linnakangas        532               1 :     metadata = GinPageGetMeta(page);
                                533                 : 
                                534               1 :     stats.version = metadata->ginVersion;
                                535               1 :     stats.pending_pages = metadata->nPendingPages;
                                536               1 :     stats.pending_tuples = metadata->nPendingHeapTuples;
                                537                 : 
                                538               1 :     UnlockReleaseBuffer(buffer);
                                539               1 :     relation_close(rel, AccessShareLock);
                                540                 : 
                                541                 :     /*
                                542                 :      * Build a tuple descriptor for our result type
                                543                 :      */
                                544               1 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 3777 heikki.linnakangas        545 UBC           0 :         elog(ERROR, "return type must be a row type");
                                546                 : 
 3777 heikki.linnakangas        547 CBC           1 :     values[0] = Int32GetDatum(stats.version);
                                548               1 :     values[1] = UInt32GetDatum(stats.pending_pages);
                                549               1 :     values[2] = Int64GetDatum(stats.pending_tuples);
                                550                 : 
                                551                 :     /*
                                552                 :      * Build and return the tuple
                                553                 :      */
                                554               1 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
                                555               1 :     result = HeapTupleGetDatum(tuple);
                                556                 : 
 2061 peter_e                   557               1 :     return result;
                                558                 : }
                                559                 : 
                                560                 : /* ------------------------------------------------------
                                561                 :  * pgstathashindex()
                                562                 :  *
                                563                 :  * Usage: SELECT * FROM pgstathashindex('hashindex');
                                564                 :  * ------------------------------------------------------
                                565                 :  */
                                566                 : Datum
 2256 rhaas                     567               8 : pgstathashindex(PG_FUNCTION_ARGS)
                                568                 : {
                                569               8 :     Oid         relid = PG_GETARG_OID(0);
                                570                 :     BlockNumber nblocks;
                                571                 :     BlockNumber blkno;
                                572                 :     Relation    rel;
                                573                 :     HashIndexStat stats;
                                574                 :     BufferAccessStrategy bstrategy;
                                575                 :     HeapTuple   tuple;
                                576                 :     TupleDesc   tupleDesc;
                                577                 :     Datum       values[8];
  267 peter                     578 GNC           8 :     bool        nulls[8] = {0};
                                579                 :     Buffer      metabuf;
                                580                 :     HashMetaPage metap;
                                581                 :     float8      free_percent;
                                582                 :     uint64      total_space;
                                583                 : 
 2256 rhaas                     584 CBC           8 :     rel = index_open(relid, AccessShareLock);
                                585                 : 
                                586                 :     /* index_open() checks that it's an index */
                                587               4 :     if (!IS_HASH(rel))
 2222 sfrost                    588               2 :         ereport(ERROR,
                                589                 :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                590                 :                  errmsg("relation \"%s\" is not a hash index",
                                591                 :                         RelationGetRelationName(rel))));
                                592                 : 
                                593                 :     /*
                                594                 :      * Reject attempts to read non-local temporary relations; we would be
                                595                 :      * likely to get wrong data since we have no visibility into the owning
                                596                 :      * session's local buffers.
                                597                 :      */
 2256 rhaas                     598               2 :     if (RELATION_IS_OTHER_TEMP(rel))
 2256 rhaas                     599 UBC           0 :         ereport(ERROR,
                                600                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                601                 :                  errmsg("cannot access temporary indexes of other sessions")));
                                602                 : 
                                603                 :     /* Get the information we need from the metapage. */
 2256 rhaas                     604 CBC           2 :     memset(&stats, 0, sizeof(stats));
                                605               2 :     metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
                                606               2 :     metap = HashPageGetMeta(BufferGetPage(metabuf));
                                607               2 :     stats.version = metap->hashm_version;
                                608               2 :     stats.space_per_page = metap->hashm_bsize;
                                609               2 :     _hash_relbuf(rel, metabuf);
                                610                 : 
                                611                 :     /* Get the current relation length */
                                612               2 :     nblocks = RelationGetNumberOfBlocks(rel);
                                613                 : 
                                614                 :     /* prepare access strategy for this index */
                                615               2 :     bstrategy = GetAccessStrategy(BAS_BULKREAD);
                                616                 : 
                                617                 :     /* Start from blkno 1 as 0th block is metapage */
                                618              16 :     for (blkno = 1; blkno < nblocks; blkno++)
                                619                 :     {
                                620                 :         Buffer      buf;
                                621                 :         Page        page;
                                622                 : 
                                623              14 :         CHECK_FOR_INTERRUPTS();
                                624                 : 
                                625              14 :         buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
                                626                 :                                  bstrategy);
                                627              14 :         LockBuffer(buf, BUFFER_LOCK_SHARE);
                                628              14 :         page = (Page) BufferGetPage(buf);
                                629                 : 
                                630              14 :         if (PageIsNew(page))
 2188 rhaas                     631 UBC           0 :             stats.unused_pages++;
 2256 rhaas                     632 CBC          14 :         else if (PageGetSpecialSize(page) !=
                                633                 :                  MAXALIGN(sizeof(HashPageOpaqueData)))
 2256 rhaas                     634 UBC           0 :             ereport(ERROR,
                                635                 :                     (errcode(ERRCODE_INDEX_CORRUPTED),
                                636                 :                      errmsg("index \"%s\" contains corrupted page at block %u",
                                637                 :                             RelationGetRelationName(rel),
                                638                 :                             BufferGetBlockNumber(buf))));
                                639                 :         else
                                640                 :         {
                                641                 :             HashPageOpaque opaque;
                                642                 :             int         pagetype;
                                643                 : 
  373 michael                   644 CBC          14 :             opaque = HashPageGetOpaque(page);
 2188 rhaas                     645              14 :             pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
                                646                 : 
                                647              14 :             if (pagetype == LH_BUCKET_PAGE)
                                648                 :             {
 2256                           649              12 :                 stats.bucket_pages++;
                                650              12 :                 GetHashPageStats(page, &stats);
                                651                 :             }
 2188                           652               2 :             else if (pagetype == LH_OVERFLOW_PAGE)
                                653                 :             {
 2256 rhaas                     654 UBC           0 :                 stats.overflow_pages++;
                                655               0 :                 GetHashPageStats(page, &stats);
                                656                 :             }
 2188 rhaas                     657 CBC           2 :             else if (pagetype == LH_BITMAP_PAGE)
 2256                           658               2 :                 stats.bitmap_pages++;
 2188 rhaas                     659 UBC           0 :             else if (pagetype == LH_UNUSED_PAGE)
                                660               0 :                 stats.unused_pages++;
                                661                 :             else
 2256                           662               0 :                 ereport(ERROR,
                                663                 :                         (errcode(ERRCODE_INDEX_CORRUPTED),
                                664                 :                          errmsg("unexpected page type 0x%04X in HASH index \"%s\" block %u",
                                665                 :                                 opaque->hasho_flag, RelationGetRelationName(rel),
                                666                 :                                 BufferGetBlockNumber(buf))));
                                667                 :         }
 2256 rhaas                     668 CBC          14 :         UnlockReleaseBuffer(buf);
                                669                 :     }
                                670                 : 
                                671                 :     /* Done accessing the index */
                                672               2 :     index_close(rel, AccessShareLock);
                                673                 : 
                                674                 :     /* Count unused pages as free space. */
 2068                           675               2 :     stats.free_space += (uint64) stats.unused_pages * stats.space_per_page;
                                676                 : 
                                677                 :     /*
                                678                 :      * Total space available for tuples excludes the metapage and the bitmap
                                679                 :      * pages.
                                680                 :      */
                                681               2 :     total_space = (uint64) (nblocks - (stats.bitmap_pages + 1)) *
                                682               2 :         stats.space_per_page;
                                683                 : 
 2256                           684               2 :     if (total_space == 0)
 2256 rhaas                     685 UBC           0 :         free_percent = 0.0;
                                686                 :     else
 2256 rhaas                     687 CBC           2 :         free_percent = 100.0 * stats.free_space / total_space;
                                688                 : 
                                689                 :     /*
                                690                 :      * Build a tuple descriptor for our result type
                                691                 :      */
                                692               2 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 2256 rhaas                     693 UBC           0 :         elog(ERROR, "return type must be a row type");
                                694                 : 
 2256 rhaas                     695 CBC           2 :     tupleDesc = BlessTupleDesc(tupleDesc);
                                696                 : 
                                697                 :     /*
                                698                 :      * Build and return the tuple
                                699                 :      */
                                700               2 :     values[0] = Int32GetDatum(stats.version);
                                701               2 :     values[1] = Int64GetDatum((int64) stats.bucket_pages);
                                702               2 :     values[2] = Int64GetDatum((int64) stats.overflow_pages);
                                703               2 :     values[3] = Int64GetDatum((int64) stats.bitmap_pages);
 2188                           704               2 :     values[4] = Int64GetDatum((int64) stats.unused_pages);
 2256                           705               2 :     values[5] = Int64GetDatum(stats.live_items);
                                706               2 :     values[6] = Int64GetDatum(stats.dead_items);
                                707               2 :     values[7] = Float8GetDatum(free_percent);
 2256 rhaas                     708 GIC           2 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
 2256 rhaas                     709 ECB             : 
 2256 rhaas                     710 GIC           2 :     PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
                                711                 : }
                                712                 : 
                                713                 : /* -------------------------------------------------
                                714                 :  * GetHashPageStats()
                                715                 :  *
                                716                 :  * Collect statistics of single hash page
                                717                 :  * -------------------------------------------------
                                718                 :  */
 2256 rhaas                     719 ECB             : static void
 2256 rhaas                     720 GIC          12 : GetHashPageStats(Page page, HashIndexStat *stats)
 2256 rhaas                     721 ECB             : {
 2256 rhaas                     722 GIC          12 :     OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
                                723                 :     int         off;
                                724                 : 
 2256 rhaas                     725 ECB             :     /* count live and dead tuples, and free space */
 2256 rhaas                     726 GIC          12 :     for (off = FirstOffsetNumber; off <= maxoff; off++)
 2256 rhaas                     727 EUB             :     {
 2153 bruce                     728 UIC           0 :         ItemId      id = PageGetItemId(page, off);
 2256 rhaas                     729 EUB             : 
 2256 rhaas                     730 UBC           0 :         if (!ItemIdIsDead(id))
 2256 rhaas                     731 UIC           0 :             stats->live_items++;
 2256 rhaas                     732 EUB             :         else
 2256 rhaas                     733 UIC           0 :             stats->dead_items++;
 2256 rhaas                     734 ECB             :     }
 2256 rhaas                     735 CBC          12 :     stats->free_space += PageGetExactFreeSpace(page);
 2256 rhaas                     736 GIC          12 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a