From b9c649159bc3291785dfe7a56baf4443db70062a Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <peter_e@gmx.net>
Date: Thu, 29 Sep 2016 12:00:00 -0400
Subject: [PATCH 1/2] Add tests for pageinspect

---
 contrib/pageinspect/.gitignore         |  4 ++
 contrib/pageinspect/Makefile           |  2 +
 contrib/pageinspect/expected/brin.out  | 51 ++++++++++++++++++++++++
 contrib/pageinspect/expected/btree.out | 45 +++++++++++++++++++++
 contrib/pageinspect/expected/gin.out   | 30 ++++++++++++++
 contrib/pageinspect/expected/page.out  | 73 ++++++++++++++++++++++++++++++++++
 contrib/pageinspect/sql/brin.sql       | 18 +++++++++
 contrib/pageinspect/sql/btree.sql      | 17 ++++++++
 contrib/pageinspect/sql/gin.sql        | 14 +++++++
 contrib/pageinspect/sql/page.sql       | 30 ++++++++++++++
 10 files changed, 284 insertions(+)
 create mode 100644 contrib/pageinspect/.gitignore
 create mode 100644 contrib/pageinspect/expected/brin.out
 create mode 100644 contrib/pageinspect/expected/btree.out
 create mode 100644 contrib/pageinspect/expected/gin.out
 create mode 100644 contrib/pageinspect/expected/page.out
 create mode 100644 contrib/pageinspect/sql/brin.sql
 create mode 100644 contrib/pageinspect/sql/btree.sql
 create mode 100644 contrib/pageinspect/sql/gin.sql
 create mode 100644 contrib/pageinspect/sql/page.sql

diff --git a/contrib/pageinspect/.gitignore b/contrib/pageinspect/.gitignore
new file mode 100644
index 0000000..5dcb3ff
--- /dev/null
+++ b/contrib/pageinspect/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/contrib/pageinspect/Makefile b/contrib/pageinspect/Makefile
index c73d728..ecf0df0 100644
--- a/contrib/pageinspect/Makefile
+++ b/contrib/pageinspect/Makefile
@@ -11,6 +11,8 @@ DATA = pageinspect--1.6.sql pageinspect--1.5--1.6.sql \
 	pageinspect--1.0--1.1.sql pageinspect--unpackaged--1.0.sql
 PGFILEDESC = "pageinspect - functions to inspect contents of database pages"
 
+REGRESS = page btree brin gin
+
 ifdef USE_PGXS
 PG_CONFIG = pg_config
 PGXS := $(shell $(PG_CONFIG) --pgxs)
diff --git a/contrib/pageinspect/expected/brin.out b/contrib/pageinspect/expected/brin.out
new file mode 100644
index 0000000..71eb190
--- /dev/null
+++ b/contrib/pageinspect/expected/brin.out
@@ -0,0 +1,51 @@
+CREATE TABLE test1 (a int, b text);
+INSERT INTO test1 VALUES (1, 'one');
+CREATE INDEX test1_a_idx ON test1 USING brin (a);
+SELECT brin_page_type(get_raw_page('test1_a_idx', 0));
+ brin_page_type 
+----------------
+ meta
+(1 row)
+
+SELECT brin_page_type(get_raw_page('test1_a_idx', 1));
+ brin_page_type 
+----------------
+ revmap
+(1 row)
+
+SELECT brin_page_type(get_raw_page('test1_a_idx', 2));
+ brin_page_type 
+----------------
+ regular
+(1 row)
+
+SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 0));
+   magic    | version | pagesperrange | lastrevmappage 
+------------+---------+---------------+----------------
+ 0xA8109CFA |       1 |           128 |              1
+(1 row)
+
+SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 1));
+ERROR:  page is not a BRIN page of type "metapage"
+DETAIL:  Expected special type 0000f091, got 0000f092.
+SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 0)) LIMIT 5;
+ERROR:  page is not a BRIN page of type "revmap"
+DETAIL:  Expected special type 0000f092, got 0000f091.
+SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 1)) LIMIT 5;
+ pages 
+-------
+ (2,1)
+ (0,0)
+ (0,0)
+ (0,0)
+ (0,0)
+(5 rows)
+
+SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx')
+    ORDER BY blknum, attnum LIMIT 5;
+ itemoffset | blknum | attnum | allnulls | hasnulls | placeholder |  value   
+------------+--------+--------+----------+----------+-------------+----------
+          1 |      0 |      1 | f        | f        | f           | {1 .. 1}
+(1 row)
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out
new file mode 100644
index 0000000..ef7f86e
--- /dev/null
+++ b/contrib/pageinspect/expected/btree.out
@@ -0,0 +1,45 @@
+CREATE TABLE test1 (a int, b text);
+INSERT INTO test1 VALUES (1, 'one');
+CREATE INDEX test1_a_idx ON test1 USING btree (a);
+\x
+SELECT * FROM bt_metap('test1_a_idx');
+-[ RECORD 1 ]-----
+magic     | 340322
+version   | 2
+root      | 1
+level     | 0
+fastroot  | 1
+fastlevel | 0
+
+SELECT * FROM bt_page_stats('test1_a_idx', 0);
+ERROR:  block 0 is a meta page
+SELECT * FROM bt_page_stats('test1_a_idx', 1);
+-[ RECORD 1 ]-+-----
+blkno         | 1
+type          | l
+live_items    | 1
+dead_items    | 0
+avg_item_size | 16
+page_size     | 8192
+free_size     | 8128
+btpo_prev     | 0
+btpo_next     | 0
+btpo          | 0
+btpo_flags    | 3
+
+SELECT * FROM bt_page_stats('test1_a_idx', 2);
+ERROR:  block number out of range
+SELECT * FROM bt_page_items('test1_a_idx', 0);
+ERROR:  block 0 is a meta page
+SELECT * FROM bt_page_items('test1_a_idx', 1);
+-[ RECORD 1 ]-----------------------
+itemoffset | 1
+ctid       | (0,1)
+itemlen    | 16
+nulls      | f
+vars       | f
+data       | 01 00 00 00 00 00 00 00
+
+SELECT * FROM bt_page_items('test1_a_idx', 2);
+ERROR:  block number out of range
+DROP TABLE test1;
diff --git a/contrib/pageinspect/expected/gin.out b/contrib/pageinspect/expected/gin.out
new file mode 100644
index 0000000..4f341e1
--- /dev/null
+++ b/contrib/pageinspect/expected/gin.out
@@ -0,0 +1,30 @@
+CREATE TABLE test1 (x int, y int[]);
+INSERT INTO test1 VALUES (1, ARRAY[11, 111]);
+CREATE INDEX test1_y_idx ON test1 USING gin (y);
+\x
+SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 0));
+-[ RECORD 1 ]----+-----------
+pending_head     | 4294967295
+pending_tail     | 4294967295
+tail_free_size   | 0
+n_pending_pages  | 0
+n_pending_tuples | 0
+n_total_pages    | 2
+n_entry_pages    | 1
+n_data_pages     | 0
+n_entries        | 2
+version          | 2
+
+SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 1));
+ERROR:  input page is not a GIN metapage
+DETAIL:  Flags 0002, expected 0008
+SELECT * FROM gin_page_opaque_info(get_raw_page('test1_y_idx', 1));
+-[ RECORD 1 ]---------
+rightlink | 4294967295
+maxoff    | 0
+flags     | {leaf}
+
+SELECT * FROM gin_leafpage_items(get_raw_page('test1_y_idx', 1));
+ERROR:  input page is not a compressed GIN data leaf page
+DETAIL:  Flags 0002, expected 0083
+DROP TABLE test1;
diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out
new file mode 100644
index 0000000..673a852
--- /dev/null
+++ b/contrib/pageinspect/expected/page.out
@@ -0,0 +1,73 @@
+CREATE EXTENSION pageinspect;
+CREATE TABLE test1 (a int, b text);
+INSERT INTO test1 VALUES (1, 'one');
+VACUUM test1;  -- set up FSM
+-- The page contents can vary, so just test that it can be read
+-- successfully, but don't keep the output.
+SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0;
+ main_0 
+--------
+   8192
+(1 row)
+
+SELECT octet_length(get_raw_page('test1', 'main', 1)) AS main_1;
+ERROR:  block number 1 is out of range for relation "test1"
+SELECT octet_length(get_raw_page('test1', 'fsm', 0)) AS fsm_0;
+ fsm_0 
+-------
+  8192
+(1 row)
+
+SELECT octet_length(get_raw_page('test1', 'fsm', 1)) AS fsm_1;
+ fsm_1 
+-------
+  8192
+(1 row)
+
+SELECT octet_length(get_raw_page('test1', 'vm', 0)) AS vm_0;
+ vm_0 
+------
+ 8192
+(1 row)
+
+SELECT octet_length(get_raw_page('test1', 'vm', 1)) AS vm_1;
+ERROR:  block number 1 is out of range for relation "test1"
+SELECT octet_length(get_raw_page('xxx', 'main', 0));
+ERROR:  relation "xxx" does not exist
+SELECT octet_length(get_raw_page('test1', 'xxx', 0));
+ERROR:  invalid fork name
+HINT:  Valid fork names are "main", "fsm", "vm", and "init".
+SELECT get_raw_page('test1', 0) = get_raw_page('test1', 'main', 0);
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits)
+    FROM heap_page_items(get_raw_page('test1', 0));
+       tuple_data_split        
+-------------------------------
+ {"\\x01000000","\\x096f6e65"}
+(1 row)
+
+SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
+ fsm_page_contents 
+-------------------
+ 0: 254           +
+ 1: 254           +
+ 3: 254           +
+ 7: 254           +
+ 15: 254          +
+ 31: 254          +
+ 63: 254          +
+ 127: 254         +
+ 255: 254         +
+ 511: 254         +
+ 1023: 254        +
+ 2047: 254        +
+ 4095: 254        +
+ fp_next_slot: 0  +
+ 
+(1 row)
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/brin.sql b/contrib/pageinspect/sql/brin.sql
new file mode 100644
index 0000000..735bc3b
--- /dev/null
+++ b/contrib/pageinspect/sql/brin.sql
@@ -0,0 +1,18 @@
+CREATE TABLE test1 (a int, b text);
+INSERT INTO test1 VALUES (1, 'one');
+CREATE INDEX test1_a_idx ON test1 USING brin (a);
+
+SELECT brin_page_type(get_raw_page('test1_a_idx', 0));
+SELECT brin_page_type(get_raw_page('test1_a_idx', 1));
+SELECT brin_page_type(get_raw_page('test1_a_idx', 2));
+
+SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 0));
+SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 1));
+
+SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 0)) LIMIT 5;
+SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 1)) LIMIT 5;
+
+SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx')
+    ORDER BY blknum, attnum LIMIT 5;
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql
new file mode 100644
index 0000000..4fa3416
--- /dev/null
+++ b/contrib/pageinspect/sql/btree.sql
@@ -0,0 +1,17 @@
+CREATE TABLE test1 (a int, b text);
+INSERT INTO test1 VALUES (1, 'one');
+CREATE INDEX test1_a_idx ON test1 USING btree (a);
+
+\x
+
+SELECT * FROM bt_metap('test1_a_idx');
+
+SELECT * FROM bt_page_stats('test1_a_idx', 0);
+SELECT * FROM bt_page_stats('test1_a_idx', 1);
+SELECT * FROM bt_page_stats('test1_a_idx', 2);
+
+SELECT * FROM bt_page_items('test1_a_idx', 0);
+SELECT * FROM bt_page_items('test1_a_idx', 1);
+SELECT * FROM bt_page_items('test1_a_idx', 2);
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/gin.sql b/contrib/pageinspect/sql/gin.sql
new file mode 100644
index 0000000..ba79ff2
--- /dev/null
+++ b/contrib/pageinspect/sql/gin.sql
@@ -0,0 +1,14 @@
+CREATE TABLE test1 (x int, y int[]);
+INSERT INTO test1 VALUES (1, ARRAY[11, 111]);
+CREATE INDEX test1_y_idx ON test1 USING gin (y);
+
+\x
+
+SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 0));
+SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 1));
+
+SELECT * FROM gin_page_opaque_info(get_raw_page('test1_y_idx', 1));
+
+SELECT * FROM gin_leafpage_items(get_raw_page('test1_y_idx', 1));
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql
new file mode 100644
index 0000000..a304151
--- /dev/null
+++ b/contrib/pageinspect/sql/page.sql
@@ -0,0 +1,30 @@
+CREATE EXTENSION pageinspect;
+
+CREATE TABLE test1 (a int, b text);
+INSERT INTO test1 VALUES (1, 'one');
+
+VACUUM test1;  -- set up FSM
+
+-- The page contents can vary, so just test that it can be read
+-- successfully, but don't keep the output.
+
+SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0;
+SELECT octet_length(get_raw_page('test1', 'main', 1)) AS main_1;
+
+SELECT octet_length(get_raw_page('test1', 'fsm', 0)) AS fsm_0;
+SELECT octet_length(get_raw_page('test1', 'fsm', 1)) AS fsm_1;
+
+SELECT octet_length(get_raw_page('test1', 'vm', 0)) AS vm_0;
+SELECT octet_length(get_raw_page('test1', 'vm', 1)) AS vm_1;
+
+SELECT octet_length(get_raw_page('xxx', 'main', 0));
+SELECT octet_length(get_raw_page('test1', 'xxx', 0));
+
+SELECT get_raw_page('test1', 0) = get_raw_page('test1', 'main', 0);
+
+SELECT tuple_data_split('test1'::regclass, t_data, t_infomask, t_infomask2, t_bits)
+    FROM heap_page_items(get_raw_page('test1', 0));
+
+SELECT * FROM fsm_page_contents(get_raw_page('test1', 'fsm', 0));
+
+DROP TABLE test1;
-- 
2.10.0

