Thank you for pointing that out. I'll post a fixed patch.

+               SpinLockAcquire(&pgss->mutex);

You might noticed, but there a purpose of using the following
idiom. Without that, compiler might optimize out the comparison
assuming *pgss won't change.

        volatile pgssSharedState *s = (volatile pgssSharedState *) pgss; \
        SpinLockAcquire(&s->mutex); \

+               SpinLockAcquire(&pgss->mutex);
+               pgss->reset_time = GetCurrentTimestamp();

Fix the use of this idiom when modifying *pgss.

We should avoid (possiblly) time-cosuming thing like
GetCurrentTimestamp();

I understood your point to be "It's better not to execute GetCurrentTimestamp()
while spinlock is running.
Fix to store the result of GetCurrentTimestamp() in a local variable before
running spinlock. This value is stored in reset_time.

+      this function shows last reset time only when
<function>pg_stat_statements_reset(0,0,0)</function> is called.

This reads as "この関数はpg_statstatement_reset(0,0,0) が呼び出された
ときにだけ最終リセット時刻を表示します。", which I think is different
from what is intentended.

And the wording is not alike with the documentation for similar functions.

https://www.postgresql.org/docs/13/functions-datetime.html
current_timestamp → timestamp with time zone
Current date and time (start of current transaction); see Section 9.9.4

https://www.postgresql.org/docs/13/monitoring-stats.html
pg_stat_archiver view
stats_reset timestamp with time zone
Time at which these statistics were last reset

So something like the following?

Time at which pg_stat_statements_reset(0,0,0) was last called.

or

Time at which statistics are last discarded by calling
pg_stat_statements_reset(0,0,0).

 I have made the following corrections.

this function shows last reset time only when <function>pg_stat_statements_reset(0,0,0)</function> is called. →this function shows the time at which <function>pg_stat_statements_reset(0,0,0)</function> was last called.

<function>pg_stat_statements_reset_time(void) returns time stamp with time zone</function> →<function>pg_stat_statements_reset_time(void) returns timestamp with time zone</function>

Regards.
diff --git a/contrib/pg_stat_statements/Makefile b/contrib/pg_stat_statements/Makefile
index 081f997d70..3ec627b956 100644
--- a/contrib/pg_stat_statements/Makefile
+++ b/contrib/pg_stat_statements/Makefile
@@ -6,7 +6,7 @@ OBJS = \
 	pg_stat_statements.o
 
 EXTENSION = pg_stat_statements
-DATA = pg_stat_statements--1.4.sql \
+DATA = pg_stat_statements--1.4.sql pg_stat_statements--1.8--1.9.sql \
 	pg_stat_statements--1.7--1.8.sql pg_stat_statements--1.6--1.7.sql \
 	pg_stat_statements--1.5--1.6.sql pg_stat_statements--1.4--1.5.sql \
 	pg_stat_statements--1.3--1.4.sql pg_stat_statements--1.2--1.3.sql \
diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql b/contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql
new file mode 100644
index 0000000000..3d9768b158
--- /dev/null
+++ b/contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql
@@ -0,0 +1,12 @@
+/* contrib/pg_stat_statements/pg_stat_statements--1.8--1.9.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+
+\echo Use "ALTER EXTENSION pg_stat_statements UPDATE TO '1.9'" to load this file. \quit
+
+--- Define pg_stat_statements_reset_time
+
+CREATE FUNCTION pg_stat_statements_reset_time()
+RETURNS TIMESTAMP WITH TIME ZONE
+AS 'MODULE_PATHNAME'
+LANGUAGE C VOLATILE STRICT;
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 1eac9edaee..8639923f5b 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -81,6 +81,7 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/memutils.h"
+#include "utils/timestamp.h"
 
 PG_MODULE_MAGIC;
 
@@ -222,6 +223,7 @@ typedef struct pgssSharedState
 	Size		extent;			/* current extent of query file */
 	int			n_writers;		/* number of active writers to query file */
 	int			gc_count;		/* query file garbage collection cycle count */
+	TimestampTz reset_time;     /* timestamp with all stats reset */
 } pgssSharedState;
 
 /*
@@ -327,6 +329,7 @@ PG_FUNCTION_INFO_V1(pg_stat_statements_1_2);
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_3);
 PG_FUNCTION_INFO_V1(pg_stat_statements_1_8);
 PG_FUNCTION_INFO_V1(pg_stat_statements);
+PG_FUNCTION_INFO_V1(pg_stat_statements_reset_time);
 
 static void pgss_shmem_startup(void);
 static void pgss_shmem_shutdown(int code, Datum arg);
@@ -554,6 +557,7 @@ pgss_shmem_startup(void)
 		pgss->extent = 0;
 		pgss->n_writers = 0;
 		pgss->gc_count = 0;
+		pgss->reset_time = 0;
 	}
 
 	memset(&info, 0, sizeof(info));
@@ -673,6 +677,10 @@ pgss_shmem_startup(void)
 		entry->counters = temp.counters;
 	}
 
+	/* read timestamp when all stats were reseted */
+	if (fread(&pgss->reset_time, sizeof(TimestampTz), 1, file) != 1)
+		goto read_error;
+
 	pfree(buffer);
 	FreeFile(file);
 	FreeFile(qfile);
@@ -794,6 +802,10 @@ pgss_shmem_shutdown(int code, Datum arg)
 		}
 	}
 
+	/* store timestamp when all stats were reseted */
+	if (fwrite(&pgss->reset_time, sizeof(TimestampTz), 1, file) != 1)
+			goto error;
+
 	free(qbuffer);
 	qbuffer = NULL;
 
@@ -1483,6 +1495,18 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();
 }
 
+Datum pg_stat_statements_reset_time(PG_FUNCTION_ARGS)
+{
+	TimestampTz reset_ts;
+	{
+		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+		SpinLockAcquire(&s->mutex);
+		reset_ts = s->reset_time;
+		SpinLockRelease(&s->mutex);
+	}
+	PG_RETURN_TIMESTAMP(reset_ts);
+};
+
 /* Number of output arguments (columns) for various API versions */
 #define PG_STAT_STATEMENTS_COLS_V1_0	14
 #define PG_STAT_STATEMENTS_COLS_V1_1	18
@@ -2458,6 +2482,9 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	long		num_entries;
 	long		num_remove = 0;
 	pgssHashKey key;
+	TimestampTz reset_ts;
+
+	reset_ts = GetCurrentTimestamp();
 
 	if (!pgss || !pgss_hash)
 		ereport(ERROR,
@@ -2496,6 +2523,13 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	}
 	else
 	{
+		{
+			volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+			SpinLockAcquire(&s->mutex);
+			s->reset_time = reset_ts;
+			SpinLockRelease(&s->mutex);
+		}
+
 		/* Remove all entries. */
 		hash_seq_init(&hash_seq, pgss_hash);
 		while ((entry = hash_seq_search(&hash_seq)) != NULL)
diff --git a/contrib/pg_stat_statements/pg_stat_statements.control b/contrib/pg_stat_statements/pg_stat_statements.control
index 65b18b11d2..2f1ce6ed50 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.control
+++ b/contrib/pg_stat_statements/pg_stat_statements.control
@@ -1,5 +1,5 @@
 # pg_stat_statements extension
 comment = 'track planning and execution statistics of all SQL statements executed'
-default_version = '1.8'
+default_version = '1.9'
 module_pathname = '$libdir/pg_stat_statements'
 relocatable = true
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index cf2d25b7b2..d5a573dd70 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -24,9 +24,9 @@
    When <filename>pg_stat_statements</filename> is loaded, it tracks
    statistics across all databases of the server.  To access and manipulate
    these statistics, the module provides a view, <structname>pg_stat_statements</structname>,
-   and the utility functions <function>pg_stat_statements_reset</function> and
-   <function>pg_stat_statements</function>.  These are not available globally but
-   can be enabled for a specific database with
+   and the utility functions <function>pg_stat_statements_reset</function>, 
+   <function>pg_stat_statements</function>, and  <function>pg_stat_statements_reset_time</function>.  
+   These are not available globally but can be enabled for a specific database with
    <command>CREATE EXTENSION pg_stat_statements</command>.
  </para>
 
@@ -508,6 +508,22 @@
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+   <term>
+     <function>pg_stat_statements_reset_time(void) returns timestamp with time zone</function>
+     <indexterm>
+      <primary>pg_stat_statements_reset_time</primary>
+     </indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      this function shows the time at which <function>pg_stat_statements_reset(0,0,0)</function> was last called.
+     </para>
+    </listitem>
+
+   </varlistentry>
+
    <varlistentry>
     <term>
      <function>pg_stat_statements(showtext boolean) returns setof record</function>

Reply via email to