3
3
* pg_buffercache_pages.c
4
4
* display some contents of the buffer cache
5
5
*
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 $
7
7
*-------------------------------------------------------------------------
8
8
*/
9
9
#include "postgres.h"
10
- #include "funcapi.h"
10
+
11
+ #include "access/heapam.h"
11
12
#include "catalog/pg_type.h"
13
+ #include "funcapi.h"
12
14
#include "storage/buf_internals.h"
13
15
#include "storage/bufmgr.h"
14
16
#include "utils/relcache.h"
@@ -26,15 +28,13 @@ Datumpg_buffercache_pages(PG_FUNCTION_ARGS);
26
28
*/
27
29
typedef struct
28
30
{
29
-
30
31
uint32bufferid;
31
32
Oidrelfilenode;
32
33
Oidreltablespace;
33
34
Oidreldatabase;
34
35
BlockNumber blocknum;
35
36
boolisvalid;
36
37
boolisdirty;
37
-
38
38
}BufferCachePagesRec;
39
39
40
40
@@ -43,11 +43,8 @@ typedef struct
43
43
*/
44
44
typedef struct
45
45
{
46
-
47
- AttInMetadata *attinmeta;
46
+ TupleDesctupdesc;
48
47
BufferCachePagesRec *record;
49
- char *values[NUM_BUFFERCACHE_PAGES_ELEM];
50
-
51
48
}BufferCachePagesContext;
52
49
53
50
@@ -56,10 +53,10 @@ typedef struct
56
53
* relation node/tablespace/database/blocknum and dirty indicator.
57
54
*/
58
55
PG_FUNCTION_INFO_V1(pg_buffercache_pages);
56
+
59
57
Datum
60
58
pg_buffercache_pages(PG_FUNCTION_ARGS)
61
59
{
62
-
63
60
FuncCallContext *funcctx;
64
61
Datumresult;
65
62
MemoryContext oldcontext;
@@ -77,7 +74,10 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
77
74
/* Switch context when allocating stuff to be used in later calls */
78
75
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
79
76
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. */
81
81
tupledesc = CreateTemplateTupleDesc(NUM_BUFFERCACHE_PAGES_ELEM, false);
82
82
TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
83
83
INT4OID, -1, 0);
@@ -92,27 +92,14 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
92
92
TupleDescInitEntry(tupledesc, (AttrNumber) 6, "isdirty",
93
93
BOOLOID, -1, 0);
94
94
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);
105
96
106
97
/* Allocate NBuffers worth of BufferCachePagesRec records. */
107
98
fctx->record = (BufferCachePagesRec *) palloc(sizeof(BufferCachePagesRec) * NBuffers);
108
99
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;
116
103
117
104
/* Return to original context when allocating transient memory */
118
105
MemoryContextSwitchTo(oldcontext);
@@ -167,19 +154,11 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
167
154
if (funcctx->call_cntr < funcctx->max_calls)
168
155
{
169
156
uint32i = funcctx->call_cntr;
170
- char *values[NUM_BUFFERCACHE_PAGES_ELEM];
171
- intj;
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
+ Datumvalues[NUM_BUFFERCACHE_PAGES_ELEM];
158
+ boolnulls[NUM_BUFFERCACHE_PAGES_ELEM];
182
159
160
+ values[0] = Int32GetDatum(fctx->record[i].bufferid);
161
+ nulls[0] = false;
183
162
184
163
/*
185
164
* Set all fields except the bufferid to null if the buffer is unused
@@ -188,43 +167,32 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
188
167
if (fctx->record[i].blocknum == InvalidBlockNumber ||
189
168
fctx->record[i].isvalid == false)
190
169
{
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;
199
175
}
200
176
else
201
177
{
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;
217
188
}
218
189
219
-
220
190
/* Build and return the tuple. */
221
- tuple =BuildTupleFromCStrings(funcctx->attinmeta , values);
191
+ tuple =heap_form_tuple(fctx->tupdesc , values, nulls );
222
192
result = HeapTupleGetDatum(tuple);
223
193
224
-
225
194
SRF_RETURN_NEXT(funcctx, result);
226
195
}
227
196
else
228
197
SRF_RETURN_DONE(funcctx);
229
-
230
198
}