Hi.

You may have guessed from $subject that the two don't work together.

create table p (a int) partition by list (a);
create table p1 partition of p for values in (1, 2) partition by list (a);
create table p11 partition of p1 for values in (1);
create table p12 partition of p1 for values in (2);
insert into p select i % 2 + 1 from generate_series(1, 1000) i;

On HEAD:

select pg_relation_size('p');
 pg_relation_size
------------------
                0
(1 row)

select pg_total_relation_size('p');
 pg_total_relation_size
------------------------
                      0
(1 row)

After applying the attached patch:

select pg_relation_size('p');
 pg_relation_size
------------------
            49152
(1 row)

select pg_total_relation_size('p');
 pg_total_relation_size
------------------------
                  98304
(1 row)

The patch basically accumulates and returns the sizes of all leaf
partitions when passed a partitioned table.  Will add it to next CF.

Thanks,
Amit
From 4a5db12ad0155e043500d87caf2cc9438eb87e23 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Thu, 14 Dec 2017 13:56:08 +0900
Subject: [PATCH] Teach dbsize.c functions about partitioned tables

---
 src/backend/utils/adt/dbsize.c | 101 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 85 insertions(+), 16 deletions(-)

diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c
index 58c0b01bdc..145f511c6c 100644
--- a/src/backend/utils/adt/dbsize.c
+++ b/src/backend/utils/adt/dbsize.c
@@ -17,6 +17,7 @@
 #include "access/htup_details.h"
 #include "catalog/catalog.h"
 #include "catalog/namespace.h"
+#include "catalog/partition.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_tablespace.h"
 #include "commands/dbcommands.h"
@@ -307,13 +308,17 @@ calculate_relation_size(RelFileNode *rfn, BackendId 
backend, ForkNumber forknum)
        return totalsize;
 }
 
-Datum
-pg_relation_size(PG_FUNCTION_ARGS)
+/*
+ * Computes and stores in *size the file size of the specified fork of the
+ * relation with OID relOid.
+
+ * Returns true if size was sucessfully calculated and stored in *size, false
+ * otherwise.
+ */
+static bool
+pg_relation_size_internal(Oid relOid, char *forkName, int64 *size)
 {
-       Oid                     relOid = PG_GETARG_OID(0);
-       text       *forkName = PG_GETARG_TEXT_PP(1);
        Relation        rel;
-       int64           size;
 
        rel = try_relation_open(relOid, AccessShareLock);
 
@@ -321,17 +326,52 @@ pg_relation_size(PG_FUNCTION_ARGS)
         * Before 9.2, we used to throw an error if the relation didn't exist, 
but
         * that makes queries like "SELECT pg_relation_size(oid) FROM pg_class"
         * less robust, because while we scan pg_class with an MVCC snapshot,
-        * someone else might drop the table. It's better to return NULL for
-        * already-dropped tables than throw an error and abort the whole query.
+        * someone else might drop the table. It's better to return that we
+        * couldn't get the size for already-dropped tables than throw an error
+        * and abort the whole query.
         */
        if (rel == NULL)
-               PG_RETURN_NULL();
+               return false;
+
+       /*
+        * For a partitioned table, get the size by accumulating that of its
+        * leaf partitions.
+        */
+       if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+       {
+               PartitionDesc   partdesc = rel->rd_partdesc;
+               int             i;
 
-       size = calculate_relation_size(&(rel->rd_node), rel->rd_backend,
-                                                                  
forkname_to_number(text_to_cstring(forkName)));
+               *size = 0;
+               for (i = 0; i < partdesc->nparts; i++)
+               {
+                       int64   partsize;
+
+                       if (pg_relation_size_internal(partdesc->oids[i], 
forkName,
+                                                                               
  &partsize))
+                               *size += partsize;
+               }
+       }
+       else
+               *size = calculate_relation_size(&(rel->rd_node), 
rel->rd_backend,
+                                                                               
forkname_to_number(forkName));
 
        relation_close(rel, AccessShareLock);
 
+       return true;
+}
+
+Datum
+pg_relation_size(PG_FUNCTION_ARGS)
+{
+       Oid                     relOid = PG_GETARG_OID(0);
+       text       *forkName = PG_GETARG_TEXT_PP(1);
+       int64           size;
+
+       if (!pg_relation_size_internal(relOid, text_to_cstring(forkName),
+                                                                  &size))
+               PG_RETURN_NULL();
+
        PG_RETURN_INT64(size);
 }
 
@@ -508,22 +548,51 @@ calculate_total_relation_size(Relation rel)
        return size;
 }
 
-Datum
-pg_total_relation_size(PG_FUNCTION_ARGS)
+static int64
+pg_total_relation_size_internal(Oid relOid, int64 *size)
 {
-       Oid                     relOid = PG_GETARG_OID(0);
        Relation        rel;
-       int64           size;
 
        rel = try_relation_open(relOid, AccessShareLock);
 
        if (rel == NULL)
-               PG_RETURN_NULL();
+               return false;
 
-       size = calculate_total_relation_size(rel);
+       /*
+        * For a partitioned table, get the size by accumulating that of its
+        * leaf partitions.
+        */
+       if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+       {
+               PartitionDesc   partdesc = rel->rd_partdesc;
+               int             i;
+
+               *size = 0;
+               for (i = 0; i < partdesc->nparts; i++)
+               {
+                       int64   partsize;
+
+                       if (pg_total_relation_size_internal(partdesc->oids[i], 
&partsize))
+                               *size += partsize;
+               }
+       }
+       else
+               *size = calculate_total_relation_size(rel);
 
        relation_close(rel, AccessShareLock);
 
+       return true;
+}
+
+Datum
+pg_total_relation_size(PG_FUNCTION_ARGS)
+{
+       Oid                     relOid = PG_GETARG_OID(0);
+       int64           size;
+
+       if (!pg_total_relation_size_internal(relOid, &size))
+               PG_RETURN_NULL();
+
        PG_RETURN_INT64(size);
 }
 
-- 
2.11.0

Reply via email to