OBJS = pg_buffercache_pages.o $(WIN32RES)
EXTENSION = pg_buffercache
-DATA = pg_buffercache--1.2.sql pg_buffercache--1.1--1.2.sql \
- pg_buffercache--1.0--1.1.sql pg_buffercache--unpackaged--1.0.sql
+DATA = pg_buffercache--1.2.sql pg_buffercache--1.2--1.3.sql \
+ pg_buffercache--1.1--1.2.sql pg_buffercache--1.0--1.1.sql \
+ pg_buffercache--unpackaged--1.0.sql
PGFILEDESC = "pg_buffercache - monitoring of shared buffer cache in real-time"
ifdef USE_PGXS
--- /dev/null
+/* contrib/pg_buffercache/pg_buffercache--1.2--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_buffercache UPDATE TO '1.3'" to load this file. \quit
+
+GRANT EXECUTE ON FUNCTION pg_buffercache_pages() TO pg_monitor;
+GRANT SELECT ON pg_buffercache TO pg_monitor;
# pg_buffercache extension
comment = 'examine the shared buffer cache'
-default_version = '1.2'
+default_version = '1.3'
module_pathname = '$libdir/pg_buffercache'
relocatable = true
OBJS = pg_freespacemap.o $(WIN32RES)
EXTENSION = pg_freespacemap
-DATA = pg_freespacemap--1.1.sql pg_freespacemap--1.0--1.1.sql \
- pg_freespacemap--unpackaged--1.0.sql
+DATA = pg_freespacemap--1.1.sql pg_freespacemap--1.1--1.2.sql \
+ pg_freespacemap--1.0--1.1.sql pg_freespacemap--unpackaged--1.0.sql
PGFILEDESC = "pg_freespacemap - monitoring of free space map"
ifdef USE_PGXS
--- /dev/null
+/* contrib/pg_freespacemap/pg_freespacemap--1.1--1.2.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_freespacemap UPDATE TO '1.2'" to load this file. \quit
+
+GRANT EXECUTE ON FUNCTION pg_freespace(regclass, bigint) TO pg_stat_scan_tables;
+GRANT EXECUTE ON FUNCTION pg_freespace(regclass) TO pg_stat_scan_tables;
# pg_freespacemap extension
comment = 'examine the free space map (FSM)'
-default_version = '1.1'
+default_version = '1.2'
module_pathname = '$libdir/pg_freespacemap'
relocatable = true
OBJS = pg_stat_statements.o $(WIN32RES)
EXTENSION = pg_stat_statements
-DATA = pg_stat_statements--1.4.sql pg_stat_statements--1.3--1.4.sql \
- pg_stat_statements--1.2--1.3.sql pg_stat_statements--1.1--1.2.sql \
- pg_stat_statements--1.0--1.1.sql pg_stat_statements--unpackaged--1.0.sql
+DATA = pg_stat_statements--1.4.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 \
+ pg_stat_statements--1.1--1.2.sql pg_stat_statements--1.0--1.1.sql \
+ pg_stat_statements--unpackaged--1.0.sql
PGFILEDESC = "pg_stat_statements - execution statistics of SQL statements"
LDFLAGS_SL += $(filter -lm, $(LIBS))
--- /dev/null
+/* contrib/pg_stat_statements/pg_stat_statements--1.4--1.5.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_stat_statements UPDATE TO '1.5'" to load this file. \quit
+
+GRANT EXECUTE ON FUNCTION pg_stat_statements_reset() TO pg_read_all_stats;
#include <unistd.h>
#include "access/hash.h"
+#include "catalog/pg_authid.h"
#include "executor/instrument.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
MemoryContext per_query_ctx;
MemoryContext oldcontext;
Oid userid = GetUserId();
- bool is_superuser = superuser();
+ bool is_allowed_role = false;
char *qbuffer = NULL;
Size qbuffer_size = 0;
Size extent = 0;
HASH_SEQ_STATUS hash_seq;
pgssEntry *entry;
+ /* Superusers or members of pg_read_all_stats members are allowed */
+ is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS);
+
/* hash table must exist already */
if (!pgss || !pgss_hash)
ereport(ERROR,
values[i++] = ObjectIdGetDatum(entry->key.userid);
values[i++] = ObjectIdGetDatum(entry->key.dbid);
- if (is_superuser || entry->key.userid == userid)
+ if (is_allowed_role || entry->key.userid == userid)
{
if (api_version >= PGSS_V1_2)
values[i++] = Int64GetDatumFast(queryid);
# pg_stat_statements extension
comment = 'track execution statistics of all SQL statements executed'
-default_version = '1.4'
+default_version = '1.5'
module_pathname = '$libdir/pg_stat_statements'
relocatable = true
OBJS = pg_visibility.o $(WIN32RES)
EXTENSION = pg_visibility
-DATA = pg_visibility--1.1.sql pg_visibility--1.0--1.1.sql
+DATA = pg_visibility--1.1.sql pg_visibility--1.1--1.2.sql \
+ pg_visibility--1.0--1.1.sql
PGFILEDESC = "pg_visibility - page visibility information"
REGRESS = pg_visibility
--- /dev/null
+/* contrib/pg_visibility/pg_visibility--1.1--1.2.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_visibility UPDATE TO '1.2'" to load this file. \quit
+
+-- Allow use of monitoring functions by pg_monitor members
+GRANT EXECUTE ON FUNCTION pg_visibility_map(regclass, bigint) TO pg_stat_scan_tables;
+GRANT EXECUTE ON FUNCTION pg_visibility(regclass, bigint) TO pg_stat_scan_tables;
+GRANT EXECUTE ON FUNCTION pg_visibility_map(regclass) TO pg_stat_scan_tables;
+GRANT EXECUTE ON FUNCTION pg_visibility(regclass) TO pg_stat_scan_tables;
+GRANT EXECUTE ON FUNCTION pg_visibility_map_summary(regclass) TO pg_stat_scan_tables;
+GRANT EXECUTE ON FUNCTION pg_check_frozen(regclass) TO pg_stat_scan_tables;
+GRANT EXECUTE ON FUNCTION pg_check_visible(regclass) TO pg_stat_scan_tables;
# pg_visibility extension
comment = 'examine the visibility map (VM) and page-level visibility info'
-default_version = '1.1'
+default_version = '1.2'
module_pathname = '$libdir/pg_visibility'
relocatable = true
#include "access/relscan.h"
#include "access/xact.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
rel = heap_openrv(relrv, AccessShareLock);
- /* check permissions: must have SELECT on table */
- aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
- ACL_SELECT);
+ /* check permissions: must have SELECT on table or be in pg_stat_scan_tables */
+ aclresult = (pg_class_aclcheck(RelationGetRelid(rel), GetUserId(),
+ ACL_SELECT) ||
+ is_member_of_role(GetUserId(), DEFAULT_ROLE_STAT_SCAN_TABLES);
+
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_CLASS,
RelationGetRelationName(rel));
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstattuple(text) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pgstattuple(text) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pgstatindex(IN relname text,
OUT version INT,
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstatindex(text) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pgstatindex(text) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pg_relpages(IN relname text)
RETURNS BIGINT
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pg_relpages(text) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pg_relpages(text) TO pg_stat_scan_tables;
/* New stuff in 1.1 begins here */
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstatginindex(regclass) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pgstatginindex(regclass) TO pg_stat_scan_tables;
/* New stuff in 1.2 begins here */
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstattuple(regclass) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pgstattuple(regclass) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pgstatindex(IN relname regclass,
OUT version INT,
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstatindex(regclass) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pgstatindex(regclass) TO pg_stat_scan_tables;
CREATE OR REPLACE FUNCTION pg_relpages(IN relname regclass)
RETURNS BIGINT
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pg_relpages(regclass) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pg_relpages(regclass) TO pg_stat_scan_tables;
/* New stuff in 1.3 begins here */
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstattuple_approx(regclass) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pgstattuple_approx(regclass) TO pg_stat_scan_tables;
/* New stuff in 1.5 begins here */
LANGUAGE C STRICT PARALLEL SAFE;
REVOKE EXECUTE ON FUNCTION pgstathashindex(regclass) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION pgstathashindex(regclass) TO pg_stat_scan_tables;
<entry><type>text</type></entry>
<entry>Configuration file the current value was set in (null for
values set from sources other than configuration files, or when
- examined by a non-superuser);
- helpful when using <literal>include</> directives in configuration files</entry>
+ examined by a user who is neither a superuser or a member of
+ <literal>pg_read_all_settings</literal>); helpful when using
+ <literal>include</> directives in configuration files</entry>
</row>
<row>
<entry><structfield>sourceline</structfield></entry>
<entry><type>integer</type></entry>
<entry>Line number within the configuration file the current value was
set at (null for values set from sources other than configuration files,
- or when examined by a non-superuser)
+ or when examined by a user who is neither a superuser or a member of
+ <literal>pg_read_all_settings</literal>).
</entry>
</row>
<row>
accept the OID or name of a database or tablespace, and return the total
disk space used therein. To use <function>pg_database_size</function>,
you must have <literal>CONNECT</> permission on the specified database
- (which is granted by default). To use <function>pg_tablespace_size</>,
- you must have <literal>CREATE</> permission on the specified tablespace,
- unless it is the default tablespace for the current database.
+ (which is granted by default), or be a member of the <literal>pg_read_all_stats</>
+ role. To use <function>pg_tablespace_size</>, you must have
+ <literal>CREATE</> permission on the specified tablespace, or be a member
+ of the <literal>pg_read_all_stats</> role unless it is the default tablespace for
+ the current database.
</para>
<para>
<entry><type>setof record</type></entry>
<entry>
List the name, size, and last modification time of files in the log
- directory. Access may be granted to non-superuser roles.
+ directory. Access is granted to members of the <literal>pg_monitor</>
+ role and may be granted to other non-superuser roles.
</entry>
</row>
<row>
<entry><type>setof record</type></entry>
<entry>
List the name, size, and last modification time of files in the WAL
- directory. Access may be granted to non-superuser roles.
+ directory. Access is granted to members of the <literal>pg_monitor</>
+ role and may be granted to other non-superuser roles.
</entry>
</row>
<row>
<para>
<function>pg_ls_logdir</> returns the name, size, and last modified time
(mtime) of each file in the log directory. By default, only superusers
- can use this function, but access may be granted to others using
- <command>GRANT</command>.
+ and members of the <literal>pg_monitor</> role can use this function.
+ Access may be granted to others using <command>GRANT</command>.
</para>
<indexterm>
<para>
<function>pg_ls_waldir</> returns the name, size, and last modified time
(mtime) of each file in the write ahead log (WAL) directory. By
- default only superusers can use this function, but access may be granted
- to others using <command>GRANT</command>.
+ default only superusers and members of the <literal>pg_monitor</> role
+ can use this function. Access may be granted to others using
+ <command>GRANT</command>.
</para>
<indexterm>
</para>
<para>
- By default public access is revoked from both of these, just in case there
- are security issues lurking.
+ By default use is restricted to superusers and members of the
+ <literal>pg_read_all_stats</literal> role. Access may be granted to others
+ using <command>GRANT</command>.
</para>
<sect2>
</para>
<para>
- By default public access is revoked from the functions, just in case
- there are security issues lurking.
+ By default use is restricted to superusers and members of the
+ <literal>pg_stat_scan_tables</literal> role. Access may be granted to others
+ using <command>GRANT</command>.
</para>
<sect2>
locking information for a specified table.
</para>
+ <para>
+ By default use is restricted to superusers, members of the
+ <literal>pg_stat_scan_tables</literal> role, and users with
+ <literal>SELECT</literal> permissions on the table.
+ </para>
+
+
<sect2>
<title>Overview</title>
</table>
<para>
- For security reasons, non-superusers are not allowed to see the SQL
- text or <structfield>queryid</structfield> of queries executed by other users.
- They can see the statistics, however, if the view has been installed in their
- database.
+ For security reasons, only superusers and members of the
+ <literal>pg_read_all_stats<literal> role are allowed to see the SQL text and
+ <structfield>queryid</structfield> of queries executed by other users.
+ Other users can see the statistics, however, if the view has been installed
+ in their database.
</para>
<para>
As these functions return detailed page-level information, only the superuser
has EXECUTE privileges on them upon installation. After the functions have
been installed, users may issue <command>GRANT</command> commands to change
- the privileges on the functions to allow non-superusers to execute them. See
+ the privileges on the functions to allow non-superusers to execute them. Members
+ of the <literal>pg_stat_scan_tables</literal> role are granted access by default. See
the description of the <xref linkend="sql-grant"> command for specifics.
</para>
</variablelist>
<para>
- By default, these functions are executable only by superusers.
+ By default, these functions are executable only by superusers and members of the
+ <literal>pg_stat_scan_tables</literal> role, with the exception of
+ <function>pg_truncate_visibility_map(relation regclass)</function> which can only
+ be executed by superusers.
</para>
</sect2>
</row>
</thead>
<tbody>
+ <row>
+ <entry>pg_read_all_settings</entry>
+ <entry>Read all configuration variables, even those normally visible only to
+ superusers.</entry>
+ </row>
+ <row>
+ <entry>pg_read_all_stats</entry>
+ <entry>Read all pg_stat_* views and use various statistics related extensions,
+ even those normally visible only to superusers.</entry>
+ </row>
+ <row>
+ <entry>pg_stat_scan_tables</entry>
+ <entry>Execute monitoring functions that may take AccessShareLocks on tables,
+ potentially for a long time.</entry>
+ </row>
<row>
<entry>pg_signal_backend</entry>
<entry>Send signals to other backends (eg: cancel query, terminate).</entry>
</row>
+ <row>
+ <entry>pg_monitor</entry>
+ <entry>Read/execute various monitoring views and functions.
+ This role is a member of <literal>pg_read_all_settings</literal>,
+ <literal>pg_read_all_stats</literal> and
+ <literal>pg_stat_scan_tables</literal>.</entry>
+ </row>
</tbody>
</tgroup>
</table>
+ <para>
+ The <literal>pg_monitor</literal>, <literal>pg_read_all_settings</literal>,
+ <literal>pg_read_all_stats</literal> and <literal>pg_stat_scan_tables</literal>
+ roles are intended to allow administrators to easily configure a role for the
+ purpose of monitoring the database server. They grant a set of common privileges
+ allowing the role to read various useful configuration settings, statistics and
+ other system information normally restricted to superusers.
+ </para>
+
+ <para>
+ Care should be taken when granting these roles to ensure they are only used where
+ needed to perform the desired monitoring.
+ </para>
+
<para>
Administrators can grant access to these roles to users using the GRANT
command:
REVOKE EXECUTE ON FUNCTION pg_ls_logdir() FROM public;
REVOKE EXECUTE ON FUNCTION pg_ls_waldir() FROM public;
+GRANT EXECUTE ON FUNCTION pg_ls_logdir() TO pg_monitor;
+GRANT EXECUTE ON FUNCTION pg_ls_waldir() TO pg_monitor;
+
+GRANT pg_read_all_settings TO pg_monitor;
+GRANT pg_read_all_stats TO pg_monitor;
+GRANT pg_stat_scan_tables TO pg_monitor;
#include "access/timeline.h"
#include "access/transam.h"
#include "access/xlog_internal.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
/* Fetch values */
values[0] = Int32GetDatum(walrcv->pid);
- if (!superuser())
+ if (!is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
{
/*
* Only superusers can see details. Other users only get the pid value
#include "access/htup_details.h"
#include "catalog/catalog.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_tablespace.h"
#include "commands/dbcommands.h"
#include "commands/tablespace.h"
char pathname[MAXPGPATH];
AclResult aclresult;
- /* User must have connect privilege for target database */
+ /*
+ * User must have connect privilege for target database
+ * or be a member of pg_read_all_stats
+ */
aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT);
- if (aclresult != ACLCHECK_OK)
+ if (aclresult != ACLCHECK_OK &&
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
+ {
aclcheck_error(aclresult, ACL_KIND_DATABASE,
get_database_name(dbOid));
+ }
/* Shared storage in pg_global is not counted */
AclResult aclresult;
/*
- * User must have CREATE privilege for target tablespace, either
- * explicitly granted or implicitly because it is default for current
- * database.
+ * User must be a member of pg_read_all_stats or have CREATE privilege for
+ * target tablespace, either explicitly granted or implicitly because
+ * it is default for current database.
*/
- if (tblspcOid != MyDatabaseTableSpace)
+ if (tblspcOid != MyDatabaseTableSpace &&
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
{
aclresult = pg_tablespace_aclcheck(tblspcOid, GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
#include "postgres.h"
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
#include "funcapi.h"
nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = true;
}
- /* Values only available to role member */
- if (has_privs_of_role(GetUserId(), beentry->st_userid))
+ /* Values only available to role member or pg_read_all_stats */
+ if (has_privs_of_role(GetUserId(), beentry->st_userid) ||
+ is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
{
SockAddr zero_clientaddr;
#include "access/xact.h"
#include "access/xlog_internal.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "commands/async.h"
#include "commands/prepare.h"
#include "commands/user.h"
}
if (restrict_superuser &&
(record->flags & GUC_SUPERUSER_ONLY) &&
- !superuser())
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to examine \"%s\"", name)));
+ errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
+ name)));
switch (record->vartype)
{
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("unrecognized configuration parameter \"%s\"", name)));
- if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser())
+ if ((record->flags & GUC_SUPERUSER_ONLY) &&
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to examine \"%s\"", name)));
+ errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
+ name)));
switch (record->vartype)
{
errmsg("unrecognized configuration parameter \"%s\"", name)));
}
- if ((record->flags & GUC_SUPERUSER_ONLY) && !superuser())
+ if ((record->flags & GUC_SUPERUSER_ONLY) &&
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to examine \"%s\"", name)));
+ errmsg("must be superuser or a member of pg_read_all_settings to examine \"%s\"",
+ name)));
if (varname)
*varname = record->name;
if (noshow)
{
if ((conf->flags & GUC_NO_SHOW_ALL) ||
- ((conf->flags & GUC_SUPERUSER_ONLY) && !superuser()))
+ ((conf->flags & GUC_SUPERUSER_ONLY) &&
+ !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_SETTINGS)))
*noshow = true;
else
*noshow = false;
* ----------------
*/
DATA(insert OID = 10 ( "POSTGRES" t t t t t t t -1 _null_ _null_));
+DATA(insert OID = 3373 ( "pg_monitor" f t f f f f f -1 _null_ _null_));
+DATA(insert OID = 3374 ( "pg_read_all_settings" f t f f f f f -1 _null_ _null_));
+DATA(insert OID = 3375 ( "pg_read_all_stats" f t f f f f f -1 _null_ _null_));
+DATA(insert OID = 3377 ( "pg_stat_scan_tables" f t f f f f f -1 _null_ _null_));
DATA(insert OID = 4200 ( "pg_signal_backend" f t f f f f f -1 _null_ _null_));
#define BOOTSTRAP_SUPERUSERID 10
+#define DEFAULT_ROLE_MONITOR 3373
+#define DEFAULT_ROLE_READ_ALL_SETTINGS 3374
+#define DEFAULT_ROLE_READ_ALL_STATS 3375
+#define DEFAULT_ROLE_STAT_SCAN_TABLES 3377
#define DEFAULT_ROLE_SIGNAL_BACKENDID 4200
#endif /* PG_AUTHID_H */