Skip to content

Commit 1dc1186

Browse files
committed
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.
1 parent d26888b commit 1dc1186

File tree

8 files changed

+280
-29
lines changed

8 files changed

+280
-29
lines changed

contrib/pgstattuple/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ MODULE_big = pgstattuple
44
OBJS = pgstattuple.o pgstatindex.o
55

66
EXTENSION = pgstattuple
7-
DATA = pgstattuple--1.1.sql pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql
7+
DATA = pgstattuple--1.2.sql pgstattuple--1.1--1.2.sql pgstattuple--1.0--1.1.sql pgstattuple--unpackaged--1.0.sql
88

99
REGRESS = pgstattuple
1010

contrib/pgstattuple/expected/pgstattuple.out

+84
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,78 @@ CREATE EXTENSION pgstattuple;
55
-- indexes should be that.
66
--
77
create table test (a int primary key, b int[]);
8+
select * from pgstattuple('test');
9+
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
10+
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
11+
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
12+
(1 row)
13+
814
select * from pgstattuple('test'::text);
915
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
1016
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
1117
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1218
(1 row)
1319

20+
select * from pgstattuple('test'::name);
21+
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
22+
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
23+
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
24+
(1 row)
25+
1426
select * from pgstattuple('test'::regclass);
1527
table_len | tuple_count | tuple_len | tuple_percent | dead_tuple_count | dead_tuple_len | dead_tuple_percent | free_space | free_percent
1628
-----------+-------------+-----------+---------------+------------------+----------------+--------------------+------------+--------------
1729
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
1830
(1 row)
1931

32+
select pgstattuple(oid) from pg_class where relname = 'test';
33+
pgstattuple
34+
---------------------
35+
(0,0,0,0,0,0,0,0,0)
36+
(1 row)
37+
38+
select pgstattuple(relname) from pg_class where relname = 'test';
39+
pgstattuple
40+
---------------------
41+
(0,0,0,0,0,0,0,0,0)
42+
(1 row)
43+
2044
select * from pgstatindex('test_pkey');
2145
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
2246
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
2347
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
2448
(1 row)
2549

50+
select * from pgstatindex('test_pkey'::text);
51+
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
52+
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
53+
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
54+
(1 row)
55+
56+
select * from pgstatindex('test_pkey'::name);
57+
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
58+
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
59+
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
60+
(1 row)
61+
62+
select * from pgstatindex('test_pkey'::regclass);
63+
version | tree_level | index_size | root_block_no | internal_pages | leaf_pages | empty_pages | deleted_pages | avg_leaf_density | leaf_fragmentation
64+
---------+------------+------------+---------------+----------------+------------+-------------+---------------+------------------+--------------------
65+
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NaN | NaN
66+
(1 row)
67+
68+
select pgstatindex(oid) from pg_class where relname = 'test_pkey';
69+
pgstatindex
70+
---------------------------
71+
(2,0,0,0,0,0,0,0,NaN,NaN)
72+
(1 row)
73+
74+
select pgstatindex(relname) from pg_class where relname = 'test_pkey';
75+
pgstatindex
76+
---------------------------
77+
(2,0,0,0,0,0,0,0,NaN,NaN)
78+
(1 row)
79+
2680
select pg_relpages('test');
2781
pg_relpages
2882
-------------
@@ -35,6 +89,36 @@ select pg_relpages('test_pkey');
3589
1
3690
(1 row)
3791

92+
select pg_relpages('test_pkey'::text);
93+
pg_relpages
94+
-------------
95+
1
96+
(1 row)
97+
98+
select pg_relpages('test_pkey'::name);
99+
pg_relpages
100+
-------------
101+
1
102+
(1 row)
103+
104+
select pg_relpages('test_pkey'::regclass);
105+
pg_relpages
106+
-------------
107+
1
108+
(1 row)
109+
110+
select pg_relpages(oid) from pg_class where relname = 'test_pkey';
111+
pg_relpages
112+
-------------
113+
1
114+
(1 row)
115+
116+
select pg_relpages(relname) from pg_class where relname = 'test_pkey';
117+
pg_relpages
118+
-------------
119+
1
120+
(1 row)
121+
38122
create index test_ginidx on test using gin (b);
39123
select * from pgstatginindex('test_ginidx');
40124
version | pending_pages | pending_tuples

contrib/pgstattuple/pgstatindex.c

+66-6
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,24 @@
3939
#include "utils/rel.h"
4040

4141

42+
/*
43+
* Because of backward-compatibility issue, we have decided to have
44+
* two types of interfaces, with regclass-type input arg and text-type
45+
* input arg, for each function.
46+
*
47+
* Those functions which have text-type input arg will be deprecated
48+
* in the future release.
49+
*/
4250
extern Datum pgstatindex(PG_FUNCTION_ARGS);
51+
extern Datum pgstatindexbyid(PG_FUNCTION_ARGS);
4352
extern Datum pg_relpages(PG_FUNCTION_ARGS);
53+
extern Datum pg_relpagesbyid(PG_FUNCTION_ARGS);
4454
extern Datum pgstatginindex(PG_FUNCTION_ARGS);
4555

4656
PG_FUNCTION_INFO_V1(pgstatindex);
57+
PG_FUNCTION_INFO_V1(pgstatindexbyid);
4758
PG_FUNCTION_INFO_V1(pg_relpages);
59+
PG_FUNCTION_INFO_V1(pg_relpagesbyid);
4860
PG_FUNCTION_INFO_V1(pgstatginindex);
4961

5062
#define IS_INDEX(r) ((r)->rd_rel->relkind == RELKIND_INDEX)
@@ -97,6 +109,8 @@ typedef struct GinIndexStat
97109
int64 pending_tuples;
98110
} GinIndexStat;
99111

112+
static Datum pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo);
113+
100114
/* ------------------------------------------------------
101115
* pgstatindex()
102116
*
@@ -109,11 +123,6 @@ pgstatindex(PG_FUNCTION_ARGS)
109123
text *relname = PG_GETARG_TEXT_P(0);
110124
Relation rel;
111125
RangeVar *relrv;
112-
Datum result;
113-
BlockNumber nblocks;
114-
BlockNumber blkno;
115-
BTIndexStat indexStat;
116-
BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
117126

118127
if (!superuser())
119128
ereport(ERROR,
@@ -123,6 +132,34 @@ pgstatindex(PG_FUNCTION_ARGS)
123132
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
124133
rel = relation_openrv(relrv, AccessShareLock);
125134

135+
PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
136+
}
137+
138+
Datum
139+
pgstatindexbyid(PG_FUNCTION_ARGS)
140+
{
141+
Oid relid = PG_GETARG_OID(0);
142+
Relation rel;
143+
144+
if (!superuser())
145+
ereport(ERROR,
146+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
147+
(errmsg("must be superuser to use pgstattuple functions"))));
148+
149+
rel = relation_open(relid, AccessShareLock);
150+
151+
PG_RETURN_DATUM(pgstatindex_impl(rel, fcinfo));
152+
}
153+
154+
static Datum
155+
pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
156+
{
157+
Datum result;
158+
BlockNumber nblocks;
159+
BlockNumber blkno;
160+
BTIndexStat indexStat;
161+
BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
162+
126163
if (!IS_INDEX(rel) || !IS_BTREE(rel))
127164
elog(ERROR, "relation \"%s\" is not a btree index",
128165
RelationGetRelationName(rel));
@@ -274,7 +311,7 @@ pgstatindex(PG_FUNCTION_ARGS)
274311
result = HeapTupleGetDatum(tuple);
275312
}
276313

277-
PG_RETURN_DATUM(result);
314+
return result;
278315
}
279316

280317
/* --------------------------------------------------------
@@ -311,6 +348,29 @@ pg_relpages(PG_FUNCTION_ARGS)
311348
PG_RETURN_INT64(relpages);
312349
}
313350

351+
Datum
352+
pg_relpagesbyid(PG_FUNCTION_ARGS)
353+
{
354+
Oid relid = PG_GETARG_OID(0);
355+
int64 relpages;
356+
Relation rel;
357+
358+
if (!superuser())
359+
ereport(ERROR,
360+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
361+
(errmsg("must be superuser to use pgstattuple functions"))));
362+
363+
rel = relation_open(relid, AccessShareLock);
364+
365+
/* note: this will work OK on non-local temp tables */
366+
367+
relpages = RelationGetNumberOfBlocks(rel);
368+
369+
relation_close(rel, AccessShareLock);
370+
371+
PG_RETURN_INT64(relpages);
372+
}
373+
314374
/* ------------------------------------------------------
315375
* pgstatginindex()
316376
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* contrib/pgstattuple/pgstattuple--1.1--1.2.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION pgstattuple UPDATE TO '1.2'" to load this file. \quit
5+
6+
ALTER EXTENSION pgstattuple DROP FUNCTION pgstattuple(oid);
7+
DROP FUNCTION pgstattuple(oid);
8+
9+
CREATE FUNCTION pgstattuple(IN reloid regclass,
10+
OUT table_len BIGINT, -- physical table length in bytes
11+
OUT tuple_count BIGINT, -- number of live tuples
12+
OUT tuple_len BIGINT, -- total tuples length in bytes
13+
OUT tuple_percent FLOAT8, -- live tuples in %
14+
OUT dead_tuple_count BIGINT, -- number of dead tuples
15+
OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes
16+
OUT dead_tuple_percent FLOAT8, -- dead tuples in %
17+
OUT free_space BIGINT, -- free space in bytes
18+
OUT free_percent FLOAT8) -- free space in %
19+
AS 'MODULE_PATHNAME', 'pgstattuplebyid'
20+
LANGUAGE C STRICT;
21+
22+
CREATE FUNCTION pgstatindex(IN relname regclass,
23+
OUT version INT,
24+
OUT tree_level INT,
25+
OUT index_size BIGINT,
26+
OUT root_block_no BIGINT,
27+
OUT internal_pages BIGINT,
28+
OUT leaf_pages BIGINT,
29+
OUT empty_pages BIGINT,
30+
OUT deleted_pages BIGINT,
31+
OUT avg_leaf_density FLOAT8,
32+
OUT leaf_fragmentation FLOAT8)
33+
AS 'MODULE_PATHNAME', 'pgstatindexbyid'
34+
LANGUAGE C STRICT;
35+
36+
CREATE FUNCTION pg_relpages(IN relname regclass)
37+
RETURNS BIGINT
38+
AS 'MODULE_PATHNAME', 'pg_relpagesbyid'
39+
LANGUAGE C STRICT;

contrib/pgstattuple/pgstattuple--1.1.sql renamed to contrib/pgstattuple/pgstattuple--1.2.sql

+35-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* contrib/pgstattuple/pgstattuple--1.1.sql */
1+
/* contrib/pgstattuple/pgstattuple--1.2.sql */
22

33
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
44
\echo Use "CREATE EXTENSION pgstattuple" to load this file. \quit
@@ -16,19 +16,6 @@ CREATE FUNCTION pgstattuple(IN relname text,
1616
AS 'MODULE_PATHNAME', 'pgstattuple'
1717
LANGUAGE C STRICT;
1818

19-
CREATE FUNCTION pgstattuple(IN reloid oid,
20-
OUT table_len BIGINT, -- physical table length in bytes
21-
OUT tuple_count BIGINT, -- number of live tuples
22-
OUT tuple_len BIGINT, -- total tuples length in bytes
23-
OUT tuple_percent FLOAT8, -- live tuples in %
24-
OUT dead_tuple_count BIGINT, -- number of dead tuples
25-
OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes
26-
OUT dead_tuple_percent FLOAT8, -- dead tuples in %
27-
OUT free_space BIGINT, -- free space in bytes
28-
OUT free_percent FLOAT8) -- free space in %
29-
AS 'MODULE_PATHNAME', 'pgstattuplebyid'
30-
LANGUAGE C STRICT;
31-
3219
CREATE FUNCTION pgstatindex(IN relname text,
3320
OUT version INT,
3421
OUT tree_level INT,
@@ -56,3 +43,37 @@ CREATE FUNCTION pgstatginindex(IN relname regclass,
5643
OUT pending_tuples BIGINT)
5744
AS 'MODULE_PATHNAME', 'pgstatginindex'
5845
LANGUAGE C STRICT;
46+
47+
/* New stuff in 1.2 begins here */
48+
49+
CREATE FUNCTION pgstattuple(IN reloid regclass,
50+
OUT table_len BIGINT, -- physical table length in bytes
51+
OUT tuple_count BIGINT, -- number of live tuples
52+
OUT tuple_len BIGINT, -- total tuples length in bytes
53+
OUT tuple_percent FLOAT8, -- live tuples in %
54+
OUT dead_tuple_count BIGINT, -- number of dead tuples
55+
OUT dead_tuple_len BIGINT, -- total dead tuples length in bytes
56+
OUT dead_tuple_percent FLOAT8, -- dead tuples in %
57+
OUT free_space BIGINT, -- free space in bytes
58+
OUT free_percent FLOAT8) -- free space in %
59+
AS 'MODULE_PATHNAME', 'pgstattuplebyid'
60+
LANGUAGE C STRICT;
61+
62+
CREATE FUNCTION pgstatindex(IN relname regclass,
63+
OUT version INT,
64+
OUT tree_level INT,
65+
OUT index_size BIGINT,
66+
OUT root_block_no BIGINT,
67+
OUT internal_pages BIGINT,
68+
OUT leaf_pages BIGINT,
69+
OUT empty_pages BIGINT,
70+
OUT deleted_pages BIGINT,
71+
OUT avg_leaf_density FLOAT8,
72+
OUT leaf_fragmentation FLOAT8)
73+
AS 'MODULE_PATHNAME', 'pgstatindexbyid'
74+
LANGUAGE C STRICT;
75+
76+
CREATE FUNCTION pg_relpages(IN relname regclass)
77+
RETURNS BIGINT
78+
AS 'MODULE_PATHNAME', 'pg_relpagesbyid'
79+
LANGUAGE C STRICT;
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pgstattuple extension
22
comment = 'show tuple-level statistics'
3-
default_version = '1.1'
3+
default_version = '1.2'
44
module_pathname = '$libdir/pgstattuple'
55
relocatable = true

contrib/pgstattuple/sql/pgstattuple.sql

+14
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,27 @@ CREATE EXTENSION pgstattuple;
88

99
create table test (a int primary key, b int[]);
1010

11+
select * from pgstattuple('test');
1112
select * from pgstattuple('test'::text);
13+
select * from pgstattuple('test'::name);
1214
select * from pgstattuple('test'::regclass);
15+
select pgstattuple(oid) from pg_class where relname = 'test';
16+
select pgstattuple(relname) from pg_class where relname = 'test';
1317

1418
select * from pgstatindex('test_pkey');
19+
select * from pgstatindex('test_pkey'::text);
20+
select * from pgstatindex('test_pkey'::name);
21+
select * from pgstatindex('test_pkey'::regclass);
22+
select pgstatindex(oid) from pg_class where relname = 'test_pkey';
23+
select pgstatindex(relname) from pg_class where relname = 'test_pkey';
1524

1625
select pg_relpages('test');
1726
select pg_relpages('test_pkey');
27+
select pg_relpages('test_pkey'::text);
28+
select pg_relpages('test_pkey'::name);
29+
select pg_relpages('test_pkey'::regclass);
30+
select pg_relpages(oid) from pg_class where relname = 'test_pkey';
31+
select pg_relpages(relname) from pg_class where relname = 'test_pkey';
1832

1933
create index test_ginidx on test using gin (b);
2034

0 commit comments

Comments
 (0)