commit 6f76f11a3842e5401cbbb740bc346bb5329a06e0
Author: Masahiko Sawada <sawada.mshk@gmail.com>
Date:   Fri Jun 10 16:28:39 2016 -0700

    Add cheat func.

diff --git a/contrib/pg_visibility/pg_visibility--1.1.sql b/contrib/pg_visibility/pg_visibility--1.1.sql
index b49b644..a289a45 100644
--- a/contrib/pg_visibility/pg_visibility--1.1.sql
+++ b/contrib/pg_visibility/pg_visibility--1.1.sql
@@ -57,6 +57,30 @@ RETURNS SETOF tid
 AS 'MODULE_PATHNAME', 'pg_check_visible'
 LANGUAGE C STRICT;
 
+CREATE FUNCTION set_vm_status(
+rel regclass,
+blkno bigint,
+all_visible bool,
+all_frozen bool,
+blkno OUT INT
+)
+RETURNS INT
+AS 'MODULE_PATHNAME', 'set_vm_status'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION set_vm_status(
+rel regclass,
+all_visible bool,
+all_frozen bool,
+blkno OUT BIGINT,
+status OUT INT)
+RETURNS SETOF RECORD
+AS $$
+   SELECT blkno, set_vm_status(rel, blkno, $2, $3)
+	FROM generate_series(0, pg_relation_size($1) / current_setting('block_size')::bigint - 1) AS blkno;
+$$
+LANGUAGE SQL STRICT;
+
 -- Don't want these to be available to public.
 REVOKE ALL ON FUNCTION pg_visibility_map(regclass, bigint) FROM PUBLIC;
 REVOKE ALL ON FUNCTION pg_visibility(regclass, bigint) FROM PUBLIC;
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index 3ccc981..e43cc23 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -41,6 +41,8 @@ PG_FUNCTION_INFO_V1(pg_visibility_map_summary);
 PG_FUNCTION_INFO_V1(pg_check_frozen);
 PG_FUNCTION_INFO_V1(pg_check_visible);
 
+PG_FUNCTION_INFO_V1(set_vm_status);
+
 static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd);
 static vbits *collect_visibility_data(Oid relid, bool include_pd);
 static corrupt_items *collect_corrupt_items(Oid relid, bool all_visible,
@@ -609,3 +611,60 @@ record_corrupt_item(corrupt_items *items, ItemPointer tid)
 	/* and add the new item */
 	items->tids[items->next++] = *tid;
 }
+
+
+/*
+ * Set spurious visibility map status to specified block.
+ */
+Datum
+set_vm_status(PG_FUNCTION_ARGS)
+{
+	Oid		relid = PG_GETARG_OID(0);
+	BlockNumber	blkno = PG_GETARG_INT64(1);
+	bool	all_visible = PG_GETARG_BOOL(2);
+	bool	all_frozen = PG_GETARG_BOOL(3);
+	Buffer	buffer = InvalidBuffer;
+	Buffer	vmbuffer = InvalidBuffer;
+	uint8		flags = 0;
+	Relation	rel;
+	uint8		status;
+	Page		page;
+	BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
+
+	rel = relation_open(relid, ShareUpdateExclusiveLock);
+
+	if (blkno < 0 || blkno > MaxBlockNumber)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid block number")));
+
+	buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
+								bstrategy);
+	LockBuffer(buffer, BUFFER_LOCK_SHARE);
+	page = BufferGetPage(buffer);
+
+	/* Create visibility map bits */
+	if (all_visible)
+		flags = VISIBILITYMAP_ALL_VISIBLE;
+	if (all_frozen)
+		flags |= VISIBILITYMAP_ALL_FROZEN;
+
+	/* Set visibility map status anyway */
+	PageSetAllVisible(page);
+	visibilitymap_pin(rel, blkno, &vmbuffer);
+	if (flags)
+		visibilitymap_set(rel, blkno, buffer, InvalidXLogRecPtr,
+						  vmbuffer, InvalidTransactionId, flags);
+	else
+		visibilitymap_clear(rel, blkno, vmbuffer);
+
+	status = visibilitymap_get_status(rel, blkno, &vmbuffer);
+	MarkBufferDirty(buffer);
+
+	UnlockReleaseBuffer(buffer);
+	ReleaseBuffer(vmbuffer);
+
+	relation_close(rel, ShareUpdateExclusiveLock);
+
+	PG_RETURN_INT16(status);
+}
