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");
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), "pg_tblspc/%s/%s/%u",
158  direntry->d_name, TABLESPACE_VERSION_DIRECTORY, dbOid);
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:5128
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2688
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3876
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3153
static int64 db_dir_size(const char *path)
Definition: dbsize.c:74
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2909
int FreeDir(DIR *dir)
Definition: fd.c:2961
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:514
@ OBJECT_DATABASE
Definition: parsenodes.h:2272
#define ACL_CONNECT
Definition: parsenodes.h:87
#define MAXPGPATH
#define snprintf
Definition: port.h:238
#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, 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:4760
ForkNumber
Definition: relpath.h:48
#define MAX_FORKNUM
Definition: relpath.h:62
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:882
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define relpathbackend(rlocator, backend, forknum)
Definition: relpath.h:85
#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:775
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, "pg_tblspc/%u/%s", 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:93
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2305
#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, 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 624 of file dbsize.c.

625 {
626  Datum d = NumericGetDatum(n);
627  Datum result;
628 
629  result = DirectFunctionCall1(numeric_abs, d);
630  return DatumGetNumeric(result);
631 }
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1384
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
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 634 of file dbsize.c.

635 {
636  Datum d = NumericGetDatum(n);
637  Datum zero;
638  Datum one;
639  Datum two;
640  Datum result;
641 
645 
647  d = DirectFunctionCall2(numeric_add, d, one);
648  else
649  d = DirectFunctionCall2(numeric_sub, d, one);
650 
651  result = DirectFunctionCall2(numeric_div_trunc, d, two);
652  return DatumGetNumeric(result);
653 }
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition: numeric.c:2925
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4283
Datum numeric_ge(PG_FUNCTION_ARGS)
Definition: numeric.c:2460
Datum numeric_div_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:3259
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2848
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
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 615 of file dbsize.c.

616 {
617  Datum da = NumericGetDatum(a);
618  Datum db = NumericGetDatum(b);
619 
621 }
Datum numeric_lt(PG_FUNCTION_ARGS)
Definition: numeric.c:2475
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 607 of file dbsize.c.

608 {
609  Datum d = NumericGetDatum(n);
610 
612 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:807
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 656 of file dbsize.c.

657 {
658  Datum d = NumericGetDatum(n);
659  Datum divisor_numeric;
660  Datum result;
661 
662  divisor_numeric = NumericGetDatum(int64_to_numeric(divisor));
663  result = DirectFunctionCall2(numeric_div_trunc, d, divisor_numeric);
664  return DatumGetNumeric(result);
665 }

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:746
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3106
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
const char * dbName
Definition: pgbench.c:297
Definition: c.h:741

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

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

876 {
877  Oid relid = PG_GETARG_OID(0);
878  RelFileNumber result;
879  HeapTuple tuple;
880  Form_pg_class relform;
881 
882  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
883  if (!HeapTupleIsValid(tuple))
884  PG_RETURN_NULL();
885  relform = (Form_pg_class) GETSTRUCT(tuple);
886 
887  if (RELKIND_HAS_STORAGE(relform->relkind))
888  {
889  if (relform->relfilenode)
890  result = relform->relfilenode;
891  else /* Consult the relation mapper */
892  result = RelationMapOidToFilenumber(relid,
893  relform->relisshared);
894  }
895  else
896  {
897  /* no storage, return NULL */
898  result = InvalidRelFileNumber;
899  }
900 
901  ReleaseSysCache(tuple);
902 
903  if (!RelFileNumberIsValid(result))
904  PG_RETURN_NULL();
905 
906  PG_RETURN_OID(result);
907 }
#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:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218

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

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

710 {
711  text *arg = PG_GETARG_TEXT_PP(0);
712  char *str,
713  *strptr,
714  *endptr;
715  char saved_char;
716  Numeric num;
717  int64 result;
718  bool have_digits = false;
719 
721 
722  /* Skip leading whitespace */
723  strptr = str;
724  while (isspace((unsigned char) *strptr))
725  strptr++;
726 
727  /* Check that we have a valid number and determine where it ends */
728  endptr = strptr;
729 
730  /* Part (1): sign */
731  if (*endptr == '-' || *endptr == '+')
732  endptr++;
733 
734  /* Part (2): main digit string */
735  if (isdigit((unsigned char) *endptr))
736  {
737  have_digits = true;
738  do
739  endptr++;
740  while (isdigit((unsigned char) *endptr));
741  }
742 
743  /* Part (3): optional decimal point and fractional digits */
744  if (*endptr == '.')
745  {
746  endptr++;
747  if (isdigit((unsigned char) *endptr))
748  {
749  have_digits = true;
750  do
751  endptr++;
752  while (isdigit((unsigned char) *endptr));
753  }
754  }
755 
756  /* Complain if we don't have a valid number at this point */
757  if (!have_digits)
758  ereport(ERROR,
759  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
760  errmsg("invalid size: \"%s\"", str)));
761 
762  /* Part (4): optional exponent */
763  if (*endptr == 'e' || *endptr == 'E')
764  {
765  long exponent;
766  char *cp;
767 
768  /*
769  * Note we might one day support EB units, so if what follows 'E'
770  * isn't a number, just treat it all as a unit to be parsed.
771  */
772  exponent = strtol(endptr + 1, &cp, 10);
773  (void) exponent; /* Silence -Wunused-result warnings */
774  if (cp > endptr + 1)
775  endptr = cp;
776  }
777 
778  /*
779  * Parse the number, saving the next character, which may be the first
780  * character of the unit string.
781  */
782  saved_char = *endptr;
783  *endptr = '\0';
784 
786  CStringGetDatum(strptr),
788  Int32GetDatum(-1)));
789 
790  *endptr = saved_char;
791 
792  /* Skip whitespace between number and unit */
793  strptr = endptr;
794  while (isspace((unsigned char) *strptr))
795  strptr++;
796 
797  /* Handle possible unit */
798  if (*strptr != '\0')
799  {
800  const struct size_pretty_unit *unit;
801  int64 multiplier = 0;
802 
803  /* Trim any trailing whitespace */
804  endptr = str + VARSIZE_ANY_EXHDR(arg) - 1;
805 
806  while (isspace((unsigned char) *endptr))
807  endptr--;
808 
809  endptr++;
810  *endptr = '\0';
811 
812  for (unit = size_pretty_units; unit->name != NULL; unit++)
813  {
814  /* Parse the unit case-insensitively */
815  if (pg_strcasecmp(strptr, unit->name) == 0)
816  break;
817  }
818 
819  /* If not found, look in table of aliases */
820  if (unit->name == NULL)
821  {
822  for (const struct size_bytes_unit_alias *a = size_bytes_aliases; a->alias != NULL; a++)
823  {
824  if (pg_strcasecmp(strptr, a->alias) == 0)
825  {
826  unit = &size_pretty_units[a->unit_index];
827  break;
828  }
829  }
830  }
831 
832  /* Verify we found a valid unit in the loop above */
833  if (unit->name == NULL)
834  ereport(ERROR,
835  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
836  errmsg("invalid size: \"%s\"", text_to_cstring(arg)),
837  errdetail("Invalid size unit: \"%s\".", strptr),
838  errhint("Valid units are \"bytes\", \"B\", \"kB\", \"MB\", \"GB\", \"TB\", and \"PB\".")));
839 
840  multiplier = ((int64) 1) << unit->unitbits;
841 
842  if (multiplier > 1)
843  {
844  Numeric mul_num;
845 
846  mul_num = int64_to_numeric(multiplier);
847 
849  NumericGetDatum(mul_num),
850  NumericGetDatum(num)));
851  }
852  }
853 
855  NumericGetDatum(num)));
856 
857  PG_RETURN_INT64(result);
858 }
Datum numeric_int8(PG_FUNCTION_ARGS)
Definition: numeric.c:4535
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:628
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3003
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:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
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 
579  /* use this unit if there are no more units or we're below the limit */
580  if (unit[1].name == NULL || i64abs(size) < unit->limit)
581  {
582  if (unit->round)
584 
585  snprintf(buf, sizeof(buf), INT64_FORMAT " %s", size, unit->name);
586  break;
587  }
588 
589  /*
590  * Determine the number of bits to use to build the divisor. We may
591  * need to use 1 bit less than the difference between this and the
592  * next unit if the next unit uses half rounding. Or we may need to
593  * shift an extra bit if this unit uses half rounding and the next one
594  * does not. We use division rather than shifting right by this
595  * number of bits to ensure positive and negative values are rounded
596  * in the same way.
597  */
598  bits = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
599  + (unit->round == true));
600  size /= ((int64) 1) << bits;
601  }
602 
604 }
#define INT64_FORMAT
Definition: c.h:548
unsigned char uint8
Definition: c.h:504
#define i64abs(i)
Definition: c.h:1307
#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, i64abs, 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 668 of file dbsize.c.

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