test-patch-comprehensive.sql
application/octet-stream
Filename: test-patch-comprehensive.sql
Type: application/octet-stream
Part: 1
-- ============================================================================
-- Test Script: Add temp table monitoring columns to pg_stat_database
--
-- Patch: v1-0001-Add-temp-table-monitoring-columns-to-pg_stat_data.patch
-- Thread: [PATCH v1] Add temp table monitoring columns to pg_stat_database
--
-- This script verifies the new columns added to pg_stat_database:
-- temp_tables - number of temporary tables created
-- local_blks_hit - local buffer cache hits (temp tables)
-- local_blks_read - local blocks read from disk (temp tables)
-- local_blks_dirtied - local blocks dirtied (temp tables)
-- local_blks_written - local blocks written to disk (temp tables)
--
-- Prerequisites:
-- - PostgreSQL 19devel built with the patch applied
-- - Connected to a test database
--
-- Usage:
-- createdb tempt
-- psql -d tempt -f test-patch-comprehensive.sql
-- ============================================================================
\echo '============================================================'
\echo 'Temp Table Monitoring Patch - Comprehensive Test Suite'
\echo '============================================================'
\echo ''
\x on
-- Reset stats for clean baseline
SELECT pg_stat_reset();
SELECT pg_sleep(2);
-- ============================================================================
\echo '--- Test 1: Verify new columns exist in pg_stat_database ---'
-- ============================================================================
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = 'pg_stat_database'
AND column_name IN ('temp_tables', 'local_blks_hit', 'local_blks_read',
'local_blks_dirtied', 'local_blks_written')
ORDER BY column_name;
-- Expected: 5 rows showing all new columns as bigint
-- ============================================================================
\echo ''
\echo '--- Test 2: Baseline - all counters start at zero ---'
-- ============================================================================
SELECT datname,
temp_tables,
local_blks_hit,
local_blks_read,
local_blks_dirtied,
local_blks_written
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: All zeros after reset
-- ============================================================================
\echo ''
\echo '--- Test 3: temp_tables increments on CREATE TEMP TABLE ---'
-- ============================================================================
CREATE TEMP TABLE t1 (id int);
CREATE TEMP TABLE t2 (id int, data text);
CREATE TEMP TABLE t3 AS SELECT generate_series(1, 100) AS id;
SELECT pg_sleep(2);
SELECT datname, temp_tables
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: temp_tables = 3
-- ============================================================================
\echo ''
\echo '--- Test 4: Regular tables do NOT increment temp_tables ---'
-- ============================================================================
CREATE TABLE regular_test (id int);
CREATE UNLOGGED TABLE unlogged_test (id int);
SELECT pg_sleep(2);
SELECT datname, temp_tables
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: temp_tables still = 3 (regular/unlogged don't count)
DROP TABLE regular_test;
DROP TABLE unlogged_test;
-- ============================================================================
\echo ''
\echo '--- Test 5: local_blks_written tracks temp table disk writes ---'
-- ============================================================================
SELECT pg_stat_reset();
SELECT pg_sleep(2);
CREATE TEMP TABLE write_test AS
SELECT i, md5(i::text) as hash
FROM generate_series(1, 10000) i;
SELECT pg_sleep(2);
SELECT datname,
temp_tables,
local_blks_written,
pg_size_pretty(local_blks_written * 8192) as written_size
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: temp_tables = 1, local_blks_written > 0
-- ============================================================================
\echo ''
\echo '--- Test 6: local_blks_hit tracks cache hits ---'
-- ============================================================================
-- Scan the table multiple times (data should be in cache)
SELECT count(*) FROM write_test;
SELECT count(*) FROM write_test WHERE i > 5000;
SELECT avg(i) FROM write_test;
SELECT pg_sleep(2);
SELECT datname,
local_blks_hit,
local_blks_read,
CASE
WHEN (local_blks_hit + local_blks_read) > 0
THEN round(100.0 * local_blks_hit / (local_blks_hit + local_blks_read), 2)
ELSE 0
END as temp_hit_ratio_pct
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: local_blks_hit > 0, hit ratio should be high (near 100%)
-- ============================================================================
\echo ''
\echo '--- Test 7: local_blks_dirtied tracks UPDATE operations ---'
-- ============================================================================
SELECT pg_stat_reset();
SELECT pg_sleep(2);
CREATE TEMP TABLE dirty_test (id int, value int);
INSERT INTO dirty_test SELECT i, i * 2 FROM generate_series(1, 5000) i;
-- Update rows to dirty blocks
UPDATE dirty_test SET value = value + 100 WHERE id <= 2500;
SELECT pg_sleep(2);
SELECT datname,
local_blks_dirtied,
local_blks_written
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: local_blks_dirtied > 0
-- ============================================================================
\echo ''
\echo '--- Test 8: local_blks_read with small temp_buffers ---'
-- ============================================================================
-- Reconnect to get a fresh session. temp_buffers can only be set before
-- first temp table access in a session. Without \connect you get:
--
-- ERROR: invalid value for parameter "temp_buffers": 100
-- DETAIL: "temp_buffers" cannot be changed after any temporary tables
-- have been accessed in the session.
--
\connect
\x on
SELECT pg_stat_reset();
SELECT pg_sleep(2);
\echo ' Setting temp_buffers = 800kB (minimum allowed) to force disk reads'
\echo ' when temp table data exceeds the local buffer cache size.'
SET temp_buffers = '800kB';
CREATE TEMP TABLE read_test AS
SELECT i, repeat('data', 50) as padding
FROM generate_series(1, 20000) i;
-- Scan to force reads from disk (exceeds 800kB cache)
SELECT count(*) FROM read_test;
SELECT count(*) FROM read_test WHERE i > 10000;
SELECT pg_sleep(2);
SELECT datname,
local_blks_hit AS temp_cache_hits,
local_blks_read AS temp_disk_reads,
local_blks_written AS temp_disk_writes,
CASE
WHEN (local_blks_hit + local_blks_read) > 0
THEN round(100.0 * local_blks_hit / (local_blks_hit + local_blks_read), 2)
ELSE 0
END as temp_hit_ratio_pct
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: local_blks_read > 0 (cache too small for data)
-- Expected: hit ratio < 100% (some reads had to go to disk)
-- ============================================================================
\echo ''
\echo '--- Test 9: pg_stat_reset clears all counters ---'
-- ============================================================================
SELECT pg_stat_reset();
SELECT pg_sleep(2);
SELECT datname,
temp_tables,
local_blks_hit,
local_blks_read,
local_blks_dirtied,
local_blks_written
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: All zeros after reset
-- ============================================================================
\echo ''
\echo '--- Test 10: Temp table with ON COMMIT DROP still counts ---'
-- ============================================================================
BEGIN;
CREATE TEMP TABLE on_commit_test (id int) ON COMMIT DROP;
INSERT INTO on_commit_test VALUES (1), (2), (3);
COMMIT;
SELECT pg_sleep(2);
SELECT datname, temp_tables
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: temp_tables = 1 (creation counted even though table was dropped)
-- ============================================================================
\echo ''
\echo '--- Test 11: Multiple temp tables in one transaction ---'
-- ============================================================================
BEGIN;
CREATE TEMP TABLE multi1 (id int);
CREATE TEMP TABLE multi2 (id int);
CREATE TEMP TABLE multi3 (id int);
COMMIT;
SELECT pg_sleep(2);
SELECT datname, temp_tables
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: temp_tables = 4 (1 from test 10 + 3 from this test)
-- ============================================================================
\echo ''
\echo '--- Test 12: Use Case - Detecting Undersized temp_buffers ---'
-- ============================================================================
-- This test demonstrates the primary use case: comparing cache efficiency
-- with different temp_buffers settings to identify sizing issues.
\echo ''
\echo ' Scenario A: Small cache (800kB) - same workload'
-- Fresh session needed for SET temp_buffers
\connect
\x on
SELECT pg_stat_reset();
SELECT pg_sleep(2);
SET temp_buffers = '800kB';
CREATE TEMP TABLE sizing_test_small AS
SELECT i, md5(i::text) as hash, repeat('x', 80) as padding
FROM generate_series(1, 30000) i;
SELECT count(*) FROM sizing_test_small;
SELECT count(*) FROM sizing_test_small WHERE i > 15000;
SELECT avg(i) FROM sizing_test_small;
SELECT pg_sleep(2);
SELECT
'Small Cache (800kB)' as scenario,
temp_tables,
local_blks_hit,
local_blks_read,
local_blks_written,
CASE
WHEN (local_blks_hit + local_blks_read) > 0
THEN round(100.0 * local_blks_hit / (local_blks_hit + local_blks_read), 2)
ELSE 0
END as hit_ratio
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: hit_ratio < 100% (cache too small, disk reads needed)
\echo ''
\echo ' Scenario B: Large cache (10MB) - same workload'
-- Fresh session needed for SET temp_buffers
\connect
\x on
SELECT pg_stat_reset();
SELECT pg_sleep(2);
SET temp_buffers = '10MB';
CREATE TEMP TABLE sizing_test_large AS
SELECT i, md5(i::text) as hash, repeat('x', 80) as padding
FROM generate_series(1, 30000) i;
SELECT count(*) FROM sizing_test_large;
SELECT count(*) FROM sizing_test_large WHERE i > 15000;
SELECT avg(i) FROM sizing_test_large;
SELECT pg_sleep(2);
SELECT
'Large Cache (10MB)' as scenario,
temp_tables,
local_blks_hit,
local_blks_read,
local_blks_written,
CASE
WHEN (local_blks_hit + local_blks_read) > 0
THEN round(100.0 * local_blks_hit / (local_blks_hit + local_blks_read), 2)
ELSE 0
END as hit_ratio
FROM pg_stat_database
WHERE datname = current_database();
-- Expected: hit_ratio = 100% (cache large enough, no disk reads)
-- Conclusion: If hit_ratio is low, increase temp_buffers!
-- ============================================================================
\echo ''
\echo '============================================================'
\echo 'All tests complete!'
\echo ''
\echo 'Summary of what was tested:'
\echo ' 1. New columns exist in pg_stat_database'
\echo ' 2. Counters start at zero after reset'
\echo ' 3. temp_tables increments on CREATE TEMP TABLE'
\echo ' 4. Regular/unlogged tables do NOT increment'
\echo ' 5. local_blks_written tracks disk writes'
\echo ' 6. local_blks_hit tracks cache hits'
\echo ' 7. local_blks_dirtied tracks UPDATE operations'
\echo ' 8. local_blks_read tracks disk reads (small cache)'
\echo ' 9. pg_stat_reset clears all counters'
\echo ' 10. ON COMMIT DROP still counts creation'
\echo ' 11. Multiple temp tables in one transaction'
\echo ' 12. Use Case: Detecting undersized temp_buffers (small vs large)'
\echo '============================================================'
-- Final cleanup
SELECT pg_stat_reset();