33 * pg_buffercache_pages.c
44 * display some contents of the buffer cache
55 *
6- * $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.10 2006/10/19 18:32:46 tgl Exp $
6+ * $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.11 2006/10/22 17:49:21 tgl Exp $
77 *-------------------------------------------------------------------------
88 */
99#include "postgres.h"
10- #include "funcapi.h"
10+
11+ #include "access/heapam.h"
1112#include "catalog/pg_type.h"
13+ #include "funcapi.h"
1214#include "storage/buf_internals.h"
1315#include "storage/bufmgr.h"
1416#include "utils/relcache.h"
@@ -26,15 +28,13 @@ Datum pg_buffercache_pages(PG_FUNCTION_ARGS);
2628 */
2729typedef struct
2830{
29-
3031 uint32 bufferid ;
3132 Oid relfilenode ;
3233 Oid reltablespace ;
3334 Oid reldatabase ;
3435 BlockNumber blocknum ;
3536 bool isvalid ;
3637 bool isdirty ;
37-
3838} BufferCachePagesRec ;
3939
4040
@@ -43,11 +43,8 @@ typedef struct
4343 */
4444typedef struct
4545{
46-
47- AttInMetadata * attinmeta ;
46+ TupleDesc tupdesc ;
4847 BufferCachePagesRec * record ;
49- char * values [NUM_BUFFERCACHE_PAGES_ELEM ];
50-
5148} BufferCachePagesContext ;
5249
5350
@@ -56,10 +53,10 @@ typedef struct
5653 * relation node/tablespace/database/blocknum and dirty indicator.
5754 */
5855PG_FUNCTION_INFO_V1 (pg_buffercache_pages );
56+
5957Datum
6058pg_buffercache_pages (PG_FUNCTION_ARGS )
6159{
62-
6360 FuncCallContext * funcctx ;
6461 Datum result ;
6562 MemoryContext oldcontext ;
@@ -77,7 +74,10 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
7774 /* Switch context when allocating stuff to be used in later calls */
7875 oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
7976
80- /* Construct a tuple to return. */
77+ /* Create a user function context for cross-call persistence */
78+ fctx = (BufferCachePagesContext * ) palloc (sizeof (BufferCachePagesContext ));
79+
80+ /* Construct a tuple descriptor for the result rows. */
8181 tupledesc = CreateTemplateTupleDesc (NUM_BUFFERCACHE_PAGES_ELEM , false);
8282 TupleDescInitEntry (tupledesc , (AttrNumber ) 1 , "bufferid" ,
8383 INT4OID , -1 , 0 );
@@ -92,27 +92,14 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
9292 TupleDescInitEntry (tupledesc , (AttrNumber ) 6 , "isdirty" ,
9393 BOOLOID , -1 , 0 );
9494
95- /* Generate attribute metadata needed later to produce tuples */
96- funcctx -> attinmeta = TupleDescGetAttInMetadata (tupledesc );
97-
98- /*
99- * Create a function context for cross-call persistence and initialize
100- * the buffer counters.
101- */
102- fctx = (BufferCachePagesContext * ) palloc (sizeof (BufferCachePagesContext ));
103- funcctx -> max_calls = NBuffers ;
104- funcctx -> user_fctx = fctx ;
95+ fctx -> tupdesc = BlessTupleDesc (tupledesc );
10596
10697 /* Allocate NBuffers worth of BufferCachePagesRec records. */
10798 fctx -> record = (BufferCachePagesRec * ) palloc (sizeof (BufferCachePagesRec ) * NBuffers );
10899
109- /* allocate the strings for tuple formation */
110- fctx -> values [0 ] = (char * ) palloc (3 * sizeof (uint32 ) + 1 );
111- fctx -> values [1 ] = (char * ) palloc (3 * sizeof (uint32 ) + 1 );
112- fctx -> values [2 ] = (char * ) palloc (3 * sizeof (uint32 ) + 1 );
113- fctx -> values [3 ] = (char * ) palloc (3 * sizeof (uint32 ) + 1 );
114- fctx -> values [4 ] = (char * ) palloc (3 * sizeof (uint32 ) + 1 );
115- fctx -> values [5 ] = (char * ) palloc (2 );
100+ /* Set max calls and remember the user function context. */
101+ funcctx -> max_calls = NBuffers ;
102+ funcctx -> user_fctx = fctx ;
116103
117104 /* Return to original context when allocating transient memory */
118105 MemoryContextSwitchTo (oldcontext );
@@ -167,19 +154,11 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
167154 if (funcctx -> call_cntr < funcctx -> max_calls )
168155 {
169156 uint32 i = funcctx -> call_cntr ;
170- char * values [NUM_BUFFERCACHE_PAGES_ELEM ];
171- int j ;
172-
173- /*
174- * Use a temporary values array, initially pointing to fctx->values,
175- * so it can be reassigned w/o losing the storage for subsequent
176- * calls.
177- */
178- for (j = 0 ; j < NUM_BUFFERCACHE_PAGES_ELEM ; j ++ )
179- {
180- values [j ] = fctx -> values [j ];
181- }
157+ Datum values [NUM_BUFFERCACHE_PAGES_ELEM ];
158+ bool nulls [NUM_BUFFERCACHE_PAGES_ELEM ];
182159
160+ values [0 ] = Int32GetDatum (fctx -> record [i ].bufferid );
161+ nulls [0 ] = false;
183162
184163 /*
185164 * Set all fields except the bufferid to null if the buffer is unused
@@ -188,43 +167,32 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
188167 if (fctx -> record [i ].blocknum == InvalidBlockNumber ||
189168 fctx -> record [i ].isvalid == false)
190169 {
191-
192- sprintf (values [0 ], "%u" , fctx -> record [i ].bufferid );
193- values [1 ] = NULL ;
194- values [2 ] = NULL ;
195- values [3 ] = NULL ;
196- values [4 ] = NULL ;
197- values [5 ] = NULL ;
198-
170+ nulls [1 ] = true;
171+ nulls [2 ] = true;
172+ nulls [3 ] = true;
173+ nulls [4 ] = true;
174+ nulls [5 ] = true;
199175 }
200176 else
201177 {
202-
203- sprintf (values [0 ], "%u" , fctx -> record [i ].bufferid );
204- sprintf (values [1 ], "%u" , fctx -> record [i ].relfilenode );
205- sprintf (values [2 ], "%u" , fctx -> record [i ].reltablespace );
206- sprintf (values [3 ], "%u" , fctx -> record [i ].reldatabase );
207- sprintf (values [4 ], "%u" , fctx -> record [i ].blocknum );
208- if (fctx -> record [i ].isdirty )
209- {
210- strcpy (values [5 ], "t" );
211- }
212- else
213- {
214- strcpy (values [5 ], "f" );
215- }
216-
178+ values [1 ] = ObjectIdGetDatum (fctx -> record [i ].relfilenode );
179+ nulls [1 ] = false;
180+ values [2 ] = ObjectIdGetDatum (fctx -> record [i ].reltablespace );
181+ nulls [2 ] = false;
182+ values [3 ] = ObjectIdGetDatum (fctx -> record [i ].reldatabase );
183+ nulls [3 ] = false;
184+ values [4 ] = Int64GetDatum ((int64 ) fctx -> record [i ].blocknum );
185+ nulls [4 ] = false;
186+ values [5 ] = BoolGetDatum (fctx -> record [i ].isdirty );
187+ nulls [5 ] = false;
217188 }
218189
219-
220190 /* Build and return the tuple. */
221- tuple = BuildTupleFromCStrings ( funcctx -> attinmeta , values );
191+ tuple = heap_form_tuple ( fctx -> tupdesc , values , nulls );
222192 result = HeapTupleGetDatum (tuple );
223193
224-
225194 SRF_RETURN_NEXT (funcctx , result );
226195 }
227196 else
228197 SRF_RETURN_DONE (funcctx );
229-
230198}
0 commit comments