summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/monitoring.sgml9
-rw-r--r--src/backend/catalog/system_views.sql3
-rw-r--r--src/backend/utils/activity/pgstat.c1
-rw-r--r--src/backend/utils/activity/pgstat_function.c6
-rw-r--r--src/backend/utils/adt/pgstatfuncs.c18
-rw-r--r--src/include/catalog/catversion.h2
-rw-r--r--src/include/catalog/pg_proc.dat4
-rw-r--r--src/include/pgstat.h3
-rw-r--r--src/include/utils/pgstat_internal.h1
-rw-r--r--src/test/isolation/expected/stats.out20
-rw-r--r--src/test/isolation/expected/stats_1.out20
-rw-r--r--src/test/isolation/specs/stats.spec8
-rw-r--r--src/test/regress/expected/rules.out3
13 files changed, 90 insertions, 8 deletions
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 6e3aac3d815..789ac16b444 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -4736,6 +4736,15 @@ description | Waiting for a newly initialized WAL file to reach durable storage
other functions called by it, in milliseconds
</para></entry>
</row>
+
+ <row>
+ <entry role="catalog_table_entry"><para role="column_definition">
+ <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
+ </para>
+ <para>
+ Time at which these statistics were last reset
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 884b6a23817..c94f1f05f52 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1131,7 +1131,8 @@ CREATE VIEW pg_stat_user_functions AS
P.proname AS funcname,
pg_stat_get_function_calls(P.oid) AS calls,
pg_stat_get_function_total_time(P.oid) AS total_time,
- pg_stat_get_function_self_time(P.oid) AS self_time
+ pg_stat_get_function_self_time(P.oid) AS self_time,
+ pg_stat_get_function_stat_reset_time(P.oid) AS stats_reset
FROM pg_proc P LEFT JOIN pg_namespace N ON (N.oid = P.pronamespace)
WHERE P.prolang != 12 -- fast check to eliminate built-in functions
AND pg_stat_get_function_calls(P.oid) IS NOT NULL;
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index 48f57e408e1..7ef06150df7 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -328,6 +328,7 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
.pending_size = sizeof(PgStat_FunctionCounts),
.flush_pending_cb = pgstat_function_flush_cb,
+ .reset_timestamp_cb = pgstat_function_reset_timestamp_cb,
},
[PGSTAT_KIND_REPLSLOT] = {
diff --git a/src/backend/utils/activity/pgstat_function.c b/src/backend/utils/activity/pgstat_function.c
index 6214f93d36e..b5db9d15e07 100644
--- a/src/backend/utils/activity/pgstat_function.c
+++ b/src/backend/utils/activity/pgstat_function.c
@@ -214,6 +214,12 @@ pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
return true;
}
+void
+pgstat_function_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
+{
+ ((PgStatShared_Function *) header)->stats.stat_reset_timestamp = ts;
+}
+
/*
* find any existing PgStat_FunctionCounts entry for specified function
*
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 7e89a8048d5..3802a4cb888 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -204,6 +204,24 @@ PG_STAT_GET_FUNCENTRY_FLOAT8_MS(total_time)
PG_STAT_GET_FUNCENTRY_FLOAT8_MS(self_time)
Datum
+pg_stat_get_function_stat_reset_time(PG_FUNCTION_ARGS)
+{
+ Oid funcid = PG_GETARG_OID(0);
+ TimestampTz result;
+ PgStat_StatFuncEntry *funcentry;
+
+ if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
+ result = 0;
+ else
+ result = funcentry->stat_reset_timestamp;
+
+ if (result == 0)
+ PG_RETURN_NULL();
+ else
+ PG_RETURN_TIMESTAMPTZ(result);
+}
+
+Datum
pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 642abe5217e..00b3bce1e12 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202510062
+#define CATALOG_VERSION_NO 202510081
#endif
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 7c20180637f..6bb31892d1d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6071,6 +6071,10 @@
proname => 'pg_stat_get_function_self_time', provolatile => 's',
proparallel => 'r', prorettype => 'float8', proargtypes => 'oid',
prosrc => 'pg_stat_get_function_self_time' },
+{ oid => '8745', descr => 'statistics: last reset for a function',
+ proname => 'pg_stat_get_function_stat_reset_time', provolatile => 's',
+ proparallel => 'r', prorettype => 'timestamptz', proargtypes => 'oid',
+ prosrc => 'pg_stat_get_function_stat_reset_time' },
{ oid => '3037',
descr => 'statistics: number of scans done for table/index in current transaction',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 8e8adb01176..d24bf864a22 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -212,7 +212,7 @@ typedef struct PgStat_TableXactStatus
* ------------------------------------------------------------
*/
-#define PGSTAT_FILE_FORMAT_ID 0x01A5BCB8
+#define PGSTAT_FILE_FORMAT_ID 0x01A5BCB9
typedef struct PgStat_ArchiverStats
{
@@ -384,6 +384,7 @@ typedef struct PgStat_StatFuncEntry
PgStat_Counter total_time; /* times in microseconds */
PgStat_Counter self_time;
+ TimestampTz stat_reset_timestamp;
} PgStat_StatFuncEntry;
typedef struct PgStat_StatReplSlotEntry
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index dc42d8043b5..4d2b8aa6081 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -691,6 +691,7 @@ extern void pgstat_database_reset_timestamp_cb(PgStatShared_Common *header, Time
*/
extern bool pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
+extern void pgstat_function_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts);
/*
diff --git a/src/test/isolation/expected/stats.out b/src/test/isolation/expected/stats.out
index 8c7fe60217e..cfad309ccf3 100644
--- a/src/test/isolation/expected/stats.out
+++ b/src/test/isolation/expected/stats.out
@@ -1025,7 +1025,7 @@ test_stat_func| | |
(1 row)
-starting permutation: s1_track_funcs_all s2_track_funcs_all s1_func_call s2_func_call s2_func_call2 s1_ff s2_ff s1_func_stats s2_func_call s2_func_call2 s2_ff s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset s1_func_stats s1_func_stats2 s1_func_stats
+starting permutation: s1_track_funcs_all s2_track_funcs_all s1_func_call s2_func_call s2_func_call2 s1_ff s2_ff s1_func_stats s2_func_call s2_func_call2 s2_ff s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset_check s1_func_stats_reset s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset_check
pg_stat_force_next_flush
------------------------
@@ -1137,6 +1137,15 @@ name |pg_stat_get_function_calls|total_above_zero|self_above_zero
test_stat_func| 3|t |t
(1 row)
+step s1_func_stats_reset_check:
+ SELECT pg_stat_get_function_stat_reset_time('test_stat_func'::regproc)
+ IS NOT NULL AS has_stats_reset;
+
+has_stats_reset
+---------------
+f
+(1 row)
+
step s1_func_stats_reset: SELECT pg_stat_reset_single_function_counters('test_stat_func'::regproc);
pg_stat_reset_single_function_counters
--------------------------------------
@@ -1185,6 +1194,15 @@ name |pg_stat_get_function_calls|total_above_zero|self_above_zero
test_stat_func| 0|f |f
(1 row)
+step s1_func_stats_reset_check:
+ SELECT pg_stat_get_function_stat_reset_time('test_stat_func'::regproc)
+ IS NOT NULL AS has_stats_reset;
+
+has_stats_reset
+---------------
+t
+(1 row)
+
starting permutation: s1_func_stats_nonexistent s1_func_stats_reset_nonexistent s1_func_stats_nonexistent
pg_stat_force_next_flush
diff --git a/src/test/isolation/expected/stats_1.out b/src/test/isolation/expected/stats_1.out
index 6b965bb9553..e1d937784cb 100644
--- a/src/test/isolation/expected/stats_1.out
+++ b/src/test/isolation/expected/stats_1.out
@@ -1025,7 +1025,7 @@ test_stat_func| | |
(1 row)
-starting permutation: s1_track_funcs_all s2_track_funcs_all s1_func_call s2_func_call s2_func_call2 s1_ff s2_ff s1_func_stats s2_func_call s2_func_call2 s2_ff s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset s1_func_stats s1_func_stats2 s1_func_stats
+starting permutation: s1_track_funcs_all s2_track_funcs_all s1_func_call s2_func_call s2_func_call2 s1_ff s2_ff s1_func_stats s2_func_call s2_func_call2 s2_ff s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset_check s1_func_stats_reset s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset_check
pg_stat_force_next_flush
------------------------
@@ -1137,6 +1137,15 @@ name |pg_stat_get_function_calls|total_above_zero|self_above_zero
test_stat_func| 3|t |t
(1 row)
+step s1_func_stats_reset_check:
+ SELECT pg_stat_get_function_stat_reset_time('test_stat_func'::regproc)
+ IS NOT NULL AS has_stats_reset;
+
+has_stats_reset
+---------------
+f
+(1 row)
+
step s1_func_stats_reset: SELECT pg_stat_reset_single_function_counters('test_stat_func'::regproc);
pg_stat_reset_single_function_counters
--------------------------------------
@@ -1185,6 +1194,15 @@ name |pg_stat_get_function_calls|total_above_zero|self_above_zero
test_stat_func| 0|f |f
(1 row)
+step s1_func_stats_reset_check:
+ SELECT pg_stat_get_function_stat_reset_time('test_stat_func'::regproc)
+ IS NOT NULL AS has_stats_reset;
+
+has_stats_reset
+---------------
+t
+(1 row)
+
starting permutation: s1_func_stats_nonexistent s1_func_stats_reset_nonexistent s1_func_stats_nonexistent
pg_stat_force_next_flush
diff --git a/src/test/isolation/specs/stats.spec b/src/test/isolation/specs/stats.spec
index e6d29749915..da16710da0f 100644
--- a/src/test/isolation/specs/stats.spec
+++ b/src/test/isolation/specs/stats.spec
@@ -58,6 +58,10 @@ step s1_track_funcs_none { SET track_functions = 'none'; }
step s1_func_call { SELECT test_stat_func(); }
step s1_func_drop { DROP FUNCTION test_stat_func(); }
step s1_func_stats_reset { SELECT pg_stat_reset_single_function_counters('test_stat_func'::regproc); }
+step s1_func_stats_reset_check {
+ SELECT pg_stat_get_function_stat_reset_time('test_stat_func'::regproc)
+ IS NOT NULL AS has_stats_reset;
+}
step s1_func_stats_reset_nonexistent { SELECT pg_stat_reset_single_function_counters(12000); }
step s1_reset { SELECT pg_stat_reset(); }
step s1_func_stats {
@@ -235,9 +239,9 @@ permutation
s1_ff s2_ff
s1_func_stats
s2_func_call s2_func_call2 s2_ff
- s1_func_stats s1_func_stats2 s1_func_stats
+ s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset_check
s1_func_stats_reset
- s1_func_stats s1_func_stats2 s1_func_stats
+ s1_func_stats s1_func_stats2 s1_func_stats s1_func_stats_reset_check
# test pg_stat_reset_single_function_counters of non-existing function
permutation
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 7f1cb3bb4af..8859a5a885f 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2244,7 +2244,8 @@ pg_stat_user_functions| SELECT p.oid AS funcid,
p.proname AS funcname,
pg_stat_get_function_calls(p.oid) AS calls,
pg_stat_get_function_total_time(p.oid) AS total_time,
- pg_stat_get_function_self_time(p.oid) AS self_time
+ pg_stat_get_function_self_time(p.oid) AS self_time,
+ pg_stat_get_function_stat_reset_time(p.oid) AS stats_reset
FROM (pg_proc p
LEFT JOIN pg_namespace n ON ((n.oid = p.pronamespace)))
WHERE ((p.prolang <> (12)::oid) AND (pg_stat_get_function_calls(p.oid) IS NOT NULL));