Thanks Bruce,

Here are updated Japanese README, and uninstall_pgstattuple.sql.

Bruce Momjian wrote:
> Patch applied.  Thanks.
> 
> I updated the README documentation for the new functions, attached.  I
> could not update the Japanese version of the README.
> 
> ---------------------------------------------------------------------------
> 
> 
> Satoshi Nagayasu wrote:
>> Bruce,
>>
>> Attached patch has been cleaned up,
>> and modified to be able to work with CVS HEAD.
>>
>> Thanks.
>>
>> Satoshi Nagayasu wrote:
>>> Alvaro,
>>>
>>> Alvaro Herrera wrote:
>>>> Huh, I bet it works with 8.1.4, but it doesn't work on CVS HEAD:
>>>>
>>>> /pgsql/source/00orig/contrib/pgstattuple/pgstatindex.c: In function 
>>>> 'GetBTPageStatistics':
>>>> /pgsql/source/00orig/contrib/pgstattuple/pgstatindex.c:182: error: 
>>>> 'BTItem' undeclared (first use in this function)
>>>>
>>>>
>>>> While you're at it, please consider removing C++ style comments and
>>>> unused code.
>>>>
>>>> Formatting is way off as well, but I guess that is easily fixed with
>>>> pgindent.
>>> Thanks for comments. I'm going to fix my patch from now.
>>>
>>>> Regarding the pg_relpages function, why do you think it's necessary?
>>>> (It returns the true number of blocks of a given relation).  It may
>>>> belong into core given a reasonable use case, but otherwise it doesn't
>>>> seem to belong into pgstatindex (or pgstattuple for that matter).
>>> I wanted to sample some pages from the table/index, and get their statistics
>>> to know table/index conditions. I know pgstattuple() reports table
>>> statistics, however, pgstattuple() generates heavy CPU and I/O load.
>>>
>>> When we need to sample some pages from table/index, we need to know
>>> true number of blocks.
>>>
>>> I have another function, called pgstatpage(), to get information inside
>>> a single block/page statistics of the table. pg_relpages() will be used
>>> with this.
>>>
>>> Sorry for not mentioned in previous post about pgstatpage(),
>>> but I've remembered about it just now.
>>>
>>> Many memories in my brain have already `paged-out` (too busy in last few 
>>> months),
>>> and some of them got `out-of-memory`. :^)
>>>
>>> Thanks.
>>
>> -- 
>> NAGAYASU Satoshi <[EMAIL PROTECTED]>
>> Phone: +81-3-3523-8122
> 
>> diff -ruN pgstattuple.orig/Makefile pgstattuple/Makefile
>> --- pgstattuple.orig/Makefile        2006-02-27 21:54:40.000000000 +0900
>> +++ pgstattuple/Makefile     2006-08-14 09:28:58.000000000 +0900
>> @@ -6,7 +6,7 @@
>>  #
>>  #-------------------------------------------------------------------------
>>  
>> -SRCS                = pgstattuple.c
>> +SRCS                = pgstattuple.c pgstatindex.c
>>  
>>  MODULE_big  = pgstattuple
>>  OBJS                = $(SRCS:.c=.o)
>> diff -ruN pgstattuple.orig/pgstatindex.c pgstattuple/pgstatindex.c
>> --- pgstattuple.orig/pgstatindex.c   1970-01-01 09:00:00.000000000 +0900
>> +++ pgstattuple/pgstatindex.c        2006-08-14 11:24:23.000000000 +0900
>> @@ -0,0 +1,706 @@
>> +/*
>> + * pgstatindex
>> + *
>> + * Copyright (c) 2006 Satoshi Nagayasu <[EMAIL PROTECTED]>
>> + *
>> + * Permission to use, copy, modify, and distribute this software and
>> + * its documentation for any purpose, without fee, and without a
>> + * written agreement is hereby granted, provided that the above
>> + * copyright notice and this paragraph and the following two
>> + * paragraphs appear in all copies.
>> + *
>> + * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
>> + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
>> + * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
>> + * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED
>> + * OF THE POSSIBILITY OF SUCH DAMAGE.
>> + *
>> + * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
>> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
>> + * A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS
>> + * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE,
>> + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
>> + */
>> +
>> +#include "postgres.h"
>> +
>> +#include "fmgr.h"
>> +#include "funcapi.h"
>> +#include "access/heapam.h"
>> +#include "access/itup.h"
>> +#include "access/nbtree.h"
>> +#include "access/transam.h"
>> +#include "catalog/namespace.h"
>> +#include "catalog/pg_type.h"
>> +#include "utils/builtins.h"
>> +#include "utils/inval.h"
>> +
>> +PG_FUNCTION_INFO_V1(pgstatindex);
>> +PG_FUNCTION_INFO_V1(bt_metap);
>> +PG_FUNCTION_INFO_V1(bt_page_items);
>> +PG_FUNCTION_INFO_V1(bt_page_stats);
>> +PG_FUNCTION_INFO_V1(pg_relpages);
>> +
>> +extern Datum pgstatindex(PG_FUNCTION_ARGS);
>> +extern Datum bt_metap(PG_FUNCTION_ARGS);
>> +extern Datum bt_page_items(PG_FUNCTION_ARGS);
>> +extern Datum bt_page_stats(PG_FUNCTION_ARGS);
>> +extern Datum pg_relpages(PG_FUNCTION_ARGS);
>> +
>> +#define PGSTATINDEX_TYPE "public.pgstatindex_type"
>> +#define PGSTATINDEX_NCOLUMNS 10
>> +
>> +#define BTMETAP_TYPE "public.bt_metap_type"
>> +#define BTMETAP_NCOLUMNS 6
>> +
>> +#define BTPAGEITEMS_TYPE "public.bt_page_items_type"
>> +#define BTPAGEITEMS_NCOLUMNS 6
>> +
>> +#define BTPAGESTATS_TYPE "public.bt_page_stats_type"
>> +#define BTPAGESTATS_NCOLUMNS 11
>> +
>> +
>> +#define IS_INDEX(r) ((r)->rd_rel->relkind == 'i')
>> +#define IS_BTREE(r) ((r)->rd_rel->relam == BTREE_AM_OID)
>> +
>> +#define CHECK_PAGE_OFFSET_RANGE(page, offset) { \
>> +            if ( !(FirstOffsetNumber<=(offset) && \
>> +                                            
>> (offset)<=PageGetMaxOffsetNumber(page)) ) \
>> +                     elog(ERROR, "Page offset number out of range."); }
>> +
>> +#define CHECK_RELATION_BLOCK_RANGE(rel, blkno) { \
>> +            if ( (blkno)<0 && RelationGetNumberOfBlocks((rel))<=(blkno) ) \
>> +                     elog(ERROR, "Block number out of range."); }
>> +
>> +/* ------------------------------------------------
>> + * structure for single btree page statistics
>> + * ------------------------------------------------
>> + */
>> +typedef struct BTPageStat
>> +{
>> +    uint32          blkno;
>> +    uint32          live_items;
>> +    uint32          dead_items;
>> +    uint32          page_size;
>> +    uint32          max_avail;
>> +    uint32          free_size;
>> +    uint32          avg_item_size;
>> +    uint32          fragments;
>> +    char            type;
>> +
>> +    /* opaque data */
>> +    BlockNumber btpo_prev;
>> +    BlockNumber btpo_next;
>> +    union
>> +    {
>> +            uint32          level;
>> +            TransactionId xact;
>> +    }                       btpo;
>> +    uint16          btpo_flags;
>> +    BTCycleId       btpo_cycleid;
>> +}   BTPageStat;
>> +
>> +/* ------------------------------------------------
>> + * A structure for a whole btree index statistics
>> + * used by pgstatindex().
>> + * ------------------------------------------------
>> + */
>> +typedef struct BTIndexStat
>> +{
>> +    uint32          magic;
>> +    uint32          version;
>> +    BlockNumber root_blkno;
>> +    uint32          level;
>> +
>> +    BlockNumber fastroot;
>> +    uint32          fastlevel;
>> +
>> +    uint32          live_items;
>> +    uint32          dead_items;
>> +
>> +    uint32          root_pages;
>> +    uint32          internal_pages;
>> +    uint32          leaf_pages;
>> +    uint32          empty_pages;
>> +    uint32          deleted_pages;
>> +
>> +    uint32          page_size;
>> +    uint32          avg_item_size;
>> +
>> +    uint32          max_avail;
>> +    uint32          free_space;
>> +
>> +    uint32          fragments;
>> +}   BTIndexStat;
>> +
>> +/* -------------------------------------------------
>> + * GetBTPageStatistics()
>> + *
>> + * Collect statistics of single b-tree leaf page
>> + * -------------------------------------------------
>> + */
>> +static bool
>> +GetBTPageStatistics(BlockNumber blkno, Buffer buffer, BTPageStat * stat)
>> +{
>> +    Page            page = BufferGetPage(buffer);
>> +    PageHeader      phdr = (PageHeader) page;
>> +    OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
>> +    BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
>> +    int                     item_size = 0;
>> +    int                     off;
>> +
>> +    stat->blkno = blkno;
>> +
>> +    stat->max_avail = BLCKSZ - (BLCKSZ - phdr->pd_special + 
>> SizeOfPageHeaderData);
>> +
>> +    stat->dead_items = stat->live_items = 0;
>> +
>> +    stat->page_size = PageGetPageSize(page);
>> +
>> +    /* page type (flags) */
>> +    if (P_ISDELETED(opaque))
>> +    {
>> +            stat->type = 'd';
>> +            return true;
>> +    }
>> +    else if (P_IGNORE(opaque))
>> +            stat->type = 'e';
>> +    else if (P_ISLEAF(opaque))
>> +            stat->type = 'l';
>> +    else if (P_ISROOT(opaque))
>> +            stat->type = 'r';
>> +    else
>> +            stat->type = 'i';
>> +
>> +    /* btpage opaque data */
>> +    stat->btpo_prev = opaque->btpo_prev;
>> +    stat->btpo_next = opaque->btpo_next;
>> +    if (P_ISDELETED(opaque))
>> +            stat->btpo.xact = opaque->btpo.xact;
>> +    else
>> +            stat->btpo.level = opaque->btpo.level;
>> +    stat->btpo_flags = opaque->btpo_flags;
>> +    stat->btpo_cycleid = opaque->btpo_cycleid;
>> +
>> +    /*----------------------------------------------
>> +     * If a next leaf is on the previous block,
>> +     * it means a fragmentation.
>> +     *----------------------------------------------
>> +     */
>> +    stat->fragments = 0;
>> +    if (stat->type == 'l')
>> +    {
>> +            if (opaque->btpo_next != P_NONE && opaque->btpo_next < blkno)
>> +                    stat->fragments++;
>> +    }
>> +
>> +    /* count live and dead tuples, and free space */
>> +    for (off = FirstOffsetNumber; off <= maxoff; off++)
>> +    {
>> +            IndexTuple      itup;
>> +
>> +            ItemId          id = PageGetItemId(page, off);
>> +
>> +            itup = (IndexTuple) PageGetItem(page, id);
>> +
>> +            item_size += IndexTupleSize(itup);
>> +
>> +            if (!ItemIdDeleted(id))
>> +                    stat->live_items++;
>> +            else
>> +                    stat->dead_items++;
>> +    }
>> +    stat->free_size = PageGetFreeSpace(page);
>> +
>> +    if ((stat->live_items + stat->dead_items) > 0)
>> +            stat->avg_item_size = item_size / (stat->live_items + 
>> stat->dead_items);
>> +    else
>> +            stat->avg_item_size = 0;
>> +
>> +    return true;
>> +}
>> +
>> +
>> +/* ------------------------------------------------------
>> + * pgstatindex()
>> + *
>> + * Usage: SELECT * FROM pgstatindex('t1_pkey');
>> + * ------------------------------------------------------
>> + */
>> +Datum
>> +pgstatindex(PG_FUNCTION_ARGS)
>> +{
>> +    text       *relname = PG_GETARG_TEXT_P(0);
>> +    Relation        rel;
>> +    RangeVar   *relrv;
>> +    Datum           result;
>> +    uint32          nblocks;
>> +    uint32          blkno;
>> +    BTIndexStat indexStat;
>> +
>> +    relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
>> +    rel = relation_openrv(relrv, AccessShareLock);
>> +
>> +    if (!IS_INDEX(rel) || !IS_BTREE(rel))
>> +            elog(ERROR, "pgstatindex() can be used only on b-tree index.");
>> +
>> +    /*-------------------
>> +     * Read a metapage
>> +     *-------------------
>> +     */
>> +    {
>> +            Buffer          buffer = ReadBuffer(rel, 0);
>> +            Page            page = BufferGetPage(buffer);
>> +            BTMetaPageData *metad = BTPageGetMeta(page);
>> +
>> +            indexStat.magic = metad->btm_magic;
>> +            indexStat.version = metad->btm_version;
>> +            indexStat.root_blkno = metad->btm_root;
>> +            indexStat.level = metad->btm_level;
>> +            indexStat.fastroot = metad->btm_fastroot;
>> +            indexStat.fastlevel = metad->btm_fastlevel;
>> +
>> +            ReleaseBuffer(buffer);
>> +    }
>> +
>> +    nblocks = RelationGetNumberOfBlocks(rel);
>> +
>> +    /* -- init stat -- */
>> +    indexStat.fragments = 0;
>> +
>> +    indexStat.root_pages = 0;
>> +    indexStat.leaf_pages = 0;
>> +    indexStat.internal_pages = 0;
>> +    indexStat.empty_pages = 0;
>> +    indexStat.deleted_pages = 0;
>> +
>> +    indexStat.max_avail = 0;
>> +    indexStat.free_space = 0;
>> +
>> +    /*-----------------------
>> +     * Scan all blocks
>> +     *-----------------------
>> +     */
>> +    for (blkno = 1; blkno < nblocks; blkno++)
>> +    {
>> +            Buffer          buffer = ReadBuffer(rel, blkno);
>> +            BTPageStat      stat;
>> +
>> +            /* scan one page */
>> +            stat.blkno = blkno;
>> +            GetBTPageStatistics(blkno, buffer, &stat);
>> +
>> +            /*---------------------
>> +             * page status (type)
>> +             *---------------------
>> +             */
>> +            switch (stat.type)
>> +            {
>> +                    case 'd':
>> +                            indexStat.deleted_pages++;
>> +                            break;
>> +                    case 'l':
>> +                            indexStat.leaf_pages++;
>> +                            break;
>> +                    case 'i':
>> +                            indexStat.internal_pages++;
>> +                            break;
>> +                    case 'e':
>> +                            indexStat.empty_pages++;
>> +                            break;
>> +                    case 'r':
>> +                            indexStat.root_pages++;
>> +                            break;
>> +                    default:
>> +                            elog(ERROR, "unknown page status.");
>> +            }
>> +
>> +            /* -- leaf fragmentation -- */
>> +            indexStat.fragments += stat.fragments;
>> +
>> +            if (stat.type == 'l')
>> +            {
>> +                    indexStat.max_avail += stat.max_avail;
>> +                    indexStat.free_space += stat.free_size;
>> +            }
>> +
>> +            ReleaseBuffer(buffer);
>> +    }
>> +
>> +    relation_close(rel, AccessShareLock);
>> +
>> +    /*----------------------------
>> +     * Build a result tuple
>> +     *----------------------------
>> +     */
>> +    {
>> +            TupleDesc       tupleDesc;
>> +            int                     j;
>> +            char       *values[PGSTATINDEX_NCOLUMNS];
>> +
>> +            HeapTupleData tupleData;
>> +            HeapTuple       tuple = &tupleData;
>> +
>> +            tupleDesc = RelationNameGetTupleDesc(PGSTATINDEX_TYPE);
>> +
>> +            j = 0;
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", indexStat.version);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", indexStat.level);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", (indexStat.root_pages +
>> +                                                                            
>>  indexStat.leaf_pages +
>> +                                                                            
>>  indexStat.internal_pages +
>> +                                                                            
>>  indexStat.deleted_pages +
>> +                                                                            
>>  indexStat.empty_pages) * BLCKSZ);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", indexStat.root_blkno);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", indexStat.internal_pages);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", indexStat.leaf_pages);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", indexStat.empty_pages);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", indexStat.deleted_pages);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%.2f", 100.0 - (float) 
>> indexStat.free_space / (float) indexStat.max_avail * 100.0);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%.2f", (float) indexStat.fragments / 
>> (float) indexStat.leaf_pages * 100.0);
>> +
>> +            tuple = 
>> BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
>> +                                                                       
>> values);
>> +
>> +            result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple);
>> +    }
>> +
>> +    PG_RETURN_DATUM(result);
>> +}
>> +
>> +/* -----------------------------------------------
>> + * bt_page()
>> + *
>> + * Usage: SELECT * FROM bt_page('t1_pkey', 0);
>> + * -----------------------------------------------
>> + */
>> +Datum
>> +bt_page_stats(PG_FUNCTION_ARGS)
>> +{
>> +    text       *relname = PG_GETARG_TEXT_P(0);
>> +    uint32          blkno = PG_GETARG_UINT32(1);
>> +    Buffer          buffer;
>> +
>> +    Relation        rel;
>> +    RangeVar   *relrv;
>> +    Datum           result;
>> +
>> +    relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
>> +    rel = relation_openrv(relrv, AccessShareLock);
>> +
>> +    CHECK_RELATION_BLOCK_RANGE(rel, blkno);
>> +
>> +    buffer = ReadBuffer(rel, blkno);
>> +
>> +    if (!IS_INDEX(rel) || !IS_BTREE(rel))
>> +            elog(ERROR, "bt_page_stats() can be used only on b-tree 
>> index.");
>> +
>> +    if (blkno == 0)
>> +            elog(ERROR, "Block 0 is a meta page.");
>> +
>> +    {
>> +            HeapTuple       tuple;
>> +            TupleDesc       tupleDesc;
>> +            int                     j;
>> +            char       *values[BTPAGESTATS_NCOLUMNS];
>> +
>> +            BTPageStat      stat;
>> +
>> +            GetBTPageStatistics(blkno, buffer, &stat);
>> +
>> +            tupleDesc = RelationNameGetTupleDesc(BTPAGESTATS_TYPE);
>> +
>> +            j = 0;
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.blkno);
>> +
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%c", stat.type);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.live_items);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.dead_items);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.avg_item_size);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.page_size);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.free_size);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.btpo_prev);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.btpo_next);
>> +
>> +            values[j] = palloc(32);
>> +            if (stat.type == 'd')
>> +                    snprintf(values[j++], 32, "%d", stat.btpo.xact);
>> +            else
>> +                    snprintf(values[j++], 32, "%d", stat.btpo.level);
>> +
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", stat.btpo_flags);
>> +
>> +            tuple = 
>> BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
>> +                                                                       
>> values);
>> +
>> +            result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple);
>> +    }
>> +
>> +    ReleaseBuffer(buffer);
>> +
>> +    relation_close(rel, AccessShareLock);
>> +
>> +    PG_RETURN_DATUM(result);
>> +}
>> +
>> +/*-------------------------------------------------------
>> + * bt_page_items()
>> + *
>> + * Get IndexTupleData set in a leaf page
>> + *
>> + * Usage: SELECT * FROM bt_page_items('t1_pkey', 0);
>> + *-------------------------------------------------------
>> + */
>> +/* ---------------------------------------------------
>> + * data structure for SRF to hold a scan information
>> + * ---------------------------------------------------
>> + */
>> +struct user_args
>> +{
>> +    TupleDesc       tupd;
>> +    Relation        rel;
>> +    Buffer          buffer;
>> +    Page            page;
>> +    uint16          offset;
>> +};
>> +
>> +Datum
>> +bt_page_items(PG_FUNCTION_ARGS)
>> +{
>> +    text       *relname = PG_GETARG_TEXT_P(0);
>> +    uint32          blkno = PG_GETARG_UINT32(1);
>> +
>> +    RangeVar   *relrv;
>> +    Datum           result;
>> +    char       *values[BTPAGEITEMS_NCOLUMNS];
>> +    BTPageOpaque opaque;
>> +    HeapTuple       tuple;
>> +    ItemId          id;
>> +
>> +    FuncCallContext *fctx;
>> +    MemoryContext mctx;
>> +    struct user_args *uargs = NULL;
>> +
>> +    if (blkno == 0)
>> +            elog(ERROR, "Block 0 is a meta page.");
>> +
>> +    if (SRF_IS_FIRSTCALL())
>> +    {
>> +            fctx = SRF_FIRSTCALL_INIT();
>> +            mctx = MemoryContextSwitchTo(fctx->multi_call_memory_ctx);
>> +
>> +            uargs = palloc(sizeof(struct user_args));
>> +
>> +            uargs->tupd = RelationNameGetTupleDesc(BTPAGEITEMS_TYPE);
>> +            uargs->offset = FirstOffsetNumber;
>> +
>> +            relrv = 
>> makeRangeVarFromNameList(textToQualifiedNameList(relname));
>> +            uargs->rel = relation_openrv(relrv, AccessShareLock);
>> +
>> +            CHECK_RELATION_BLOCK_RANGE(uargs->rel, blkno);
>> +
>> +            uargs->buffer = ReadBuffer(uargs->rel, blkno);
>> +
>> +            if (!IS_INDEX(uargs->rel) || !IS_BTREE(uargs->rel))
>> +                    elog(ERROR, "bt_page_items() can be used only on b-tree 
>> index.");
>> +
>> +            uargs->page = BufferGetPage(uargs->buffer);
>> +
>> +            opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page);
>> +
>> +            if (P_ISDELETED(opaque))
>> +                    elog(NOTICE, "bt_page_items(): this page is deleted.");
>> +
>> +            fctx->max_calls = PageGetMaxOffsetNumber(uargs->page);
>> +            fctx->user_fctx = uargs;
>> +
>> +            MemoryContextSwitchTo(mctx);
>> +    }
>> +
>> +    fctx = SRF_PERCALL_SETUP();
>> +    uargs = fctx->user_fctx;
>> +
>> +    if (fctx->call_cntr < fctx->max_calls)
>> +    {
>> +            IndexTuple      itup;
>> +
>> +            id = PageGetItemId(uargs->page, uargs->offset);
>> +
>> +            if (!ItemIdIsValid(id))
>> +                    elog(ERROR, "Invalid ItemId.");
>> +
>> +            itup = (IndexTuple) PageGetItem(uargs->page, id);
>> +
>> +            {
>> +                    int                     j = 0;
>> +
>> +                    BlockNumber blkno = 
>> BlockIdGetBlockNumber(&(itup->t_tid.ip_blkid));
>> +
>> +                    values[j] = palloc(32);
>> +                    snprintf(values[j++], 32, "%d", uargs->offset);
>> +                    values[j] = palloc(32);
>> +                    snprintf(values[j++], 32, "(%u,%u)", blkno, 
>> itup->t_tid.ip_posid);
>> +                    values[j] = palloc(32);
>> +                    snprintf(values[j++], 32, "%d", IndexTupleSize(itup));
>> +                    values[j] = palloc(32);
>> +                    snprintf(values[j++], 32, "%c", 
>> IndexTupleHasNulls(itup) ? 't' : 'f');
>> +                    values[j] = palloc(32);
>> +                    snprintf(values[j++], 32, "%c", 
>> IndexTupleHasVarwidths(itup) ? 't' : 'f');
>> +
>> +                    {
>> +                            int                     off;
>> +                            char       *dump;
>> +                            char       *ptr = (char *) itup + 
>> IndexInfoFindDataOffset(itup->t_info);
>> +
>> +                            dump = palloc(IndexTupleSize(itup) * 3);
>> +                            memset(dump, 0, IndexTupleSize(itup) * 3);
>> +
>> +                            for (off = 0;
>> +                                     off < IndexTupleSize(itup) - 
>> IndexInfoFindDataOffset(itup->t_info);
>> +                                     off++)
>> +                            {
>> +                                    if (dump[0] == '\0')
>> +                                            sprintf(dump, "%02x", *(ptr + 
>> off) & 0xff);
>> +                                    else
>> +                                    {
>> +                                            char            buf[4];
>> +
>> +                                            sprintf(buf, " %02x", *(ptr + 
>> off) & 0xff);
>> +                                            strcat(dump, buf);
>> +                                    }
>> +                            }
>> +                            values[j] = dump;
>> +                    }
>> +
>> +                    tuple = 
>> BuildTupleFromCStrings(TupleDescGetAttInMetadata(uargs->tupd), values);
>> +                    result = TupleGetDatum(TupleDescGetSlot(uargs->tupd), 
>> tuple);
>> +            }
>> +
>> +            uargs->offset = uargs->offset + 1;
>> +
>> +            SRF_RETURN_NEXT(fctx, result);
>> +    }
>> +    else
>> +    {
>> +            ReleaseBuffer(uargs->buffer);
>> +            relation_close(uargs->rel, AccessShareLock);
>> +
>> +            SRF_RETURN_DONE(fctx);
>> +    }
>> +}
>> +
>> +
>> +/* ------------------------------------------------
>> + * bt_metap()
>> + *
>> + * Get a btree meta-page information
>> + *
>> + * Usage: SELECT * FROM bt_metap('t1_pkey')
>> + * ------------------------------------------------
>> + */
>> +Datum
>> +bt_metap(PG_FUNCTION_ARGS)
>> +{
>> +    text       *relname = PG_GETARG_TEXT_P(0);
>> +    Buffer          buffer;
>> +
>> +    Relation        rel;
>> +    RangeVar   *relrv;
>> +    Datum           result;
>> +
>> +    relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
>> +    rel = relation_openrv(relrv, AccessShareLock);
>> +
>> +    if (!IS_INDEX(rel) || !IS_BTREE(rel))
>> +            elog(ERROR, "bt_metap() can be used only on b-tree index.");
>> +
>> +    buffer = ReadBuffer(rel, 0);
>> +
>> +    {
>> +            BTMetaPageData *metad;
>> +
>> +            TupleDesc       tupleDesc;
>> +            int                     j;
>> +            char       *values[BTMETAP_NCOLUMNS];
>> +            HeapTuple       tuple;
>> +
>> +            Page            page = BufferGetPage(buffer);
>> +
>> +            metad = BTPageGetMeta(page);
>> +
>> +            tupleDesc = RelationNameGetTupleDesc(BTMETAP_TYPE);
>> +
>> +            j = 0;
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", metad->btm_magic);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", metad->btm_version);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", metad->btm_root);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", metad->btm_level);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", metad->btm_fastroot);
>> +            values[j] = palloc(32);
>> +            snprintf(values[j++], 32, "%d", metad->btm_fastlevel);
>> +
>> +            tuple = 
>> BuildTupleFromCStrings(TupleDescGetAttInMetadata(tupleDesc),
>> +                                                                       
>> values);
>> +
>> +            result = TupleGetDatum(TupleDescGetSlot(tupleDesc), tuple);
>> +    }
>> +
>> +    ReleaseBuffer(buffer);
>> +
>> +    relation_close(rel, AccessShareLock);
>> +
>> +    PG_RETURN_DATUM(result);
>> +}
>> +
>> +/* --------------------------------------------------------
>> + * pg_relpages()
>> + *
>> + * Get a number of pages of the table/index.
>> + *
>> + * Usage: SELECT pg_relpages('t1');
>> + *            SELECT pg_relpages('t1_pkey');
>> + * --------------------------------------------------------
>> + */
>> +Datum
>> +pg_relpages(PG_FUNCTION_ARGS)
>> +{
>> +    text       *relname = PG_GETARG_TEXT_P(0);
>> +
>> +    Relation        rel;
>> +    RangeVar   *relrv;
>> +    int4            relpages;
>> +
>> +    relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
>> +    rel = relation_openrv(relrv, AccessShareLock);
>> +
>> +    relpages = RelationGetNumberOfBlocks(rel);
>> +
>> +    relation_close(rel, AccessShareLock);
>> +
>> +    PG_RETURN_INT32(relpages);
>> +}
>> diff -ruN pgstattuple.orig/pgstattuple.sql.in pgstattuple/pgstattuple.sql.in
>> --- pgstattuple.orig/pgstattuple.sql.in      2006-02-28 01:09:50.000000000 
>> +0900
>> +++ pgstattuple/pgstattuple.sql.in   2006-08-14 10:37:32.000000000 +0900
>> @@ -22,3 +22,96 @@
>>  RETURNS pgstattuple_type
>>  AS 'MODULE_PATHNAME', 'pgstattuplebyid'
>>  LANGUAGE C STRICT;
>> +
>> +--
>> +-- pgstatindex
>> +--
>> +DROP TYPE pgstatindex_type CASCADE;
>> +CREATE TYPE pgstatindex_type AS (
>> +  version int4,
>> +  tree_level int4,
>> +  index_size int4,
>> +  root_block_no int4,
>> +  internal_pages int4,
>> +  leaf_pages int4,
>> +  empty_pages int4,
>> +  deleted_pages int4,
>> +  avg_leaf_density float8,
>> +  leaf_fragmentation float8
>> +);
>> +
>> +CREATE OR REPLACE FUNCTION pgstatindex(text)
>> +RETURNS pgstatindex_type
>> +AS 'MODULE_PATHNAME', 'pgstatindex'
>> +LANGUAGE 'C' STRICT;
>> +
>> +--
>> +-- bt_metap()
>> +--
>> +DROP TYPE bt_metap_type CASCADE;
>> +CREATE TYPE bt_metap_type AS (
>> +  magic int4,
>> +  version int4,
>> +  root int4,
>> +  level int4,
>> +  fastroot int4,
>> +  fastlevel int4
>> +);
>> +
>> +CREATE OR REPLACE FUNCTION bt_metap(text)
>> +RETURNS bt_metap_type
>> +AS 'MODULE_PATHNAME', 'bt_metap'
>> +LANGUAGE 'C' STRICT;
>> +
>> +--
>> +-- bt_page_items()
>> +--
>> +DROP TYPE bt_page_items_type CASCADE;
>> +CREATE TYPE bt_page_items_type AS (
>> +  itemoffset int4,
>> +  ctid tid,
>> +  itemlen int4,
>> +  nulls bool,
>> +  vars bool,
>> +  data text
>> +);
>> +
>> +DROP FUNCTION bt_page_items(text, int4);
>> +
>> +CREATE OR REPLACE FUNCTION bt_page_items(text, int4)
>> +RETURNS SETOF bt_page_items_type
>> +AS 'MODULE_PATHNAME', 'bt_page_items'
>> +LANGUAGE 'C' STRICT;
>> +
>> +--
>> +-- bt_page_stats()
>> +--
>> +DROP TYPE bt_page_stats_type CASCADE;
>> +CREATE TYPE bt_page_stats_type AS (
>> +  blkno int4,
>> +  type char,
>> +  live_items int4,
>> +  dead_items int4,
>> +  avg_item_size float,
>> +  page_size int4,
>> +  free_size int4,
>> +  btpo_prev int4,
>> +  btpo_next int4,
>> +  btpo int4,
>> +  btpo_flags int4
>> +);
>> +
>> +DROP FUNCTION bt_page_stats(text, int4);
>> +
>> +CREATE OR REPLACE FUNCTION bt_page_stats(text, int4)
>> +RETURNS bt_page_stats_type
>> +AS 'MODULE_PATHNAME', 'bt_page_stats'
>> +LANGUAGE 'C' STRICT;
>> +
>> +--
>> +-- pg_relpages()
>> +--
>> +CREATE OR REPLACE FUNCTION pg_relpages(text)
>> +RETURNS int
>> +AS 'MODULE_PATHNAME', 'pg_relpages'
>> +LANGUAGE 'C' STRICT;
>> diff -ruN pgstattuple.orig/test.sh pgstattuple/test.sh
>> --- pgstattuple.orig/test.sh 1970-01-01 09:00:00.000000000 +0900
>> +++ pgstattuple/test.sh      2006-08-14 10:23:08.000000000 +0900
>> @@ -0,0 +1,27 @@
>> +#!/bin/sh
>> +
>> +PGHOME=/home/snaga/pgsql20060814
>> +export PATH=${PGHOME}/bin:$PATH
>> +
>> +psql -p 9999 pgbench<<EOF
>> +DROP FUNCTION pgstatindex(text);
>> +EOF
>> +
>> +psql -p 9999 -f ${PGHOME}/share/contrib/pgstattuple.sql pgbench
>> +
>> +psql -p 9999 pgbench<<EOF
>> +SELECT * FROM pg_relpages('accounts_pkey');
>> +\x
>> +SELECT * FROM pgstatindex('accounts_pkey');
>> +SELECT * FROM bt_metap('accounts_pkey');
>> +\x
>> +SELECT * FROM bt_page_items('accounts_pkey', 0);
>> +SELECT * FROM bt_page_items('accounts_pkey', 1) limit 20;
>> +
>> +SELECT * FROM bt_page_stats('accounts_pkey', 1);
>> +\x
>> +SELECT * FROM bt_page_stats('accounts_pkey', 1);
>> +SELECT * FROM bt_page_stats('accounts_pkey', 361);
>> +\x
>> +SELECT * FROM bt_page_items('accounts_pkey', 361);
>> +EOF
>>
>>
>> ------------------------------------------------------------------------
>>
>> pgstattuple README                   2002/08/29 Tatsuo Ishii
>>
>> 1. Functions supported:
>>
>>     pgstattuple
>>     -----------
>>     pgstattuple() returns the relation length, percentage of the "dead"
>>     tuples of a relation and other info. This may help users to determine
>>     whether vacuum is necessary or not. Here is an example session:
>>
>>         test=> \x
>>         Expanded display is on.
>>         test=> SELECT * FROM pgstattuple('pg_catalog.pg_proc');
>>         -[ RECORD 1 ]------+-------
>>         table_len          | 458752
>>         tuple_count        | 1470
>>         tuple_len          | 438896
>>         tuple_percent      | 95.67
>>         dead_tuple_count   | 11
>>         dead_tuple_len     | 3157
>>         dead_tuple_percent | 0.69
>>         free_space         | 8932
>>         free_percent       | 1.95
>>
>>     Here are explanations for each column:
>>
>>         table_len            -- physical relation length in bytes
>>         tuple_count          -- number of live tuples
>>         tuple_len            -- total tuples length in bytes
>>         tuple_percent        -- live tuples in %
>>         dead_tuple_len       -- total dead tuples length in bytes
>>         dead_tuple_percent   -- dead tuples in %
>>         free_space           -- free space in bytes
>>         free_percent -- free space in %
>>
>>     pg_relpages
>>     -----------
>>     pg_relpages() returns the number of pages in the relation.
>>
>>     pgstatindex
>>     -----------
>>     pgstatindex() returns an array showing the information about an index:
>>
>>         test=> \x
>>         Expanded display is on.
>>         test=> SELECT * FROM pgstatindex('pg_cast_oid_index');
>>         -[ RECORD 1 ]------+------
>>         version            | 2
>>         tree_level         | 0
>>         index_size         | 8192
>>         root_block_no      | 1
>>         internal_pages     | 0
>>         leaf_pages         | 1
>>         empty_pages        | 0
>>         deleted_pages      | 0
>>         avg_leaf_density   | 50.27
>>         leaf_fragmentation | 0
>>
>>     bt_metap
>>     --------
>>     bt_metap() returns information about the btree index metapage:
>>
>>         test=> SELECT * FROM bt_metap('pg_cast_oid_index');
>>         -[ RECORD 1 ]-----
>>         magic     | 340322
>>         version   | 2
>>         root      | 1
>>         level     | 0
>>         fastroot  | 1
>>         fastlevel | 0
>>
>>     bt_page_stats
>>     -------------
>>     bt_page_stats() shows information about single btree pages:
>>
>>         test=> SELECT * FROM bt_page_stats('pg_cast_oid_index', 1);
>>         -[ RECORD 1 ]-+-----
>>         blkno         | 1
>>         type          | l
>>         live_items    | 256
>>         dead_items    | 0
>>         avg_item_size | 12
>>         page_size     | 8192
>>         free_size     | 4056
>>         btpo_prev     | 0
>>         btpo_next     | 0
>>         btpo          | 0
>>         btpo_flags    | 3
>>
>>     bt_page_items
>>     -------------
>>     bt_page_items() returns information about specific items on btree pages:
>>
>>         test=> SELECT * FROM bt_page_items('pg_cast_oid_index', 1);
>>          itemoffset |  ctid   | itemlen | nulls | vars |    data
>>         ------------+---------+---------+-------+------+-------------
>>                   1 | (0,1)   |      12 | f     | f    | 23 27 00 00
>>                   2 | (0,2)   |      12 | f     | f    | 24 27 00 00
>>                   3 | (0,3)   |      12 | f     | f    | 25 27 00 00
>>                   4 | (0,4)   |      12 | f     | f    | 26 27 00 00
>>                   5 | (0,5)   |      12 | f     | f    | 27 27 00 00
>>                   6 | (0,6)   |      12 | f     | f    | 28 27 00 00
>>                   7 | (0,7)   |      12 | f     | f    | 29 27 00 00
>>                   8 | (0,8)   |      12 | f     | f    | 2a 27 00 00
>>
>>
>> 2. Installing pgstattuple
>>
>>     $ make
>>     $ make install
>>     $ psql -e -f /usr/local/pgsql/share/contrib/pgstattuple.sql test
>>
>>
>> 3. Using pgstattuple
>>
>>     pgstattuple may be called as a relation function and is
>>     defined as follows:
>>
>>     CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS pgstattuple_type
>>      AS 'MODULE_PATHNAME', 'pgstattuple'
>>      LANGUAGE C STRICT;
>>
>>     CREATE OR REPLACE FUNCTION pgstattuple(oid) RETURNS pgstattuple_type
>>      AS 'MODULE_PATHNAME', 'pgstattuplebyid'
>>      LANGUAGE C STRICT;
>>
>>     The argument is the relation name (optionally it may be qualified)
>>     or the OID of the relation.  Note that pgstattuple only returns
>>     one row.
>>
>>
>> 4. Notes
>>
>>     pgstattuple acquires only a read lock on the relation. So concurrent
>>     update may affect the result.
>>
>>     pgstattuple judges a tuple is "dead" if HeapTupleSatisfiesNow()
>>     returns false.
>>
>>
>> 5. History
>>
>>     2006/06/28
>>
>>      Extended to work against indexes.


-- 
NAGAYASU Satoshi <[EMAIL PROTECTED]>
Phone: +81-3-3523-8122
$PostgreSQL: pgsql/contrib/pgstattuple/README.pgstattuple.euc_jp,v 1.7 
2006/07/06 02:18:07 momjian Exp $

pgstattuple README              2002/08/22 ÀаæãÉ×

1. ¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë´Ø¿ô

   pgstattuple
   -----------
   pgstattuple¤Ï¡¤UPDATE¤äDELETE¤Çºî¤é¤ì¤¿¥ê¥ì¡¼¥·¥ç¥ó¤Î¥´¥ßÎΰè¤ÎÂ礭¤µ¤ò¡¤
   ¥ê¥ì¡¼¥·¥ç¥ó¼«ÂΤÎʪÍýŪ¤ÊÂ礭¤µ¤ËÂФ¹¤ë¥Ñ¡¼¥»¥ó¥Æ¡¼¥¸¤ÇÊֵѤ·¤Þ¤¹¡¥¤Ä
   ¤Þ¤ê¡¤ÊÖµÑÃͤ¬Â礭¤±¤ì¤Ð¡¤¤½¤ì¤À¤±¥´¥ß¤â¿¤¤¤Î¤Ç¡¤vacuum¤ò¤«¤±¤ëɬ
   Íפ¬¤¢¤ë¤È¤¤¤¦È½ÃǤνõ¤±¤Ë¤Ê¤ë¤ï¤±¤Ç¤¹¡¥¤³¤ì°Ê³°¤Ë¤â¤¤¤í¤¤¤í¤Ê¾ðÊó
   ¤¬ÊÖ¤ê¤Þ¤¹¡¥
   pgstattuple() ¤Ï¡¢¥ê¥ì¡¼¥·¥ç¥ó¤ÎŤµ¤ä¡¢¥¿¥×¥ë¤Î"¥´¥ßÎΰè"¤Î³ä¹ç¤Ê¤É¤Î
   ¾ðÊó¤òÊֵѤ·¤Þ¤¹¡£¤³¤ì¤é¤Î¾ðÊó¤Ï¡¢vacuum ¤¬É¬Íפ«¤É¤¦¤«¡¢¥æ¡¼¥¶¤¬È½ÃÇ
   ¤¹¤ë¤Î¤ËÌòΩ¤Ä¤Ç¤·¤ç¤¦¡£Î㤨¤Ð°Ê²¼¤Î¤è¤¦¤Ê·Á¤Ë¤Ê¤ê¤Þ¤¹¡§

       test=> \x
       Expanded display is on.
       test=> SELECT * FROM pgstattuple('pg_catalog.pg_proc');
       -[ RECORD 1 ]------+-------
       table_len          | 458752
       tuple_count        | 1470
       tuple_len          | 438896
       tuple_percent      | 95.67
       dead_tuple_count   | 11
       dead_tuple_len     | 3157
       dead_tuple_percent | 0.69
       free_space         | 8932
       free_percent       | 1.95

   °Ê²¼¤¬³Æ¹àÌܤÎÆâÍƤǤ¹¡§

       table_len                -- ¥ê¥ì¡¼¥·¥ç¥ó¤ÎʪÍýŪ¤ÊÂ礭¤µ(¥Ð¥¤¥È)
       tuple_count              -- ¥¿¥×¥ë¿ô
       tuple_len                -- ¥¿¥×¥ëĹ¤Î¹ç·×(¥Ð¥¤¥È)
       tuple_percent    -- ¥¿¥×¥ë¤Î³ä¹ç¡¥table_len¤ËÂФ¹¤ëtuple_len¤ÎÈæΨ¡¥
       dead_tuple_len   -- ¥Ç¥Ã¥É¥¿¥×¥ë¿ô
       dead_tuple_percent       -- 
¥Ç¥Ã¥É¥¿¥×¥ë¤Î³ä¹ç¡¥table_len¤ËÂФ¹¤ëtuple_len¤ÎÈæΨ¡¥
       free_space               -- ºÆÍøÍѲÄǽ¤ÊÎΰè(¥Ð¥¤¥È)
       free_percent     -- ºÆÍøÍѲÄǽ¤ÊÎΰ补table_len¤ËÂФ¹¤ëfree_space¤ÎÈæΨ¡¥

   pg_relpages
   -----------
   pg_relpages() ¤Ï¥ê¥ì¡¼¥·¥ç¥ó¤Î¥Ú¡¼¥¸¿ô¤òÊֵѤ·¤Þ¤¹¡¥

   pgstatindex
   -----------
   pgstatindex() ¤Ï¥¤¥ó¥Ç¥Ã¥¯¥¹¤Ë´Ø¤¹¤ë¾ðÊó¤òÊֵѤ·¤Þ¤¹¡§

       test=> \x
       Expanded display is on.
       test=> SELECT * FROM pgstatindex('pg_cast_oid_index');
       -[ RECORD 1 ]------+------
       version            | 2
       tree_level         | 0
       index_size         | 8192
       root_block_no      | 1
       internal_pages     | 0
       leaf_pages         | 1
       empty_pages        | 0
       deleted_pages      | 0
       avg_leaf_density   | 50.27
       leaf_fragmentation | 0

   bt_metap
   --------
   bt_metap() ¤Ïbtree¥¤¥ó¥Ç¥Ã¥¯¥¹¤Î¥á¥¿¥Ú¡¼¥¸¤Ë´Ø¤¹¤ë¾ðÊó¤òÊֵѤ·¤Þ¤¹¡§

       test=> SELECT * FROM bt_metap('pg_cast_oid_index');
       -[ RECORD 1 ]-----
       magic     | 340322
       version   | 2
       root      | 1
       level     | 0
       fastroot  | 1
       fastlevel | 0

   bt_page_stats
   -------------
   bt_page_stats() ¤Ï¡¢btree¤Îñ°ì¤Î¥Ú¡¼¥¸¤Ë´Ø¤¹¤ë¾ðÊó¤òɽ¼¨¤·¤Þ¤¹¡§

       test=> SELECT * FROM bt_page_stats('pg_cast_oid_index', 1);
       -[ RECORD 1 ]-+-----
       blkno         | 1
       type          | l
       live_items    | 256
       dead_items    | 0
       avg_item_size | 12
       page_size     | 8192
       free_size     | 4056
       btpo_prev     | 0
       btpo_next     | 0
       btpo          | 0
       btpo_flags    | 3

   bt_page_items
   -------------
   bt_page_items() ¤Ï¡¢³Æbtree¥Ú¡¼¥¸¤Î¸ÄÊ̤Υ¢¥¤¥Æ¥à¤Ë´Ø¤¹¤ë¾ðÊó¤òɽ¼¨¤·¤Þ¤¹¡§

       test=> SELECT * FROM bt_page_items('pg_cast_oid_index', 1);
        itemoffset |  ctid   | itemlen | nulls | vars |    data
       ------------+---------+---------+-------+------+-------------
                 1 | (0,1)   |      12 | f     | f    | 23 27 00 00
                 2 | (0,2)   |      12 | f     | f    | 24 27 00 00
                 3 | (0,3)   |      12 | f     | f    | 25 27 00 00
                 4 | (0,4)   |      12 | f     | f    | 26 27 00 00
                 5 | (0,5)   |      12 | f     | f    | 27 27 00 00
                 6 | (0,6)   |      12 | f     | f    | 28 27 00 00
                 7 | (0,7)   |      12 | f     | f    | 29 27 00 00
                 8 | (0,8)   |      12 | f     | f    | 2a 27 00 00
 

2. pgstattuple¤Î¥¤¥ó¥¹¥È¡¼¥ë

   PostgreSQL¤¬/usr/local/pgsql¤Ë¥¤¥ó¥¹¥È¡¼¥ëºÑ¤Ç¤¢¤ê¡¤test¥Ç¡¼¥¿¥Ù¡¼
   ¥¹¤Ëpgstattuple¤ò¥¤¥ó¥¹¥È¡¼¥ë¤¹¤ë¾ì¹ç¤Î¼ê½ç¤ò¼¨¤·¤Þ¤¹¡¥

    $ make
    $ make install

    ¥æ¡¼¥¶ÄêµÁ´Ø¿ô¤òÅÐÏ¿¤·¤Þ¤¹¡¥

    $ psql -e -f /usr/local/pgsql/share/contrib/pgstattuple.sql test


3. pgstattuple¤Î»È¤¤Êý

   pgstattuple¤Î¸Æ¤Ó½Ð¤··Á¼°¤Ï°Ê²¼¤Ç¤¹¡¥

   CREATE OR REPLACE FUNCTION pgstattuple(text) RETURNS pgstattuple_type
     AS 'MODULE_PATHNAME', 'pgstattuple'
     LANGUAGE C STRICT;

   Âè°ì°ú¿ô: ¥ê¥ì¡¼¥·¥ç¥ó̾

   ´Ø¿ô¤ÎÌá¤ê¤Ïpgstattuple_type·¿¤Ç¤¹¡¥

   pgstattuple¤Ï¥ê¥ì¡¼¥·¥ç¥ó¤ËAccessShareLock¤·¤«¤«¤±¤Ê¤¤¤Î¤Ç¡¤
   pgstattuple ¤ò¼Â¹ÔÃæ¤Ë³ºÅö¥ê¥ì¡¼¥·¥ç¥ó¤Ë¹¹¿·¤äºï½ü¤¬È¯À¸¤¹¤ë¤È¡¤Àµ¤·¤¯
   ¤Ê¤¤·ë²Ì¤òÊÖ¤¹²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡¥

   pgstattuple¤¬¥¿¥×¥ë¤ò¡Ö¥´¥ß¡×¤ÈȽÃǤ¹¤ë´ð½à¤Ï¡¤
   HeapTupleSatisfiesNow()¤¬µ¶¤òÊÖ¤·¤¿¤È¤­¤Ç¤¹¡¥

4. pgstattuple¤Î¥é¥¤¥»¥ó¥¹¾ò·ï¤Ë¤Ä¤¤¤Æ

   pgstattuple.c¤ÎËÁƬ¤Ë½ñ¤¤¤Æ¤¢¤ëÄ̤ê¤Ç¤¹¡¥¤Þ¤¿¡¤pgstattuple ¤Ï´°Á´¤Ë̵ÊÝ
   ¾Ú¤Ç¤¹¡¥pgstattuple ¤ò»ÈÍѤ·¤¿¤³¤È¤Ë¤è¤Ã¤ÆÀ¸¤¸¤ë¤¤¤«¤Ê¤ë·ë²Ì¤Ë´Ø¤·¤Æ
   ¤âÀÕǤ¤òÉ餤¤Þ¤»¤ó¡¥

5. ²þÄûÍúÎò

   2006/06/28

        ¥¤¥ó¥Ç¥Ã¥¯¥¹¤ËÂФ·¤Æ¤âÆ°ºî¤¹¤ë¤è¤¦¤Ë³ÈÄ¥¡£

   2002/09/04

        SRFÊѹ¹¤Ëȼ¤¤¡¤Tom Lane ¤¬½¤Àµ¥¤¥ó¥¿¡¼¥Õ¥§¥¤¥¹¤Î½¤Àµ¤ò¹Ô¤Ã¤¿¡¥
        ¤½¤Î¤³¤È¤ò¤³¤ÎREADME¤Ë¤âÈ¿±Ç¡¥

   2002/08/23

        SRF(Set Returning Function)¤ò»È¤Ã¤Æ7.3ÍѤ˽ñ¤­´¹¤¨¡¥

   2001/12/20 Tom Lane¤Ë¤è¤ë½¤Àµ

        Fix pgstattuple to acquire a read lock on the target table.  This
        prevents embarassments such as having the table dropped or truncated
        partway through the scan.  Also, fix free space calculation to include
        pages that currently contain no tuples.

   2001/10/01 PostgreSQL 7.2 ÍÑcontrib module¤ËÅÐÏ¿

   2001/08/30 pgstattuple ¥Ð¡¼¥¸¥ç¥ó 0.1¥ê¥ê¡¼¥¹
-- Adjust this setting to control where the objects get created.
SET search_path = public;

DROP FUNCTION pgstattuple(oid);

DROP FUNCTION pgstattuple(text);

DROP TYPE pgstattuple_type;

DROP FUNCTION pgstatindex(text);
DROP FUNCTION bt_metap(text);
DROP FUNCTION bt_page_items(text, int4);
DROP FUNCTION bt_page_stats(text, int4);
DROP FUNCTION pg_relpages(text);

DROP TYPE pgstatindex_type;
DROP TYPE bt_metap_type;
DROP TYPE bt_page_items_type;
DROP TYPE bt_page_stats_type;
---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?

               http://www.postgresql.org/docs/faq

Reply via email to