Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
638 changes: 519 additions & 119 deletions contrib/pg_stat_statements/pg_stat_statements.c

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions contrib/pg_stat_statements_nsp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Generated by regression tests
/results/
/regression.diffs
/regression.out
/tmp_check/
/log/
23 changes: 23 additions & 0 deletions contrib/pg_stat_statements_nsp/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# contrib/pg_stat_statements_nsp/Makefile

MODULE_big = pg_stat_statements_nsp
OBJS = \
$(WIN32RES) \
pg_stat_statements_nsp.o

EXTENSION = pg_stat_statements_nsp
DATA = pg_stat_statements_nsp--1.0.sql
PGFILEDESC = "pg_stat_statements_nsp - execution statistics without shared_preload_libraries"

REGRESS = pg_stat_statements_nsp

ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/pg_stat_statements_nsp
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
107 changes: 107 additions & 0 deletions contrib/pg_stat_statements_nsp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# pg_stat_statements_nsp

A query statistics extension that works **without** requiring `shared_preload_libraries`.

## Overview

This extension demonstrates how to use the DSM (Dynamic Shared Memory) Registry,
introduced in PostgreSQL 17, to create shared data structures that persist across
sessions without needing to be loaded at server startup.

Unlike the standard `pg_stat_statements`, this extension can be loaded dynamically
via the `LOAD` command or `session_preload_libraries`, making it ideal for:

- Cloud environments where modifying `shared_preload_libraries` requires a restart
- Development and testing scenarios
- Situations where you want to enable query tracking without server downtime

## Key Features

- **No server restart required**: Load via `LOAD 'pg_stat_statements_nsp'`
- **Shared statistics**: Statistics are shared across all sessions once initialized
- **Similar API**: Provides a familiar interface similar to `pg_stat_statements`

## Limitations

Compared to the full `pg_stat_statements`:

- Statistics do **not** persist across server restarts (no disk storage)
- Fixed maximum number of tracked statements (1000)
- Simplified statistics (no planning stats, WAL stats, etc.)
- Query text is not stored (only query IDs are tracked)
- No GUC parameters for configuration

## Installation

1. Build and install:
```bash
cd contrib/pg_stat_statements_nsp
make
make install
```

2. Create the extension in your database:
```sql
CREATE EXTENSION pg_stat_statements_nsp;
```

## Usage

1. Enable query ID computation and load the module:
```sql
SET compute_query_id = on;
LOAD 'pg_stat_statements_nsp';
```

2. Run some queries to collect statistics:
```sql
SELECT 1;
SELECT * FROM pg_class LIMIT 10;
```

3. View the collected statistics:
```sql
SELECT * FROM pg_stat_statements_nsp;
```

4. Reset statistics:
```sql
SELECT pg_stat_statements_nsp_reset();
```

## Output Columns

| Column | Type | Description |
|--------|------|-------------|
| userid | oid | User OID who executed the query |
| dbid | oid | Database OID where query was executed |
| queryid | bigint | Query identifier (hash) |
| calls | bigint | Number of times executed |
| total_time | double precision | Total execution time in milliseconds |
| min_time | double precision | Minimum execution time |
| max_time | double precision | Maximum execution time |
| mean_time | double precision | Mean execution time |
| rows | bigint | Total rows retrieved or affected |

## Technical Details

This extension uses:

- **DSM Registry** (`GetNamedDSMSegment`, `GetNamedDSHash`): For lazy allocation
of shared memory without requiring `shared_preload_libraries`
- **dshash**: A concurrent hash table that supports dynamic resizing in DSM
- **Executor hooks**: To track query execution (works without preload)

## Requirements

- PostgreSQL 17 or later (for DSM Registry `GetNamedDSHash` support)
- `compute_query_id` must be enabled (either `on` or `auto`)

## See Also

- `pg_stat_statements` - The full-featured query statistics extension
- DSM Registry documentation in PostgreSQL source

## License

PostgreSQL License
84 changes: 84 additions & 0 deletions contrib/pg_stat_statements_nsp/expected/pg_stat_statements_nsp.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
-- Test pg_stat_statements_nsp extension
-- This extension works without shared_preload_libraries
-- First, ensure compute_query_id is enabled
SET compute_query_id = on;
-- Load the extension module (this simulates loading via LOAD command)
LOAD 'pg_stat_statements_nsp';
-- Create the extension (installs functions and views)
CREATE EXTENSION pg_stat_statements_nsp;
-- Reset any existing statistics
SELECT pg_stat_statements_nsp_reset();
pg_stat_statements_nsp_reset
------------------------------

(1 row)

-- Run some test queries
SELECT 1 AS simple_select;
simple_select
---------------
1
(1 row)

SELECT 1 + 1 AS addition;
addition
----------
2
(1 row)

SELECT generate_series(1, 5);
generate_series
-----------------
1
2
3
4
5
(5 rows)

-- Create a test table and run some queries on it
CREATE TABLE test_nsp (id int, val text);
INSERT INTO test_nsp VALUES (1, 'one'), (2, 'two'), (3, 'three');
SELECT * FROM test_nsp WHERE id = 1;
id | val
----+-----
1 | one
(1 row)

UPDATE test_nsp SET val = 'ONE' WHERE id = 1;
DELETE FROM test_nsp WHERE id = 3;
-- Check that we have recorded statistics
-- Note: We check for non-zero calls rather than exact counts
-- because query IDs might vary across runs
SELECT
calls > 0 AS has_calls,
total_time >= 0 AS has_time,
rows >= 0 AS has_rows
FROM pg_stat_statements_nsp
WHERE dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
LIMIT 5;
has_calls | has_time | has_rows
-----------+----------+----------
t | t | t
t | t | t
t | t | t
t | t | t
t | t | t
(5 rows)

-- Check the view works
SELECT count(*) > 0 AS has_entries FROM pg_stat_statements_nsp;
has_entries
-------------
t
(1 row)

-- Clean up
DROP TABLE test_nsp;
SELECT pg_stat_statements_nsp_reset();
pg_stat_statements_nsp_reset
------------------------------

(1 row)

DROP EXTENSION pg_stat_statements_nsp;
43 changes: 43 additions & 0 deletions contrib/pg_stat_statements_nsp/pg_stat_statements_nsp--1.0.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* contrib/pg_stat_statements_nsp/pg_stat_statements_nsp--1.0.sql */

-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION pg_stat_statements_nsp" to load this file. \quit

-- Register the function to retrieve statistics
CREATE FUNCTION pg_stat_statements_nsp(
OUT userid oid,
OUT dbid oid,
OUT queryid bigint,
OUT calls bigint,
OUT total_time double precision,
OUT min_time double precision,
OUT max_time double precision,
OUT rows bigint
)
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'pg_stat_statements_nsp'
LANGUAGE C STRICT VOLATILE PARALLEL SAFE;

-- Register the function to reset statistics
CREATE FUNCTION pg_stat_statements_nsp_reset()
RETURNS void
AS 'MODULE_PATHNAME', 'pg_stat_statements_nsp_reset'
LANGUAGE C STRICT VOLATILE PARALLEL SAFE;

-- Create a view for convenient access
CREATE VIEW pg_stat_statements_nsp AS
SELECT
s.userid,
s.dbid,
s.queryid,
s.calls,
s.total_time,
s.min_time,
s.max_time,
CASE WHEN s.calls > 0 THEN s.total_time / s.calls ELSE 0 END AS mean_time,
s.rows
FROM pg_stat_statements_nsp() s;

-- Grant access to pg_read_all_stats role (like pg_stat_statements does)
GRANT SELECT ON pg_stat_statements_nsp TO pg_read_all_stats;
GRANT EXECUTE ON FUNCTION pg_stat_statements_nsp() TO pg_read_all_stats;
Loading