]> granicus.if.org Git - postgresql/commitdiff
Fix pgstattuple functions to use regclass-type as the argument.
authorFujii Masao <fujii@postgresql.org>
Thu, 18 Jul 2013 18:50:20 +0000 (03:50 +0900)
committerFujii Masao <fujii@postgresql.org>
Thu, 18 Jul 2013 18:50:20 +0000 (03:50 +0900)
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.

contrib/pgstattuple/Makefile
contrib/pgstattuple/expected/pgstattuple.out
contrib/pgstattuple/pgstatindex.c
contrib/pgstattuple/pgstattuple--1.1--1.2.sql [new file with mode: 0644]
contrib/pgstattuple/pgstattuple--1.2.sql [moved from contrib/pgstattuple/pgstattuple--1.1.sql with 75% similarity]
contrib/pgstattuple/pgstattuple.control
contrib/pgstattuple/sql/pgstattuple.sql
doc/src/sgml/pgstattuple.sgml

index fc893d8c8556ef1b18c293a4c9b6c8f9473dc17b..d991c3a803993b2af59dafe70ecd6498df988c06 100644 (file)
@@ -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
 
index ab28f50cb086a4ff297b9f47813d87efbf28d432..7aab96766539c45a4596c17b8bf40fd24e3984a1 100644 (file)
@@ -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 
index 97f897ec1e5bb17d94ba170c0190bdd9d8b044bf..282d82ca8280b5d9aa74b8fe8219ef777f5b5712 100644 (file)
 #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 (file)
index 0000000..2783a63
--- /dev/null
@@ -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;
similarity index 75%
rename from contrib/pgstattuple/pgstattuple--1.1.sql
rename to contrib/pgstattuple/pgstattuple--1.2.sql
index b21fbf83e466484069f2715e8576a6d2e1206b38..e5fa2f58dab2aa415d0fb4effc90fb17701dcb76 100644 (file)
@@ -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;
index fcfd36f1b1ab39eecd86234643b2fca88a25ae09..a7cf47fd9217a1238bd2a7cfd5b0aab5ab60da0c 100644 (file)
@@ -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
index 8cb350d6ee1ae8a5efb5525dd231a4bd82416438..0e0ad0e15d5a7b256c06d6208327d178a5f9d251 100644 (file)
@@ -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);
 
index f2bc2a68f888196e57f41de6311da352f632209b..6cae04a9c8b9ae8b08f412a10352bef9c3d4833e 100644 (file)
@@ -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>