PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
dbsize.c File Reference
#include "postgres.h"
#include <sys/stat.h>
#include "access/htup_details.h"
#include "access/relation.h"
#include "catalog/namespace.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
#include "catalog/pg_tablespace.h"
#include "commands/dbcommands.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/numeric.h"
#include "utils/rel.h"
#include "utils/relfilenumbermap.h"
#include "utils/relmapper.h"
#include "utils/syscache.h"
Include dependency graph for dbsize.c:

Go to the source code of this file.

Data Structures

struct  size_pretty_unit
 
struct  size_bytes_unit_alias
 

Macros

#define half_rounded(x)   (((x) + ((x) < 0 ? -1 : 1)) / 2)
 

Functions

static int64 db_dir_size (const char *path)
 
static int64 calculate_database_size (Oid dbOid)
 
Datum pg_database_size_oid (PG_FUNCTION_ARGS)
 
Datum pg_database_size_name (PG_FUNCTION_ARGS)
 
static int64 calculate_tablespace_size (Oid tblspcOid)
 
Datum pg_tablespace_size_oid (PG_FUNCTION_ARGS)
 
Datum pg_tablespace_size_name (PG_FUNCTION_ARGS)
 
static int64 calculate_relation_size (RelFileLocator *rfn, ProcNumber backend, ForkNumber forknum)
 
Datum pg_relation_size (PG_FUNCTION_ARGS)
 
static int64 calculate_toast_table_size (Oid toastrelid)
 
static int64 calculate_table_size (Relation rel)
 
static int64 calculate_indexes_size (Relation rel)
 
Datum pg_table_size (PG_FUNCTION_ARGS)
 
Datum pg_indexes_size (PG_FUNCTION_ARGS)
 
static int64 calculate_total_relation_size (Relation rel)
 
Datum pg_total_relation_size (PG_FUNCTION_ARGS)
 
Datum pg_size_pretty (PG_FUNCTION_ARGS)
 
static char * numeric_to_cstring (Numeric n)
 
static bool numeric_is_less (Numeric a, Numeric b)
 
static Numeric numeric_absolute (Numeric n)
 
static Numeric numeric_half_rounded (Numeric n)
 
static Numeric numeric_truncated_divide (Numeric n, int64 divisor)
 
Datum pg_size_pretty_numeric (PG_FUNCTION_ARGS)
 
Datum pg_size_bytes (PG_FUNCTION_ARGS)
 
Datum pg_relation_filenode (PG_FUNCTION_ARGS)
 
Datum pg_filenode_relation (PG_FUNCTION_ARGS)
 
Datum pg_relation_filepath (PG_FUNCTION_ARGS)
 

Variables

static const struct size_pretty_unit size_pretty_units []
 
static const struct size_bytes_unit_alias size_bytes_aliases []
 

Macro Definition Documentation

◆ half_rounded

#define half_rounded (   x)    (((x) + ((x) < 0 ? -1 : 1)) / 2)

Definition at line 35 of file dbsize.c.

Function Documentation

◆ calculate_database_size()

static int64 calculate_database_size ( Oid  dbOid)
static

Definition at line 118 of file dbsize.c.

119{
120 int64 totalsize;
121 DIR *dirdesc;
122 struct dirent *direntry;
123 char dirpath[MAXPGPATH];
124 char pathname[MAXPGPATH + 21 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
125 AclResult aclresult;
126
127 /*
128 * User must have connect privilege for target database or have privileges
129 * of pg_read_all_stats
130 */
131 aclresult = object_aclcheck(DatabaseRelationId, dbOid, GetUserId(), ACL_CONNECT);
132 if (aclresult != ACLCHECK_OK &&
133 !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
134 {
136 get_database_name(dbOid));
137 }
138
139 /* Shared storage in pg_global is not counted */
140
141 /* Include pg_default storage */
142 snprintf(pathname, sizeof(pathname), "base/%u", dbOid);
143 totalsize = db_dir_size(pathname);
144
145 /* Scan the non-default tablespaces */
147 dirdesc = AllocateDir(dirpath);
148
149 while ((direntry = ReadDir(dirdesc, dirpath)) != NULL)
150 {
152
153 if (strcmp(direntry->d_name, ".") == 0 ||
154 strcmp(direntry->d_name, "..") == 0)
155 continue;
156
157 snprintf(pathname, sizeof(pathname), "%s/%s/%s/%u",
159 totalsize += db_dir_size(pathname);
160 }
161
162 FreeDir(dirdesc);
163
164 return totalsize;
165}
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
int64_t int64
Definition: c.h:485
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3187
static int64 db_dir_size(const char *path)
Definition: dbsize.c:74
int FreeDir(DIR *dir)
Definition: fd.c:2983
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2931
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:517
@ OBJECT_DATABASE
Definition: parsenodes.h:2321
#define ACL_CONNECT
Definition: parsenodes.h:87
#define MAXPGPATH
#define snprintf
Definition: port.h:238
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

References ACL_CONNECT, aclcheck_error(), ACLCHECK_OK, AllocateDir(), CHECK_FOR_INTERRUPTS, dirent::d_name, db_dir_size(), FreeDir(), get_database_name(), GetUserId(), has_privs_of_role(), MAXPGPATH, object_aclcheck(), OBJECT_DATABASE, PG_TBLSPC_DIR, ReadDir(), snprintf, and TABLESPACE_VERSION_DIRECTORY.

Referenced by pg_database_size_name(), and pg_database_size_oid().

◆ calculate_indexes_size()

static int64 calculate_indexes_size ( Relation  rel)
static

Definition at line 469 of file dbsize.c.

470{
471 int64 size = 0;
472
473 /*
474 * Aggregate all indexes on the given relation
475 */
476 if (rel->rd_rel->relhasindex)
477 {
478 List *index_oids = RelationGetIndexList(rel);
479 ListCell *cell;
480
481 foreach(cell, index_oids)
482 {
483 Oid idxOid = lfirst_oid(cell);
484 Relation idxRel;
485 ForkNumber forkNum;
486
487 idxRel = relation_open(idxOid, AccessShareLock);
488
489 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
491 idxRel->rd_backend,
492 forkNum);
493
495 }
496
497 list_free(index_oids);
498 }
499
500 return size;
501}
static int64 calculate_relation_size(RelFileLocator *rfn, ProcNumber backend, ForkNumber forknum)
Definition: dbsize.c:326
void list_free(List *list)
Definition: list.c:1546
#define AccessShareLock
Definition: lockdefs.h:36
#define lfirst_oid(lc)
Definition: pg_list.h:174
unsigned int Oid
Definition: postgres_ext.h:32
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4756
ForkNumber
Definition: relpath.h:56
#define MAX_FORKNUM
Definition: relpath.h:70
static pg_noinline void Size size
Definition: slab.c:607
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
Definition: pg_list.h:54
ProcNumber rd_backend
Definition: rel.h:60
RelFileLocator rd_locator
Definition: rel.h:57
Form_pg_class rd_rel
Definition: rel.h:111

References AccessShareLock, calculate_relation_size(), lfirst_oid, list_free(), MAX_FORKNUM, RelationData::rd_backend, RelationData::rd_locator, RelationData::rd_rel, relation_close(), relation_open(), RelationGetIndexList(), and size.

Referenced by calculate_total_relation_size(), and pg_indexes_size().

◆ calculate_relation_size()

static int64 calculate_relation_size ( RelFileLocator rfn,
ProcNumber  backend,
ForkNumber  forknum 
)
static

Definition at line 326 of file dbsize.c.

327{
328 int64 totalsize = 0;
329 char *relationpath;
330 char pathname[MAXPGPATH];
331 unsigned int segcount = 0;
332
333 relationpath = relpathbackend(*rfn, backend, forknum);
334
335 for (segcount = 0;; segcount++)
336 {
337 struct stat fst;
338
340
341 if (segcount == 0)
342 snprintf(pathname, MAXPGPATH, "%s",
343 relationpath);
344 else
345 snprintf(pathname, MAXPGPATH, "%s.%u",
346 relationpath, segcount);
347
348 if (stat(pathname, &fst) < 0)
349 {
350 if (errno == ENOENT)
351 break;
352 else
355 errmsg("could not stat file \"%s\": %m", pathname)));
356 }
357 totalsize += fst.st_size;
358 }
359
360 return totalsize;
361}
int errcode_for_file_access(void)
Definition: elog.c:876
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define relpathbackend(rlocator, backend, forknum)
Definition: relpath.h:93
#define stat
Definition: win32_port.h:274

References CHECK_FOR_INTERRUPTS, ereport, errcode_for_file_access(), errmsg(), ERROR, MAXPGPATH, relpathbackend, snprintf, stat::st_size, and stat.

Referenced by calculate_indexes_size(), calculate_table_size(), calculate_toast_table_size(), and pg_relation_size().

◆ calculate_table_size()

static int64 calculate_table_size ( Relation  rel)
static

Definition at line 442 of file dbsize.c.

443{
444 int64 size = 0;
445 ForkNumber forkNum;
446
447 /*
448 * heap size, including FSM and VM
449 */
450 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
452 forkNum);
453
454 /*
455 * Size of toast relation
456 */
457 if (OidIsValid(rel->rd_rel->reltoastrelid))
458 size += calculate_toast_table_size(rel->rd_rel->reltoastrelid);
459
460 return size;
461}
#define OidIsValid(objectId)
Definition: c.h:732
static int64 calculate_toast_table_size(Oid toastrelid)
Definition: dbsize.c:396

References calculate_relation_size(), calculate_toast_table_size(), MAX_FORKNUM, OidIsValid, RelationData::rd_backend, RelationData::rd_locator, RelationData::rd_rel, and size.

Referenced by calculate_total_relation_size(), and pg_table_size().

◆ calculate_tablespace_size()

static int64 calculate_tablespace_size ( Oid  tblspcOid)
static

Definition at line 211 of file dbsize.c.

212{
213 char tblspcPath[MAXPGPATH];
214 char pathname[MAXPGPATH * 2];
215 int64 totalsize = 0;
216 DIR *dirdesc;
217 struct dirent *direntry;
218 AclResult aclresult;
219
220 /*
221 * User must have privileges of pg_read_all_stats or have CREATE privilege
222 * for target tablespace, either explicitly granted or implicitly because
223 * it is default for current database.
224 */
225 if (tblspcOid != MyDatabaseTableSpace &&
226 !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
227 {
228 aclresult = object_aclcheck(TableSpaceRelationId, tblspcOid, GetUserId(), ACL_CREATE);
229 if (aclresult != ACLCHECK_OK)
231 get_tablespace_name(tblspcOid));
232 }
233
234 if (tblspcOid == DEFAULTTABLESPACE_OID)
235 snprintf(tblspcPath, MAXPGPATH, "base");
236 else if (tblspcOid == GLOBALTABLESPACE_OID)
237 snprintf(tblspcPath, MAXPGPATH, "global");
238 else
239 snprintf(tblspcPath, MAXPGPATH, "%s/%u/%s", PG_TBLSPC_DIR, tblspcOid,
241
242 dirdesc = AllocateDir(tblspcPath);
243
244 if (!dirdesc)
245 return -1;
246
247 while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL)
248 {
249 struct stat fst;
250
252
253 if (strcmp(direntry->d_name, ".") == 0 ||
254 strcmp(direntry->d_name, "..") == 0)
255 continue;
256
257 snprintf(pathname, sizeof(pathname), "%s/%s", tblspcPath, direntry->d_name);
258
259 if (stat(pathname, &fst) < 0)
260 {
261 if (errno == ENOENT)
262 continue;
263 else
266 errmsg("could not stat file \"%s\": %m", pathname)));
267 }
268
269 if (S_ISDIR(fst.st_mode))
270 totalsize += db_dir_size(pathname);
271
272 totalsize += fst.st_size;
273 }
274
275 FreeDir(dirdesc);
276
277 return totalsize;
278}
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid MyDatabaseTableSpace
Definition: globals.c:95
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2354
#define ACL_CREATE
Definition: parsenodes.h:85
#define S_ISDIR(m)
Definition: win32_port.h:315

References ACL_CREATE, aclcheck_error(), ACLCHECK_OK, AllocateDir(), CHECK_FOR_INTERRUPTS, dirent::d_name, db_dir_size(), ereport, errcode_for_file_access(), errmsg(), ERROR, FreeDir(), get_tablespace_name(), GetUserId(), has_privs_of_role(), MAXPGPATH, MyDatabaseTableSpace, object_aclcheck(), OBJECT_TABLESPACE, PG_TBLSPC_DIR, ReadDir(), S_ISDIR, snprintf, stat::st_mode, stat::st_size, stat, and TABLESPACE_VERSION_DIRECTORY.

Referenced by pg_tablespace_size_name(), and pg_tablespace_size_oid().

◆ calculate_toast_table_size()

static int64 calculate_toast_table_size ( Oid  toastrelid)
static

Definition at line 396 of file dbsize.c.

397{
398 int64 size = 0;
399 Relation toastRel;
400 ForkNumber forkNum;
401 ListCell *lc;
402 List *indexlist;
403
404 toastRel = relation_open(toastrelid, AccessShareLock);
405
406 /* toast heap size, including FSM and VM size */
407 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
409 toastRel->rd_backend, forkNum);
410
411 /* toast index size, including FSM and VM size */
412 indexlist = RelationGetIndexList(toastRel);
413
414 /* Size is calculated using all the indexes available */
415 foreach(lc, indexlist)
416 {
417 Relation toastIdxRel;
418
419 toastIdxRel = relation_open(lfirst_oid(lc),
421 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
422 size += calculate_relation_size(&(toastIdxRel->rd_locator),
423 toastIdxRel->rd_backend, forkNum);
424
425 relation_close(toastIdxRel, AccessShareLock);
426 }
427 list_free(indexlist);
429
430 return size;
431}

References AccessShareLock, calculate_relation_size(), lfirst_oid, list_free(), MAX_FORKNUM, RelationData::rd_backend, RelationData::rd_locator, relation_close(), relation_open(), RelationGetIndexList(), and size.

Referenced by calculate_table_size().

◆ calculate_total_relation_size()

static int64 calculate_total_relation_size ( Relation  rel)
static

Definition at line 546 of file dbsize.c.

547{
548 int64 size;
549
550 /*
551 * Aggregate the table size, this includes size of the heap, toast and
552 * toast index with free space and visibility map
553 */
555
556 /*
557 * Add size of all attached indexes as well
558 */
560
561 return size;
562}
static int64 calculate_indexes_size(Relation rel)
Definition: dbsize.c:469
static int64 calculate_table_size(Relation rel)
Definition: dbsize.c:442

References calculate_indexes_size(), calculate_table_size(), and size.

Referenced by pg_total_relation_size().

◆ db_dir_size()

static int64 db_dir_size ( const char *  path)
static

Definition at line 74 of file dbsize.c.

75{
76 int64 dirsize = 0;
77 struct dirent *direntry;
78 DIR *dirdesc;
79 char filename[MAXPGPATH * 2];
80
81 dirdesc = AllocateDir(path);
82
83 if (!dirdesc)
84 return 0;
85
86 while ((direntry = ReadDir(dirdesc, path)) != NULL)
87 {
88 struct stat fst;
89
91
92 if (strcmp(direntry->d_name, ".") == 0 ||
93 strcmp(direntry->d_name, "..") == 0)
94 continue;
95
96 snprintf(filename, sizeof(filename), "%s/%s", path, direntry->d_name);
97
98 if (stat(filename, &fst) < 0)
99 {
100 if (errno == ENOENT)
101 continue;
102 else
105 errmsg("could not stat file \"%s\": %m", filename)));
106 }
107 dirsize += fst.st_size;
108 }
109
110 FreeDir(dirdesc);
111 return dirsize;
112}
static char * filename
Definition: pg_dumpall.c:119

References AllocateDir(), CHECK_FOR_INTERRUPTS, dirent::d_name, ereport, errcode_for_file_access(), errmsg(), ERROR, filename, FreeDir(), MAXPGPATH, ReadDir(), snprintf, stat::st_size, and stat.

Referenced by calculate_database_size(), and calculate_tablespace_size().

◆ numeric_absolute()

static Numeric numeric_absolute ( Numeric  n)
static

Definition at line 646 of file dbsize.c.

647{
648 Datum d = NumericGetDatum(n);
649 Datum result;
650
651 result = DirectFunctionCall1(numeric_abs, d);
652 return DatumGetNumeric(result);
653}
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1393
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:61
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:73
uintptr_t Datum
Definition: postgres.h:69

References DatumGetNumeric(), DirectFunctionCall1, numeric_abs(), and NumericGetDatum().

Referenced by pg_size_pretty_numeric().

◆ numeric_half_rounded()

static Numeric numeric_half_rounded ( Numeric  n)
static

Definition at line 656 of file dbsize.c.

657{
658 Datum d = NumericGetDatum(n);
659 Datum zero;
660 Datum one;
661 Datum two;
662 Datum result;
663
667
669 d = DirectFunctionCall2(numeric_add, d, one);
670 else
671 d = DirectFunctionCall2(numeric_sub, d, one);
672
673 result = DirectFunctionCall2(numeric_div_trunc, d, two);
674 return DatumGetNumeric(result);
675}
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition: numeric.c:3043
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4401
Datum numeric_ge(PG_FUNCTION_ARGS)
Definition: numeric.c:2578
Datum numeric_div_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:3377
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2966
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:643
static bool DatumGetBool(Datum X)
Definition: postgres.h:95

References DatumGetBool(), DatumGetNumeric(), DirectFunctionCall2, int64_to_numeric(), numeric_add(), numeric_div_trunc(), numeric_ge(), numeric_sub(), and NumericGetDatum().

Referenced by pg_size_pretty_numeric().

◆ numeric_is_less()

static bool numeric_is_less ( Numeric  a,
Numeric  b 
)
static

Definition at line 637 of file dbsize.c.

638{
639 Datum da = NumericGetDatum(a);
640 Datum db = NumericGetDatum(b);
641
643}
Datum numeric_lt(PG_FUNCTION_ARGS)
Definition: numeric.c:2593
int b
Definition: isn.c:69
int a
Definition: isn.c:68

References a, b, DatumGetBool(), DirectFunctionCall2, numeric_lt(), and NumericGetDatum().

Referenced by pg_size_pretty_numeric().

◆ numeric_to_cstring()

static char * numeric_to_cstring ( Numeric  n)
static

Definition at line 629 of file dbsize.c.

630{
631 Datum d = NumericGetDatum(n);
632
634}
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:816
static char * DatumGetCString(Datum X)
Definition: postgres.h:340

References DatumGetCString(), DirectFunctionCall1, numeric_out(), and NumericGetDatum().

Referenced by pg_size_pretty_numeric().

◆ numeric_truncated_divide()

static Numeric numeric_truncated_divide ( Numeric  n,
int64  divisor 
)
static

Definition at line 678 of file dbsize.c.

679{
680 Datum d = NumericGetDatum(n);
681 Datum divisor_numeric;
682 Datum result;
683
684 divisor_numeric = NumericGetDatum(int64_to_numeric(divisor));
685 result = DirectFunctionCall2(numeric_div_trunc, d, divisor_numeric);
686 return DatumGetNumeric(result);
687}

References DatumGetNumeric(), DirectFunctionCall2, int64_to_numeric(), numeric_div_trunc(), and NumericGetDatum().

Referenced by pg_size_pretty_numeric().

◆ pg_database_size_name()

Datum pg_database_size_name ( PG_FUNCTION_ARGS  )

Definition at line 191 of file dbsize.c.

192{
194 Oid dbOid = get_database_oid(NameStr(*dbName), false);
195 int64 size;
196
198
199 if (size == 0)
201
203}
#define NameStr(name)
Definition: c.h:703
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3140
static int64 calculate_database_size(Oid dbOid)
Definition: dbsize.c:118
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
static const char * dbName
Definition: pgbench.c:297
Definition: c.h:698

References calculate_database_size(), dbName, get_database_oid(), NameStr, PG_GETARG_NAME, PG_RETURN_INT64, PG_RETURN_NULL, and size.

◆ pg_database_size_oid()

Datum pg_database_size_oid ( PG_FUNCTION_ARGS  )

Definition at line 168 of file dbsize.c.

169{
170 Oid dbOid = PG_GETARG_OID(0);
171 int64 size;
172
173 /*
174 * Not needed for correctness, but avoid non-user-facing error message
175 * later if the database doesn't exist.
176 */
177 if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(dbOid)))
179 errcode(ERRCODE_UNDEFINED_OBJECT),
180 errmsg("database with OID %u does not exist", dbOid));
181
183
184 if (size == 0)
186
188}
int errcode(int sqlerrcode)
Definition: elog.c:853
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100

References calculate_database_size(), ereport, errcode(), errmsg(), ERROR, ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, SearchSysCacheExists1, and size.

◆ pg_filenode_relation()

Datum pg_filenode_relation ( PG_FUNCTION_ARGS  )

Definition at line 945 of file dbsize.c.

946{
947 Oid reltablespace = PG_GETARG_OID(0);
948 RelFileNumber relfilenumber = PG_GETARG_OID(1);
949 Oid heaprel;
950
951 /* test needed so RelidByRelfilenumber doesn't misbehave */
952 if (!RelFileNumberIsValid(relfilenumber))
954
955 heaprel = RelidByRelfilenumber(reltablespace, relfilenumber);
956
957 if (!OidIsValid(heaprel))
959 else
960 PG_RETURN_OID(heaprel);
961}
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
Oid RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
Oid RelFileNumber
Definition: relpath.h:25
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27

References OidIsValid, PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_OID, RelFileNumberIsValid, and RelidByRelfilenumber().

◆ pg_indexes_size()

Datum pg_indexes_size ( PG_FUNCTION_ARGS  )

Definition at line 523 of file dbsize.c.

524{
525 Oid relOid = PG_GETARG_OID(0);
526 Relation rel;
527 int64 size;
528
529 rel = try_relation_open(relOid, AccessShareLock);
530
531 if (rel == NULL)
533
535
537
539}
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88

References AccessShareLock, calculate_indexes_size(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, relation_close(), size, and try_relation_open().

◆ pg_relation_filenode()

Datum pg_relation_filenode ( PG_FUNCTION_ARGS  )

Definition at line 897 of file dbsize.c.

898{
899 Oid relid = PG_GETARG_OID(0);
900 RelFileNumber result;
901 HeapTuple tuple;
902 Form_pg_class relform;
903
904 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
905 if (!HeapTupleIsValid(tuple))
907 relform = (Form_pg_class) GETSTRUCT(tuple);
908
909 if (RELKIND_HAS_STORAGE(relform->relkind))
910 {
911 if (relform->relfilenode)
912 result = relform->relfilenode;
913 else /* Consult the relation mapper */
914 result = RelationMapOidToFilenumber(relid,
915 relform->relisshared);
916 }
917 else
918 {
919 /* no storage, return NULL */
920 result = InvalidRelFileNumber;
921 }
922
923 ReleaseSysCache(tuple);
924
925 if (!RelFileNumberIsValid(result))
927
928 PG_RETURN_OID(result);
929}
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared)
Definition: relmapper.c:165
#define InvalidRelFileNumber
Definition: relpath.h:26
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References GETSTRUCT, HeapTupleIsValid, InvalidRelFileNumber, ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_OID, RelationMapOidToFilenumber(), ReleaseSysCache(), RelFileNumberIsValid, and SearchSysCache1().

◆ pg_relation_filepath()

Datum pg_relation_filepath ( PG_FUNCTION_ARGS  )

Definition at line 969 of file dbsize.c.

970{
971 Oid relid = PG_GETARG_OID(0);
972 HeapTuple tuple;
973 Form_pg_class relform;
974 RelFileLocator rlocator;
975 ProcNumber backend;
976 char *path;
977
978 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
979 if (!HeapTupleIsValid(tuple))
981 relform = (Form_pg_class) GETSTRUCT(tuple);
982
983 if (RELKIND_HAS_STORAGE(relform->relkind))
984 {
985 /* This logic should match RelationInitPhysicalAddr */
986 if (relform->reltablespace)
987 rlocator.spcOid = relform->reltablespace;
988 else
989 rlocator.spcOid = MyDatabaseTableSpace;
990 if (rlocator.spcOid == GLOBALTABLESPACE_OID)
991 rlocator.dbOid = InvalidOid;
992 else
993 rlocator.dbOid = MyDatabaseId;
994 if (relform->relfilenode)
995 rlocator.relNumber = relform->relfilenode;
996 else /* Consult the relation mapper */
997 rlocator.relNumber = RelationMapOidToFilenumber(relid,
998 relform->relisshared);
999 }
1000 else
1001 {
1002 /* no storage, return NULL */
1004 /* some compilers generate warnings without these next two lines */
1005 rlocator.dbOid = InvalidOid;
1006 rlocator.spcOid = InvalidOid;
1007 }
1008
1009 if (!RelFileNumberIsValid(rlocator.relNumber))
1010 {
1011 ReleaseSysCache(tuple);
1013 }
1014
1015 /* Determine owning backend. */
1016 switch (relform->relpersistence)
1017 {
1018 case RELPERSISTENCE_UNLOGGED:
1019 case RELPERSISTENCE_PERMANENT:
1020 backend = INVALID_PROC_NUMBER;
1021 break;
1022 case RELPERSISTENCE_TEMP:
1023 if (isTempOrTempToastNamespace(relform->relnamespace))
1024 backend = ProcNumberForTempRelations();
1025 else
1026 {
1027 /* Do it the hard way. */
1028 backend = GetTempNamespaceProcNumber(relform->relnamespace);
1029 Assert(backend != INVALID_PROC_NUMBER);
1030 }
1031 break;
1032 default:
1033 elog(ERROR, "invalid relpersistence: %c", relform->relpersistence);
1034 backend = INVALID_PROC_NUMBER; /* placate compiler */
1035 break;
1036 }
1037
1038 ReleaseSysCache(tuple);
1039
1040 path = relpathbackend(rlocator, backend, MAIN_FORKNUM);
1041
1043}
#define Assert(condition)
Definition: c.h:815
#define elog(elevel,...)
Definition: elog.h:225
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
Oid MyDatabaseId
Definition: globals.c:93
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3673
ProcNumber GetTempNamespaceProcNumber(Oid namespaceId)
Definition: namespace.c:3766
#define InvalidOid
Definition: postgres_ext.h:37
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
int ProcNumber
Definition: procnumber.h:24
#define ProcNumberForTempRelations()
Definition: procnumber.h:40
@ MAIN_FORKNUM
Definition: relpath.h:58
RelFileNumber relNumber
text * cstring_to_text(const char *s)
Definition: varlena.c:184

References Assert, cstring_to_text(), RelFileLocator::dbOid, elog, ERROR, GETSTRUCT, GetTempNamespaceProcNumber(), HeapTupleIsValid, INVALID_PROC_NUMBER, InvalidOid, InvalidRelFileNumber, isTempOrTempToastNamespace(), MAIN_FORKNUM, MyDatabaseId, MyDatabaseTableSpace, ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_NULL, PG_RETURN_TEXT_P, ProcNumberForTempRelations, RelationMapOidToFilenumber(), ReleaseSysCache(), RelFileNumberIsValid, RelFileLocator::relNumber, relpathbackend, SearchSysCache1(), and RelFileLocator::spcOid.

◆ pg_relation_size()

Datum pg_relation_size ( PG_FUNCTION_ARGS  )

Definition at line 364 of file dbsize.c.

365{
366 Oid relOid = PG_GETARG_OID(0);
367 text *forkName = PG_GETARG_TEXT_PP(1);
368 Relation rel;
369 int64 size;
370
371 rel = try_relation_open(relOid, AccessShareLock);
372
373 /*
374 * Before 9.2, we used to throw an error if the relation didn't exist, but
375 * that makes queries like "SELECT pg_relation_size(oid) FROM pg_class"
376 * less robust, because while we scan pg_class with an MVCC snapshot,
377 * someone else might drop the table. It's better to return NULL for
378 * already-dropped tables than throw an error and abort the whole query.
379 */
380 if (rel == NULL)
382
385
387
389}
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:50
Definition: c.h:644
char * text_to_cstring(const text *t)
Definition: varlena.c:217

References AccessShareLock, calculate_relation_size(), forkname_to_number(), PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_INT64, PG_RETURN_NULL, RelationData::rd_backend, RelationData::rd_locator, relation_close(), size, text_to_cstring(), and try_relation_open().

◆ pg_size_bytes()

Datum pg_size_bytes ( PG_FUNCTION_ARGS  )

Definition at line 731 of file dbsize.c.

732{
734 char *str,
735 *strptr,
736 *endptr;
737 char saved_char;
738 Numeric num;
739 int64 result;
740 bool have_digits = false;
741
743
744 /* Skip leading whitespace */
745 strptr = str;
746 while (isspace((unsigned char) *strptr))
747 strptr++;
748
749 /* Check that we have a valid number and determine where it ends */
750 endptr = strptr;
751
752 /* Part (1): sign */
753 if (*endptr == '-' || *endptr == '+')
754 endptr++;
755
756 /* Part (2): main digit string */
757 if (isdigit((unsigned char) *endptr))
758 {
759 have_digits = true;
760 do
761 endptr++;
762 while (isdigit((unsigned char) *endptr));
763 }
764
765 /* Part (3): optional decimal point and fractional digits */
766 if (*endptr == '.')
767 {
768 endptr++;
769 if (isdigit((unsigned char) *endptr))
770 {
771 have_digits = true;
772 do
773 endptr++;
774 while (isdigit((unsigned char) *endptr));
775 }
776 }
777
778 /* Complain if we don't have a valid number at this point */
779 if (!have_digits)
781 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
782 errmsg("invalid size: \"%s\"", str)));
783
784 /* Part (4): optional exponent */
785 if (*endptr == 'e' || *endptr == 'E')
786 {
787 long exponent;
788 char *cp;
789
790 /*
791 * Note we might one day support EB units, so if what follows 'E'
792 * isn't a number, just treat it all as a unit to be parsed.
793 */
794 exponent = strtol(endptr + 1, &cp, 10);
795 (void) exponent; /* Silence -Wunused-result warnings */
796 if (cp > endptr + 1)
797 endptr = cp;
798 }
799
800 /*
801 * Parse the number, saving the next character, which may be the first
802 * character of the unit string.
803 */
804 saved_char = *endptr;
805 *endptr = '\0';
806
808 CStringGetDatum(strptr),
810 Int32GetDatum(-1)));
811
812 *endptr = saved_char;
813
814 /* Skip whitespace between number and unit */
815 strptr = endptr;
816 while (isspace((unsigned char) *strptr))
817 strptr++;
818
819 /* Handle possible unit */
820 if (*strptr != '\0')
821 {
822 const struct size_pretty_unit *unit;
823 int64 multiplier = 0;
824
825 /* Trim any trailing whitespace */
826 endptr = str + VARSIZE_ANY_EXHDR(arg) - 1;
827
828 while (isspace((unsigned char) *endptr))
829 endptr--;
830
831 endptr++;
832 *endptr = '\0';
833
834 for (unit = size_pretty_units; unit->name != NULL; unit++)
835 {
836 /* Parse the unit case-insensitively */
837 if (pg_strcasecmp(strptr, unit->name) == 0)
838 break;
839 }
840
841 /* If not found, look in table of aliases */
842 if (unit->name == NULL)
843 {
844 for (const struct size_bytes_unit_alias *a = size_bytes_aliases; a->alias != NULL; a++)
845 {
846 if (pg_strcasecmp(strptr, a->alias) == 0)
847 {
848 unit = &size_pretty_units[a->unit_index];
849 break;
850 }
851 }
852 }
853
854 /* Verify we found a valid unit in the loop above */
855 if (unit->name == NULL)
857 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
858 errmsg("invalid size: \"%s\"", text_to_cstring(arg)),
859 errdetail("Invalid size unit: \"%s\".", strptr),
860 errhint("Valid units are \"bytes\", \"B\", \"kB\", \"MB\", \"GB\", \"TB\", and \"PB\".")));
861
862 multiplier = ((int64) 1) << unit->unitbits;
863
864 if (multiplier > 1)
865 {
866 Numeric mul_num;
867
868 mul_num = int64_to_numeric(multiplier);
869
871 NumericGetDatum(mul_num),
872 NumericGetDatum(num)));
873 }
874 }
875
877 NumericGetDatum(num)));
878
879 PG_RETURN_INT64(result);
880}
Datum numeric_int8(PG_FUNCTION_ARGS)
Definition: numeric.c:4653
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:637
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3121
static const struct size_bytes_unit_alias size_bytes_aliases[]
Definition: dbsize.c:67
static const struct size_pretty_unit size_pretty_units[]
Definition: dbsize.c:49
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:645
const char * str
void * arg
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:390
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
const char * name
Definition: dbsize.c:40
uint8 unitbits
Definition: dbsize.c:44
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References a, arg, CStringGetDatum(), DatumGetInt64(), DatumGetNumeric(), DirectFunctionCall1, DirectFunctionCall2, DirectFunctionCall3, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, Int32GetDatum(), int64_to_numeric(), InvalidOid, size_pretty_unit::name, numeric_in(), numeric_int8(), numeric_mul(), NumericGetDatum(), ObjectIdGetDatum(), PG_GETARG_TEXT_PP, PG_RETURN_INT64, pg_strcasecmp(), size_bytes_aliases, size_pretty_units, str, text_to_cstring(), size_pretty_unit::unitbits, and VARSIZE_ANY_EXHDR.

◆ pg_size_pretty()

Datum pg_size_pretty ( PG_FUNCTION_ARGS  )

Definition at line 587 of file dbsize.c.

588{
590 char buf[64];
591 const struct size_pretty_unit *unit;
592
593 for (unit = size_pretty_units; unit->name != NULL; unit++)
594 {
595 uint8 bits;
596 uint64 abs_size = size < 0 ? 0 - (uint64) size : (uint64) size;
597
598 /*
599 * Use this unit if there are no more units or the absolute size is
600 * below the limit for the current unit.
601 */
602 if (unit[1].name == NULL || abs_size < unit->limit)
603 {
604 if (unit->round)
606
607 snprintf(buf, sizeof(buf), INT64_FORMAT " %s", size, unit->name);
608 break;
609 }
610
611 /*
612 * Determine the number of bits to use to build the divisor. We may
613 * need to use 1 bit less than the difference between this and the
614 * next unit if the next unit uses half rounding. Or we may need to
615 * shift an extra bit if this unit uses half rounding and the next one
616 * does not. We use division rather than shifting right by this
617 * number of bits to ensure positive and negative values are rounded
618 * in the same way.
619 */
620 bits = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
621 + (unit->round == true));
622 size /= ((int64) 1) << bits;
623 }
624
626}
uint8_t uint8
Definition: c.h:486
#define INT64_FORMAT
Definition: c.h:506
uint64_t uint64
Definition: c.h:489
#define half_rounded(x)
Definition: dbsize.c:35
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
static char * buf
Definition: pg_test_fsync.c:72
uint32 limit
Definition: dbsize.c:41
const char * name

References buf, cstring_to_text(), half_rounded, INT64_FORMAT, size_pretty_unit::limit, name, size_pretty_unit::name, PG_GETARG_INT64, PG_RETURN_TEXT_P, size_pretty_unit::round, size, size_pretty_units, snprintf, and size_pretty_unit::unitbits.

◆ pg_size_pretty_numeric()

Datum pg_size_pretty_numeric ( PG_FUNCTION_ARGS  )

Definition at line 690 of file dbsize.c.

691{
693 char *result = NULL;
694 const struct size_pretty_unit *unit;
695
696 for (unit = size_pretty_units; unit->name != NULL; unit++)
697 {
698 unsigned int shiftby;
699
700 /* use this unit if there are no more units or we're below the limit */
701 if (unit[1].name == NULL ||
703 int64_to_numeric(unit->limit)))
704 {
705 if (unit->round)
707
708 result = psprintf("%s %s", numeric_to_cstring(size), unit->name);
709 break;
710 }
711
712 /*
713 * Determine the number of bits to use to build the divisor. We may
714 * need to use 1 bit less than the difference between this and the
715 * next unit if the next unit uses half rounding. Or we may need to
716 * shift an extra bit if this unit uses half rounding and the next one
717 * does not.
718 */
719 shiftby = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
720 + (unit->round == true));
721 size = numeric_truncated_divide(size, ((int64) 1) << shiftby);
722 }
723
725}
static char * numeric_to_cstring(Numeric n)
Definition: dbsize.c:629
static bool numeric_is_less(Numeric a, Numeric b)
Definition: dbsize.c:637
static Numeric numeric_truncated_divide(Numeric n, int64 divisor)
Definition: dbsize.c:678
static Numeric numeric_absolute(Numeric n)
Definition: dbsize.c:646
static Numeric numeric_half_rounded(Numeric n)
Definition: dbsize.c:656
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:78
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43

References cstring_to_text(), int64_to_numeric(), size_pretty_unit::limit, name, size_pretty_unit::name, numeric_absolute(), numeric_half_rounded(), numeric_is_less(), numeric_to_cstring(), numeric_truncated_divide(), PG_GETARG_NUMERIC, PG_RETURN_TEXT_P, psprintf(), size_pretty_unit::round, size, size_pretty_units, and size_pretty_unit::unitbits.

◆ pg_table_size()

Datum pg_table_size ( PG_FUNCTION_ARGS  )

Definition at line 504 of file dbsize.c.

505{
506 Oid relOid = PG_GETARG_OID(0);
507 Relation rel;
508 int64 size;
509
510 rel = try_relation_open(relOid, AccessShareLock);
511
512 if (rel == NULL)
514
516
518
520}

References AccessShareLock, calculate_table_size(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, relation_close(), size, and try_relation_open().

◆ pg_tablespace_size_name()

Datum pg_tablespace_size_name ( PG_FUNCTION_ARGS  )

Definition at line 304 of file dbsize.c.

305{
306 Name tblspcName = PG_GETARG_NAME(0);
307 Oid tblspcOid = get_tablespace_oid(NameStr(*tblspcName), false);
308 int64 size;
309
310 size = calculate_tablespace_size(tblspcOid);
311
312 if (size < 0)
314
316}
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
static int64 calculate_tablespace_size(Oid tblspcOid)
Definition: dbsize.c:211

References calculate_tablespace_size(), get_tablespace_oid(), NameStr, PG_GETARG_NAME, PG_RETURN_INT64, PG_RETURN_NULL, and size.

◆ pg_tablespace_size_oid()

Datum pg_tablespace_size_oid ( PG_FUNCTION_ARGS  )

Definition at line 281 of file dbsize.c.

282{
283 Oid tblspcOid = PG_GETARG_OID(0);
284 int64 size;
285
286 /*
287 * Not needed for correctness, but avoid non-user-facing error message
288 * later if the tablespace doesn't exist.
289 */
290 if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tblspcOid)))
292 errcode(ERRCODE_UNDEFINED_OBJECT),
293 errmsg("tablespace with OID %u does not exist", tblspcOid));
294
295 size = calculate_tablespace_size(tblspcOid);
296
297 if (size < 0)
299
301}

References calculate_tablespace_size(), ereport, errcode(), errmsg(), ERROR, ObjectIdGetDatum(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, SearchSysCacheExists1, and size.

◆ pg_total_relation_size()

Datum pg_total_relation_size ( PG_FUNCTION_ARGS  )

Definition at line 565 of file dbsize.c.

566{
567 Oid relOid = PG_GETARG_OID(0);
568 Relation rel;
569 int64 size;
570
571 rel = try_relation_open(relOid, AccessShareLock);
572
573 if (rel == NULL)
575
577
579
581}
static int64 calculate_total_relation_size(Relation rel)
Definition: dbsize.c:546

References AccessShareLock, calculate_total_relation_size(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, relation_close(), size, and try_relation_open().

Variable Documentation

◆ size_bytes_aliases

const struct size_bytes_unit_alias size_bytes_aliases[]
static
Initial value:
= {
{"B", 0},
{NULL}
}

Definition at line 67 of file dbsize.c.

Referenced by pg_size_bytes().

◆ size_pretty_units

const struct size_pretty_unit size_pretty_units[]
static
Initial value:
= {
{"bytes", 10 * 1024, false, 0},
{"kB", 20 * 1024 - 1, true, 10},
{"MB", 20 * 1024 - 1, true, 20},
{"GB", 20 * 1024 - 1, true, 30},
{"TB", 20 * 1024 - 1, true, 40},
{"PB", 20 * 1024 - 1, true, 50},
{NULL, 0, false, 0}
}

Definition at line 49 of file dbsize.c.

Referenced by pg_size_bytes(), pg_size_pretty(), and pg_size_pretty_numeric().