LCOV - differential code coverage report
Current view: top level - contrib/pgstattuple - pgstatindex.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 68.1 % 235 160 75 160
Current Date: 2024-04-14 14:21:10 Functions: 80.8 % 26 21 5 21
Baseline: 16@8cea358b128 Branches: 34.6 % 136 47 89 47
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed (60,120] days: 100.0 % 2 2 2
(120,180] days: 50.0 % 6 3 3 3
(240..) days: 68.3 % 227 155 72 155
Function coverage date bins:
(240..) days: 80.8 % 26 21 5 21
Branch coverage date bins:
(60,120] days: 100.0 % 4 4 4
(120,180] days: 25.0 % 12 3 9 3
(240..) days: 33.3 % 120 40 80 40

 Age         Owner                    Branch data    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                 :                :  */
 6076 tgl@sss.pgh.pa.us          55                 :CBC           1 : PG_FUNCTION_INFO_V1(pgstatindex);
 3922 fujii@postgresql.org       56                 :              1 : PG_FUNCTION_INFO_V1(pgstatindexbyid);
 6076 tgl@sss.pgh.pa.us          57                 :              1 : PG_FUNCTION_INFO_V1(pg_relpages);
 3922 fujii@postgresql.org       58                 :              1 : PG_FUNCTION_INFO_V1(pg_relpagesbyid);
 4148 heikki.linnakangas@i       59                 :              1 : PG_FUNCTION_INFO_V1(pgstatginindex);
 2627 rhaas@postgresql.org       60                 :              2 : PG_FUNCTION_INFO_V1(pgstathashindex);
                                 61                 :                : 
 2754 sfrost@snowman.net         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
 6434 bruce@momjian.us          145                 :UBC           0 : pgstatindex(PG_FUNCTION_ARGS)
                                146                 :                : {
 2590 noah@leadboat.com         147                 :              0 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                148                 :                :     Relation    rel;
                                149                 :                :     RangeVar   *relrv;
                                150                 :                : 
 6076 tgl@sss.pgh.pa.us         151         [ #  # ]:              0 :     if (!superuser())
                                152         [ #  # ]:              0 :         ereport(ERROR,
                                153                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                154                 :                :                  errmsg("must be superuser to use pgstattuple functions")));
                                155                 :                : 
 6434 bruce@momjian.us          156                 :              0 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                157                 :              0 :     rel = relation_openrv(relrv, AccessShareLock);
                                158                 :                : 
 3922 fujii@postgresql.org      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
 2754 sfrost@snowman.net        170                 :CBC          10 : pgstatindex_v1_5(PG_FUNCTION_ARGS)
                                171                 :                : {
 2590 noah@leadboat.com         172                 :             10 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                173                 :                :     Relation    rel;
                                174                 :                :     RangeVar   *relrv;
                                175                 :                : 
 2754 sfrost@snowman.net        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
 3922 fujii@postgresql.org      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
 2754 sfrost@snowman.net        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
 3922 fujii@postgresql.org      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                 :                : 
 6434 bruce@momjian.us          224   [ +  +  +  + ]:             11 :     if (!IS_INDEX(rel) || !IS_BTREE(rel))
 2593 sfrost@snowman.net        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                 :                :      */
 5493 tgl@sss.pgh.pa.us         235   [ -  +  -  - ]:              5 :     if (RELATION_IS_OTHER_TEMP(rel))
 5493 tgl@sss.pgh.pa.us         236         [ #  # ]:UBC           0 :         ereport(ERROR,
                                237                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                238                 :                :                  errmsg("cannot access temporary tables of other sessions")));
                                239                 :                : 
                                240                 :                :     /*
                                241                 :                :      * A !indisready index could lead to ERRCODE_DATA_CORRUPTED later, so exit
                                242                 :                :      * early.  We're capable of assessing an indisready&&!indisvalid index,
                                243                 :                :      * but the results could be confusing.  For example, the index's size
                                244                 :                :      * could be too low for a valid index of the table.
                                245                 :                :      */
  167 noah@leadboat.com         246         [ -  + ]:CBC           5 :     if (!rel->rd_index->indisvalid)
  167 noah@leadboat.com         247         [ #  # ]:UBC           0 :         ereport(ERROR,
                                248                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                249                 :                :                  errmsg("index \"%s\" is not valid",
                                250                 :                :                         RelationGetRelationName(rel))));
                                251                 :                : 
                                252                 :                :     /*
                                253                 :                :      * Read metapage
                                254                 :                :      */
                                255                 :                :     {
 4415 rhaas@postgresql.org      256                 :CBC           5 :         Buffer      buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy);
 2916 kgrittn@postgresql.o      257                 :              5 :         Page        page = BufferGetPage(buffer);
 6434 bruce@momjian.us          258                 :              5 :         BTMetaPageData *metad = BTPageGetMeta(page);
                                259                 :                : 
                                260                 :              5 :         indexStat.version = metad->btm_version;
                                261                 :              5 :         indexStat.level = metad->btm_level;
 5868 tgl@sss.pgh.pa.us         262                 :              5 :         indexStat.root_blkno = metad->btm_root;
                                263                 :                : 
 6434 bruce@momjian.us          264                 :              5 :         ReleaseBuffer(buffer);
                                265                 :                :     }
                                266                 :                : 
                                267                 :                :     /* -- init counters -- */
                                268                 :              5 :     indexStat.internal_pages = 0;
 5868 tgl@sss.pgh.pa.us         269                 :              5 :     indexStat.leaf_pages = 0;
 6434 bruce@momjian.us          270                 :              5 :     indexStat.empty_pages = 0;
                                271                 :              5 :     indexStat.deleted_pages = 0;
                                272                 :                : 
                                273                 :              5 :     indexStat.max_avail = 0;
                                274                 :              5 :     indexStat.free_space = 0;
                                275                 :                : 
 5868 tgl@sss.pgh.pa.us         276                 :              5 :     indexStat.fragments = 0;
                                277                 :                : 
                                278                 :                :     /*
                                279                 :                :      * Scan all blocks except the metapage
                                280                 :                :      */
                                281                 :              5 :     nblocks = RelationGetNumberOfBlocks(rel);
                                282                 :                : 
 6434 bruce@momjian.us          283         [ -  + ]:              5 :     for (blkno = 1; blkno < nblocks; blkno++)
                                284                 :                :     {
                                285                 :                :         Buffer      buffer;
                                286                 :                :         Page        page;
                                287                 :                :         BTPageOpaque opaque;
                                288                 :                : 
 4574 rhaas@postgresql.org      289         [ #  # ]:UBC           0 :         CHECK_FOR_INTERRUPTS();
                                290                 :                : 
                                291                 :                :         /* Read and lock buffer */
 4326 bruce@momjian.us          292                 :              0 :         buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
 6177                           293                 :              0 :         LockBuffer(buffer, BUFFER_LOCK_SHARE);
                                294                 :                : 
 2916 kgrittn@postgresql.o      295                 :              0 :         page = BufferGetPage(buffer);
  744 michael@paquier.xyz       296                 :              0 :         opaque = BTPageGetOpaque(page);
                                297                 :                : 
                                298                 :                :         /*
                                299                 :                :          * Determine page type, and update totals.
                                300                 :                :          *
                                301                 :                :          * Note that we arbitrarily bucket deleted pages together without
                                302                 :                :          * considering if they're leaf pages or internal pages.
                                303                 :                :          */
 2978 tgl@sss.pgh.pa.us         304         [ #  # ]:              0 :         if (P_ISDELETED(opaque))
                                305                 :              0 :             indexStat.deleted_pages++;
                                306         [ #  # ]:              0 :         else if (P_IGNORE(opaque))
                                307                 :              0 :             indexStat.empty_pages++;    /* this is the "half dead" state */
                                308         [ #  # ]:              0 :         else if (P_ISLEAF(opaque))
                                309                 :                :         {
                                310                 :                :             int         max_avail;
                                311                 :                : 
 5995 bruce@momjian.us          312                 :              0 :             max_avail = BLCKSZ - (BLCKSZ - ((PageHeader) page)->pd_special + SizeOfPageHeaderData);
 6177                           313                 :              0 :             indexStat.max_avail += max_avail;
                                314                 :              0 :             indexStat.free_space += PageGetFreeSpace(page);
                                315                 :                : 
                                316                 :              0 :             indexStat.leaf_pages++;
                                317                 :                : 
                                318                 :                :             /*
                                319                 :                :              * If the next leaf is on an earlier block, it means a
                                320                 :                :              * fragmentation.
                                321                 :                :              */
                                322   [ #  #  #  # ]:              0 :             if (opaque->btpo_next != P_NONE && opaque->btpo_next < blkno)
                                323                 :              0 :                 indexStat.fragments++;
                                324                 :                :         }
                                325                 :                :         else
                                326                 :              0 :             indexStat.internal_pages++;
                                327                 :                : 
                                328                 :                :         /* Unlock and release buffer */
                                329                 :              0 :         LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
 6434                           330                 :              0 :         ReleaseBuffer(buffer);
                                331                 :                :     }
                                332                 :                : 
 6434 bruce@momjian.us          333                 :CBC           5 :     relation_close(rel, AccessShareLock);
                                334                 :                : 
                                335                 :                :     /*----------------------------
                                336                 :                :      * Build a result tuple
                                337                 :                :      *----------------------------
                                338                 :                :      */
                                339                 :                :     {
                                340                 :                :         TupleDesc   tupleDesc;
                                341                 :                :         int         j;
                                342                 :                :         char       *values[10];
                                343                 :                :         HeapTuple   tuple;
                                344                 :                : 
                                345                 :                :         /* Build a tuple descriptor for our result type */
 6076 tgl@sss.pgh.pa.us         346         [ -  + ]:              5 :         if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 6076 tgl@sss.pgh.pa.us         347         [ #  # ]:UBC           0 :             elog(ERROR, "return type must be a row type");
                                348                 :                : 
 6434 bruce@momjian.us          349                 :CBC           5 :         j = 0;
 3751 peter_e@gmx.net           350                 :              5 :         values[j++] = psprintf("%d", indexStat.version);
                                351                 :              5 :         values[j++] = psprintf("%d", indexStat.level);
                                352                 :             10 :         values[j++] = psprintf(INT64_FORMAT,
                                353                 :                :                                (1 + /* include the metapage in index_size */
 3631 bruce@momjian.us          354                 :              5 :                                 indexStat.leaf_pages +
                                355                 :              5 :                                 indexStat.internal_pages +
                                356                 :              5 :                                 indexStat.deleted_pages +
                                357                 :              5 :                                 indexStat.empty_pages) * BLCKSZ);
 3751 peter_e@gmx.net           358                 :              5 :         values[j++] = psprintf("%u", indexStat.root_blkno);
                                359                 :              5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.internal_pages);
                                360                 :              5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.leaf_pages);
                                361                 :              5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.empty_pages);
                                362                 :              5 :         values[j++] = psprintf(INT64_FORMAT, indexStat.deleted_pages);
 4617 tgl@sss.pgh.pa.us         363         [ -  + ]:              5 :         if (indexStat.max_avail > 0)
 3751 peter_e@gmx.net           364                 :UBC           0 :             values[j++] = psprintf("%.2f",
 3631 bruce@momjian.us          365                 :              0 :                                    100.0 - (double) indexStat.free_space / (double) indexStat.max_avail * 100.0);
                                366                 :                :         else
 3751 peter_e@gmx.net           367                 :CBC           5 :             values[j++] = pstrdup("NaN");
 4617 tgl@sss.pgh.pa.us         368         [ -  + ]:              5 :         if (indexStat.leaf_pages > 0)
 3751 peter_e@gmx.net           369                 :UBC           0 :             values[j++] = psprintf("%.2f",
 3631 bruce@momjian.us          370                 :              0 :                                    (double) indexStat.fragments / (double) indexStat.leaf_pages * 100.0);
                                371                 :                :         else
 3751 peter_e@gmx.net           372                 :CBC           5 :             values[j++] = pstrdup("NaN");
                                373                 :                : 
 6434 bruce@momjian.us          374                 :              5 :         tuple = BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
                                375                 :                :                                        values);
                                376                 :                : 
 6076 tgl@sss.pgh.pa.us         377                 :              5 :         result = HeapTupleGetDatum(tuple);
                                378                 :                :     }
                                379                 :                : 
 3922 fujii@postgresql.org      380                 :              5 :     return result;
                                381                 :                : }
                                382                 :                : 
                                383                 :                : /* --------------------------------------------------------
                                384                 :                :  * pg_relpages()
                                385                 :                :  *
                                386                 :                :  * Get the number of pages of the table/index.
                                387                 :                :  *
                                388                 :                :  * Usage: SELECT pg_relpages('t1');
                                389                 :                :  *        SELECT pg_relpages('t1_pkey');
                                390                 :                :  *
                                391                 :                :  * Must keep superuser() check, see above.
                                392                 :                :  * --------------------------------------------------------
                                393                 :                :  */
                                394                 :                : Datum
 6434 bruce@momjian.us          395                 :UBC           0 : pg_relpages(PG_FUNCTION_ARGS)
                                396                 :                : {
 2590 noah@leadboat.com         397                 :              0 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                398                 :                :     Relation    rel;
                                399                 :                :     RangeVar   *relrv;
                                400                 :                : 
 6076 tgl@sss.pgh.pa.us         401         [ #  # ]:              0 :     if (!superuser())
                                402         [ #  # ]:              0 :         ereport(ERROR,
                                403                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                404                 :                :                  errmsg("must be superuser to use pgstattuple functions")));
                                405                 :                : 
 6434 bruce@momjian.us          406                 :              0 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                407                 :              0 :     rel = relation_openrv(relrv, AccessShareLock);
                                408                 :                : 
 1011 peter@eisentraut.org      409                 :              0 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                410                 :                : }
                                411                 :                : 
                                412                 :                : /* No need for superuser checks in v1.5, see above */
                                413                 :                : Datum
 2754 sfrost@snowman.net        414                 :CBC           9 : pg_relpages_v1_5(PG_FUNCTION_ARGS)
                                415                 :                : {
 2590 noah@leadboat.com         416                 :              9 :     text       *relname = PG_GETARG_TEXT_PP(0);
                                417                 :                :     Relation    rel;
                                418                 :                :     RangeVar   *relrv;
                                419                 :                : 
 2754 sfrost@snowman.net        420                 :              9 :     relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
                                421                 :              9 :     rel = relation_openrv(relrv, AccessShareLock);
                                422                 :                : 
 1011 peter@eisentraut.org      423                 :              9 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                424                 :                : }
                                425                 :                : 
                                426                 :                : /* Must keep superuser() check, see above. */
                                427                 :                : Datum
 3922 fujii@postgresql.org      428                 :UBC           0 : pg_relpagesbyid(PG_FUNCTION_ARGS)
                                429                 :                : {
                                430                 :              0 :     Oid         relid = PG_GETARG_OID(0);
                                431                 :                :     Relation    rel;
                                432                 :                : 
                                433         [ #  # ]:              0 :     if (!superuser())
                                434         [ #  # ]:              0 :         ereport(ERROR,
                                435                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                436                 :                :                  errmsg("must be superuser to use pgstattuple functions")));
                                437                 :                : 
                                438                 :              0 :     rel = relation_open(relid, AccessShareLock);
                                439                 :                : 
 1011 peter@eisentraut.org      440                 :              0 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                441                 :                : }
                                442                 :                : 
                                443                 :                : /* No need for superuser checks in v1.5, see above */
                                444                 :                : Datum
 2754 sfrost@snowman.net        445                 :CBC           3 : pg_relpagesbyid_v1_5(PG_FUNCTION_ARGS)
                                446                 :                : {
                                447                 :              3 :     Oid         relid = PG_GETARG_OID(0);
                                448                 :                :     Relation    rel;
                                449                 :                : 
                                450                 :              3 :     rel = relation_open(relid, AccessShareLock);
                                451                 :                : 
 1011 peter@eisentraut.org      452                 :              3 :     PG_RETURN_INT64(pg_relpages_impl(rel));
                                453                 :                : }
                                454                 :                : 
                                455                 :                : static int64
                                456                 :             12 : pg_relpages_impl(Relation rel)
                                457                 :                : {
                                458                 :                :     int64       relpages;
                                459                 :                : 
                                460   [ +  +  +  +  :             12 :     if (!RELKIND_HAS_STORAGE(rel->rd_rel->relkind))
                                     +  -  +  +  +  
                                                 - ]
                                461         [ +  - ]:              3 :         ereport(ERROR,
                                462                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                463                 :                :                  errmsg("cannot get page count of relation \"%s\"",
                                464                 :                :                         RelationGetRelationName(rel)),
                                465                 :                :                  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
                                466                 :                : 
                                467                 :                :     /* note: this will work OK on non-local temp tables */
                                468                 :                : 
 2754 sfrost@snowman.net        469                 :              9 :     relpages = RelationGetNumberOfBlocks(rel);
                                470                 :                : 
                                471                 :              9 :     relation_close(rel, AccessShareLock);
                                472                 :                : 
 1011 peter@eisentraut.org      473                 :              9 :     return relpages;
                                474                 :                : }
                                475                 :                : 
                                476                 :                : /* ------------------------------------------------------
                                477                 :                :  * pgstatginindex()
                                478                 :                :  *
                                479                 :                :  * Usage: SELECT * FROM pgstatginindex('ginindex');
                                480                 :                :  *
                                481                 :                :  * Must keep superuser() check, see above.
                                482                 :                :  * ------------------------------------------------------
                                483                 :                :  */
                                484                 :                : Datum
 4148 heikki.linnakangas@i      485                 :UBC           0 : pgstatginindex(PG_FUNCTION_ARGS)
                                486                 :                : {
                                487                 :              0 :     Oid         relid = PG_GETARG_OID(0);
                                488                 :                : 
 2754 sfrost@snowman.net        489         [ #  # ]:              0 :     if (!superuser())
                                490         [ #  # ]:              0 :         ereport(ERROR,
                                491                 :                :                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                492                 :                :                  errmsg("must be superuser to use pgstattuple functions")));
                                493                 :                : 
                                494                 :              0 :     PG_RETURN_DATUM(pgstatginindex_internal(relid, fcinfo));
                                495                 :                : }
                                496                 :                : 
                                497                 :                : /* No need for superuser checks in v1.5, see above */
                                498                 :                : Datum
 2754 sfrost@snowman.net        499                 :CBC           7 : pgstatginindex_v1_5(PG_FUNCTION_ARGS)
                                500                 :                : {
                                501                 :              7 :     Oid         relid = PG_GETARG_OID(0);
                                502                 :                : 
                                503                 :              7 :     PG_RETURN_DATUM(pgstatginindex_internal(relid, fcinfo));
                                504                 :                : }
                                505                 :                : 
                                506                 :                : Datum
                                507                 :              7 : pgstatginindex_internal(Oid relid, FunctionCallInfo fcinfo)
                                508                 :                : {
                                509                 :                :     Relation    rel;
                                510                 :                :     Buffer      buffer;
                                511                 :                :     Page        page;
                                512                 :                :     GinMetaPageData *metadata;
                                513                 :                :     GinIndexStat stats;
                                514                 :                :     HeapTuple   tuple;
                                515                 :                :     TupleDesc   tupleDesc;
                                516                 :                :     Datum       values[3];
 4148 heikki.linnakangas@i      517                 :              7 :     bool        nulls[3] = {false, false, false};
                                518                 :                :     Datum       result;
                                519                 :                : 
                                520                 :              7 :     rel = relation_open(relid, AccessShareLock);
                                521                 :                : 
                                522   [ +  +  +  + ]:              7 :     if (!IS_INDEX(rel) || !IS_GIN(rel))
 2593 sfrost@snowman.net        523         [ +  - ]:              6 :         ereport(ERROR,
                                524                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                525                 :                :                  errmsg("relation \"%s\" is not a GIN index",
                                526                 :                :                         RelationGetRelationName(rel))));
                                527                 :                : 
                                528                 :                :     /*
                                529                 :                :      * Reject attempts to read non-local temporary relations; we would be
                                530                 :                :      * likely to get wrong data since we have no visibility into the owning
                                531                 :                :      * session's local buffers.
                                532                 :                :      */
 4148 heikki.linnakangas@i      533   [ -  +  -  - ]:              1 :     if (RELATION_IS_OTHER_TEMP(rel))
 4148 heikki.linnakangas@i      534         [ #  # ]:UBC           0 :         ereport(ERROR,
                                535                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                536                 :                :                  errmsg("cannot access temporary indexes of other sessions")));
                                537                 :                : 
                                538                 :                :     /* see pgstatindex_impl */
  167 noah@leadboat.com         539         [ -  + ]:CBC           1 :     if (!rel->rd_index->indisvalid)
  167 noah@leadboat.com         540         [ #  # ]:UBC           0 :         ereport(ERROR,
                                541                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                542                 :                :                  errmsg("index \"%s\" is not valid",
                                543                 :                :                         RelationGetRelationName(rel))));
                                544                 :                : 
                                545                 :                :     /*
                                546                 :                :      * Read metapage
                                547                 :                :      */
 4148 heikki.linnakangas@i      548                 :CBC           1 :     buffer = ReadBuffer(rel, GIN_METAPAGE_BLKNO);
                                549                 :              1 :     LockBuffer(buffer, GIN_SHARE);
 2916 kgrittn@postgresql.o      550                 :              1 :     page = BufferGetPage(buffer);
 4148 heikki.linnakangas@i      551                 :              1 :     metadata = GinPageGetMeta(page);
                                552                 :                : 
                                553                 :              1 :     stats.version = metadata->ginVersion;
                                554                 :              1 :     stats.pending_pages = metadata->nPendingPages;
                                555                 :              1 :     stats.pending_tuples = metadata->nPendingHeapTuples;
                                556                 :                : 
                                557                 :              1 :     UnlockReleaseBuffer(buffer);
                                558                 :              1 :     relation_close(rel, AccessShareLock);
                                559                 :                : 
                                560                 :                :     /*
                                561                 :                :      * Build a tuple descriptor for our result type
                                562                 :                :      */
                                563         [ -  + ]:              1 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 4148 heikki.linnakangas@i      564         [ #  # ]:UBC           0 :         elog(ERROR, "return type must be a row type");
                                565                 :                : 
 4148 heikki.linnakangas@i      566                 :CBC           1 :     values[0] = Int32GetDatum(stats.version);
                                567                 :              1 :     values[1] = UInt32GetDatum(stats.pending_pages);
                                568                 :              1 :     values[2] = Int64GetDatum(stats.pending_tuples);
                                569                 :                : 
                                570                 :                :     /*
                                571                 :                :      * Build and return the tuple
                                572                 :                :      */
                                573                 :              1 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
                                574                 :              1 :     result = HeapTupleGetDatum(tuple);
                                575                 :                : 
 2432 peter_e@gmx.net           576                 :              1 :     return result;
                                577                 :                : }
                                578                 :                : 
                                579                 :                : /* ------------------------------------------------------
                                580                 :                :  * pgstathashindex()
                                581                 :                :  *
                                582                 :                :  * Usage: SELECT * FROM pgstathashindex('hashindex');
                                583                 :                :  * ------------------------------------------------------
                                584                 :                :  */
                                585                 :                : Datum
 2627 rhaas@postgresql.org      586                 :              9 : pgstathashindex(PG_FUNCTION_ARGS)
                                587                 :                : {
                                588                 :              9 :     Oid         relid = PG_GETARG_OID(0);
                                589                 :                :     BlockNumber nblocks;
                                590                 :                :     BlockNumber blkno;
                                591                 :                :     Relation    rel;
                                592                 :                :     HashIndexStat stats;
                                593                 :                :     BufferAccessStrategy bstrategy;
                                594                 :                :     HeapTuple   tuple;
                                595                 :                :     TupleDesc   tupleDesc;
                                596                 :                :     Datum       values[8];
  638 peter@eisentraut.org      597                 :              9 :     bool        nulls[8] = {0};
                                598                 :                :     Buffer      metabuf;
                                599                 :                :     HashMetaPage metap;
                                600                 :                :     float8      free_percent;
                                601                 :                :     uint64      total_space;
                                602                 :                : 
  117 michael@paquier.xyz       603                 :              9 :     rel = relation_open(relid, AccessShareLock);
                                604                 :                : 
                                605   [ +  +  +  + ]:              9 :     if (!IS_INDEX(rel) || !IS_HASH(rel))
 2593 sfrost@snowman.net        606         [ +  - ]:              7 :         ereport(ERROR,
                                607                 :                :                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                608                 :                :                  errmsg("relation \"%s\" is not a hash index",
                                609                 :                :                         RelationGetRelationName(rel))));
                                610                 :                : 
                                611                 :                :     /*
                                612                 :                :      * Reject attempts to read non-local temporary relations; we would be
                                613                 :                :      * likely to get wrong data since we have no visibility into the owning
                                614                 :                :      * session's local buffers.
                                615                 :                :      */
 2627 rhaas@postgresql.org      616   [ -  +  -  - ]:              2 :     if (RELATION_IS_OTHER_TEMP(rel))
 2627 rhaas@postgresql.org      617         [ #  # ]:UBC           0 :         ereport(ERROR,
                                618                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                619                 :                :                  errmsg("cannot access temporary indexes of other sessions")));
                                620                 :                : 
                                621                 :                :     /* see pgstatindex_impl */
  167 noah@leadboat.com         622         [ -  + ]:CBC           2 :     if (!rel->rd_index->indisvalid)
  167 noah@leadboat.com         623         [ #  # ]:UBC           0 :         ereport(ERROR,
                                624                 :                :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                625                 :                :                  errmsg("index \"%s\" is not valid",
                                626                 :                :                         RelationGetRelationName(rel))));
                                627                 :                : 
                                628                 :                :     /* Get the information we need from the metapage. */
 2627 rhaas@postgresql.org      629                 :CBC           2 :     memset(&stats, 0, sizeof(stats));
                                630                 :              2 :     metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
                                631                 :              2 :     metap = HashPageGetMeta(BufferGetPage(metabuf));
                                632                 :              2 :     stats.version = metap->hashm_version;
                                633                 :              2 :     stats.space_per_page = metap->hashm_bsize;
                                634                 :              2 :     _hash_relbuf(rel, metabuf);
                                635                 :                : 
                                636                 :                :     /* Get the current relation length */
                                637                 :              2 :     nblocks = RelationGetNumberOfBlocks(rel);
                                638                 :                : 
                                639                 :                :     /* prepare access strategy for this index */
                                640                 :              2 :     bstrategy = GetAccessStrategy(BAS_BULKREAD);
                                641                 :                : 
                                642                 :                :     /* Start from blkno 1 as 0th block is metapage */
                                643         [ +  + ]:             16 :     for (blkno = 1; blkno < nblocks; blkno++)
                                644                 :                :     {
                                645                 :                :         Buffer      buf;
                                646                 :                :         Page        page;
                                647                 :                : 
                                648         [ -  + ]:             14 :         CHECK_FOR_INTERRUPTS();
                                649                 :                : 
                                650                 :             14 :         buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
                                651                 :                :                                  bstrategy);
                                652                 :             14 :         LockBuffer(buf, BUFFER_LOCK_SHARE);
                                653                 :             14 :         page = (Page) BufferGetPage(buf);
                                654                 :                : 
                                655         [ -  + ]:             14 :         if (PageIsNew(page))
 2559 rhaas@postgresql.org      656                 :UBC           0 :             stats.unused_pages++;
 2627 rhaas@postgresql.org      657         [ -  + ]:CBC          14 :         else if (PageGetSpecialSize(page) !=
                                658                 :                :                  MAXALIGN(sizeof(HashPageOpaqueData)))
 2627 rhaas@postgresql.org      659         [ #  # ]:UBC           0 :             ereport(ERROR,
                                660                 :                :                     (errcode(ERRCODE_INDEX_CORRUPTED),
                                661                 :                :                      errmsg("index \"%s\" contains corrupted page at block %u",
                                662                 :                :                             RelationGetRelationName(rel),
                                663                 :                :                             BufferGetBlockNumber(buf))));
                                664                 :                :         else
                                665                 :                :         {
                                666                 :                :             HashPageOpaque opaque;
                                667                 :                :             int         pagetype;
                                668                 :                : 
  744 michael@paquier.xyz       669                 :CBC          14 :             opaque = HashPageGetOpaque(page);
 2559 rhaas@postgresql.org      670                 :             14 :             pagetype = opaque->hasho_flag & LH_PAGE_TYPE;
                                671                 :                : 
                                672         [ +  + ]:             14 :             if (pagetype == LH_BUCKET_PAGE)
                                673                 :                :             {
 2627                           674                 :             12 :                 stats.bucket_pages++;
                                675                 :             12 :                 GetHashPageStats(page, &stats);
                                676                 :                :             }
 2559                           677         [ -  + ]:              2 :             else if (pagetype == LH_OVERFLOW_PAGE)
                                678                 :                :             {
 2627 rhaas@postgresql.org      679                 :UBC           0 :                 stats.overflow_pages++;
                                680                 :              0 :                 GetHashPageStats(page, &stats);
                                681                 :                :             }
 2559 rhaas@postgresql.org      682         [ +  - ]:CBC           2 :             else if (pagetype == LH_BITMAP_PAGE)
 2627                           683                 :              2 :                 stats.bitmap_pages++;
 2559 rhaas@postgresql.org      684         [ #  # ]:UBC           0 :             else if (pagetype == LH_UNUSED_PAGE)
                                685                 :              0 :                 stats.unused_pages++;
                                686                 :                :             else
 2627                           687         [ #  # ]:              0 :                 ereport(ERROR,
                                688                 :                :                         (errcode(ERRCODE_INDEX_CORRUPTED),
                                689                 :                :                          errmsg("unexpected page type 0x%04X in HASH index \"%s\" block %u",
                                690                 :                :                                 opaque->hasho_flag, RelationGetRelationName(rel),
                                691                 :                :                                 BufferGetBlockNumber(buf))));
                                692                 :                :         }
 2627 rhaas@postgresql.org      693                 :CBC          14 :         UnlockReleaseBuffer(buf);
                                694                 :                :     }
                                695                 :                : 
                                696                 :                :     /* Done accessing the index */
                                697                 :              2 :     index_close(rel, AccessShareLock);
                                698                 :                : 
                                699                 :                :     /* Count unused pages as free space. */
 2439                           700                 :              2 :     stats.free_space += (uint64) stats.unused_pages * stats.space_per_page;
                                701                 :                : 
                                702                 :                :     /*
                                703                 :                :      * Total space available for tuples excludes the metapage and the bitmap
                                704                 :                :      * pages.
                                705                 :                :      */
                                706                 :              2 :     total_space = (uint64) (nblocks - (stats.bitmap_pages + 1)) *
                                707                 :              2 :         stats.space_per_page;
                                708                 :                : 
 2627                           709         [ -  + ]:              2 :     if (total_space == 0)
 2627 rhaas@postgresql.org      710                 :UBC           0 :         free_percent = 0.0;
                                711                 :                :     else
 2627 rhaas@postgresql.org      712                 :CBC           2 :         free_percent = 100.0 * stats.free_space / total_space;
                                713                 :                : 
                                714                 :                :     /*
                                715                 :                :      * Build a tuple descriptor for our result type
                                716                 :                :      */
                                717         [ -  + ]:              2 :     if (get_call_result_type(fcinfo, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
 2627 rhaas@postgresql.org      718         [ #  # ]:UBC           0 :         elog(ERROR, "return type must be a row type");
                                719                 :                : 
 2627 rhaas@postgresql.org      720                 :CBC           2 :     tupleDesc = BlessTupleDesc(tupleDesc);
                                721                 :                : 
                                722                 :                :     /*
                                723                 :                :      * Build and return the tuple
                                724                 :                :      */
                                725                 :              2 :     values[0] = Int32GetDatum(stats.version);
                                726                 :              2 :     values[1] = Int64GetDatum((int64) stats.bucket_pages);
                                727                 :              2 :     values[2] = Int64GetDatum((int64) stats.overflow_pages);
                                728                 :              2 :     values[3] = Int64GetDatum((int64) stats.bitmap_pages);
 2559                           729                 :              2 :     values[4] = Int64GetDatum((int64) stats.unused_pages);
 2627                           730                 :              2 :     values[5] = Int64GetDatum(stats.live_items);
                                731                 :              2 :     values[6] = Int64GetDatum(stats.dead_items);
                                732                 :              2 :     values[7] = Float8GetDatum(free_percent);
                                733                 :              2 :     tuple = heap_form_tuple(tupleDesc, values, nulls);
                                734                 :                : 
                                735                 :              2 :     PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
                                736                 :                : }
                                737                 :                : 
                                738                 :                : /* -------------------------------------------------
                                739                 :                :  * GetHashPageStats()
                                740                 :                :  *
                                741                 :                :  * Collect statistics of single hash page
                                742                 :                :  * -------------------------------------------------
                                743                 :                :  */
                                744                 :                : static void
                                745                 :             12 : GetHashPageStats(Page page, HashIndexStat *stats)
                                746                 :                : {
                                747                 :             12 :     OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
                                748                 :                :     int         off;
                                749                 :                : 
                                750                 :                :     /* count live and dead tuples, and free space */
                                751         [ -  + ]:             12 :     for (off = FirstOffsetNumber; off <= maxoff; off++)
                                752                 :                :     {
 2524 bruce@momjian.us          753                 :UBC           0 :         ItemId      id = PageGetItemId(page, off);
                                754                 :                : 
 2627 rhaas@postgresql.org      755         [ #  # ]:              0 :         if (!ItemIdIsDead(id))
                                756                 :              0 :             stats->live_items++;
                                757                 :                :         else
                                758                 :              0 :             stats->dead_items++;
                                759                 :                :     }
 2627 rhaas@postgresql.org      760                 :CBC          12 :     stats->free_space += PageGetExactFreeSpace(page);
                                761                 :             12 : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622