mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-21 03:13:05 +08:00
Fix pgstattuple functions to use regclass-type as the argument.
This allows us to specify the target relation with several expressions, 'relname', 'schemaname.relname' and OID in all pgstattuple functions. pgstatindex() and pg_relpages() could not accept OID as the argument so far. Per discussion on -hackers, we decided to keep two types of interfaces, with regclass-type and TEXT-type argument, for each pgstattuple function because of the backward-compatibility issue. The functions which have TEXT-type argument will be deprecated in the future release. Patch by Satoshi Nagayasu, reviewed by Rushabh Lathia and Fujii Masao.
This commit is contained in:
parent
d26888bc4d
commit
1dc118660b
@ -4,7 +4,7 @@ MODULE_big = pgstattuple
|
||||
OBJS = pgstattuple.o pgstatindex.o
|
||||
|
||||
EXTENSION = pgstattuple
|
||||
DATA = pgstattuple--1.1.sql pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql
|
||||
DATA = pgstattuple--1.2.sql pgstattuple--1.1--1.2.sql pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql
|
||||
|
||||
REGRESS = pgstattuple
|
||||
|
||||
|
@ -5,24 +5,78 @@ CREATE EXTENSION pgstattuple;
|
||||
-- indexes should be that.
|
||||
--
|
||||
create table test (a int primary key, b int[]);
|
||||
select * from pgstattuple('test');
|
||||
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
|
||||
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
||||
(1 row)
|
||||
|
||||
select * from pgstattuple('test'::text);
|
||||
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
|
||||
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
||||
(1 row)
|
||||
|
||||
select * from pgstattuple('test'::name);
|
||||
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
|
||||
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
||||
(1 row)
|
||||
|
||||
select * from pgstattuple('test'::regclass);
|
||||
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
|
||||
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
|
||||
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
|
||||
(1 row)
|
||||
|
||||
select pgstattuple(oid) from pg_class where relname = 'test';
|
||||
pgstattuple
|
||||
---------------------
|
||||
(0,0,0,0,0,0,0,0,0)
|
||||
(1 row)
|
||||
|
||||
select pgstattuple(relname) from pg_class where relname = 'test';
|
||||
pgstattuple
|
||||
---------------------
|
||||
(0,0,0,0,0,0,0,0,0)
|
||||
(1 row)
|
||||
|
||||
select * from pgstatindex('test_pkey');
|
||||
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
|
||||
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
|
||||
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
|
||||
(1 row)
|
||||
|
||||
select * from pgstatindex('test_pkey'::text);
|
||||
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
|
||||
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
|
||||
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
|
||||
(1 row)
|
||||
|
||||
select * from pgstatindex('test_pkey'::name);
|
||||
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
|
||||
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
|
||||
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
|
||||
(1 row)
|
||||
|
||||
select * from pgstatindex('test_pkey'::regclass);
|
||||
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
|
||||
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
|
||||
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
|
||||
(1 row)
|
||||
|
||||
select pgstatindex(oid) from pg_class where relname = 'test_pkey';
|
||||
pgstatindex
|
||||
---------------------------
|
||||
(2,0,0,0,0,0,0,0,NaN,NaN)
|
||||
(1 row)
|
||||
|
||||
select pgstatindex(relname) from pg_class where relname = 'test_pkey';
|
||||
pgstatindex
|
||||
---------------------------
|
||||
(2,0,0,0,0,0,0,0,NaN,NaN)
|
||||
(1 row)
|
||||
|
||||
select pg_relpages('test');
|
||||
pg_relpages
|
||||
-------------
|
||||
@ -35,6 +89,36 @@ select pg_relpages('test_pkey');
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select pg_relpages('test_pkey'::text);
|
||||
pg_relpages
|
||||
-------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select pg_relpages('test_pkey'::name);
|
||||
pg_relpages
|
||||
-------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select pg_relpages('test_pkey'::regclass);
|
||||
pg_relpages
|
||||
-------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select pg_relpages(oid) from pg_class where relname = 'test_pkey';
|
||||
pg_relpages
|
||||
-------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select pg_relpages(relname) from pg_class where relname = 'test_pkey';
|
||||
pg_relpages
|
||||
-------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
create index test_ginidx on test using gin (b);
|
||||
select * from pgstatginindex('test_ginidx');
|
||||
version | pending_pages | pending_tuples
|
||||
|
@ -39,12 +39,24 @@
|
||||
#include "utils/rel.h"
|
||||
|
||||
|
||||
/*
|
||||
* Because of backward-compatibility issue, we have decided to have
|
||||
* two types of interfaces, with regclass-type input arg and text-type
|
||||
* input arg, for each function.
|
||||
*
|
||||
* Those functions which have text-type input arg will be deprecated
|
||||
* in the future release.
|
||||
*/
|
||||
extern Datum pgstatindex(PG_FUNCTION_ARGS);
|
||||
extern Datum pgstatindexbyid(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_relpages(PG_FUNCTION_ARGS);
|
||||
extern Datum pg_relpagesbyid(PG_FUNCTION_ARGS);
|
||||
extern Datum pgstatginindex(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(pgstatindex);
|
||||
PG_FUNCTION_INFO_V1(pgstatindexbyid);
|
||||
PG_FUNCTION_INFO_V1(pg_relpages);
|
||||
PG_FUNCTION_INFO_V1(pg_relpagesbyid);
|
||||
PG_FUNCTION_INFO_V1(pgstatginindex);
|
||||
|
||||
#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
|
||||
@ -97,6 +109,8 @@ typedef struct GinIndexStat
|
||||
int64 pending_tuples;
|
||||
} GinIndexStat;
|
||||
|
||||
static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo);
|
||||
|
||||
/* ------------------------------------------------------
|
||||
* pgstatindex()
|
||||
*
|
||||
@ -109,11 +123,6 @@ pgstatindex(PG_FUNCTION_ARGS)
|
||||
text *relname = PG_GETARG_TEXT_P(0);
|
||||
Relation rel;
|
||||
RangeVar *relrv;
|
||||
Datum result;
|
||||
BlockNumber nblocks;
|
||||
BlockNumber blkno;
|
||||
BTIndexStat indexStat;
|
||||
BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
|
||||
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
@ -123,6 +132,34 @@ pgstatindex(PG_FUNCTION_ARGS)
|
||||
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
|
||||
rel = relation_openrv(relrv, AccessShareLock);
|
||||
|
||||
PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
|
||||
}
|
||||
|
||||
Datum
|
||||
pgstatindexbyid(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid relid = PG_GETARG_OID(0);
|
||||
Relation rel;
|
||||
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser to use pgstattuple functions"))));
|
||||
|
||||
rel = relation_open(relid, AccessShareLock);
|
||||
|
||||
PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
|
||||
}
|
||||
|
||||
static Datum
|
||||
pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
|
||||
{
|
||||
Datum result;
|
||||
BlockNumber nblocks;
|
||||
BlockNumber blkno;
|
||||
BTIndexStat indexStat;
|
||||
BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
|
||||
|
||||
if (!IS_INDEX(rel) || !IS_BTREE(rel))
|
||||
elog(ERROR, "relation \"%s\" is not a btree index",
|
||||
RelationGetRelationName(rel));
|
||||
@ -274,7 +311,7 @@ pgstatindex(PG_FUNCTION_ARGS)
|
||||
result = HeapTupleGetDatum(tuple);
|
||||
}
|
||||
|
||||
PG_RETURN_DATUM(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------
|
||||
@ -311,6 +348,29 @@ pg_relpages(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_INT64(relpages);
|
||||
}
|
||||
|
||||
Datum
|
||||
pg_relpagesbyid(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Oid relid = PG_GETARG_OID(0);
|
||||
int64 relpages;
|
||||
Relation rel;
|
||||
|
||||
if (!superuser())
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
(errmsg("must be superuser to use pgstattuple functions"))));
|
||||
|
||||
rel = relation_open(relid, AccessShareLock);
|
||||
|
||||
/* note: this will work OK on non-local temp tables */
|
||||
|
||||
relpages = RelationGetNumberOfBlocks(rel);
|
||||
|
||||
relation_close(rel, AccessShareLock);
|
||||
|
||||
PG_RETURN_INT64(relpages);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------
|
||||
* pgstatginindex()
|
||||
*
|
||||
|
39
contrib/pgstattuple/pgstattuple--1.1--1.2.sql
Normal file
39
contrib/pgstattuple/pgstattuple--1.1--1.2.sql
Normal file
@ -0,0 +1,39 @@
|
||||
/* contrib/pgstattuple/pgstattuple--1.1--1.2.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
|
||||
\echo Use "ALTER EXTENSION pgstattuple UPDATE TO '1.2'" to load this file. \quit
|
||||
|
||||
ALTER EXTENSION pgstattuple DROP FUNCTION pgstattuple(oid);
|
||||
DROP FUNCTION pgstattuple(oid);
|
||||
|
||||
CREATE FUNCTION pgstattuple(IN reloid regclass,
|
||||
OUT table_len BIGINT, -- physical table length in bytes
|
||||
OUT tuple_count BIGINT, -- number of live tuples
|
||||
OUT tuple_len BIGINT, -- total tuples length in bytes
|
||||
OUT tuple_percent FLOAT8, -- live tuples in %
|
||||
OUT dead_tuple_count BIGINT, -- number of dead tuples
|
||||
OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes
|
||||
OUT dead_tuple_percent FLOAT8, -- dead tuples in %
|
||||
OUT free_space BIGINT, -- free space in bytes
|
||||
OUT free_percent FLOAT8) -- free space in %
|
||||
AS 'MODULE_PATHNAME', 'pgstattuplebyid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION pgstatindex(IN relname regclass,
|
||||
OUT version INT,
|
||||
OUT tree_level INT,
|
||||
OUT index_size BIGINT,
|
||||
OUT root_block_no BIGINT,
|
||||
OUT internal_pages BIGINT,
|
||||
OUT leaf_pages BIGINT,
|
||||
OUT empty_pages BIGINT,
|
||||
OUT deleted_pages BIGINT,
|
||||
OUT avg_leaf_density FLOAT8,
|
||||
OUT leaf_fragmentation FLOAT8)
|
||||
AS 'MODULE_PATHNAME', 'pgstatindexbyid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION pg_relpages(IN relname regclass)
|
||||
RETURNS BIGINT
|
||||
AS 'MODULE_PATHNAME', 'pg_relpagesbyid'
|
||||
LANGUAGE C STRICT;
|
@ -1,4 +1,4 @@
|
||||
/* contrib/pgstattuple/pgstattuple--1.1.sql */
|
||||
/* contrib/pgstattuple/pgstattuple--1.2.sql */
|
||||
|
||||
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit
|
||||
@ -16,19 +16,6 @@ CREATE FUNCTION pgstattuple(IN relname text,
|
||||
AS 'MODULE_PATHNAME', 'pgstattuple'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION pgstattuple(IN reloid oid,
|
||||
OUT table_len BIGINT, -- physical table length in bytes
|
||||
OUT tuple_count BIGINT, -- number of live tuples
|
||||
OUT tuple_len BIGINT, -- total tuples length in bytes
|
||||
OUT tuple_percent FLOAT8, -- live tuples in %
|
||||
OUT dead_tuple_count BIGINT, -- number of dead tuples
|
||||
OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes
|
||||
OUT dead_tuple_percent FLOAT8, -- dead tuples in %
|
||||
OUT free_space BIGINT, -- free space in bytes
|
||||
OUT free_percent FLOAT8) -- free space in %
|
||||
AS 'MODULE_PATHNAME', 'pgstattuplebyid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION pgstatindex(IN relname text,
|
||||
OUT version INT,
|
||||
OUT tree_level INT,
|
||||
@ -56,3 +43,37 @@ CREATE FUNCTION pgstatginindex(IN relname regclass,
|
||||
OUT pending_tuples BIGINT)
|
||||
AS 'MODULE_PATHNAME', 'pgstatginindex'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
/* New stuff in 1.2 begins here */
|
||||
|
||||
CREATE FUNCTION pgstattuple(IN reloid regclass,
|
||||
OUT table_len BIGINT, -- physical table length in bytes
|
||||
OUT tuple_count BIGINT, -- number of live tuples
|
||||
OUT tuple_len BIGINT, -- total tuples length in bytes
|
||||
OUT tuple_percent FLOAT8, -- live tuples in %
|
||||
OUT dead_tuple_count BIGINT, -- number of dead tuples
|
||||
OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes
|
||||
OUT dead_tuple_percent FLOAT8, -- dead tuples in %
|
||||
OUT free_space BIGINT, -- free space in bytes
|
||||
OUT free_percent FLOAT8) -- free space in %
|
||||
AS 'MODULE_PATHNAME', 'pgstattuplebyid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION pgstatindex(IN relname regclass,
|
||||
OUT version INT,
|
||||
OUT tree_level INT,
|
||||
OUT index_size BIGINT,
|
||||
OUT root_block_no BIGINT,
|
||||
OUT internal_pages BIGINT,
|
||||
OUT leaf_pages BIGINT,
|
||||
OUT empty_pages BIGINT,
|
||||
OUT deleted_pages BIGINT,
|
||||
OUT avg_leaf_density FLOAT8,
|
||||
OUT leaf_fragmentation FLOAT8)
|
||||
AS 'MODULE_PATHNAME', 'pgstatindexbyid'
|
||||
LANGUAGE C STRICT;
|
||||
|
||||
CREATE FUNCTION pg_relpages(IN relname regclass)
|
||||
RETURNS BIGINT
|
||||
AS 'MODULE_PATHNAME', 'pg_relpagesbyid'
|
||||
LANGUAGE C STRICT;
|
@ -1,5 +1,5 @@
|
||||
# pgstattuple extension
|
||||
comment = 'show tuple-level statistics'
|
||||
default_version = '1.1'
|
||||
default_version = '1.2'
|
||||
module_pathname = '$libdir/pgstattuple'
|
||||
relocatable = true
|
||||
|
@ -8,13 +8,27 @@ CREATE EXTENSION pgstattuple;
|
||||
|
||||
create table test (a int primary key, b int[]);
|
||||
|
||||
select * from pgstattuple('test');
|
||||
select * from pgstattuple('test'::text);
|
||||
select * from pgstattuple('test'::name);
|
||||
select * from pgstattuple('test'::regclass);
|
||||
select pgstattuple(oid) from pg_class where relname = 'test';
|
||||
select pgstattuple(relname) from pg_class where relname = 'test';
|
||||
|
||||
select * from pgstatindex('test_pkey');
|
||||
select * from pgstatindex('test_pkey'::text);
|
||||
select * from pgstatindex('test_pkey'::name);
|
||||
select * from pgstatindex('test_pkey'::regclass);
|
||||
select pgstatindex(oid) from pg_class where relname = 'test_pkey';
|
||||
select pgstatindex(relname) from pg_class where relname = 'test_pkey';
|
||||
|
||||
select pg_relpages('test');
|
||||
select pg_relpages('test_pkey');
|
||||
select pg_relpages('test_pkey'::text);
|
||||
select pg_relpages('test_pkey'::name);
|
||||
select pg_relpages('test_pkey'::regclass);
|
||||
select pg_relpages(oid) from pg_class where relname = 'test_pkey';
|
||||
select pg_relpages(relname) from pg_class where relname = 'test_pkey';
|
||||
|
||||
create index test_ginidx on test using gin (b);
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
</indexterm>
|
||||
|
||||
<term>
|
||||
<function>pgstattuple(text) returns record</>
|
||||
<function>pgstattuple(regclass) returns record</>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
@ -30,7 +30,7 @@
|
||||
<function>pgstattuple</function> returns a relation's physical length,
|
||||
percentage of <quote>dead</> tuples, and other info. This may help users
|
||||
to determine whether vacuum is necessary or not. The argument is the
|
||||
target relation's name (optionally schema-qualified).
|
||||
target relation's name (optionally schema-qualified) or OID.
|
||||
For example:
|
||||
<programlisting>
|
||||
test=> SELECT * FROM pgstattuple('pg_catalog.pg_proc');
|
||||
@ -125,13 +125,15 @@ free_percent | 1.95
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>pgstattuple(oid) returns record</>
|
||||
<function>pgstattuple(text) returns record</>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
This is the same as <function>pgstattuple(text)</function>, except
|
||||
that the target relation is specified by OID.
|
||||
This is the same as <function>pgstattuple(regclass)</function>, except
|
||||
that the target relation is specified by TEXT. This function is kept
|
||||
because of backward-compatibility so far, and will be deprecated in
|
||||
the future release.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -141,7 +143,7 @@ free_percent | 1.95
|
||||
<indexterm>
|
||||
<primary>pgstatindex</primary>
|
||||
</indexterm>
|
||||
<function>pgstatindex(text) returns record</>
|
||||
<function>pgstatindex(regclass) returns record</>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
@ -251,6 +253,21 @@ leaf_fragmentation | 0
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>pgstatindex(text) returns record</>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
This is the same as <function>pgstatindex(regclass)</function>, except
|
||||
that the target index is specified by TEXT. This function is kept
|
||||
because of backward-compatibility so far, and will be deprecated in
|
||||
the future release.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<indexterm>
|
||||
@ -316,7 +333,7 @@ pending_tuples | 0
|
||||
<indexterm>
|
||||
<primary>pg_relpages</primary>
|
||||
</indexterm>
|
||||
<function>pg_relpages(text) returns bigint</>
|
||||
<function>pg_relpages(regclass) returns bigint</>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
@ -326,6 +343,22 @@ pending_tuples | 0
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>
|
||||
<function>pg_relpages(text) returns bigint</>
|
||||
</term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
This is the same as <function>pg_relpages(regclass)</function>, except
|
||||
that the target relation is specified by TEXT. This function is kept
|
||||
because of backward-compatibility so far, and will be deprecated in
|
||||
the future release.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</sect2>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user