diff --git a/contrib/pgstattuple/Makefile b/contrib/pgstattuple/Makefile index fc893d8c8556ef1b18c293a4c9b6c8f9473dc17b..d991c3a803993b2af59dafe70ecd6498df988c06 100644 --- a/contrib/pgstattuple/Makefile +++ b/contrib/pgstattuple/Makefile @@ -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 diff --git a/contrib/pgstattuple/expected/pgstattuple.out b/contrib/pgstattuple/expected/pgstattuple.out index ab28f50cb086a4ff297b9f47813d87efbf28d432..7aab96766539c45a4596c17b8bf40fd24e3984a1 100644 --- a/contrib/pgstattuple/expected/pgstattuple.out +++ b/contrib/pgstattuple/expected/pgstattuple.out @@ -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 diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c index 97f897ec1e5bb17d94ba170c0190bdd9d8b044bf..282d82ca8280b5d9aa74b8fe8219ef777f5b5712 100644 --- a/contrib/pgstattuple/pgstatindex.c +++ b/contrib/pgstattuple/pgstatindex.c @@ -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() * diff --git a/contrib/pgstattuple/pgstattuple--1.1--1.2.sql b/contrib/pgstattuple/pgstattuple--1.1--1.2.sql new file mode 100644 index 0000000000000000000000000000000000000000..2783a63fb155c72d8755742526bc1271ffda80e7 --- /dev/null +++ b/contrib/pgstattuple/pgstattuple--1.1--1.2.sql @@ -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; diff --git a/contrib/pgstattuple/pgstattuple--1.1.sql b/contrib/pgstattuple/pgstattuple--1.2.sql similarity index 75% rename from contrib/pgstattuple/pgstattuple--1.1.sql rename to contrib/pgstattuple/pgstattuple--1.2.sql index b21fbf83e466484069f2715e8576a6d2e1206b38..e5fa2f58dab2aa415d0fb4effc90fb17701dcb76 100644 --- a/contrib/pgstattuple/pgstattuple--1.1.sql +++ b/contrib/pgstattuple/pgstattuple--1.2.sql @@ -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; diff --git a/contrib/pgstattuple/pgstattuple.control b/contrib/pgstattuple/pgstattuple.control index fcfd36f1b1ab39eecd86234643b2fca88a25ae09..a7cf47fd9217a1238bd2a7cfd5b0aab5ab60da0c 100644 --- a/contrib/pgstattuple/pgstattuple.control +++ b/contrib/pgstattuple/pgstattuple.control @@ -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 diff --git a/contrib/pgstattuple/sql/pgstattuple.sql b/contrib/pgstattuple/sql/pgstattuple.sql index 8cb350d6ee1ae8a5efb5525dd231a4bd82416438..0e0ad0e15d5a7b256c06d6208327d178a5f9d251 100644 --- a/contrib/pgstattuple/sql/pgstattuple.sql +++ b/contrib/pgstattuple/sql/pgstattuple.sql @@ -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); diff --git a/doc/src/sgml/pgstattuple.sgml b/doc/src/sgml/pgstattuple.sgml index f2bc2a68f888196e57f41de6311da352f632209b..6cae04a9c8b9ae8b08f412a10352bef9c3d4833e 100644 --- a/doc/src/sgml/pgstattuple.sgml +++ b/doc/src/sgml/pgstattuple.sgml @@ -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>