contrib-move-v1.patch
text/x-patch
Filename: contrib-move-v1.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v1
| File | + | − |
|---|---|---|
| contrib/Makefile | 0 | 1 |
| contrib/pg_buffercache/Makefile | 0 | 18 |
| contrib/pg_buffercache/pg_buffercache--1.0.sql | 0 | 17 |
| contrib/pg_buffercache/pg_buffercache.control | 0 | 5 |
| contrib/pg_buffercache/pg_buffercache_pages.c | 0 | 219 |
| contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql | 0 | 4 |
| src/extension/extension-global.mk | 5 | 0 |
| src/extension/Makefile | 36 | 0 |
| src/extension/pg_buffercache/Makefile | 19 | 0 |
| src/extension/pg_buffercache/pg_buffercache--1.0.sql | 17 | 0 |
| src/extension/pg_buffercache/pg_buffercache.control | 5 | 0 |
| src/extension/pg_buffercache/pg_buffercache_pages.c | 219 | 0 |
| src/extension/pg_buffercache/pg_buffercache--unpackaged--1.0.sql | 4 | 0 |
diff --git a/contrib/Makefile b/contrib/Makefile
index 6967767..04cf330 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -30,7 +30,6 @@ SUBDIRS = \
pageinspect \
passwordcheck \
pg_archivecleanup \
- pg_buffercache \
pg_freespacemap \
pg_standby \
pg_stat_statements \
diff --git a/contrib/pg_buffercache/Makefile b/contrib/pg_buffercache/Makefile
deleted file mode 100644
index 323c0ac..0000000
--- a/contrib/pg_buffercache/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-# contrib/pg_buffercache/Makefile
-
-MODULE_big = pg_buffercache
-OBJS = pg_buffercache_pages.o
-
-EXTENSION = pg_buffercache
-DATA = pg_buffercache--1.0.sql pg_buffercache--unpackaged--1.0.sql
-
-ifdef USE_PGXS
-PG_CONFIG = pg_config
-PGXS := $(shell $(PG_CONFIG) --pgxs)
-include $(PGXS)
-else
-subdir = contrib/pg_buffercache
-top_builddir = ../..
-include $(top_builddir)/src/Makefile.global
-include $(top_srcdir)/contrib/contrib-global.mk
-endif
diff --git a/contrib/pg_buffercache/pg_buffercache--1.0.sql b/contrib/pg_buffercache/pg_buffercache--1.0.sql
deleted file mode 100644
index 9407d21..0000000
--- a/contrib/pg_buffercache/pg_buffercache--1.0.sql
+++ /dev/null
@@ -1,17 +0,0 @@
-/* contrib/pg_buffercache/pg_buffercache--1.0.sql */
-
--- Register the function.
-CREATE FUNCTION pg_buffercache_pages()
-RETURNS SETOF RECORD
-AS 'MODULE_PATHNAME', 'pg_buffercache_pages'
-LANGUAGE C;
-
--- Create a view for convenient access.
-CREATE VIEW pg_buffercache AS
- SELECT P.* FROM pg_buffercache_pages() AS P
- (bufferid integer, relfilenode oid, reltablespace oid, reldatabase oid,
- relforknumber int2, relblocknumber int8, isdirty bool, usagecount int2);
-
--- Don't want these to be available to public.
-REVOKE ALL ON FUNCTION pg_buffercache_pages() FROM PUBLIC;
-REVOKE ALL ON pg_buffercache FROM PUBLIC;
diff --git a/contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql b/contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql
deleted file mode 100644
index f00a954..0000000
--- a/contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-/* contrib/pg_buffercache/pg_buffercache--unpackaged--1.0.sql */
-
-ALTER EXTENSION pg_buffercache ADD function pg_buffercache_pages();
-ALTER EXTENSION pg_buffercache ADD view pg_buffercache;
diff --git a/contrib/pg_buffercache/pg_buffercache.control b/contrib/pg_buffercache/pg_buffercache.control
deleted file mode 100644
index 709513c..0000000
--- a/contrib/pg_buffercache/pg_buffercache.control
+++ /dev/null
@@ -1,5 +0,0 @@
-# pg_buffercache extension
-comment = 'examine the shared buffer cache'
-default_version = '1.0'
-module_pathname = '$libdir/pg_buffercache'
-relocatable = true
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
deleted file mode 100644
index ed88288..0000000
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_buffercache_pages.c
- * display some contents of the buffer cache
- *
- * contrib/pg_buffercache/pg_buffercache_pages.c
- *-------------------------------------------------------------------------
- */
-#include "postgres.h"
-
-#include "access/heapam.h"
-#include "catalog/pg_type.h"
-#include "funcapi.h"
-#include "storage/buf_internals.h"
-#include "storage/bufmgr.h"
-#include "utils/relcache.h"
-
-
-#define NUM_BUFFERCACHE_PAGES_ELEM 8
-
-PG_MODULE_MAGIC;
-
-Datum pg_buffercache_pages(PG_FUNCTION_ARGS);
-
-
-/*
- * Record structure holding the to be exposed cache data.
- */
-typedef struct
-{
- uint32 bufferid;
- Oid relfilenode;
- Oid reltablespace;
- Oid reldatabase;
- ForkNumber forknum;
- BlockNumber blocknum;
- bool isvalid;
- bool isdirty;
- uint16 usagecount;
-} BufferCachePagesRec;
-
-
-/*
- * Function context for data persisting over repeated calls.
- */
-typedef struct
-{
- TupleDesc tupdesc;
- BufferCachePagesRec *record;
-} BufferCachePagesContext;
-
-
-/*
- * Function returning data from the shared buffer cache - buffer number,
- * relation node/tablespace/database/blocknum and dirty indicator.
- */
-PG_FUNCTION_INFO_V1(pg_buffercache_pages);
-
-Datum
-pg_buffercache_pages(PG_FUNCTION_ARGS)
-{
- FuncCallContext *funcctx;
- Datum result;
- MemoryContext oldcontext;
- BufferCachePagesContext *fctx; /* User function context. */
- TupleDesc tupledesc;
- HeapTuple tuple;
-
- if (SRF_IS_FIRSTCALL())
- {
- int i;
- volatile BufferDesc *bufHdr;
-
- funcctx = SRF_FIRSTCALL_INIT();
-
- /* Switch context when allocating stuff to be used in later calls */
- oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
-
- /* Create a user function context for cross-call persistence */
- fctx = (BufferCachePagesContext *) palloc(sizeof(BufferCachePagesContext));
-
- /* Construct a tuple descriptor for the result rows. */
- tupledesc = CreateTemplateTupleDesc(NUM_BUFFERCACHE_PAGES_ELEM, false);
- TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
- INT4OID, -1, 0);
- TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode",
- OIDOID, -1, 0);
- TupleDescInitEntry(tupledesc, (AttrNumber) 3, "reltablespace",
- OIDOID, -1, 0);
- TupleDescInitEntry(tupledesc, (AttrNumber) 4, "reldatabase",
- OIDOID, -1, 0);
- TupleDescInitEntry(tupledesc, (AttrNumber) 5, "relforknumber",
- INT2OID, -1, 0);
- TupleDescInitEntry(tupledesc, (AttrNumber) 6, "relblocknumber",
- INT8OID, -1, 0);
- TupleDescInitEntry(tupledesc, (AttrNumber) 7, "isdirty",
- BOOLOID, -1, 0);
- TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count",
- INT2OID, -1, 0);
-
- fctx->tupdesc = BlessTupleDesc(tupledesc);
-
- /* Allocate NBuffers worth of BufferCachePagesRec records. */
- fctx->record = (BufferCachePagesRec *) palloc(sizeof(BufferCachePagesRec) * NBuffers);
-
- /* Set max calls and remember the user function context. */
- funcctx->max_calls = NBuffers;
- funcctx->user_fctx = fctx;
-
- /* Return to original context when allocating transient memory */
- MemoryContextSwitchTo(oldcontext);
-
- /*
- * To get a consistent picture of the buffer state, we must lock all
- * partitions of the buffer map. Needless to say, this is horrible
- * for concurrency. Must grab locks in increasing order to avoid
- * possible deadlocks.
- */
- for (i = 0; i < NUM_BUFFER_PARTITIONS; i++)
- LWLockAcquire(FirstBufMappingLock + i, LW_SHARED);
-
- /*
- * Scan though all the buffers, saving the relevant fields in the
- * fctx->record structure.
- */
- for (i = 0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++)
- {
- /* Lock each buffer header before inspecting. */
- LockBufHdr(bufHdr);
-
- fctx->record[i].bufferid = BufferDescriptorGetBuffer(bufHdr);
- fctx->record[i].relfilenode = bufHdr->tag.rnode.relNode;
- fctx->record[i].reltablespace = bufHdr->tag.rnode.spcNode;
- fctx->record[i].reldatabase = bufHdr->tag.rnode.dbNode;
- fctx->record[i].forknum = bufHdr->tag.forkNum;
- fctx->record[i].blocknum = bufHdr->tag.blockNum;
- fctx->record[i].usagecount = bufHdr->usage_count;
-
- if (bufHdr->flags & BM_DIRTY)
- fctx->record[i].isdirty = true;
- else
- fctx->record[i].isdirty = false;
-
- /* Note if the buffer is valid, and has storage created */
- if ((bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_TAG_VALID))
- fctx->record[i].isvalid = true;
- else
- fctx->record[i].isvalid = false;
-
- UnlockBufHdr(bufHdr);
- }
-
- /*
- * And release locks. We do this in reverse order for two reasons:
- * (1) Anyone else who needs more than one of the locks will be trying
- * to lock them in increasing order; we don't want to release the
- * other process until it can get all the locks it needs. (2) This
- * avoids O(N^2) behavior inside LWLockRelease.
- */
- for (i = NUM_BUFFER_PARTITIONS; --i >= 0;)
- LWLockRelease(FirstBufMappingLock + i);
- }
-
- funcctx = SRF_PERCALL_SETUP();
-
- /* Get the saved state */
- fctx = funcctx->user_fctx;
-
- if (funcctx->call_cntr < funcctx->max_calls)
- {
- uint32 i = funcctx->call_cntr;
- Datum values[NUM_BUFFERCACHE_PAGES_ELEM];
- bool nulls[NUM_BUFFERCACHE_PAGES_ELEM];
-
- values[0] = Int32GetDatum(fctx->record[i].bufferid);
- nulls[0] = false;
-
- /*
- * Set all fields except the bufferid to null if the buffer is unused
- * or not valid.
- */
- if (fctx->record[i].blocknum == InvalidBlockNumber ||
- fctx->record[i].isvalid == false)
- {
- nulls[1] = true;
- nulls[2] = true;
- nulls[3] = true;
- nulls[4] = true;
- nulls[5] = true;
- nulls[6] = true;
- nulls[7] = true;
- }
- else
- {
- values[1] = ObjectIdGetDatum(fctx->record[i].relfilenode);
- nulls[1] = false;
- values[2] = ObjectIdGetDatum(fctx->record[i].reltablespace);
- nulls[2] = false;
- values[3] = ObjectIdGetDatum(fctx->record[i].reldatabase);
- nulls[3] = false;
- values[4] = ObjectIdGetDatum(fctx->record[i].forknum);
- nulls[4] = false;
- values[5] = Int64GetDatum((int64) fctx->record[i].blocknum);
- nulls[5] = false;
- values[6] = BoolGetDatum(fctx->record[i].isdirty);
- nulls[6] = false;
- values[7] = Int16GetDatum(fctx->record[i].usagecount);
- nulls[7] = false;
- }
-
- /* Build and return the tuple. */
- tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
- result = HeapTupleGetDatum(tuple);
-
- SRF_RETURN_NEXT(funcctx, result);
- }
- else
- SRF_RETURN_DONE(funcctx);
-}
diff --git a/src/extension/Makefile b/src/extension/Makefile
new file mode 100644
index 0000000..5d7a86a
--- /dev/null
+++ b/src/extension/Makefile
@@ -0,0 +1,36 @@
+# $PostgreSQL: pgsql/src/extension/Makefile $
+
+subdir = src/extension
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+
+SUBDIRS = \
+ pg_buffercache
+
+ifeq ($(with_openssl),yes)
+SUBDIRS += sslinfo
+endif
+
+ifeq ($(with_ossp_uuid),yes)
+SUBDIRS += uuid-ossp
+endif
+
+ifeq ($(with_libxml),yes)
+SUBDIRS += xml2
+endif
+
+# Missing:
+# start-scripts \ (does not have a makefile)
+
+
+all install installdirs uninstall distprep clean distclean maintainer-clean:
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir $@ || exit; \
+ done
+
+# We'd like check operations to run all the subtests before failing.
+check installcheck:
+ @CHECKERR=0; for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir $@ || CHECKERR=$$?; \
+ done; \
+ exit $$CHECKERR
diff --git a/src/extension/extension-global.mk b/src/extension/extension-global.mk
new file mode 100644
index 0000000..cc7643b
--- /dev/null
+++ b/src/extension/extension-global.mk
@@ -0,0 +1,5 @@
+# $PostgreSQL: pgsql/extension/extension-global.mk,v 1.10 2005/09/27 17:43:31 tgl Exp $
+
+NO_PGXS = 1
+MODULEDIR=extension
+include $(top_srcdir)/src/makefiles/pgxs.mk
diff --git a/src/extension/pg_buffercache/Makefile b/src/extension/pg_buffercache/Makefile
new file mode 100644
index 0000000..70d857f
--- /dev/null
+++ b/src/extension/pg_buffercache/Makefile
@@ -0,0 +1,19 @@
+# src/extension/pg_buffercache/Makefile
+
+MODULE_big = pg_buffercache
+OBJS = pg_buffercache_pages.o
+MODULEDIR=extension
+
+EXTENSION = pg_buffercache
+DATA = pg_buffercache--1.0.sql pg_buffercache--unpackaged--1.0.sql
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/extension/pg_buffercache
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/src/extension/extension-global.mk
+endif
diff --git a/src/extension/pg_buffercache/pg_buffercache--1.0.sql b/src/extension/pg_buffercache/pg_buffercache--1.0.sql
new file mode 100644
index 0000000..ceca6ae
--- /dev/null
+++ b/src/extension/pg_buffercache/pg_buffercache--1.0.sql
@@ -0,0 +1,17 @@
+/* src/extension/pg_buffercache/pg_buffercache--1.0.sql */
+
+-- Register the function.
+CREATE FUNCTION pg_buffercache_pages()
+RETURNS SETOF RECORD
+AS 'MODULE_PATHNAME', 'pg_buffercache_pages'
+LANGUAGE C;
+
+-- Create a view for convenient access.
+CREATE VIEW pg_buffercache AS
+ SELECT P.* FROM pg_buffercache_pages() AS P
+ (bufferid integer, relfilenode oid, reltablespace oid, reldatabase oid,
+ relforknumber int2, relblocknumber int8, isdirty bool, usagecount int2);
+
+-- Don't want these to be available to public.
+REVOKE ALL ON FUNCTION pg_buffercache_pages() FROM PUBLIC;
+REVOKE ALL ON pg_buffercache FROM PUBLIC;
diff --git a/src/extension/pg_buffercache/pg_buffercache--unpackaged--1.0.sql b/src/extension/pg_buffercache/pg_buffercache--unpackaged--1.0.sql
new file mode 100644
index 0000000..0cfa317
--- /dev/null
+++ b/src/extension/pg_buffercache/pg_buffercache--unpackaged--1.0.sql
@@ -0,0 +1,4 @@
+/* src/extension/pg_buffercache/pg_buffercache--unpackaged--1.0.sql */
+
+ALTER EXTENSION pg_buffercache ADD function pg_buffercache_pages();
+ALTER EXTENSION pg_buffercache ADD view pg_buffercache;
diff --git a/src/extension/pg_buffercache/pg_buffercache.control b/src/extension/pg_buffercache/pg_buffercache.control
new file mode 100644
index 0000000..709513c
--- /dev/null
+++ b/src/extension/pg_buffercache/pg_buffercache.control
@@ -0,0 +1,5 @@
+# pg_buffercache extension
+comment = 'examine the shared buffer cache'
+default_version = '1.0'
+module_pathname = '$libdir/pg_buffercache'
+relocatable = true
diff --git a/src/extension/pg_buffercache/pg_buffercache_pages.c b/src/extension/pg_buffercache/pg_buffercache_pages.c
new file mode 100644
index 0000000..a44610f
--- /dev/null
+++ b/src/extension/pg_buffercache/pg_buffercache_pages.c
@@ -0,0 +1,219 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_buffercache_pages.c
+ * display some contents of the buffer cache
+ *
+ * src/extension/pg_buffercache/pg_buffercache_pages.c
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_type.h"
+#include "funcapi.h"
+#include "storage/buf_internals.h"
+#include "storage/bufmgr.h"
+#include "utils/relcache.h"
+
+
+#define NUM_BUFFERCACHE_PAGES_ELEM 8
+
+PG_MODULE_MAGIC;
+
+Datum pg_buffercache_pages(PG_FUNCTION_ARGS);
+
+
+/*
+ * Record structure holding the to be exposed cache data.
+ */
+typedef struct
+{
+ uint32 bufferid;
+ Oid relfilenode;
+ Oid reltablespace;
+ Oid reldatabase;
+ ForkNumber forknum;
+ BlockNumber blocknum;
+ bool isvalid;
+ bool isdirty;
+ uint16 usagecount;
+} BufferCachePagesRec;
+
+
+/*
+ * Function context for data persisting over repeated calls.
+ */
+typedef struct
+{
+ TupleDesc tupdesc;
+ BufferCachePagesRec *record;
+} BufferCachePagesContext;
+
+
+/*
+ * Function returning data from the shared buffer cache - buffer number,
+ * relation node/tablespace/database/blocknum and dirty indicator.
+ */
+PG_FUNCTION_INFO_V1(pg_buffercache_pages);
+
+Datum
+pg_buffercache_pages(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ Datum result;
+ MemoryContext oldcontext;
+ BufferCachePagesContext *fctx; /* User function context. */
+ TupleDesc tupledesc;
+ HeapTuple tuple;
+
+ if (SRF_IS_FIRSTCALL())
+ {
+ int i;
+ volatile BufferDesc *bufHdr;
+
+ funcctx = SRF_FIRSTCALL_INIT();
+
+ /* Switch context when allocating stuff to be used in later calls */
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ /* Create a user function context for cross-call persistence */
+ fctx = (BufferCachePagesContext *) palloc(sizeof(BufferCachePagesContext));
+
+ /* Construct a tuple descriptor for the result rows. */
+ tupledesc = CreateTemplateTupleDesc(NUM_BUFFERCACHE_PAGES_ELEM, false);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode",
+ OIDOID, -1, 0);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 3, "reltablespace",
+ OIDOID, -1, 0);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 4, "reldatabase",
+ OIDOID, -1, 0);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 5, "relforknumber",
+ INT2OID, -1, 0);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 6, "relblocknumber",
+ INT8OID, -1, 0);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 7, "isdirty",
+ BOOLOID, -1, 0);
+ TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count",
+ INT2OID, -1, 0);
+
+ fctx->tupdesc = BlessTupleDesc(tupledesc);
+
+ /* Allocate NBuffers worth of BufferCachePagesRec records. */
+ fctx->record = (BufferCachePagesRec *) palloc(sizeof(BufferCachePagesRec) * NBuffers);
+
+ /* Set max calls and remember the user function context. */
+ funcctx->max_calls = NBuffers;
+ funcctx->user_fctx = fctx;
+
+ /* Return to original context when allocating transient memory */
+ MemoryContextSwitchTo(oldcontext);
+
+ /*
+ * To get a consistent picture of the buffer state, we must lock all
+ * partitions of the buffer map. Needless to say, this is horrible
+ * for concurrency. Must grab locks in increasing order to avoid
+ * possible deadlocks.
+ */
+ for (i = 0; i < NUM_BUFFER_PARTITIONS; i++)
+ LWLockAcquire(FirstBufMappingLock + i, LW_SHARED);
+
+ /*
+ * Scan though all the buffers, saving the relevant fields in the
+ * fctx->record structure.
+ */
+ for (i = 0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++)
+ {
+ /* Lock each buffer header before inspecting. */
+ LockBufHdr(bufHdr);
+
+ fctx->record[i].bufferid = BufferDescriptorGetBuffer(bufHdr);
+ fctx->record[i].relfilenode = bufHdr->tag.rnode.relNode;
+ fctx->record[i].reltablespace = bufHdr->tag.rnode.spcNode;
+ fctx->record[i].reldatabase = bufHdr->tag.rnode.dbNode;
+ fctx->record[i].forknum = bufHdr->tag.forkNum;
+ fctx->record[i].blocknum = bufHdr->tag.blockNum;
+ fctx->record[i].usagecount = bufHdr->usage_count;
+
+ if (bufHdr->flags & BM_DIRTY)
+ fctx->record[i].isdirty = true;
+ else
+ fctx->record[i].isdirty = false;
+
+ /* Note if the buffer is valid, and has storage created */
+ if ((bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_TAG_VALID))
+ fctx->record[i].isvalid = true;
+ else
+ fctx->record[i].isvalid = false;
+
+ UnlockBufHdr(bufHdr);
+ }
+
+ /*
+ * And release locks. We do this in reverse order for two reasons:
+ * (1) Anyone else who needs more than one of the locks will be trying
+ * to lock them in increasing order; we don't want to release the
+ * other process until it can get all the locks it needs. (2) This
+ * avoids O(N^2) behavior inside LWLockRelease.
+ */
+ for (i = NUM_BUFFER_PARTITIONS; --i >= 0;)
+ LWLockRelease(FirstBufMappingLock + i);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+
+ /* Get the saved state */
+ fctx = funcctx->user_fctx;
+
+ if (funcctx->call_cntr < funcctx->max_calls)
+ {
+ uint32 i = funcctx->call_cntr;
+ Datum values[NUM_BUFFERCACHE_PAGES_ELEM];
+ bool nulls[NUM_BUFFERCACHE_PAGES_ELEM];
+
+ values[0] = Int32GetDatum(fctx->record[i].bufferid);
+ nulls[0] = false;
+
+ /*
+ * Set all fields except the bufferid to null if the buffer is unused
+ * or not valid.
+ */
+ if (fctx->record[i].blocknum == InvalidBlockNumber ||
+ fctx->record[i].isvalid == false)
+ {
+ nulls[1] = true;
+ nulls[2] = true;
+ nulls[3] = true;
+ nulls[4] = true;
+ nulls[5] = true;
+ nulls[6] = true;
+ nulls[7] = true;
+ }
+ else
+ {
+ values[1] = ObjectIdGetDatum(fctx->record[i].relfilenode);
+ nulls[1] = false;
+ values[2] = ObjectIdGetDatum(fctx->record[i].reltablespace);
+ nulls[2] = false;
+ values[3] = ObjectIdGetDatum(fctx->record[i].reldatabase);
+ nulls[3] = false;
+ values[4] = ObjectIdGetDatum(fctx->record[i].forknum);
+ nulls[4] = false;
+ values[5] = Int64GetDatum((int64) fctx->record[i].blocknum);
+ nulls[5] = false;
+ values[6] = BoolGetDatum(fctx->record[i].isdirty);
+ nulls[6] = false;
+ values[7] = Int16GetDatum(fctx->record[i].usagecount);
+ nulls[7] = false;
+ }
+
+ /* Build and return the tuple. */
+ tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
+ result = HeapTupleGetDatum(tuple);
+
+ SRF_RETURN_NEXT(funcctx, result);
+ }
+ else
+ SRF_RETURN_DONE(funcctx);
+}