From fa352d662e57fa150158b9cb0a8f127250f8c97f Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Thu, 19 Jan 2012 13:06:30 +0200 Subject: [PATCH] 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 --- doc/src/sgml/func.sgml | 5 ++ src/backend/utils/adt/dbsize.c | 119 +++++++++++++++++++++++---------- 2 files changed, 89 insertions(+), 35 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 7d7aba7aee..ff9b8b0853 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -14979,6 +14979,11 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); the table name. + + If an OID that does not represent an existing object is passed as + argument to one of the above functions, NULL is returned. + + The functions shown in assist in identifying the specific disk files associated with database objects. diff --git a/src/backend/utils/adt/dbsize.c b/src/backend/utils/adt/dbsize.c index cff061c891..26a8c01432 100644 --- a/src/backend/utils/adt/dbsize.c +++ b/src/backend/utils/adt/dbsize.c @@ -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); } /* -- 2.40.0