summaryrefslogtreecommitdiffstats
path: root/contrib/pageinspect/sql
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/pageinspect/sql')
-rw-r--r--contrib/pageinspect/sql/brin.sql39
-rw-r--r--contrib/pageinspect/sql/btree.sql62
-rw-r--r--contrib/pageinspect/sql/checksum.sql31
-rw-r--r--contrib/pageinspect/sql/gin.sql41
-rw-r--r--contrib/pageinspect/sql/gist.sql69
-rw-r--r--contrib/pageinspect/sql/hash.sql113
-rw-r--r--contrib/pageinspect/sql/oldextversions.sql26
-rw-r--r--contrib/pageinspect/sql/page.sql100
8 files changed, 481 insertions, 0 deletions
diff --git a/contrib/pageinspect/sql/brin.sql b/contrib/pageinspect/sql/brin.sql
new file mode 100644
index 0000000..96b4645
--- /dev/null
+++ b/contrib/pageinspect/sql/brin.sql
@@ -0,0 +1,39 @@
+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;
+
+-- Mask DETAIL messages as these are not portable across architectures.
+\set VERBOSITY terse
+
+-- Failures for non-BRIN index.
+CREATE INDEX test1_a_btree ON test1 (a);
+SELECT brin_page_items(get_raw_page('test1_a_btree', 0), 'test1_a_btree');
+SELECT brin_page_items(get_raw_page('test1_a_btree', 0), 'test1_a_idx');
+
+-- Invalid special area size
+SELECT brin_page_type(get_raw_page('test1', 0));
+SELECT * FROM brin_metapage_info(get_raw_page('test1', 0));
+SELECT * FROM brin_revmap_data(get_raw_page('test1', 0));
+\set VERBOSITY default
+
+-- Tests with all-zero pages.
+SHOW block_size \gset
+SELECT brin_page_type(decode(repeat('00', :block_size), 'hex'));
+SELECT brin_page_items(decode(repeat('00', :block_size), 'hex'), 'test1_a_idx');
+SELECT brin_metapage_info(decode(repeat('00', :block_size), 'hex'));
+SELECT brin_revmap_data(decode(repeat('00', :block_size), 'hex'));
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql
new file mode 100644
index 0000000..102ebde
--- /dev/null
+++ b/contrib/pageinspect/sql/btree.sql
@@ -0,0 +1,62 @@
+CREATE TABLE test1 (a int8, b int4range);
+INSERT INTO test1 VALUES (72057594037927937, '[0,1)');
+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', -1);
+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);
+
+-- bt_multi_page_stats() function returns a set of records of page statistics.
+CREATE TABLE test2 AS (SELECT generate_series(1, 1000)::int8 AS col1);
+CREATE INDEX test2_col1_idx ON test2(col1);
+SELECT * FROM bt_multi_page_stats('test2_col1_idx', 0, 1);
+SELECT * FROM bt_multi_page_stats('test2_col1_idx', 1, -1);
+SELECT * FROM bt_multi_page_stats('test2_col1_idx', 1, 0);
+SELECT * FROM bt_multi_page_stats('test2_col1_idx', 1, 2);
+SELECT * FROM bt_multi_page_stats('test2_col1_idx', 3, 2);
+SELECT * FROM bt_multi_page_stats('test2_col1_idx', 7, 2);
+DROP TABLE test2;
+
+SELECT * FROM bt_page_items('test1_a_idx', -1);
+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);
+
+SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', -1));
+SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 0));
+SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 1));
+SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 2));
+
+-- Failure when using a non-btree index.
+CREATE INDEX test1_a_hash ON test1 USING hash(a);
+SELECT bt_metap('test1_a_hash');
+SELECT bt_page_stats('test1_a_hash', 0);
+SELECT bt_page_items('test1_a_hash', 0);
+SELECT bt_page_items(get_raw_page('test1_a_hash', 0));
+CREATE INDEX test1_b_gist ON test1 USING gist(b);
+-- Special area of GiST is the same as btree, this complains about inconsistent
+-- leaf data on the page.
+SELECT bt_page_items(get_raw_page('test1_b_gist', 0));
+
+-- Several failure modes.
+-- Suppress the DETAIL message, to allow the tests to work across various
+-- page sizes and architectures.
+\set VERBOSITY terse
+-- invalid page size
+SELECT bt_page_items('aaa'::bytea);
+-- invalid special area size
+CREATE INDEX test1_a_brin ON test1 USING brin(a);
+SELECT bt_page_items(get_raw_page('test1', 0));
+SELECT bt_page_items(get_raw_page('test1_a_brin', 0));
+\set VERBOSITY default
+
+-- Tests with all-zero pages.
+SHOW block_size \gset
+SELECT bt_page_items(decode(repeat('00', :block_size), 'hex'));
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/checksum.sql b/contrib/pageinspect/sql/checksum.sql
new file mode 100644
index 0000000..b877db0
--- /dev/null
+++ b/contrib/pageinspect/sql/checksum.sql
@@ -0,0 +1,31 @@
+--
+-- Verify correct calculation of checksums
+--
+-- Postgres' checksum algorithm produces different answers on little-endian
+-- and big-endian machines. The results of this test also vary depending
+-- on the configured block size. This test has several different expected
+-- results files to handle the following possibilities:
+--
+-- BLCKSZ end file
+-- 8K LE checksum.out
+-- 8K BE checksum_1.out
+--
+-- In future we might provide additional expected-results files for other
+-- block sizes, but there seems little point as long as so many other
+-- test scripts also show false failures for non-default block sizes.
+--
+
+-- This is to label the results files with blocksize:
+SHOW block_size;
+
+SHOW block_size \gset
+
+-- Apply page_checksum() to some different data patterns and block numbers
+SELECT blkno,
+ page_checksum(decode(repeat('01', :block_size), 'hex'), blkno) AS checksum_01,
+ page_checksum(decode(repeat('04', :block_size), 'hex'), blkno) AS checksum_04,
+ page_checksum(decode(repeat('ff', :block_size), 'hex'), blkno) AS checksum_ff,
+ page_checksum(decode(repeat('abcd', :block_size / 2), 'hex'), blkno) AS checksum_abcd,
+ page_checksum(decode(repeat('e6d6', :block_size / 2), 'hex'), blkno) AS checksum_e6d6,
+ page_checksum(decode(repeat('4a5e', :block_size / 2), 'hex'), blkno) AS checksum_4a5e
+ FROM generate_series(0, 100, 50) AS a (blkno);
diff --git a/contrib/pageinspect/sql/gin.sql b/contrib/pageinspect/sql/gin.sql
new file mode 100644
index 0000000..b57466d
--- /dev/null
+++ b/contrib/pageinspect/sql/gin.sql
@@ -0,0 +1,41 @@
+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) WITH (fastupdate = off);
+
+\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));
+
+INSERT INTO test1 SELECT x, ARRAY[1,10] FROM generate_series(2,10000) x;
+
+SELECT COUNT(*) > 0
+FROM gin_leafpage_items(get_raw_page('test1_y_idx',
+ (pg_relation_size('test1_y_idx') /
+ current_setting('block_size')::bigint)::int - 1));
+
+-- Failure with various modes.
+-- Suppress the DETAIL message, to allow the tests to work across various
+-- page sizes and architectures.
+\set VERBOSITY terse
+-- invalid page size
+SELECT gin_leafpage_items('aaa'::bytea);
+SELECT gin_metapage_info('bbb'::bytea);
+SELECT gin_page_opaque_info('ccc'::bytea);
+-- invalid special area size
+SELECT * FROM gin_metapage_info(get_raw_page('test1', 0));
+SELECT * FROM gin_page_opaque_info(get_raw_page('test1', 0));
+SELECT * FROM gin_leafpage_items(get_raw_page('test1', 0));
+\set VERBOSITY default
+
+-- Tests with all-zero pages.
+SHOW block_size \gset
+SELECT gin_leafpage_items(decode(repeat('00', :block_size), 'hex'));
+SELECT gin_metapage_info(decode(repeat('00', :block_size), 'hex'));
+SELECT gin_page_opaque_info(decode(repeat('00', :block_size), 'hex'));
+
+DROP TABLE test1;
diff --git a/contrib/pageinspect/sql/gist.sql b/contrib/pageinspect/sql/gist.sql
new file mode 100644
index 0000000..d263542
--- /dev/null
+++ b/contrib/pageinspect/sql/gist.sql
@@ -0,0 +1,69 @@
+-- The gist_page_opaque_info() function prints the page's LSN. Normally,
+-- that's constant 1 (GistBuildLSN) on every page of a freshly built GiST
+-- index. But with wal_level=minimal, the whole relation is dumped to WAL at
+-- the end of the transaction if it's smaller than wal_skip_threshold, which
+-- updates the LSNs. Wrap the tests on gist_page_opaque_info() in the
+-- same transaction with the CREATE INDEX so that we see the LSNs before
+-- they are possibly overwritten at end of transaction.
+BEGIN;
+
+-- Create a test table and GiST index.
+CREATE TABLE test_gist AS SELECT point(i,i) p, i::text t FROM
+ generate_series(1,1000) i;
+CREATE INDEX test_gist_idx ON test_gist USING gist (p);
+
+-- Page 0 is the root, the rest are leaf pages
+SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 0));
+SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 1));
+SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2));
+
+COMMIT;
+
+SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx');
+SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') LIMIT 5;
+
+-- gist_page_items_bytea prints the raw key data as a bytea. The output of that is
+-- platform-dependent (endianness), so omit the actual key data from the output.
+SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0));
+
+-- Suppress the DETAIL message, to allow the tests to work across various
+-- page sizes and architectures.
+\set VERBOSITY terse
+
+-- Failures with non-GiST index.
+CREATE INDEX test_gist_btree on test_gist(t);
+SELECT gist_page_items(get_raw_page('test_gist_btree', 0), 'test_gist_btree');
+SELECT gist_page_items(get_raw_page('test_gist_btree', 0), 'test_gist_idx');
+
+-- Failure with various modes.
+-- invalid page size
+SELECT gist_page_items_bytea('aaa'::bytea);
+SELECT gist_page_items('aaa'::bytea, 'test_gist_idx'::regclass);
+SELECT gist_page_opaque_info('aaa'::bytea);
+-- invalid special area size
+SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist', 0));
+SELECT gist_page_items_bytea(get_raw_page('test_gist', 0));
+SELECT gist_page_items_bytea(get_raw_page('test_gist_btree', 0));
+\set VERBOSITY default
+
+-- Tests with all-zero pages.
+SHOW block_size \gset
+SELECT gist_page_items_bytea(decode(repeat('00', :block_size), 'hex'));
+SELECT gist_page_items(decode(repeat('00', :block_size), 'hex'), 'test_gist_idx'::regclass);
+SELECT gist_page_opaque_info(decode(repeat('00', :block_size), 'hex'));
+
+-- Test gist_page_items with included columns.
+-- Non-leaf pages contain only the key attributes, and leaf pages contain
+-- the included attributes.
+ALTER TABLE test_gist ADD COLUMN i int DEFAULT NULL;
+CREATE INDEX test_gist_idx_inc ON test_gist
+ USING gist (p) INCLUDE (t, i);
+-- Mask the value of the key attribute to avoid alignment issues.
+SELECT regexp_replace(keys, '\(p\)=\("(.*?)"\)', '(p)=("<val>")') AS keys_nonleaf_1
+ FROM gist_page_items(get_raw_page('test_gist_idx_inc', 0), 'test_gist_idx_inc')
+ WHERE itemoffset = 1;
+SELECT keys AS keys_leaf_1
+ FROM gist_page_items(get_raw_page('test_gist_idx_inc', 1), 'test_gist_idx_inc')
+ WHERE itemoffset = 1;
+
+DROP TABLE test_gist;
diff --git a/contrib/pageinspect/sql/hash.sql b/contrib/pageinspect/sql/hash.sql
new file mode 100644
index 0000000..e4b9e97
--- /dev/null
+++ b/contrib/pageinspect/sql/hash.sql
@@ -0,0 +1,113 @@
+CREATE TABLE test_hash (a int, b text);
+INSERT INTO test_hash VALUES (1, 'one');
+CREATE INDEX test_hash_a_idx ON test_hash USING hash (a);
+
+CREATE TABLE test_hash_part (a int, b int) PARTITION BY RANGE (a);
+CREATE INDEX test_hash_part_idx ON test_hash_part USING hash(b);
+
+\x
+
+SELECT hash_page_type(get_raw_page('test_hash_a_idx', 0));
+SELECT hash_page_type(get_raw_page('test_hash_a_idx', 1));
+SELECT hash_page_type(get_raw_page('test_hash_a_idx', 2));
+SELECT hash_page_type(get_raw_page('test_hash_a_idx', 3));
+SELECT hash_page_type(get_raw_page('test_hash_a_idx', 4));
+SELECT hash_page_type(get_raw_page('test_hash_a_idx', 5));
+SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6));
+
+
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', -1);
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0);
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1);
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', 2);
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', 3);
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', 4);
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5);
+SELECT * FROM hash_bitmap_info('test_hash_a_idx', 6);
+SELECT * FROM hash_bitmap_info('test_hash_part_idx', 1); -- error
+
+
+SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
+lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
+hash_metapage_info(get_raw_page('test_hash_a_idx', 0));
+
+SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
+lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
+hash_metapage_info(get_raw_page('test_hash_a_idx', 1));
+
+SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
+lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
+hash_metapage_info(get_raw_page('test_hash_a_idx', 2));
+
+SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
+lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
+hash_metapage_info(get_raw_page('test_hash_a_idx', 3));
+
+SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
+lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
+hash_metapage_info(get_raw_page('test_hash_a_idx', 4));
+
+SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
+lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
+hash_metapage_info(get_raw_page('test_hash_a_idx', 5));
+
+SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno,
+hasho_bucket, hasho_flag, hasho_page_id FROM
+hash_page_stats(get_raw_page('test_hash_a_idx', 0));
+
+SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno,
+hasho_bucket, hasho_flag, hasho_page_id FROM
+hash_page_stats(get_raw_page('test_hash_a_idx', 1));
+
+SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno,
+hasho_bucket, hasho_flag, hasho_page_id FROM
+hash_page_stats(get_raw_page('test_hash_a_idx', 2));
+
+SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno,
+hasho_bucket, hasho_flag, hasho_page_id FROM
+hash_page_stats(get_raw_page('test_hash_a_idx', 3));
+
+SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno,
+hasho_bucket, hasho_flag, hasho_page_id FROM
+hash_page_stats(get_raw_page('test_hash_a_idx', 4));
+
+SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno,
+hasho_bucket, hasho_flag, hasho_page_id FROM
+hash_page_stats(get_raw_page('test_hash_a_idx', 5));
+
+SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 0));
+SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 1));
+SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 2));
+SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 3));
+SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 4));
+SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 5));
+
+-- Failure with non-hash index
+CREATE INDEX test_hash_a_btree ON test_hash USING btree (a);
+SELECT hash_bitmap_info('test_hash_a_btree', 0);
+
+-- Failure with various modes.
+-- Suppress the DETAIL message, to allow the tests to work across various
+-- page sizes and architectures.
+\set VERBOSITY terse
+-- invalid page size
+SELECT hash_metapage_info('aaa'::bytea);
+SELECT hash_page_items('bbb'::bytea);
+SELECT hash_page_stats('ccc'::bytea);
+SELECT hash_page_type('ddd'::bytea);
+-- invalid special area size
+SELECT hash_metapage_info(get_raw_page('test_hash', 0));
+SELECT hash_page_items(get_raw_page('test_hash', 0));
+SELECT hash_page_stats(get_raw_page('test_hash', 0));
+SELECT hash_page_type(get_raw_page('test_hash', 0));
+\set VERBOSITY default
+
+-- Tests with all-zero pages.
+SHOW block_size \gset
+SELECT hash_metapage_info(decode(repeat('00', :block_size), 'hex'));
+SELECT hash_page_items(decode(repeat('00', :block_size), 'hex'));
+SELECT hash_page_stats(decode(repeat('00', :block_size), 'hex'));
+SELECT hash_page_type(decode(repeat('00', :block_size), 'hex'));
+
+DROP TABLE test_hash;
+DROP TABLE test_hash_part;
diff --git a/contrib/pageinspect/sql/oldextversions.sql b/contrib/pageinspect/sql/oldextversions.sql
new file mode 100644
index 0000000..9f95349
--- /dev/null
+++ b/contrib/pageinspect/sql/oldextversions.sql
@@ -0,0 +1,26 @@
+-- test old extension version entry points
+
+DROP EXTENSION pageinspect;
+CREATE EXTENSION pageinspect VERSION '1.8';
+
+CREATE TABLE test1 (a int8, b text);
+INSERT INTO test1 VALUES (72057594037927937, 'text');
+CREATE INDEX test1_a_idx ON test1 USING btree (a);
+
+-- from page.sql
+SELECT octet_length(get_raw_page('test1', 0)) AS main_0;
+SELECT octet_length(get_raw_page('test1', 'main', 0)) AS main_0;
+SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test;
+
+-- from btree.sql
+SELECT * FROM bt_page_stats('test1_a_idx', 1);
+SELECT * FROM bt_page_items('test1_a_idx', 1);
+
+-- page_header() uses int instead of smallint for lower, upper, special and
+-- pagesize in pageinspect >= 1.10.
+ALTER EXTENSION pageinspect UPDATE TO '1.9';
+\df page_header
+SELECT pagesize, version FROM page_header(get_raw_page('test1', 0));
+
+DROP TABLE test1;
+DROP EXTENSION pageinspect;
diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql
new file mode 100644
index 0000000..5bff568
--- /dev/null
+++ b/contrib/pageinspect/sql/page.sql
@@ -0,0 +1,100 @@
+CREATE EXTENSION pageinspect;
+
+-- Use a temp table so that effects of VACUUM are predictable
+CREATE TEMP TABLE test1 (a int, b int);
+INSERT INTO test1 VALUES (16777217, 131584);
+
+VACUUM (DISABLE_PAGE_SKIPPING) 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('test1', 'main', -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 pagesize, version FROM page_header(get_raw_page('test1', 0));
+
+SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_test;
+SELECT page_checksum(get_raw_page('test1', 0), -1);
+
+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));
+
+-- If we freeze the only tuple on test1, the infomask should
+-- always be the same in all test runs.
+VACUUM (FREEZE, DISABLE_PAGE_SKIPPING) test1;
+
+SELECT t_infomask, t_infomask2, raw_flags, combined_flags
+FROM heap_page_items(get_raw_page('test1', 0)),
+ LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2);
+
+-- tests for decoding of combined flags
+-- HEAP_XMAX_SHR_LOCK = (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)
+SELECT * FROM heap_tuple_infomask_flags(x'0050'::int, 0);
+-- HEAP_XMIN_FROZEN = (HEAP_XMIN_COMMITTED | HEAP_XMIN_INVALID)
+SELECT * FROM heap_tuple_infomask_flags(x'0300'::int, 0);
+-- HEAP_MOVED = (HEAP_MOVED_IN | HEAP_MOVED_OFF)
+SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
+SELECT * FROM heap_tuple_infomask_flags(x'C000'::int, 0);
+
+-- test all flags of t_infomask and t_infomask2
+SELECT unnest(raw_flags)
+ FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
+SELECT unnest(combined_flags)
+ FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1;
+
+-- no flags at all
+SELECT * FROM heap_tuple_infomask_flags(0, 0);
+-- no combined flags
+SELECT * FROM heap_tuple_infomask_flags(x'0010'::int, 0);
+
+DROP TABLE test1;
+
+-- check that using any of these functions with a partitioned table or index
+-- would fail
+create table test_partitioned (a int) partition by range (a);
+create index test_partitioned_index on test_partitioned (a);
+select get_raw_page('test_partitioned', 0); -- error about partitioned table
+select get_raw_page('test_partitioned_index', 0); -- error about partitioned index
+
+-- a regular table which is a member of a partition set should work though
+create table test_part1 partition of test_partitioned for values from ( 1 ) to (100);
+select get_raw_page('test_part1', 0); -- get farther and error about empty table
+drop table test_partitioned;
+
+-- check null bitmap alignment for table whose number of attributes is multiple of 8
+create table test8 (f1 int, f2 int, f3 int, f4 int, f5 int, f6 int, f7 int, f8 int);
+insert into test8(f1, f8) values (x'7f00007f'::int, 0);
+select t_bits, t_data from heap_page_items(get_raw_page('test8', 0));
+select tuple_data_split('test8'::regclass, t_data, t_infomask, t_infomask2, t_bits)
+ from heap_page_items(get_raw_page('test8', 0));
+drop table test8;
+
+-- Failure with incorrect page size
+-- Suppress the DETAIL message, to allow the tests to work across various
+-- page sizes.
+\set VERBOSITY terse
+SELECT fsm_page_contents('aaa'::bytea);
+SELECT page_checksum('bbb'::bytea, 0);
+SELECT page_header('ccc'::bytea);
+\set VERBOSITY default
+
+-- Tests with all-zero pages.
+SHOW block_size \gset
+SELECT fsm_page_contents(decode(repeat('00', :block_size), 'hex'));
+SELECT page_header(decode(repeat('00', :block_size), 'hex'));
+SELECT page_checksum(decode(repeat('00', :block_size), 'hex'), 1);