Feature improvement for pg_stat_statements

Started by btnakamichinover 5 years ago22 messages
#1btnakamichin
btnakamichin@oss.nttdata.com

Hello.

I’d like to improve pg_stat_statements so that it can report the
timestamp when the stats are reset. Currently it’s difficult to check
that reset timestamp. But this information is useful, for example, when
calculating the SQL executions per second by SELECT calls / (now() -
reset_timestamp) FROM pg_stat_statements.

I’m thinking of adding adding a function called
pg_stat_statements_reset_time() that returns the last timestamp when
executed pg_stat_statements_reset(). pg_stat_statements can reset each
SQL statement. We can record each sql reset timing timestamp but I don’t
feel the need. This time, I’m thinking of updating the reset timestamp
only when all stats were reset.

what do you think ?
Regards.

Naoki Nakamichi

#2Adam Brusselback
adambrusselback@gmail.com
In reply to: btnakamichin (#1)
Re: Feature improvement for pg_stat_statements

That'd be useful in my book. My scripts just have a hard coded timestamp I
replace when I call reset so those calculations work, but it would be much
preferred to have that data available by a built in function.

-Adam

#3Andres Freund
andres@anarazel.de
In reply to: btnakamichin (#1)
Re: Feature improvement for pg_stat_statements

Hi,

On 2020-09-18 17:55:12 +0900, btnakamichin wrote:

I’m thinking of adding adding a function called
pg_stat_statements_reset_time() that returns the last timestamp when
executed pg_stat_statements_reset(). pg_stat_statements can reset each SQL
statement. We can record each sql reset timing timestamp but I don’t feel
the need. This time, I’m thinking of updating the reset timestamp only when
all stats were reset.

What exactly do you mean by "can reset each SQL statement"? I don't
really see what alternative you're analyzing?

It does make sense to me to have a function returning the time of the
last reset.

Greetings,

Andres Freund

#4btnakamichin
btnakamichin@oss.nttdata.com
In reply to: Andres Freund (#3)
1 attachment(s)
Re: Feature improvement for pg_stat_statements

2020-09-22 04:58 に Andres Freund さんは書きました:

Hi,

On 2020-09-18 17:55:12 +0900, btnakamichin wrote:

I’m thinking of adding adding a function called
pg_stat_statements_reset_time() that returns the last timestamp when
executed pg_stat_statements_reset(). pg_stat_statements can reset each
SQL
statement. We can record each sql reset timing timestamp but I don’t
feel
the need. This time, I’m thinking of updating the reset timestamp only
when
all stats were reset.

What exactly do you mean by "can reset each SQL statement"? I don't
really see what alternative you're analyzing?

It does make sense to me to have a function returning the time of the
last reset.

Greetings,

Andres Freund

I’m Sorry, I forgot to include pgsql_hackers in the cc, so I resend it
and attach the patch.
Thank you, I appreciate your comment.

I am unfamiliar with this function. I’m sorry if my interpretation is
mistaken.

What exactly do you mean by "can reset each SQL statement"? I don't
really see what alternative you're analyzing?

pg_stat_statements_reset discards statistics gathered so far by
pg_stat_statements corresponding to the specified userid, dbid and
queryid.

If no parameter is specified or all the specified parameters are
0(invalid), it will discard all statistics.

I think that it is important to record timestamp discarding all
statistics so I’d like to add a function for only all stats were reset.

The following is an example of this feature.
postgres=# select * from pg_stat_statements_reset_time();
pg_stat_statements_reset_time
-------------------------------
2020-09-24 13:36:44.87005+09
(1 row)

Best regards,

Naoki Nakamichi

Attachments:

pg_stat_statements_reset_time.patchtext/x-diff; name=pg_stat_statements_reset_time.patchDownload
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..55cd5a3a63
--- /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;
\ No newline at end of file
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 1eac9edaee..f2e7fbda77 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -81,12 +81,12 @@
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/memutils.h"
+#include "utils/timestamp.h"
 
 PG_MODULE_MAGIC;
 
 /* Location of permanent stats file (valid when database is shut down) */
 #define PGSS_DUMP_FILE	PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"
-
 /*
  * Location of external query text file.  We don't keep it in the core
  * system's stats_temp_directory.  The core system can safely use that GUC
@@ -222,6 +222,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 +328,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 +556,7 @@ pgss_shmem_startup(void)
 		pgss->extent = 0;
 		pgss->n_writers = 0;
 		pgss->gc_count = 0;
+		pgss->reset_time = GetCurrentTimestamp();
 	}
 
 	memset(&info, 0, sizeof(info));
@@ -673,6 +676,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 +801,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 +1494,17 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
 	PG_RETURN_VOID();
 }
 
+Datum pg_stat_statements_reset_time(PG_FUNCTION_ARGS)
+{
+	TimestampTz reset_ts;
+
+	SpinLockAcquire(&pgss->mutex);
+	reset_ts = pgss->reset_time;
+	SpinLockRelease(&pgss->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
@@ -2496,6 +2518,10 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	}
 	else
 	{
+		SpinLockAcquire(&pgss->mutex);
+		pgss->reset_time = GetCurrentTimestamp();
+		SpinLockRelease(&pgss->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..3aa2ef3b4c 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -508,6 +508,22 @@
     </listitem>
    </varlistentry>
 
+   <varlistentry>
+   <term>
+     <function>pg_stat_statements_reset_time(void) returns time stamp with time zone</function>
+     <indexterm>
+      <primary>pg_stat_statements_reset_time</primary>
+     </indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      this function shows last reset time only when <function>pg_stat_statements_reset(0,0,0)</function> is called.
+     </para>
+    </listitem>
+
+   </varlistentry>
+
    <varlistentry>
     <term>
      <function>pg_stat_statements(showtext boolean) returns setof record</function>
#5Yuki Seino
seinoyu@oss.nttdata.com
In reply to: btnakamichin (#4)
Re: Feature improvement for pg_stat_statements

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, failed
Spec compliant: tested, passed
Documentation: tested, failed

The patch applies cleanly and looks fine to me.I'm going to list a few points that I think need to be fixed.

1.There are unnecessary difference lines 89 in "pg_stat_statements.c".
2.It is confusing that the initial value of reset_time is the current date and time, so why not set it to null?
3.How about pg_stat_statements_reset_time creates a view?
4.How about counting the number of resets?
5."pgstatstatstatements.sgml" would need to include the function name in the following section.
    -   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
    +   these statistics, the module provides views, <structname>pg_stat_statements</structname>
    +   and <structname>pg_stat_statements_ctl</structname>,
    +   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

It would be nice to be able to keep the timing of resetting the userid, dbid and queryid as well, but I think the status quo is appropriate for management in memory.

The new status of this patch is: Waiting on Author

#6Kyotaro Horiguchi
horikyota.ntt@gmail.com
In reply to: Yuki Seino (#5)
Re: Feature improvement for pg_stat_statements

At Fri, 16 Oct 2020 10:47:50 +0000, Yuki Seino <seinoyu@oss.nttdata.com> wrote in

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, failed
Spec compliant: tested, passed
Documentation: tested, failed

The patch applies cleanly and looks fine to me.I'm going to list a few points that I think need to be fixed.

1.There are unnecessary difference lines 89 in "pg_stat_statements.c".
2.It is confusing that the initial value of reset_time is the current date and time, so why not set it to null?
3.How about pg_stat_statements_reset_time creates a view?
4.How about counting the number of resets?
5."pgstatstatstatements.sgml" would need to include the function name in the following section.
-   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
+   these statistics, the module provides views, <structname>pg_stat_statements</structname>
+   and <structname>pg_stat_statements_ctl</structname>,
+   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

It would be nice to be able to keep the timing of resetting the userid, dbid and queryid as well, but I think the status quo is appropriate for management in memory.

The new status of this patch is: Waiting on Author

+ 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();

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

+ 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).

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#7Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Kyotaro Horiguchi (#6)
1 attachment(s)
Re: Feature improvement for pg_stat_statements

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.

Attachments:

pg_stat_statements_reset_time_v2.patchtext/x-diff; name=pg_stat_statements_reset_time_v2.patchDownload
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>
#8Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Seino Yuki (#7)
Re: Feature improvement for pg_stat_statements

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

#9Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Seino Yuki (#8)
Re: Feature improvement for pg_stat_statements

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Regards.

#10Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Seino Yuki (#9)
1 attachment(s)
Re: Feature improvement for pg_stat_statements

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

I forgot the attachment and will resend it.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Regards.

Attachments:

pg_stat_statements_info_reset-time.patchtext/x-diff; name=pg_stat_statements_info_reset-time.patchDownload
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
index 2019a4ffe0..21a4b6c36f 100644
--- 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
@@ -5,9 +5,10 @@
 
 --- Define pg_stat_statements_info
 CREATE FUNCTION pg_stat_statements_info(
-    OUT dealloc bigint
+    OUT dealloc bigint,
+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE
 )
-RETURNS bigint
+RETURNS record
 AS 'MODULE_PATHNAME'
 LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
 
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 70cfdb2c9d..fd90aab471 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;
 
@@ -199,6 +200,8 @@ typedef struct Counters
 typedef struct pgssGlobalStats
 {
 	int64		dealloc;		/* # of times entries were deallocated */
+	TimestampTz reset_exec_time;    		/* timestamp with all stats reset */
+	bool		reset_exec_time_isnull;		/* if true last_dealloc is null */
 } pgssGlobalStats;
 
 /*
@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
 		pgss->n_writers = 0;
 		pgss->gc_count = 0;
 		pgss->stats.dealloc = 0;
+		pgss->stats.reset_exec_time = 0;
+		pgss->stats.reset_exec_time_isnull = true;
 	}
 
 	memset(&info, 0, sizeof(info));
@@ -1510,6 +1515,7 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
 #define PG_STAT_STATEMENTS_COLS_V1_3	23
 #define PG_STAT_STATEMENTS_COLS_V1_8	32
 #define PG_STAT_STATEMENTS_COLS			32	/* maximum of above */
+#define PG_STAT_STATEMENTS_INFO_COLS	2
 
 /*
  * Retrieve statement statistics.
@@ -1889,7 +1895,17 @@ Datum
 pg_stat_statements_info(PG_FUNCTION_ARGS)
 {
 	pgssGlobalStats stats;
+	TupleDesc	tupdesc;
+	HeapTuple	result_tuple;
+	Datum 		values[PG_STAT_STATEMENTS_INFO_COLS];
+	bool 		nulls[PG_STAT_STATEMENTS_INFO_COLS];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	tupdesc = BlessTupleDesc(tupdesc);
 
+	memset(nulls, 0, sizeof(nulls));
 	/* Read global statistics for pg_stat_statements */
 	{
 		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
@@ -1899,7 +1915,17 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 		SpinLockRelease(&s->mutex);
 	}
 
-	PG_RETURN_INT64(stats.dealloc);
+	/* Read dealloc */
+	values[0] = stats.dealloc;
+
+	/* Read reset_exec_time */
+	if (!stats.reset_exec_time_isnull)
+		values[1] = stats.reset_exec_time;
+	else
+		nulls[1] = true;
+
+	result_tuple = heap_form_tuple(tupdesc, values, nulls);
+	return HeapTupleGetDatum(result_tuple);
 }
 
 /*
@@ -2507,6 +2533,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,
@@ -2559,6 +2588,8 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 
 			SpinLockAcquire(&s->mutex);
 			s->stats.dealloc = 0;
+			s->stats.reset_exec_time = reset_ts;	/* reset execution time */
+			s->stats.reset_exec_time_isnull = false;
 			SpinLockRelease(&s->mutex);
 		}
 	}
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index 81915ea69b..821ae1f96e 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -523,6 +523,15 @@
        <varname>pg_stat_statements.max</varname> were observed
       </para></entry>
      </row>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>reset_exec_time</structfield> <type>timestamp with time zone</type>
+      </para>
+      <para>
+        Shows the time at which <function>pg_stat_statements_reset(0,0,0)</function> was last called.
+      </para></entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
#11Fujii Masao
masao.fujii@oss.nttdata.com
In reply to: Seino Yuki (#10)
Re: Feature improvement for pg_stat_statements

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

I forgot the attachment and will resend it.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Thanks for updating the patch! Here are review comments from me.

+ OUT reset_exec_time TIMESTAMP WITH TIME ZONE

I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.

Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?

@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
  		pgss->n_writers = 0;
  		pgss->gc_count = 0;
  		pgss->stats.dealloc = 0;
+		pgss->stats.reset_exec_time = 0;
+		pgss->stats.reset_exec_time_isnull = true;

The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of reset_exec_time_isnull.

+ memset(nulls, 0, sizeof(nulls));

If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.

MemSet() should be used, instead?

+ /* Read dealloc */
+ values[0] = stats.dealloc;

Int64GetDatum() should be used here?

+ reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION

#12Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Fujii Masao (#11)
1 attachment(s)
Re: Feature improvement for pg_stat_statements

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in
the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

I forgot the attachment and will resend it.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Thanks for updating the patch! Here are review comments from me.

+ OUT reset_exec_time TIMESTAMP WITH TIME ZONE

I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.

Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?

@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
pgss->n_writers = 0;
pgss->gc_count = 0;
pgss->stats.dealloc = 0;
+		pgss->stats.reset_exec_time = 0;
+		pgss->stats.reset_exec_time_isnull = true;

The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of
reset_exec_time_isnull.

+ memset(nulls, 0, sizeof(nulls));

If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.

MemSet() should be used, instead?

+ /* Read dealloc */
+ values[0] = stats.dealloc;

Int64GetDatum() should be used here?

+ reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Regards,

Thanks for the review!
Fixed the patch.

I learned a lot, especially since I didn't know about MemSet().

Regards.

Attachments:

pg_stat_statements_info_reset-time_v2.patchtext/x-diff; name=pg_stat_statements_info_reset-time_v2.patchDownload
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
index 2019a4ffe0..3504ca7eb1 100644
--- 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
@@ -5,9 +5,10 @@
 
 --- Define pg_stat_statements_info
 CREATE FUNCTION pg_stat_statements_info(
-    OUT dealloc bigint
+    OUT dealloc bigint,
+    OUT stats_reset timestamp with time zone
 )
-RETURNS bigint
+RETURNS record
 AS 'MODULE_PATHNAME'
 LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
 
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 70cfdb2c9d..e90cd24f20 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;
 
@@ -199,6 +200,7 @@ typedef struct Counters
 typedef struct pgssGlobalStats
 {
 	int64		dealloc;		/* # of times entries were deallocated */
+	TimestampTz stats_reset;    		/* timestamp with all stats reset */
 } pgssGlobalStats;
 
 /*
@@ -565,6 +567,7 @@ pgss_shmem_startup(void)
 		pgss->n_writers = 0;
 		pgss->gc_count = 0;
 		pgss->stats.dealloc = 0;
+		pgss->stats.stats_reset = GetCurrentTimestamp();
 	}
 
 	memset(&info, 0, sizeof(info));
@@ -1510,6 +1513,7 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
 #define PG_STAT_STATEMENTS_COLS_V1_3	23
 #define PG_STAT_STATEMENTS_COLS_V1_8	32
 #define PG_STAT_STATEMENTS_COLS			32	/* maximum of above */
+#define PG_STAT_STATEMENTS_INFO_COLS	2
 
 /*
  * Retrieve statement statistics.
@@ -1889,7 +1893,18 @@ Datum
 pg_stat_statements_info(PG_FUNCTION_ARGS)
 {
 	pgssGlobalStats stats;
+	TupleDesc	tupdesc;
+	HeapTuple	result_tuple;
+	Datum 		values[PG_STAT_STATEMENTS_INFO_COLS];
+	bool 		nulls[PG_STAT_STATEMENTS_INFO_COLS];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
+	tupdesc = BlessTupleDesc(tupdesc);
+
+	MemSet(values, 0, sizeof(values));
+	MemSet(nulls, 0, sizeof(nulls));
 	/* Read global statistics for pg_stat_statements */
 	{
 		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
@@ -1899,7 +1914,14 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 		SpinLockRelease(&s->mutex);
 	}
 
-	PG_RETURN_INT64(stats.dealloc);
+	/* Read dealloc */
+	values[0] = Int64GetDatum(stats.dealloc);
+
+	/* Read stats_reset */
+	values[1] = stats.stats_reset;
+
+	result_tuple = heap_form_tuple(tupdesc, values, nulls);
+	return HeapTupleGetDatum(result_tuple);
 }
 
 /*
@@ -2507,6 +2529,7 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	long		num_entries;
 	long		num_remove = 0;
 	pgssHashKey key;
+	TimestampTz reset_ts;
 
 	if (!pgss || !pgss_hash)
 		ereport(ERROR,
@@ -2553,12 +2576,14 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 			num_remove++;
 		}
 
+		reset_ts = GetCurrentTimestamp();
 		/* Reset global statistics for pg_stat_statements */
 		{
 			volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
 
 			SpinLockAcquire(&s->mutex);
 			s->stats.dealloc = 0;
+			s->stats.stats_reset = reset_ts;	/* reset execution time */
 			SpinLockRelease(&s->mutex);
 		}
 	}
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index 81915ea69b..821ae1f96e 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -523,6 +523,15 @@
        <varname>pg_stat_statements.max</varname> were observed
       </para></entry>
      </row>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>reset_exec_time</structfield> <type>timestamp with time zone</type>
+      </para>
+      <para>
+        Shows the time at which <function>pg_stat_statements_reset(0,0,0)</function> was last called.
+      </para></entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
#13Fujii Masao
masao.fujii@oss.nttdata.com
In reply to: Seino Yuki (#12)
Re: Feature improvement for pg_stat_statements

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

I forgot the attachment and will resend it.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Thanks for updating the patch! Here are review comments from me.

+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE

I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.

Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?

@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;

The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of reset_exec_time_isnull.

+    memset(nulls, 0, sizeof(nulls));

If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.

MemSet() should be used, instead?

+    /* Read dealloc */
+    values[0] = stats.dealloc;

Int64GetDatum() should be used here?

+    reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.

+ <structfield>reset_exec_time</structfield> <type>timestamp with time zone</type>

You forgot to update the column name in the doc?

+ Shows the time at which <function>pg_stat_statements_reset(0,0,0)</function> was last called.

What about updating this to something like "Time at which all statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?

+ /* Read stats_reset */
+ values[1] = stats.stats_reset;

TimestampTzGetDatum() seems necessary.

+ reset_ts = GetCurrentTimestamp();
/* Reset global statistics for pg_stat_statements */

Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION

#14Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Fujii Masao (#13)
Re: Feature improvement for pg_stat_statements

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in
the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

I forgot the attachment and will resend it.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Thanks for updating the patch! Here are review comments from me.

+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE

I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.

Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?

@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;

The reset time should be initialized with GetCurrentTimestamp()
instead
of 0? If so, I think that we can completely get rid of
reset_exec_time_isnull.

+    memset(nulls, 0, sizeof(nulls));

If some entries in "values[]" may not be set, "values[]" also needs
to
be initialized with 0.

MemSet() should be used, instead?

+    /* Read dealloc */
+    values[0] = stats.dealloc;

Int64GetDatum() should be used here?

+    reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.

+ <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>

You forgot to update the column name in the doc?

+ Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last called.

What about updating this to something like "Time at which all
statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?

+ /* Read stats_reset */
+ values[1] = stats.stats_reset;

TimestampTzGetDatum() seems necessary.

+ reset_ts = GetCurrentTimestamp();
/* Reset global statistics for pg_stat_statements */

Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?

Regards,

Thanks for the new comment.

I got the following pointers earlier.

+ reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is better,
because entry_reset is not likely to be called often.

Regards.

#15Fujii Masao
masao.fujii@oss.nttdata.com
In reply to: Seino Yuki (#14)
Re: Feature improvement for pg_stat_statements

On 2020/11/30 23:05, Seino Yuki wrote:

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

I forgot the attachment and will resend it.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Thanks for updating the patch! Here are review comments from me.

+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE

I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.

Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?

@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;

The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of reset_exec_time_isnull.

+    memset(nulls, 0, sizeof(nulls));

If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.

MemSet() should be used, instead?

+    /* Read dealloc */
+    values[0] = stats.dealloc;

Int64GetDatum() should be used here?

+    reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.

+       <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>

You forgot to update the column name in the doc?

+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last called.

What about updating this to something like "Time at which all statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?

+    /* Read stats_reset */
+    values[1] = stats.stats_reset;

TimestampTzGetDatum() seems necessary.

+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */

Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?

Regards,

Thanks for the new comment.

I got the following pointers earlier.

+    reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is better,
because entry_reset is not likely to be called often.

I was thinking that GetCurrentTimestamp() should be called before pgss->lock lwlock is taken, only when all three arguments userid, dbid and queryid are zero. But on second thought, we should call GetCurrentTimestamp() and reset the stats, after the following codes?

/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;

That is, IMO that even when pg_stat_statements_reset() with non-zero arguments is executed, if it removes all the entries, we should reset the stats. Thought?

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION

#16Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Fujii Masao (#15)
1 attachment(s)
Re: Feature improvement for pg_stat_statements

2020-12-01 01:04 に Fujii Masao さんは書きました:

On 2020/11/30 23:05, Seino Yuki wrote:

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed
in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.

Regards.

I forgot the attachment and will resend it.

The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/

Please confirm.

Thanks for updating the patch! Here are review comments from me.

+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE

I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.

Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?

@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;

The reset time should be initialized with GetCurrentTimestamp()
instead
of 0? If so, I think that we can completely get rid of
reset_exec_time_isnull.

+    memset(nulls, 0, sizeof(nulls));

If some entries in "values[]" may not be set, "values[]" also needs
to
be initialized with 0.

MemSet() should be used, instead?

+    /* Read dealloc */
+    values[0] = stats.dealloc;

Int64GetDatum() should be used here?

+    reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.

+       <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>

You forgot to update the column name in the doc?

+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last called.

What about updating this to something like "Time at which all
statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?

+    /* Read stats_reset */
+    values[1] = stats.stats_reset;

TimestampTzGetDatum() seems necessary.

+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */

Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?

Regards,

Thanks for the new comment.

I got the following pointers earlier.

+    reset_ts = GetCurrentTimestamp();

GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is better,
because entry_reset is not likely to be called often.

I was thinking that GetCurrentTimestamp() should be called before
pgss->lock lwlock is taken, only when all three arguments userid, dbid
and queryid are zero. But on second thought, we should call
GetCurrentTimestamp() and reset the stats, after the following codes?

/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;

That is, IMO that even when pg_stat_statements_reset() with non-zero
arguments is executed, if it removes all the entries, we should reset
the stats. Thought?

Regards,

+1.Fixed the patch.
We tested various reset patterns and they seemed to be fine.

Regards.

Attachments:

pg_stat_statements_info_reset-time_v3.patchtext/x-diff; name=pg_stat_statements_info_reset-time_v3.patchDownload
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
index 2019a4ffe0..3504ca7eb1 100644
--- 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
@@ -5,9 +5,10 @@
 
 --- Define pg_stat_statements_info
 CREATE FUNCTION pg_stat_statements_info(
-    OUT dealloc bigint
+    OUT dealloc bigint,
+    OUT stats_reset timestamp with time zone
 )
-RETURNS bigint
+RETURNS record
 AS 'MODULE_PATHNAME'
 LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
 
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 70cfdb2c9d..0656308040 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;
 
@@ -199,6 +200,7 @@ typedef struct Counters
 typedef struct pgssGlobalStats
 {
 	int64		dealloc;		/* # of times entries were deallocated */
+	TimestampTz stats_reset;    		/* timestamp with all stats reset */
 } pgssGlobalStats;
 
 /*
@@ -565,6 +567,7 @@ pgss_shmem_startup(void)
 		pgss->n_writers = 0;
 		pgss->gc_count = 0;
 		pgss->stats.dealloc = 0;
+		pgss->stats.stats_reset = GetCurrentTimestamp();
 	}
 
 	memset(&info, 0, sizeof(info));
@@ -1510,6 +1513,7 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
 #define PG_STAT_STATEMENTS_COLS_V1_3	23
 #define PG_STAT_STATEMENTS_COLS_V1_8	32
 #define PG_STAT_STATEMENTS_COLS			32	/* maximum of above */
+#define PG_STAT_STATEMENTS_INFO_COLS	2
 
 /*
  * Retrieve statement statistics.
@@ -1889,7 +1893,18 @@ Datum
 pg_stat_statements_info(PG_FUNCTION_ARGS)
 {
 	pgssGlobalStats stats;
+	TupleDesc	tupdesc;
+	HeapTuple	result_tuple;
+	Datum 		values[PG_STAT_STATEMENTS_INFO_COLS];
+	bool 		nulls[PG_STAT_STATEMENTS_INFO_COLS];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	tupdesc = BlessTupleDesc(tupdesc);
 
+	MemSet(values, 0, sizeof(values));
+	MemSet(nulls, 0, sizeof(nulls));
 	/* Read global statistics for pg_stat_statements */
 	{
 		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
@@ -1899,7 +1914,14 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 		SpinLockRelease(&s->mutex);
 	}
 
-	PG_RETURN_INT64(stats.dealloc);
+	/* Read dealloc */
+	values[0] = Int64GetDatum(stats.dealloc);
+
+	/* Read stats_reset */
+	values[1] = TimestampTzGetDatum(stats.stats_reset);
+
+	result_tuple = heap_form_tuple(tupdesc, values, nulls);
+	return HeapTupleGetDatum(result_tuple);
 }
 
 /*
@@ -2507,6 +2529,7 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	long		num_entries;
 	long		num_remove = 0;
 	pgssHashKey key;
+	TimestampTz reset_ts;
 
 	if (!pgss || !pgss_hash)
 		ereport(ERROR,
@@ -2566,7 +2589,17 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	/* All entries are removed? */
 	if (num_entries != num_remove)
 		goto release_lock;
+	
+	reset_ts = GetCurrentTimestamp();
+	/* Reset global statistics for pg_stat_statements */
+	{
+		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
 
+		SpinLockAcquire(&s->mutex);
+		s->stats.stats_reset = reset_ts;	/* reset execution time */
+		SpinLockRelease(&s->mutex);
+	}
+	
 	/*
 	 * Write new empty query file, perhaps even creating a new one to recover
 	 * if the file was missing.
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index 81915ea69b..56e9147b32 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -523,6 +523,15 @@
        <varname>pg_stat_statements.max</varname> were observed
       </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 all statistics in the pg_stat_statements view were last reset.
+      </para></entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
#17Li Japin
japinli@hotmail.com
In reply to: Seino Yuki (#16)
Re: Feature improvement for pg_stat_statements

Hi,

On Dec 9, 2020, at 6:37 PM, Seino Yuki <seinoyu@oss.nttdata.com<mailto:seinoyu@oss.nttdata.com>> wrote:

2020-12-01 01:04 に Fujii Masao さんは書きました:
On 2020/11/30 23:05, Seino Yuki wrote:
2020-11-30 15:02 に Fujii Masao さんは書きました:
On 2020/11/30 12:08, Seino Yuki wrote:
2020-11-27 22:39 に Fujii Masao さんは書きました:
On 2020/11/27 21:39, Seino Yuki wrote:
2020-11-27 21:37 に Seino Yuki さんは書きました:
2020-11-16 12:28 に Seino Yuki さんは書きました:
Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
The patch is posted on the 2736 side of the thread.
Regards.
I forgot the attachment and will resend it.
The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/
Please confirm.
Thanks for updating the patch! Here are review comments from me.
+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE
I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.
Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?
@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;
The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of reset_exec_time_isnull.
+    memset(nulls, 0, sizeof(nulls));
If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.
MemSet() should be used, instead?
+    /* Read dealloc */
+    values[0] = stats.dealloc;
Int64GetDatum() should be used here?
+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.
Regards,
Thanks for the review!
Fixed the patch.
Thanks for updating the patch! Here are another review comments.
+       <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>
You forgot to update the column name in the doc?
+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last called.
What about updating this to something like "Time at which all statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?
+    /* Read stats_reset */
+    values[1] = stats.stats_reset;
TimestampTzGetDatum() seems necessary.
+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */
Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?
Regards,
Thanks for the new comment.
I got the following pointers earlier.
+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.
Which do you think is better? I think the new pointing out is better,
because entry_reset is not likely to be called often.
I was thinking that GetCurrentTimestamp() should be called before
pgss->lock lwlock is taken, only when all three arguments userid, dbid
and queryid are zero. But on second thought, we should call
GetCurrentTimestamp() and reset the stats, after the following codes?
/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;
That is, IMO that even when pg_stat_statements_reset() with non-zero
arguments is executed, if it removes all the entries, we should reset
the stats. Thought?
Regards,

+1.Fixed the patch.
We tested various reset patterns and they seemed to be fine.

Since BlessTupleDesc() is for SRFs according to the comments, I think, we can
remove it here. Correct?

+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       tupdesc = BlessTupleDesc(tupdesc);

--
Best regards
ChengDu WenWu Information Technology Co.,Ltd.
Japin Li

#18Fujii Masao
masao.fujii@oss.nttdata.com
In reply to: Li Japin (#17)
Re: Feature improvement for pg_stat_statements

On 2020/12/09 20:42, Li Japin wrote:

Hi,

On Dec 9, 2020, at 6:37 PM, Seino Yuki <seinoyu@oss.nttdata.com <mailto:seinoyu@oss.nttdata.com>> wrote:

2020-12-01 01:04 に Fujii Masao さんは書きました:

On 2020/11/30 23:05, Seino Yuki wrote:

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/ <https://commitfest.postgresql.org/30/2736/&gt;
The patch is posted on the 2736 side of the thread.
Regards.

I forgot the attachment and will resend it.
The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/ <https://commitfest.postgresql.org/30/2736/&gt;
Please confirm.

Thanks for updating the patch! Here are review comments from me.
+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE
I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.
Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?
@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;
The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of reset_exec_time_isnull.
+    memset(nulls, 0, sizeof(nulls));
If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.
MemSet() should be used, instead?
+    /* Read dealloc */
+    values[0] = stats.dealloc;
Int64GetDatum() should be used here?
+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.
Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.
+       <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>
You forgot to update the column name in the doc?
+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last called.
What about updating this to something like "Time at which all statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?
+    /* Read stats_reset */
+    values[1] = stats.stats_reset;
TimestampTzGetDatum() seems necessary.
+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */
Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?
Regards,

Thanks for the new comment.
I got the following pointers earlier.

+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is better,
because entry_reset is not likely to be called often.

I was thinking that GetCurrentTimestamp() should be called before
pgss->lock lwlock is taken, only when all three arguments userid, dbid
and queryid are zero. But on second thought, we should call
GetCurrentTimestamp() and reset the stats, after the following codes?
/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;
That is, IMO that even when pg_stat_statements_reset() with non-zero
arguments is executed, if it removes all the entries, we should reset
the stats. Thought?
Regards,

+1.Fixed the patch.
We tested various reset patterns and they seemed to be fine.

Since BlessTupleDesc() is for SRFs according to the comments, I think, we can
remove it here.  Correct?

+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       tupdesc = BlessTupleDesc(tupdesc);

Here are other comments from me:

The patch seems to contain whitespace errors.
You can see them by "git diff --check".

+      <para>
+        Time at which all statistics in the pg_stat_statements view were last reset.
+      </para></entry>

"pg_stat_statements" in the above should be enclosed with
<structname> and </structname>.

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION

#19Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Fujii Masao (#18)
1 attachment(s)
Re: Feature improvement for pg_stat_statements

2020-12-09 21:14 に Fujii Masao さんは書きました:

On 2020/12/09 20:42, Li Japin wrote:

Hi,

On Dec 9, 2020, at 6:37 PM, Seino Yuki <seinoyu@oss.nttdata.com
<mailto:seinoyu@oss.nttdata.com>> wrote:

2020-12-01 01:04 に Fujii Masao さんは書きました:

On 2020/11/30 23:05, Seino Yuki wrote:

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches
discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
<https://commitfest.postgresql.org/30/2736/&gt;
The patch is posted on the 2736 side of the thread.
Regards.

I forgot the attachment and will resend it.
The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/
<https://commitfest.postgresql.org/30/2736/&gt;
Please confirm.

Thanks for updating the patch! Here are review comments from me.
+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE
I prefer "stats_reset" as the name of this column for the sake 
of
consistency with the similar column in other stats views like
pg_stat_database.
Isn't it better to use lower cases for "TIMESTAMP WITH TIME 
ZONE"
because other DDLs in pg_stat_statements do that for the 
declaraion
of data type?
@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;
The reset time should be initialized with GetCurrentTimestamp() 
instead
of 0? If so, I think that we can completely get rid of 
reset_exec_time_isnull.
+    memset(nulls, 0, sizeof(nulls));
If some entries in "values[]" may not be set, "values[]" also 
needs to
be initialized with 0.
MemSet() should be used, instead?
+    /* Read dealloc */
+    values[0] = stats.dealloc;
Int64GetDatum() should be used here?
+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the 
entries
are removed. But it's called even in other cases.
Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.
+       <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>
You forgot to update the column name in the doc?
+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last 
called.
What about updating this to something like "Time at which all 
statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?
+    /* Read stats_reset */
+    values[1] = stats.stats_reset;
TimestampTzGetDatum() seems necessary.
+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */
Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?
Regards,

Thanks for the new comment.
I got the following pointers earlier.

+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is
better,
because entry_reset is not likely to be called often.

I was thinking that GetCurrentTimestamp() should be called before
pgss->lock lwlock is taken, only when all three arguments userid,
dbid
and queryid are zero. But on second thought, we should call
GetCurrentTimestamp() and reset the stats, after the following
codes?
/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;
That is, IMO that even when pg_stat_statements_reset() with non-zero
arguments is executed, if it removes all the entries, we should
reset
the stats. Thought?
Regards,

+1.Fixed the patch.
We tested various reset patterns and they seemed to be fine.

Since BlessTupleDesc() is for SRFs according to the comments, I think,
we can
remove it here.  Correct?

+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != 
TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       tupdesc = BlessTupleDesc(tupdesc);

Here are other comments from me:

The patch seems to contain whitespace errors.
You can see them by "git diff --check".

+      <para>
+        Time at which all statistics in the pg_stat_statements view
were last reset.
+      </para></entry>

"pg_stat_statements" in the above should be enclosed with
<structname> and </structname>.

Regards,

Thank you for your comments, Mr. Fujii and Mr. Li.
I've posted a patch reflecting your comments.
Please check it out.

Attachments:

pg_stat_statements_info_reset-time_v4.patchtext/x-diff; name=pg_stat_statements_info_reset-time_v4.patchDownload
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
index 2019a4ffe0..3504ca7eb1 100644
--- 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
@@ -5,9 +5,10 @@
 
 --- Define pg_stat_statements_info
 CREATE FUNCTION pg_stat_statements_info(
-    OUT dealloc bigint
+    OUT dealloc bigint,
+    OUT stats_reset timestamp with time zone
 )
-RETURNS bigint
+RETURNS record
 AS 'MODULE_PATHNAME'
 LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
 
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 70cfdb2c9d..96b8d0135b 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;
 
@@ -199,6 +200,7 @@ typedef struct Counters
 typedef struct pgssGlobalStats
 {
 	int64		dealloc;		/* # of times entries were deallocated */
+	TimestampTz stats_reset;    		/* timestamp with all stats reset */
 } pgssGlobalStats;
 
 /*
@@ -565,6 +567,7 @@ pgss_shmem_startup(void)
 		pgss->n_writers = 0;
 		pgss->gc_count = 0;
 		pgss->stats.dealloc = 0;
+		pgss->stats.stats_reset = GetCurrentTimestamp();
 	}
 
 	memset(&info, 0, sizeof(info));
@@ -1510,6 +1513,7 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
 #define PG_STAT_STATEMENTS_COLS_V1_3	23
 #define PG_STAT_STATEMENTS_COLS_V1_8	32
 #define PG_STAT_STATEMENTS_COLS			32	/* maximum of above */
+#define PG_STAT_STATEMENTS_INFO_COLS	2
 
 /*
  * Retrieve statement statistics.
@@ -1889,7 +1893,16 @@ Datum
 pg_stat_statements_info(PG_FUNCTION_ARGS)
 {
 	pgssGlobalStats stats;
+	TupleDesc	tupdesc;
+	HeapTuple	result_tuple;
+	Datum 		values[PG_STAT_STATEMENTS_INFO_COLS];
+	bool 		nulls[PG_STAT_STATEMENTS_INFO_COLS];
+
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
 
+	MemSet(values, 0, sizeof(values));
+	MemSet(nulls, 0, sizeof(nulls));
 	/* Read global statistics for pg_stat_statements */
 	{
 		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
@@ -1899,7 +1912,14 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 		SpinLockRelease(&s->mutex);
 	}
 
-	PG_RETURN_INT64(stats.dealloc);
+	/* Read dealloc */
+	values[0] = Int64GetDatum(stats.dealloc);
+
+	/* Read stats_reset */
+	values[1] = TimestampTzGetDatum(stats.stats_reset);
+
+	result_tuple = heap_form_tuple(tupdesc, values, nulls);
+	return HeapTupleGetDatum(result_tuple);
 }
 
 /*
@@ -2507,6 +2527,7 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	long		num_entries;
 	long		num_remove = 0;
 	pgssHashKey key;
+	TimestampTz reset_ts;
 
 	if (!pgss || !pgss_hash)
 		ereport(ERROR,
@@ -2567,6 +2588,16 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 	if (num_entries != num_remove)
 		goto release_lock;
 
+	reset_ts = GetCurrentTimestamp();
+	/* Reset global statistics for pg_stat_statements */
+	{
+		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+
+		SpinLockAcquire(&s->mutex);
+		s->stats.stats_reset = reset_ts;	/* reset execution time */
+		SpinLockRelease(&s->mutex);
+	}
+
 	/*
 	 * Write new empty query file, perhaps even creating a new one to recover
 	 * if the file was missing.
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index 81915ea69b..e314b99eea 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -523,6 +523,16 @@
        <varname>pg_stat_statements.max</varname> were observed
       </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 all statistics in the <structname>pg_stat_statements
+       </structname> view were last reset.
+      </para></entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
#20Fujii Masao
masao.fujii@oss.nttdata.com
In reply to: Seino Yuki (#19)
1 attachment(s)
Re: Feature improvement for pg_stat_statements

On 2020/12/14 18:17, Seino Yuki wrote:

2020-12-09 21:14 に Fujii Masao さんは書きました:

On 2020/12/09 20:42, Li Japin wrote:

Hi,

On Dec 9, 2020, at 6:37 PM, Seino Yuki <seinoyu@oss.nttdata.com <mailto:seinoyu@oss.nttdata.com>> wrote:

2020-12-01 01:04 に Fujii Masao さんは書きました:

On 2020/11/30 23:05, Seino Yuki wrote:

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/ <https://commitfest.postgresql.org/30/2736/&gt;
The patch is posted on the 2736 side of the thread.
Regards.

I forgot the attachment and will resend it.
The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/ <https://commitfest.postgresql.org/30/2736/&gt;
Please confirm.

Thanks for updating the patch! Here are review comments from me.
+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE
I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.
Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?
@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;
The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of reset_exec_time_isnull.
+    memset(nulls, 0, sizeof(nulls));
If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.
MemSet() should be used, instead?
+    /* Read dealloc */
+    values[0] = stats.dealloc;
Int64GetDatum() should be used here?
+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.
Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.
+       <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>
You forgot to update the column name in the doc?
+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last called.
What about updating this to something like "Time at which all statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?
+    /* Read stats_reset */
+    values[1] = stats.stats_reset;
TimestampTzGetDatum() seems necessary.
+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */
Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?
Regards,

Thanks for the new comment.
I got the following pointers earlier.

+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is better,
because entry_reset is not likely to be called often.

I was thinking that GetCurrentTimestamp() should be called before
pgss->lock lwlock is taken, only when all three arguments userid, dbid
and queryid are zero. But on second thought, we should call
GetCurrentTimestamp() and reset the stats, after the following codes?
/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;
That is, IMO that even when pg_stat_statements_reset() with non-zero
arguments is executed, if it removes all the entries, we should reset
the stats. Thought?
Regards,

+1.Fixed the patch.
We tested various reset patterns and they seemed to be fine.

Since BlessTupleDesc() is for SRFs according to the comments, I think, we can
remove it here.  Correct?

+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       tupdesc = BlessTupleDesc(tupdesc);

Here are other comments from me:

The patch seems to contain whitespace errors.
You can see them by "git diff --check".

+      <para>
+        Time at which all statistics in the pg_stat_statements view
were last reset.
+      </para></entry>

"pg_stat_statements" in the above should be enclosed with
<structname> and </structname>.

Regards,

Thank you for your comments, Mr. Fujii and Mr. Li.
I've posted a patch reflecting your comments.
Please check it out.

Thanks for updating the patch!

+	reset_ts = GetCurrentTimestamp();
+	/* Reset global statistics for pg_stat_statements */
+	{
+		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+
+		SpinLockAcquire(&s->mutex);
+		s->stats.stats_reset = reset_ts;	/* reset execution time */
+		SpinLockRelease(&s->mutex);

This code makes me think that "dealloc" field also should be reset at the same time together, i.e., whenever all entries are removed. Otherwise, even when pg_stat_statements_reset() with non-zero arguments discards all statistics, "dealloc" field in pg_stat_statements_info is not reset. Only pg_stat_statements_reset(0, 0, 0) resets "dealloc" field. That seems confusing. Thought?

I updated the patch so that "dealloc" field is also reset whenever all entries are removed. Attached is the updated version of the patch.

+	result_tuple = heap_form_tuple(tupdesc, values, nulls);
+	return HeapTupleGetDatum(result_tuple);

Isn't it better to use PG_RETURN_DATUM() here, instead? I applied this change to the patch.

I also applied some cosmetic changes to the patch. Could you review this version?

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION

Attachments:

pg_stat_statements_info_reset-time_v5.patchtext/plain; charset=UTF-8; name=pg_stat_statements_info_reset-time_v5.patch; x-mac-creator=0; x-mac-type=0Download
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
index 2019a4ffe0..3504ca7eb1 100644
--- 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
@@ -5,9 +5,10 @@
 
 --- Define pg_stat_statements_info
 CREATE FUNCTION pg_stat_statements_info(
-    OUT dealloc bigint
+    OUT dealloc bigint,
+    OUT stats_reset timestamp with time zone
 )
-RETURNS bigint
+RETURNS record
 AS 'MODULE_PATHNAME'
 LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
 
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 70cfdb2c9d..844f4ea808 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;
 
@@ -98,7 +99,7 @@ PG_MODULE_MAGIC;
 #define PGSS_TEXT_FILE	PG_STAT_TMP_DIR "/pgss_query_texts.stat"
 
 /* Magic number identifying the stats file format */
-static const uint32 PGSS_FILE_HEADER = 0x20201126;
+static const uint32 PGSS_FILE_HEADER = 0x20201214;
 
 /* PostgreSQL major version number, changes in which invalidate all entries */
 static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
@@ -199,6 +200,7 @@ typedef struct Counters
 typedef struct pgssGlobalStats
 {
 	int64		dealloc;		/* # of times entries were deallocated */
+	TimestampTz stats_reset;	/* timestamp with all stats reset */
 } pgssGlobalStats;
 
 /*
@@ -565,6 +567,7 @@ pgss_shmem_startup(void)
 		pgss->n_writers = 0;
 		pgss->gc_count = 0;
 		pgss->stats.dealloc = 0;
+		pgss->stats.stats_reset = GetCurrentTimestamp();
 	}
 
 	memset(&info, 0, sizeof(info));
@@ -1882,6 +1885,9 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
 	tuplestore_donestoring(tupstore);
 }
 
+/* Number of output arguments (columns) for pg_stat_statements_info */
+#define PG_STAT_STATEMENTS_INFO_COLS	2
+
 /*
  * Return statistics of pg_stat_statements.
  */
@@ -1889,6 +1895,16 @@ Datum
 pg_stat_statements_info(PG_FUNCTION_ARGS)
 {
 	pgssGlobalStats stats;
+	TupleDesc	tupdesc;
+	Datum		values[PG_STAT_STATEMENTS_INFO_COLS];
+	bool		nulls[PG_STAT_STATEMENTS_INFO_COLS];
+
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	MemSet(values, 0, sizeof(values));
+	MemSet(nulls, 0, sizeof(nulls));
 
 	/* Read global statistics for pg_stat_statements */
 	{
@@ -1899,7 +1915,10 @@ pg_stat_statements_info(PG_FUNCTION_ARGS)
 		SpinLockRelease(&s->mutex);
 	}
 
-	PG_RETURN_INT64(stats.dealloc);
+	values[0] = Int64GetDatum(stats.dealloc);
+	values[1] = TimestampTzGetDatum(stats.stats_reset);
+
+	PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
 }
 
 /*
@@ -2552,21 +2571,26 @@ entry_reset(Oid userid, Oid dbid, uint64 queryid)
 			hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
 			num_remove++;
 		}
-
-		/* Reset global statistics for pg_stat_statements */
-		{
-			volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
-
-			SpinLockAcquire(&s->mutex);
-			s->stats.dealloc = 0;
-			SpinLockRelease(&s->mutex);
-		}
 	}
 
 	/* All entries are removed? */
 	if (num_entries != num_remove)
 		goto release_lock;
 
+	/*
+	 * Reset global statistics for pg_stat_statements since all entries are
+	 * removed.
+	 */
+	{
+		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+		TimestampTz stats_reset = GetCurrentTimestamp();
+
+		SpinLockAcquire(&s->mutex);
+		s->stats.dealloc = 0;
+		s->stats.stats_reset = stats_reset;
+		SpinLockRelease(&s->mutex);
+	}
+
 	/*
 	 * Write new empty query file, perhaps even creating a new one to recover
 	 * if the file was missing.
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index 81915ea69b..126ee31d9f 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -523,6 +523,16 @@
        <varname>pg_stat_statements.max</varname> were observed
       </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 all statistics in the
+       <structname>pg_stat_statements</structname> view were last reset.
+      </para></entry>
+     </row>
+
     </tbody>
    </tgroup>
   </table>
@@ -549,9 +559,11 @@
       specified, the default value <literal>0</literal>(invalid) is used for
       each of them and the statistics that match with other parameters will be
       reset.  If no parameter is specified or all the specified parameters are
-      <literal>0</literal>(invalid), it will discard all statistics including
-      the statistics that <structname>pg_stat_statements_info</structname>
-      displays.  By default, this function can only be executed by superusers.
+      <literal>0</literal>(invalid), it will discard all statistics.
+      If all statistics in the <filename>pg_stat_statements</filename>
+      view are discarded, it will also reset the statistics in the
+      <structname>pg_stat_statements_info</structname> view.
+      By default, this function can only be executed by superusers.
       Access may be granted to others using <command>GRANT</command>.
      </para>
     </listitem>
#21Seino Yuki
seinoyu@oss.nttdata.com
In reply to: Fujii Masao (#20)
Re: Feature improvement for pg_stat_statements

2020-12-14 23:01 に Fujii Masao さんは書きました:

On 2020/12/14 18:17, Seino Yuki wrote:

2020-12-09 21:14 に Fujii Masao さんは書きました:

On 2020/12/09 20:42, Li Japin wrote:

Hi,

On Dec 9, 2020, at 6:37 PM, Seino Yuki <seinoyu@oss.nttdata.com
<mailto:seinoyu@oss.nttdata.com>> wrote:

2020-12-01 01:04 に Fujii Masao さんは書きました:

On 2020/11/30 23:05, Seino Yuki wrote:

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches
discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/
<https://commitfest.postgresql.org/30/2736/&gt;
The patch is posted on the 2736 side of the thread.
Regards.

I forgot the attachment and will resend it.
The following patches have been committed and we have created
a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/
<https://commitfest.postgresql.org/30/2736/&gt;
Please confirm.

Thanks for updating the patch! Here are review comments from 
me.
+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE
I prefer "stats_reset" as the name of this column for the sake 
of
consistency with the similar column in other stats views like
pg_stat_database.
Isn't it better to use lower cases for "TIMESTAMP WITH TIME 
ZONE"
because other DDLs in pg_stat_statements do that for the 
declaraion
of data type?
@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;
The reset time should be initialized with 
GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of 
reset_exec_time_isnull.
+    memset(nulls, 0, sizeof(nulls));
If some entries in "values[]" may not be set, "values[]" also 
needs to
be initialized with 0.
MemSet() should be used, instead?
+    /* Read dealloc */
+    values[0] = stats.dealloc;
Int64GetDatum() should be used here?
+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the 
entries
are removed. But it's called even in other cases.
Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.
+       <structfield>reset_exec_time</structfield> 
<type>timestamp
with time zone</type>
You forgot to update the column name in the doc?
+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last 
called.
What about updating this to something like "Time at which all 
statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in 
other
tats views?
+    /* Read stats_reset */
+    values[1] = stats.stats_reset;
TimestampTzGetDatum() seems necessary.
+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */
Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?
Regards,

Thanks for the new comment.
I got the following pointers earlier.

+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the
entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is
better,
because entry_reset is not likely to be called often.

I was thinking that GetCurrentTimestamp() should be called before
pgss->lock lwlock is taken, only when all three arguments userid,
dbid
and queryid are zero. But on second thought, we should call
GetCurrentTimestamp() and reset the stats, after the following
codes?
/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;
That is, IMO that even when pg_stat_statements_reset() with
non-zero
arguments is executed, if it removes all the entries, we should
reset
the stats. Thought?
Regards,

+1.Fixed the patch.
We tested various reset patterns and they seemed to be fine.

Since BlessTupleDesc() is for SRFs according to the comments, I
think, we can
remove it here.  Correct?

+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != 
TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       tupdesc = BlessTupleDesc(tupdesc);

Here are other comments from me:

The patch seems to contain whitespace errors.
You can see them by "git diff --check".

+      <para>
+        Time at which all statistics in the pg_stat_statements view
were last reset.
+      </para></entry>

"pg_stat_statements" in the above should be enclosed with
<structname> and </structname>.

Regards,

Thank you for your comments, Mr. Fujii and Mr. Li.
I've posted a patch reflecting your comments.
Please check it out.

Thanks for updating the patch!

+	reset_ts = GetCurrentTimestamp();
+	/* Reset global statistics for pg_stat_statements */
+	{
+		volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+
+		SpinLockAcquire(&s->mutex);
+		s->stats.stats_reset = reset_ts;	/* reset execution time */
+		SpinLockRelease(&s->mutex);

This code makes me think that "dealloc" field also should be reset at
the same time together, i.e., whenever all entries are removed.
Otherwise, even when pg_stat_statements_reset() with non-zero
arguments discards all statistics, "dealloc" field in
pg_stat_statements_info is not reset. Only pg_stat_statements_reset(0,
0, 0) resets "dealloc" field. That seems confusing. Thought?

I updated the patch so that "dealloc" field is also reset whenever all
entries are removed. Attached is the updated version of the patch.

+	result_tuple = heap_form_tuple(tupdesc, values, nulls);
+	return HeapTupleGetDatum(result_tuple);

Isn't it better to use PG_RETURN_DATUM() here, instead? I applied this
change to the patch.

I also applied some cosmetic changes to the patch. Could you review
this version?

Regards,

Thank you for providing the patch.

I have checked the operation.
There was no problem.

Regards.

#22Fujii Masao
masao.fujii@oss.nttdata.com
In reply to: Seino Yuki (#21)
Re: Feature improvement for pg_stat_statements

On 2020/12/17 22:59, Seino Yuki wrote:

2020-12-14 23:01 に Fujii Masao さんは書きました:

On 2020/12/14 18:17, Seino Yuki wrote:

2020-12-09 21:14 に Fujii Masao さんは書きました:

On 2020/12/09 20:42, Li Japin wrote:

Hi,

On Dec 9, 2020, at 6:37 PM, Seino Yuki <seinoyu@oss.nttdata.com <mailto:seinoyu@oss.nttdata.com>> wrote:

2020-12-01 01:04 に Fujii Masao さんは書きました:

On 2020/11/30 23:05, Seino Yuki wrote:

2020-11-30 15:02 に Fujii Masao さんは書きました:

On 2020/11/30 12:08, Seino Yuki wrote:

2020-11-27 22:39 に Fujii Masao さんは書きました:

On 2020/11/27 21:39, Seino Yuki wrote:

2020-11-27 21:37 に Seino Yuki さんは書きました:

2020-11-16 12:28 に Seino Yuki さんは書きました:

Due to similar fixed, we have also merged the patches discussed in the
following thread.
https://commitfest.postgresql.org/30/2736/ <https://commitfest.postgresql.org/30/2736/&gt;
The patch is posted on the 2736 side of the thread.
Regards.

I forgot the attachment and will resend it.
The following patches have been committed and we have created a
compliant patch for them.
https://commitfest.postgresql.org/30/2736/ <https://commitfest.postgresql.org/30/2736/&gt;
Please confirm.

Thanks for updating the patch! Here are review comments from me.
+    OUT reset_exec_time TIMESTAMP WITH TIME ZONE
I prefer "stats_reset" as the name of this column for the sake of
consistency with the similar column in other stats views like
pg_stat_database.
Isn't it better to use lower cases for "TIMESTAMP WITH TIME ZONE"
because other DDLs in pg_stat_statements do that for the declaraion
of data type?
@@ -565,6 +568,8 @@ pgss_shmem_startup(void)
         pgss->n_writers = 0;
         pgss->gc_count = 0;
         pgss->stats.dealloc = 0;
+        pgss->stats.reset_exec_time = 0;
+        pgss->stats.reset_exec_time_isnull = true;
The reset time should be initialized with GetCurrentTimestamp() instead
of 0? If so, I think that we can completely get rid of reset_exec_time_isnull.
+    memset(nulls, 0, sizeof(nulls));
If some entries in "values[]" may not be set, "values[]" also needs to
be initialized with 0.
MemSet() should be used, instead?
+    /* Read dealloc */
+    values[0] = stats.dealloc;
Int64GetDatum() should be used here?
+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.
Regards,

Thanks for the review!
Fixed the patch.

Thanks for updating the patch! Here are another review comments.
+       <structfield>reset_exec_time</structfield> <type>timestamp
with time zone</type>
You forgot to update the column name in the doc?
+        Shows the time at which
<function>pg_stat_statements_reset(0,0,0)</function> was last called.
What about updating this to something like "Time at which all statistics
in the pg_stat_statements view were last reset." for the sale of
onsistency with the description about stats_reset column in other
tats views?
+    /* Read stats_reset */
+    values[1] = stats.stats_reset;
TimestampTzGetDatum() seems necessary.
+        reset_ts = GetCurrentTimestamp();
         /* Reset global statistics for pg_stat_statements */
Isn't it better to call GetCurrentTimestamp() before taking
an exclusive lwlock, in entry_reset()?
Regards,

Thanks for the new comment.
I got the following pointers earlier.

+    reset_ts = GetCurrentTimestamp();
GetCurrentTimestamp() needs to be called only when all the entries
are removed. But it's called even in other cases.

Which do you think is better? I think the new pointing out is better,
because entry_reset is not likely to be called often.

I was thinking that GetCurrentTimestamp() should be called before
pgss->lock lwlock is taken, only when all three arguments userid, dbid
and queryid are zero. But on second thought, we should call
GetCurrentTimestamp() and reset the stats, after the following codes?
/* All entries are removed? */
if (num_entries != num_remove)
goto release_lock;
That is, IMO that even when pg_stat_statements_reset() with non-zero
arguments is executed, if it removes all the entries, we should reset
the stats. Thought?
Regards,

+1.Fixed the patch.
We tested various reset patterns and they seemed to be fine.

Since BlessTupleDesc() is for SRFs according to the comments, I think, we can
remove it here.  Correct?

+       if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+               elog(ERROR, "return type must be a row type");
+
+       tupdesc = BlessTupleDesc(tupdesc);

Here are other comments from me:

The patch seems to contain whitespace errors.
You can see them by "git diff --check".

+      <para>
+        Time at which all statistics in the pg_stat_statements view
were last reset.
+      </para></entry>

"pg_stat_statements" in the above should be enclosed with
<structname> and </structname>.

Regards,

Thank you for your comments, Mr. Fujii and Mr. Li.
I've posted a patch reflecting your comments.
Please check it out.

Thanks for updating the patch!

+    reset_ts = GetCurrentTimestamp();
+    /* Reset global statistics for pg_stat_statements */
+    {
+        volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
+
+        SpinLockAcquire(&s->mutex);
+        s->stats.stats_reset = reset_ts;    /* reset execution time */
+        SpinLockRelease(&s->mutex);

This code makes me think that "dealloc" field also should be reset at
the same time together, i.e., whenever all entries are removed.
Otherwise, even when pg_stat_statements_reset() with non-zero
arguments discards all statistics, "dealloc" field in
pg_stat_statements_info is not reset. Only pg_stat_statements_reset(0,
0, 0) resets "dealloc" field. That seems confusing. Thought?

I updated the patch so that "dealloc" field is also reset whenever all
entries are removed. Attached is the updated version of the patch.

+    result_tuple = heap_form_tuple(tupdesc, values, nulls);
+    return HeapTupleGetDatum(result_tuple);

Isn't it better to use PG_RETURN_DATUM() here, instead? I applied this
change to the patch.

I also applied some cosmetic changes to the patch. Could you review
this version?

Regards,

Thank you for providing the patch.

I have checked the operation.
There was no problem.

So I pushed the patch. Thanks!

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION