11/*
2- * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.6 2002/05/20 23:51:40 tgl Exp $
2+ * $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.7 2002/08/23 08:19:49 ishii Exp $
33 *
4- * Copyright (c) 2001 Tatsuo Ishii
4+ * Copyright (c) 2001,2002 Tatsuo Ishii
55 *
66 * Permission to use, copy, modify, and distribute this software and
77 * its documentation for any purpose, without fee, and without a
2828#include "access/heapam.h"
2929#include "access/transam.h"
3030#include "catalog/namespace.h"
31+ #include "funcapi.h"
3132#include "utils/builtins.h"
3233
3334
@@ -37,16 +38,22 @@ extern Datum pgstattuple(PG_FUNCTION_ARGS);
3738
3839/* ----------
3940 * pgstattuple:
40- * returns the percentage of dead tuples
41+ * returns live/ dead tuples info
4142 *
4243 * C FUNCTION definition
43- * pgstattuple(NAME) returns FLOAT8
44+ * pgstattuple(TEXT) returns setof pgstattuple_view
45+ * see pgstattuple.sql for pgstattuple_view
4446 * ----------
4547 */
48+
49+ #define DUMMY_TUPLE "pgstattuple_view"
50+ #define NCOLUMNS 9
51+ #define NCHARS 32
52+
4653Datum
4754pgstattuple (PG_FUNCTION_ARGS )
4855{
49- text * relname = PG_GETARG_TEXT_P ( 0 ) ;
56+ text * relname ;
5057 RangeVar * relrv ;
5158 Relation rel ;
5259 HeapScanDesc scan ;
@@ -55,7 +62,7 @@ pgstattuple(PG_FUNCTION_ARGS)
5562 BlockNumber block = 0 ; /* next block to count free space in */
5663 BlockNumber tupblock ;
5764 Buffer buffer ;
58- double table_len ;
65+ uint64 table_len ;
5966 uint64 tuple_len = 0 ;
6067 uint64 dead_tuple_len = 0 ;
6168 uint64 tuple_count = 0 ;
@@ -65,13 +72,67 @@ pgstattuple(PG_FUNCTION_ARGS)
6572 uint64 free_space = 0 ; /* free/reusable space in bytes */
6673 double free_percent ; /* free/reusable space in % */
6774
68- relrv = makeRangeVarFromNameList (textToQualifiedNameList (relname ,
69- "pgstattuple" ));
75+ FuncCallContext * funcctx ;
76+ int call_cntr ;
77+ int max_calls ;
78+ TupleDesc tupdesc ;
79+ TupleTableSlot * slot ;
80+ AttInMetadata * attinmeta ;
81+
82+ char * * values ;
83+ int i ;
84+ Datum result ;
85+
86+ /* stuff done only on the first call of the function */
87+ if (SRF_IS_FIRSTCALL ())
88+ {
89+ /* create a function context for cross-call persistence */
90+ funcctx = SRF_FIRSTCALL_INIT ();
91+
92+ /* total number of tuples to be returned */
93+ funcctx -> max_calls = 1 ;
94+
95+ /*
96+ * Build a tuple description for a pgstattupe_view tuple
97+ */
98+ tupdesc = RelationNameGetTupleDesc (DUMMY_TUPLE );
99+
100+ /* allocate a slot for a tuple with this tupdesc */
101+ slot = TupleDescGetSlot (tupdesc );
102+
103+ /* assign slot to function context */
104+ funcctx -> slot = slot ;
105+
106+ /*
107+ * Generate attribute metadata needed later to produce tuples from raw
108+ * C strings
109+ */
110+ attinmeta = TupleDescGetAttInMetadata (tupdesc );
111+ funcctx -> attinmeta = attinmeta ;
112+ }
113+
114+ /* stuff done on every call of the function */
115+ funcctx = SRF_PERCALL_SETUP ();
116+ call_cntr = funcctx -> call_cntr ;
117+ max_calls = funcctx -> max_calls ;
118+ slot = funcctx -> slot ;
119+ attinmeta = funcctx -> attinmeta ;
120+
121+ /* Are we done? */
122+ if (call_cntr >= max_calls )
123+ {
124+ SRF_RETURN_DONE (funcctx );
125+ }
126+
127+ /* open relation */
128+ relname = PG_GETARG_TEXT_P (0 );
129+ relrv = makeRangeVarFromNameList (textToQualifiedNameList (relname ,"pgstattuple" ));
70130 rel = heap_openrv (relrv , AccessShareLock );
71131
72132 nblocks = RelationGetNumberOfBlocks (rel );
73133 scan = heap_beginscan (rel , SnapshotAny , 0 , NULL );
74134
135+ /* scan the relation */
75136 while ((tuple = heap_getnext (scan , ForwardScanDirection )) != NULL )
76137 {
77138 if (HeapTupleSatisfiesNow (tuple -> t_data ))
@@ -113,7 +174,7 @@ pgstattuple(PG_FUNCTION_ARGS)
113174
114175 heap_close (rel , AccessShareLock );
115176
116- table_len = (double ) nblocks * BLCKSZ ;
177+ table_len = (uint64 ) nblocks * BLCKSZ ;
117178
118179 if (nblocks == 0 )
119180 {
@@ -128,28 +189,39 @@ pgstattuple(PG_FUNCTION_ARGS)
128189 free_percent = (double ) free_space * 100.0 / table_len ;
129190 }
130191
131- elog (DEBUG3 , "physical length: %.2fMB live tuples: %.0f (%.2fMB, %.2f%%) dead tuples: %.0f (%.2fMB, %.2f%%) free/reusable space: %.2fMB (%.2f%%) overhead: %.2f%%" ,
132-
133- table_len / (1024 * 1024 ), /* physical length in MB */
134-
135- (double ) tuple_count , /* number of live tuples */
136- (double ) tuple_len / (1024 * 1024 ), /* live tuples in MB */
137- tuple_percent , /* live tuples in % */
138-
139- (double ) dead_tuple_count , /* number of dead tuples */
140- (double ) dead_tuple_len / (1024 * 1024 ), /* dead tuples in MB */
141- dead_tuple_percent , /* dead tuples in % */
142-
143- (double ) free_space / (1024 * 1024 ), /* free/available space in
144- * MB */
145-
146- free_percent , /* free/available space in % */
147-
148- /* overhead in % */
149- (nblocks == 0 ) ? 0.0 : 100.0
150- - tuple_percent
151- - dead_tuple_percent
152- - free_percent );
153-
154- PG_RETURN_FLOAT8 (dead_tuple_percent );
192+ /*
193+ * Prepare a values array for storage in our slot.
194+ * This should be an array of C strings which will
195+ * be processed later by the appropriate "in" functions.
196+ */
197+ values = (char * * ) palloc (NCOLUMNS * sizeof (char * ));
198+ for (i = 0 ;i < NCOLUMNS ;i ++ )
199+ {
200+ values [i ] = (char * ) palloc (NCHARS * sizeof (char ));
201+ }
202+ i = 0 ;
203+ snprintf (values [i ++ ], NCHARS , "%lld" , table_len );
204+ snprintf (values [i ++ ], NCHARS , "%lld" , tuple_count );
205+ snprintf (values [i ++ ], NCHARS , "%lld" , tuple_len );
206+ snprintf (values [i ++ ], NCHARS , "%.2f" , tuple_percent );
207+ snprintf (values [i ++ ], NCHARS , "%lld" , dead_tuple_count );
208+ snprintf (values [i ++ ], NCHARS , "%lld" , dead_tuple_len );
209+ snprintf (values [i ++ ], NCHARS , "%.2f" , dead_tuple_percent );
210+ snprintf (values [i ++ ], NCHARS , "%lld" , free_space );
211+ snprintf (values [i ++ ], NCHARS , "%.2f" , free_percent );
212+
213+ /* build a tuple */
214+ tuple = BuildTupleFromCStrings (attinmeta , values );
215+
216+ /* make the tuple into a datum */
217+ result = TupleGetDatum (slot , tuple );
218+
219+ /* Clean up */
220+ for (i = 0 ;i < NCOLUMNS ;i ++ )
221+ {
222+ pfree (values [i ]);
223+ }
224+ pfree (values );
225+
226+ SRF_RETURN_NEXT (funcctx , result );
155227}
0 commit comments