PostgreSQL Source Code  git master
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  {
135  aclcheck_error(aclresult, OBJECT_DATABASE,
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 */
146  snprintf(dirpath, MAXPGPATH, PG_TBLSPC_DIR);
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:2703
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3891
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3187
static int64 db_dir_size(const char *path)
Definition: dbsize.c:74
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2932
int FreeDir(DIR *dir)
Definition: fd.c:2984
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2866
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:514
@ OBJECT_DATABASE
Definition: parsenodes.h:2267
#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 451 of file dbsize.c.

452 {
453  int64 size = 0;
454 
455  /*
456  * Aggregate all indexes on the given relation
457  */
458  if (rel->rd_rel->relhasindex)
459  {
460  List *index_oids = RelationGetIndexList(rel);
461  ListCell *cell;
462 
463  foreach(cell, index_oids)
464  {
465  Oid idxOid = lfirst_oid(cell);
466  Relation idxRel;
467  ForkNumber forkNum;
468 
469  idxRel = relation_open(idxOid, AccessShareLock);
470 
471  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
473  idxRel->rd_backend,
474  forkNum);
475 
477  }
478 
479  list_free(index_oids);
480  }
481 
482  return size;
483 }
static int64 calculate_relation_size(RelFileLocator *rfn, ProcNumber backend, ForkNumber forknum)
Definition: dbsize.c:308
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:31
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4804
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 308 of file dbsize.c.

309 {
310  int64 totalsize = 0;
311  char *relationpath;
312  char pathname[MAXPGPATH];
313  unsigned int segcount = 0;
314 
315  relationpath = relpathbackend(*rfn, backend, forknum);
316 
317  for (segcount = 0;; segcount++)
318  {
319  struct stat fst;
320 
322 
323  if (segcount == 0)
324  snprintf(pathname, MAXPGPATH, "%s",
325  relationpath);
326  else
327  snprintf(pathname, MAXPGPATH, "%s.%u",
328  relationpath, segcount);
329 
330  if (stat(pathname, &fst) < 0)
331  {
332  if (errno == ENOENT)
333  break;
334  else
335  ereport(ERROR,
337  errmsg("could not stat file \"%s\": %m", pathname)));
338  }
339  totalsize += fst.st_size;
340  }
341 
342  return totalsize;
343 }
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:284

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 424 of file dbsize.c.

425 {
426  int64 size = 0;
427  ForkNumber forkNum;
428 
429  /*
430  * heap size, including FSM and VM
431  */
432  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
434  forkNum);
435 
436  /*
437  * Size of toast relation
438  */
439  if (OidIsValid(rel->rd_rel->reltoastrelid))
440  size += calculate_toast_table_size(rel->rd_rel->reltoastrelid);
441 
442  return size;
443 }
#define OidIsValid(objectId)
Definition: c.h:766
static int64 calculate_toast_table_size(Oid toastrelid)
Definition: dbsize.c:378

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 202 of file dbsize.c.

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

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 378 of file dbsize.c.

379 {
380  int64 size = 0;
381  Relation toastRel;
382  ForkNumber forkNum;
383  ListCell *lc;
384  List *indexlist;
385 
386  toastRel = relation_open(toastrelid, AccessShareLock);
387 
388  /* toast heap size, including FSM and VM size */
389  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
390  size += calculate_relation_size(&(toastRel->rd_locator),
391  toastRel->rd_backend, forkNum);
392 
393  /* toast index size, including FSM and VM size */
394  indexlist = RelationGetIndexList(toastRel);
395 
396  /* Size is calculated using all the indexes available */
397  foreach(lc, indexlist)
398  {
399  Relation toastIdxRel;
400 
401  toastIdxRel = relation_open(lfirst_oid(lc),
403  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
404  size += calculate_relation_size(&(toastIdxRel->rd_locator),
405  toastIdxRel->rd_backend, forkNum);
406 
407  relation_close(toastIdxRel, AccessShareLock);
408  }
409  list_free(indexlist);
410  relation_close(toastRel, AccessShareLock);
411 
412  return size;
413 }

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 528 of file dbsize.c.

529 {
530  int64 size;
531 
532  /*
533  * Aggregate the table size, this includes size of the heap, toast and
534  * toast index with free space and visibility map
535  */
536  size = calculate_table_size(rel);
537 
538  /*
539  * Add size of all attached indexes as well
540  */
542 
543  return size;
544 }
static int64 calculate_indexes_size(Relation rel)
Definition: dbsize.c:451
static int64 calculate_table_size(Relation rel)
Definition: dbsize.c:424

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
103  ereport(ERROR,
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 628 of file dbsize.c.

629 {
630  Datum d = NumericGetDatum(n);
631  Datum result;
632 
633  result = DirectFunctionCall1(numeric_abs, d);
634  return DatumGetNumeric(result);
635 }
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1392
#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:64

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 638 of file dbsize.c.

639 {
640  Datum d = NumericGetDatum(n);
641  Datum zero;
642  Datum one;
643  Datum two;
644  Datum result;
645 
649 
651  d = DirectFunctionCall2(numeric_add, d, one);
652  else
653  d = DirectFunctionCall2(numeric_sub, d, one);
654 
655  result = DirectFunctionCall2(numeric_div_trunc, d, two);
656  return DatumGetNumeric(result);
657 }
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition: numeric.c:2922
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4280
Datum numeric_ge(PG_FUNCTION_ARGS)
Definition: numeric.c:2457
Datum numeric_div_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:3256
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2845
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:643
static bool DatumGetBool(Datum X)
Definition: postgres.h:90

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 619 of file dbsize.c.

620 {
621  Datum da = NumericGetDatum(a);
622  Datum db = NumericGetDatum(b);
623 
625 }
Datum numeric_lt(PG_FUNCTION_ARGS)
Definition: numeric.c:2472
int b
Definition: isn.c:70
int a
Definition: isn.c:69

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 611 of file dbsize.c.

612 {
613  Datum d = NumericGetDatum(n);
614 
616 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:815
static char * DatumGetCString(Datum X)
Definition: postgres.h:335

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 660 of file dbsize.c.

661 {
662  Datum d = NumericGetDatum(n);
663  Datum divisor_numeric;
664  Datum result;
665 
666  divisor_numeric = NumericGetDatum(int64_to_numeric(divisor));
667  result = DirectFunctionCall2(numeric_div_trunc, d, divisor_numeric);
668  return DatumGetNumeric(result);
669 }

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 182 of file dbsize.c.

183 {
185  Oid dbOid = get_database_oid(NameStr(*dbName), false);
186  int64 size;
187 
188  size = calculate_database_size(dbOid);
189 
190  if (size == 0)
191  PG_RETURN_NULL();
192 
194 }
#define NameStr(name)
Definition: c.h:737
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:732

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  size = calculate_database_size(dbOid);
174 
175  if (size == 0)
176  PG_RETURN_NULL();
177 
179 }
#define PG_GETARG_OID(n)
Definition: fmgr.h:275

References calculate_database_size(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, and size.

◆ pg_filenode_relation()

Datum pg_filenode_relation ( PG_FUNCTION_ARGS  )

Definition at line 927 of file dbsize.c.

928 {
929  Oid reltablespace = PG_GETARG_OID(0);
930  RelFileNumber relfilenumber = PG_GETARG_OID(1);
931  Oid heaprel;
932 
933  /* test needed so RelidByRelfilenumber doesn't misbehave */
934  if (!RelFileNumberIsValid(relfilenumber))
935  PG_RETURN_NULL();
936 
937  heaprel = RelidByRelfilenumber(reltablespace, relfilenumber);
938 
939  if (!OidIsValid(heaprel))
940  PG_RETURN_NULL();
941  else
942  PG_RETURN_OID(heaprel);
943 }
#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 505 of file dbsize.c.

506 {
507  Oid relOid = PG_GETARG_OID(0);
508  Relation rel;
509  int64 size;
510 
511  rel = try_relation_open(relOid, AccessShareLock);
512 
513  if (rel == NULL)
514  PG_RETURN_NULL();
515 
517 
519 
521 }
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 879 of file dbsize.c.

880 {
881  Oid relid = PG_GETARG_OID(0);
882  RelFileNumber result;
883  HeapTuple tuple;
884  Form_pg_class relform;
885 
886  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
887  if (!HeapTupleIsValid(tuple))
888  PG_RETURN_NULL();
889  relform = (Form_pg_class) GETSTRUCT(tuple);
890 
891  if (RELKIND_HAS_STORAGE(relform->relkind))
892  {
893  if (relform->relfilenode)
894  result = relform->relfilenode;
895  else /* Consult the relation mapper */
896  result = RelationMapOidToFilenumber(relid,
897  relform->relisshared);
898  }
899  else
900  {
901  /* no storage, return NULL */
902  result = InvalidRelFileNumber;
903  }
904 
905  ReleaseSysCache(tuple);
906 
907  if (!RelFileNumberIsValid(result))
908  PG_RETURN_NULL();
909 
910  PG_RETURN_OID(result);
911 }
#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
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
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 951 of file dbsize.c.

952 {
953  Oid relid = PG_GETARG_OID(0);
954  HeapTuple tuple;
955  Form_pg_class relform;
956  RelFileLocator rlocator;
957  ProcNumber backend;
958  char *path;
959 
960  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
961  if (!HeapTupleIsValid(tuple))
962  PG_RETURN_NULL();
963  relform = (Form_pg_class) GETSTRUCT(tuple);
964 
965  if (RELKIND_HAS_STORAGE(relform->relkind))
966  {
967  /* This logic should match RelationInitPhysicalAddr */
968  if (relform->reltablespace)
969  rlocator.spcOid = relform->reltablespace;
970  else
971  rlocator.spcOid = MyDatabaseTableSpace;
972  if (rlocator.spcOid == GLOBALTABLESPACE_OID)
973  rlocator.dbOid = InvalidOid;
974  else
975  rlocator.dbOid = MyDatabaseId;
976  if (relform->relfilenode)
977  rlocator.relNumber = relform->relfilenode;
978  else /* Consult the relation mapper */
979  rlocator.relNumber = RelationMapOidToFilenumber(relid,
980  relform->relisshared);
981  }
982  else
983  {
984  /* no storage, return NULL */
985  rlocator.relNumber = InvalidRelFileNumber;
986  /* some compilers generate warnings without these next two lines */
987  rlocator.dbOid = InvalidOid;
988  rlocator.spcOid = InvalidOid;
989  }
990 
991  if (!RelFileNumberIsValid(rlocator.relNumber))
992  {
993  ReleaseSysCache(tuple);
994  PG_RETURN_NULL();
995  }
996 
997  /* Determine owning backend. */
998  switch (relform->relpersistence)
999  {
1000  case RELPERSISTENCE_UNLOGGED:
1001  case RELPERSISTENCE_PERMANENT:
1002  backend = INVALID_PROC_NUMBER;
1003  break;
1004  case RELPERSISTENCE_TEMP:
1005  if (isTempOrTempToastNamespace(relform->relnamespace))
1006  backend = ProcNumberForTempRelations();
1007  else
1008  {
1009  /* Do it the hard way. */
1010  backend = GetTempNamespaceProcNumber(relform->relnamespace);
1011  Assert(backend != INVALID_PROC_NUMBER);
1012  }
1013  break;
1014  default:
1015  elog(ERROR, "invalid relpersistence: %c", relform->relpersistence);
1016  backend = INVALID_PROC_NUMBER; /* placate compiler */
1017  break;
1018  }
1019 
1020  ReleaseSysCache(tuple);
1021 
1022  path = relpathbackend(rlocator, backend, MAIN_FORKNUM);
1023 
1025 }
#define Assert(condition)
Definition: c.h:849
#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:36
#define ProcNumberForTempRelations()
Definition: proc.h:324
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
int ProcNumber
Definition: procnumber.h:24
@ 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 346 of file dbsize.c.

347 {
348  Oid relOid = PG_GETARG_OID(0);
349  text *forkName = PG_GETARG_TEXT_PP(1);
350  Relation rel;
351  int64 size;
352 
353  rel = try_relation_open(relOid, AccessShareLock);
354 
355  /*
356  * Before 9.2, we used to throw an error if the relation didn't exist, but
357  * that makes queries like "SELECT pg_relation_size(oid) FROM pg_class"
358  * less robust, because while we scan pg_class with an MVCC snapshot,
359  * someone else might drop the table. It's better to return NULL for
360  * already-dropped tables than throw an error and abort the whole query.
361  */
362  if (rel == NULL)
363  PG_RETURN_NULL();
364 
367 
369 
371 }
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:50
Definition: c.h:678
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 713 of file dbsize.c.

714 {
715  text *arg = PG_GETARG_TEXT_PP(0);
716  char *str,
717  *strptr,
718  *endptr;
719  char saved_char;
720  Numeric num;
721  int64 result;
722  bool have_digits = false;
723 
725 
726  /* Skip leading whitespace */
727  strptr = str;
728  while (isspace((unsigned char) *strptr))
729  strptr++;
730 
731  /* Check that we have a valid number and determine where it ends */
732  endptr = strptr;
733 
734  /* Part (1): sign */
735  if (*endptr == '-' || *endptr == '+')
736  endptr++;
737 
738  /* Part (2): main digit string */
739  if (isdigit((unsigned char) *endptr))
740  {
741  have_digits = true;
742  do
743  endptr++;
744  while (isdigit((unsigned char) *endptr));
745  }
746 
747  /* Part (3): optional decimal point and fractional digits */
748  if (*endptr == '.')
749  {
750  endptr++;
751  if (isdigit((unsigned char) *endptr))
752  {
753  have_digits = true;
754  do
755  endptr++;
756  while (isdigit((unsigned char) *endptr));
757  }
758  }
759 
760  /* Complain if we don't have a valid number at this point */
761  if (!have_digits)
762  ereport(ERROR,
763  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
764  errmsg("invalid size: \"%s\"", str)));
765 
766  /* Part (4): optional exponent */
767  if (*endptr == 'e' || *endptr == 'E')
768  {
769  long exponent;
770  char *cp;
771 
772  /*
773  * Note we might one day support EB units, so if what follows 'E'
774  * isn't a number, just treat it all as a unit to be parsed.
775  */
776  exponent = strtol(endptr + 1, &cp, 10);
777  (void) exponent; /* Silence -Wunused-result warnings */
778  if (cp > endptr + 1)
779  endptr = cp;
780  }
781 
782  /*
783  * Parse the number, saving the next character, which may be the first
784  * character of the unit string.
785  */
786  saved_char = *endptr;
787  *endptr = '\0';
788 
790  CStringGetDatum(strptr),
792  Int32GetDatum(-1)));
793 
794  *endptr = saved_char;
795 
796  /* Skip whitespace between number and unit */
797  strptr = endptr;
798  while (isspace((unsigned char) *strptr))
799  strptr++;
800 
801  /* Handle possible unit */
802  if (*strptr != '\0')
803  {
804  const struct size_pretty_unit *unit;
805  int64 multiplier = 0;
806 
807  /* Trim any trailing whitespace */
808  endptr = str + VARSIZE_ANY_EXHDR(arg) - 1;
809 
810  while (isspace((unsigned char) *endptr))
811  endptr--;
812 
813  endptr++;
814  *endptr = '\0';
815 
816  for (unit = size_pretty_units; unit->name != NULL; unit++)
817  {
818  /* Parse the unit case-insensitively */
819  if (pg_strcasecmp(strptr, unit->name) == 0)
820  break;
821  }
822 
823  /* If not found, look in table of aliases */
824  if (unit->name == NULL)
825  {
826  for (const struct size_bytes_unit_alias *a = size_bytes_aliases; a->alias != NULL; a++)
827  {
828  if (pg_strcasecmp(strptr, a->alias) == 0)
829  {
830  unit = &size_pretty_units[a->unit_index];
831  break;
832  }
833  }
834  }
835 
836  /* Verify we found a valid unit in the loop above */
837  if (unit->name == NULL)
838  ereport(ERROR,
839  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
840  errmsg("invalid size: \"%s\"", text_to_cstring(arg)),
841  errdetail("Invalid size unit: \"%s\".", strptr),
842  errhint("Valid units are \"bytes\", \"B\", \"kB\", \"MB\", \"GB\", \"TB\", and \"PB\".")));
843 
844  multiplier = ((int64) 1) << unit->unitbits;
845 
846  if (multiplier > 1)
847  {
848  Numeric mul_num;
849 
850  mul_num = int64_to_numeric(multiplier);
851 
853  NumericGetDatum(mul_num),
854  NumericGetDatum(num)));
855  }
856  }
857 
859  NumericGetDatum(num)));
860 
861  PG_RETURN_INT64(result);
862 }
Datum numeric_int8(PG_FUNCTION_ARGS)
Definition: numeric.c:4532
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:636
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3000
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
int errcode(int sqlerrcode)
Definition: elog.c:853
#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:385
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
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 569 of file dbsize.c.

570 {
571  int64 size = PG_GETARG_INT64(0);
572  char buf[64];
573  const struct size_pretty_unit *unit;
574 
575  for (unit = size_pretty_units; unit->name != NULL; unit++)
576  {
577  uint8 bits;
578  uint64 abs_size = size < 0 ? 0 - (uint64) size : (uint64) size;
579 
580  /*
581  * Use this unit if there are no more units or the absolute size is
582  * below the limit for the current unit.
583  */
584  if (unit[1].name == NULL || abs_size < unit->limit)
585  {
586  if (unit->round)
588 
589  snprintf(buf, sizeof(buf), INT64_FORMAT " %s", size, unit->name);
590  break;
591  }
592 
593  /*
594  * Determine the number of bits to use to build the divisor. We may
595  * need to use 1 bit less than the difference between this and the
596  * next unit if the next unit uses half rounding. Or we may need to
597  * shift an extra bit if this unit uses half rounding and the next one
598  * does not. We use division rather than shifting right by this
599  * number of bits to ensure positive and negative values are rounded
600  * in the same way.
601  */
602  bits = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
603  + (unit->round == true));
604  size /= ((int64) 1) << bits;
605  }
606 
608 }
#define INT64_FORMAT
Definition: c.h:539
unsigned char uint8
Definition: c.h:504
#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:73
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 672 of file dbsize.c.

673 {
675  char *result = NULL;
676  const struct size_pretty_unit *unit;
677 
678  for (unit = size_pretty_units; unit->name != NULL; unit++)
679  {
680  unsigned int shiftby;
681 
682  /* use this unit if there are no more units or we're below the limit */
683  if (unit[1].name == NULL ||
685  int64_to_numeric(unit->limit)))
686  {
687  if (unit->round)
689 
690  result = psprintf("%s %s", numeric_to_cstring(size), unit->name);
691  break;
692  }
693 
694  /*
695  * Determine the number of bits to use to build the divisor. We may
696  * need to use 1 bit less than the difference between this and the
697  * next unit if the next unit uses half rounding. Or we may need to
698  * shift an extra bit if this unit uses half rounding and the next one
699  * does not.
700  */
701  shiftby = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
702  + (unit->round == true));
703  size = numeric_truncated_divide(size, ((int64) 1) << shiftby);
704  }
705 
707 }
static bool numeric_is_less(Numeric a, Numeric b)
Definition: dbsize.c:619
static Numeric numeric_truncated_divide(Numeric n, int64 divisor)
Definition: dbsize.c:660
static char * numeric_to_cstring(Numeric n)
Definition: dbsize.c:611
static Numeric numeric_absolute(Numeric n)
Definition: dbsize.c:628
static Numeric numeric_half_rounded(Numeric n)
Definition: dbsize.c:638
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:78
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

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 486 of file dbsize.c.

487 {
488  Oid relOid = PG_GETARG_OID(0);
489  Relation rel;
490  int64 size;
491 
492  rel = try_relation_open(relOid, AccessShareLock);
493 
494  if (rel == NULL)
495  PG_RETURN_NULL();
496 
497  size = calculate_table_size(rel);
498 
500 
502 }

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 286 of file dbsize.c.

287 {
288  Name tblspcName = PG_GETARG_NAME(0);
289  Oid tblspcOid = get_tablespace_oid(NameStr(*tblspcName), false);
290  int64 size;
291 
292  size = calculate_tablespace_size(tblspcOid);
293 
294  if (size < 0)
295  PG_RETURN_NULL();
296 
298 }
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
static int64 calculate_tablespace_size(Oid tblspcOid)
Definition: dbsize.c:202

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 272 of file dbsize.c.

273 {
274  Oid tblspcOid = PG_GETARG_OID(0);
275  int64 size;
276 
277  size = calculate_tablespace_size(tblspcOid);
278 
279  if (size < 0)
280  PG_RETURN_NULL();
281 
283 }

References calculate_tablespace_size(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, and size.

◆ pg_total_relation_size()

Datum pg_total_relation_size ( PG_FUNCTION_ARGS  )

Definition at line 547 of file dbsize.c.

548 {
549  Oid relOid = PG_GETARG_OID(0);
550  Relation rel;
551  int64 size;
552 
553  rel = try_relation_open(relOid, AccessShareLock);
554 
555  if (rel == NULL)
556  PG_RETURN_NULL();
557 
559 
561 
563 }
static int64 calculate_total_relation_size(Relation rel)
Definition: dbsize.c:528

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 1 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 1 of file dbsize.c.

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