]> granicus.if.org Git - postgresql/commitdiff
Make pg_relation_size() and friends return NULL if the object doesn't exist.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 19 Jan 2012 11:06:30 +0000 (13:06 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 19 Jan 2012 11:06:30 +0000 (13:06 +0200)
That avoids errors when the functions are used in queries like "SELECT
pg_relation_size(oid) FROM pg_class", and a table is dropped concurrently.

Phil Sorber

doc/src/sgml/func.sgml
src/backend/utils/adt/dbsize.c

index 7d7aba7aeef77f188326bb2c00c8626e20a1ff9b..ff9b8b0853e2ddb229c902d733828d8667f7e93d 100644 (file)
@@ -14979,6 +14979,11 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
     the table name.
    </para>
 
+   <para>
+    If an OID that does not represent an existing object is passed as
+    argument to one of the above functions, NULL is returned.
+   </para>
+
    <para>
     The functions shown in <xref linkend="functions-admin-dblocation"> assist
     in identifying the specific disk files associated with database objects.
index cff061c891d9eb3881120d696bb7d12d3f8b5b2d..26a8c01432c7048c0d15af798d401f49906f03a9 100644 (file)
@@ -120,12 +120,6 @@ calculate_database_size(Oid dbOid)
 
        FreeDir(dirdesc);
 
-       /* Complain if we found no trace of the DB at all */
-       if (!totalsize)
-               ereport(ERROR,
-                               (ERRCODE_UNDEFINED_DATABASE,
-                                errmsg("database with OID %u does not exist", dbOid)));
-
        return totalsize;
 }
 
@@ -133,8 +127,14 @@ Datum
 pg_database_size_oid(PG_FUNCTION_ARGS)
 {
        Oid                     dbOid = PG_GETARG_OID(0);
+       int64           size;
 
-       PG_RETURN_INT64(calculate_database_size(dbOid));
+       size = calculate_database_size(dbOid);
+
+       if (size == 0)
+               PG_RETURN_NULL();
+
+       PG_RETURN_INT64(size);
 }
 
 Datum
@@ -142,13 +142,20 @@ pg_database_size_name(PG_FUNCTION_ARGS)
 {
        Name            dbName = PG_GETARG_NAME(0);
        Oid                     dbOid = get_database_oid(NameStr(*dbName), false);
+       int64           size;
+
+       size = calculate_database_size(dbOid);
 
-       PG_RETURN_INT64(calculate_database_size(dbOid));
+       if (size == 0)
+               PG_RETURN_NULL();
+
+       PG_RETURN_INT64(size);
 }
 
 
 /*
- * calculate total size of tablespace
+ * Calculate total size of tablespace. Returns -1 if the tablespace directory
+ * cannot be found.
  */
 static int64
 calculate_tablespace_size(Oid tblspcOid)
@@ -184,10 +191,7 @@ calculate_tablespace_size(Oid tblspcOid)
        dirdesc = AllocateDir(tblspcPath);
 
        if (!dirdesc)
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not open tablespace directory \"%s\": %m",
-                                               tblspcPath)));
+               return -1;
 
        while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL)
        {
@@ -226,8 +230,14 @@ Datum
 pg_tablespace_size_oid(PG_FUNCTION_ARGS)
 {
        Oid                     tblspcOid = PG_GETARG_OID(0);
+       int64           size;
+
+       size = calculate_tablespace_size(tblspcOid);
 
-       PG_RETURN_INT64(calculate_tablespace_size(tblspcOid));
+       if (size < 0)
+               PG_RETURN_NULL();
+
+       PG_RETURN_INT64(size);
 }
 
 Datum
@@ -235,8 +245,14 @@ pg_tablespace_size_name(PG_FUNCTION_ARGS)
 {
        Name            tblspcName = PG_GETARG_NAME(0);
        Oid                     tblspcOid = get_tablespace_oid(NameStr(*tblspcName), false);
+       int64           size;
 
-       PG_RETURN_INT64(calculate_tablespace_size(tblspcOid));
+       size = calculate_tablespace_size(tblspcOid);
+
+       if (size < 0)
+               PG_RETURN_NULL();
+
+       PG_RETURN_INT64(size);
 }
 
 
@@ -289,7 +305,17 @@ pg_relation_size(PG_FUNCTION_ARGS)
        Relation        rel;
        int64           size;
 
-       rel = relation_open(relOid, AccessShareLock);
+       rel = try_relation_open(relOid, AccessShareLock);
+
+       /*
+        * 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
+        * alread-dropped tables than throw an error and abort the whole query.
+        */
+       if (rel == NULL)
+               PG_RETURN_NULL();
 
        size = calculate_relation_size(&(rel->rd_node), rel->rd_backend,
                                                          forkname_to_number(text_to_cstring(forkName)));
@@ -339,14 +365,11 @@ calculate_toast_table_size(Oid toastrelid)
  * those won't have attached toast tables, but they can have multiple forks.
  */
 static int64
-calculate_table_size(Oid relOid)
+calculate_table_size(Relation rel)
 {
        int64           size = 0;
-       Relation        rel;
        ForkNumber      forkNum;
 
-       rel = relation_open(relOid, AccessShareLock);
-
        /*
         * heap size, including FSM and VM
         */
@@ -360,8 +383,6 @@ calculate_table_size(Oid relOid)
        if (OidIsValid(rel->rd_rel->reltoastrelid))
                size += calculate_toast_table_size(rel->rd_rel->reltoastrelid);
 
-       relation_close(rel, AccessShareLock);
-
        return size;
 }
 
@@ -371,12 +392,9 @@ calculate_table_size(Oid relOid)
  * Can be applied safely to an index, but you'll just get zero.
  */
 static int64
-calculate_indexes_size(Oid relOid)
+calculate_indexes_size(Relation rel)
 {
        int64           size = 0;
-       Relation        rel;
-
-       rel = relation_open(relOid, AccessShareLock);
 
        /*
         * Aggregate all indexes on the given relation
@@ -405,8 +423,6 @@ calculate_indexes_size(Oid relOid)
                list_free(index_oids);
        }
 
-       relation_close(rel, AccessShareLock);
-
        return size;
 }
 
@@ -414,16 +430,38 @@ Datum
 pg_table_size(PG_FUNCTION_ARGS)
 {
        Oid                     relOid = PG_GETARG_OID(0);
+       Relation        rel;
+       int64           size;
+
+       rel = try_relation_open(relOid, AccessShareLock);
+
+       if (rel == NULL)
+               PG_RETURN_NULL();
 
-       PG_RETURN_INT64(calculate_table_size(relOid));
+       size = calculate_table_size(rel);
+
+       relation_close(rel, AccessShareLock);
+
+       PG_RETURN_INT64(size);
 }
 
 Datum
 pg_indexes_size(PG_FUNCTION_ARGS)
 {
        Oid                     relOid = PG_GETARG_OID(0);
+       Relation        rel;
+       int64           size;
 
-       PG_RETURN_INT64(calculate_indexes_size(relOid));
+       rel = try_relation_open(relOid, AccessShareLock);
+
+       if (rel == NULL)
+               PG_RETURN_NULL();
+
+       size = calculate_indexes_size(rel);
+
+       relation_close(rel, AccessShareLock);
+
+       PG_RETURN_INT64(size);
 }
 
 /*
@@ -431,7 +469,7 @@ pg_indexes_size(PG_FUNCTION_ARGS)
  *     including heap data, index data, toast data, FSM, VM.
  */
 static int64
-calculate_total_relation_size(Oid Relid)
+calculate_total_relation_size(Relation rel)
 {
        int64           size;
 
@@ -439,12 +477,12 @@ calculate_total_relation_size(Oid Relid)
         * Aggregate the table size, this includes size of the heap, toast and
         * toast index with free space and visibility map
         */
-       size = calculate_table_size(Relid);
+       size = calculate_table_size(rel);
 
        /*
         * Add size of all attached indexes as well
         */
-       size += calculate_indexes_size(Relid);
+       size += calculate_indexes_size(rel);
 
        return size;
 }
@@ -452,9 +490,20 @@ calculate_total_relation_size(Oid Relid)
 Datum
 pg_total_relation_size(PG_FUNCTION_ARGS)
 {
-       Oid                     relid = PG_GETARG_OID(0);
+       Oid                     relOid = PG_GETARG_OID(0);
+       Relation        rel;
+       int64           size;
+
+       rel = try_relation_open(relOid, AccessShareLock);
+
+       if (rel == NULL)
+               PG_RETURN_NULL();
 
-       PG_RETURN_INT64(calculate_total_relation_size(relid));
+       size = calculate_total_relation_size(rel);
+
+       relation_close(rel, AccessShareLock);
+
+       PG_RETURN_INT64(size);
 }
 
 /*