Commit fa352d66 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Make pg_relation_size() and friends return NULL if the object doesn't exist.

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
parent 6f6b46c9
...@@ -14979,6 +14979,11 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); ...@@ -14979,6 +14979,11 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
the table name. the table name.
</para> </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> <para>
The functions shown in <xref linkend="functions-admin-dblocation"> assist The functions shown in <xref linkend="functions-admin-dblocation"> assist
in identifying the specific disk files associated with database objects. in identifying the specific disk files associated with database objects.
......
...@@ -120,12 +120,6 @@ calculate_database_size(Oid dbOid) ...@@ -120,12 +120,6 @@ calculate_database_size(Oid dbOid)
FreeDir(dirdesc); 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; return totalsize;
} }
...@@ -133,8 +127,14 @@ Datum ...@@ -133,8 +127,14 @@ Datum
pg_database_size_oid(PG_FUNCTION_ARGS) pg_database_size_oid(PG_FUNCTION_ARGS)
{ {
Oid dbOid = PG_GETARG_OID(0); 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 Datum
...@@ -142,13 +142,20 @@ pg_database_size_name(PG_FUNCTION_ARGS) ...@@ -142,13 +142,20 @@ pg_database_size_name(PG_FUNCTION_ARGS)
{ {
Name dbName = PG_GETARG_NAME(0); Name dbName = PG_GETARG_NAME(0);
Oid dbOid = get_database_oid(NameStr(*dbName), false); 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 static int64
calculate_tablespace_size(Oid tblspcOid) calculate_tablespace_size(Oid tblspcOid)
...@@ -184,10 +191,7 @@ calculate_tablespace_size(Oid tblspcOid) ...@@ -184,10 +191,7 @@ calculate_tablespace_size(Oid tblspcOid)
dirdesc = AllocateDir(tblspcPath); dirdesc = AllocateDir(tblspcPath);
if (!dirdesc) if (!dirdesc)
ereport(ERROR, return -1;
(errcode_for_file_access(),
errmsg("could not open tablespace directory \"%s\": %m",
tblspcPath)));
while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL) while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL)
{ {
...@@ -226,8 +230,14 @@ Datum ...@@ -226,8 +230,14 @@ Datum
pg_tablespace_size_oid(PG_FUNCTION_ARGS) pg_tablespace_size_oid(PG_FUNCTION_ARGS)
{ {
Oid tblspcOid = PG_GETARG_OID(0); 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 Datum
...@@ -235,8 +245,14 @@ pg_tablespace_size_name(PG_FUNCTION_ARGS) ...@@ -235,8 +245,14 @@ pg_tablespace_size_name(PG_FUNCTION_ARGS)
{ {
Name tblspcName = PG_GETARG_NAME(0); Name tblspcName = PG_GETARG_NAME(0);
Oid tblspcOid = get_tablespace_oid(NameStr(*tblspcName), false); 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) ...@@ -289,7 +305,17 @@ pg_relation_size(PG_FUNCTION_ARGS)
Relation rel; Relation rel;
int64 size; 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, size = calculate_relation_size(&(rel->rd_node), rel->rd_backend,
forkname_to_number(text_to_cstring(forkName))); forkname_to_number(text_to_cstring(forkName)));
...@@ -339,14 +365,11 @@ calculate_toast_table_size(Oid toastrelid) ...@@ -339,14 +365,11 @@ calculate_toast_table_size(Oid toastrelid)
* those won't have attached toast tables, but they can have multiple forks. * those won't have attached toast tables, but they can have multiple forks.
*/ */
static int64 static int64
calculate_table_size(Oid relOid) calculate_table_size(Relation rel)
{ {
int64 size = 0; int64 size = 0;
Relation rel;
ForkNumber forkNum; ForkNumber forkNum;
rel = relation_open(relOid, AccessShareLock);
/* /*
* heap size, including FSM and VM * heap size, including FSM and VM
*/ */
...@@ -360,8 +383,6 @@ calculate_table_size(Oid relOid) ...@@ -360,8 +383,6 @@ calculate_table_size(Oid relOid)
if (OidIsValid(rel->rd_rel->reltoastrelid)) if (OidIsValid(rel->rd_rel->reltoastrelid))
size += calculate_toast_table_size(rel->rd_rel->reltoastrelid); size += calculate_toast_table_size(rel->rd_rel->reltoastrelid);
relation_close(rel, AccessShareLock);
return size; return size;
} }
...@@ -371,12 +392,9 @@ calculate_table_size(Oid relOid) ...@@ -371,12 +392,9 @@ calculate_table_size(Oid relOid)
* Can be applied safely to an index, but you'll just get zero. * Can be applied safely to an index, but you'll just get zero.
*/ */
static int64 static int64
calculate_indexes_size(Oid relOid) calculate_indexes_size(Relation rel)
{ {
int64 size = 0; int64 size = 0;
Relation rel;
rel = relation_open(relOid, AccessShareLock);
/* /*
* Aggregate all indexes on the given relation * Aggregate all indexes on the given relation
...@@ -405,8 +423,6 @@ calculate_indexes_size(Oid relOid) ...@@ -405,8 +423,6 @@ calculate_indexes_size(Oid relOid)
list_free(index_oids); list_free(index_oids);
} }
relation_close(rel, AccessShareLock);
return size; return size;
} }
...@@ -414,16 +430,38 @@ Datum ...@@ -414,16 +430,38 @@ Datum
pg_table_size(PG_FUNCTION_ARGS) pg_table_size(PG_FUNCTION_ARGS)
{ {
Oid relOid = 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_table_size(relOid)); size = calculate_table_size(rel);
relation_close(rel, AccessShareLock);
PG_RETURN_INT64(size);
} }
Datum Datum
pg_indexes_size(PG_FUNCTION_ARGS) pg_indexes_size(PG_FUNCTION_ARGS)
{ {
Oid relOid = PG_GETARG_OID(0); 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) ...@@ -431,7 +469,7 @@ pg_indexes_size(PG_FUNCTION_ARGS)
* including heap data, index data, toast data, FSM, VM. * including heap data, index data, toast data, FSM, VM.
*/ */
static int64 static int64
calculate_total_relation_size(Oid Relid) calculate_total_relation_size(Relation rel)
{ {
int64 size; int64 size;
...@@ -439,12 +477,12 @@ calculate_total_relation_size(Oid Relid) ...@@ -439,12 +477,12 @@ calculate_total_relation_size(Oid Relid)
* Aggregate the table size, this includes size of the heap, toast and * Aggregate the table size, this includes size of the heap, toast and
* toast index with free space and visibility map * 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 * Add size of all attached indexes as well
*/ */
size += calculate_indexes_size(Relid); size += calculate_indexes_size(rel);
return size; return size;
} }
...@@ -452,9 +490,20 @@ calculate_total_relation_size(Oid Relid) ...@@ -452,9 +490,20 @@ calculate_total_relation_size(Oid Relid)
Datum Datum
pg_total_relation_size(PG_FUNCTION_ARGS) 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);
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment