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/catalog.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, BackendId 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 36 of file dbsize.c.

Function Documentation

◆ calculate_database_size()

static int64 calculate_database_size ( Oid  dbOid)
static

Definition at line 119 of file dbsize.c.

120 {
121  int64 totalsize;
122  DIR *dirdesc;
123  struct dirent *direntry;
124  char dirpath[MAXPGPATH];
125  char pathname[MAXPGPATH + 21 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
126  AclResult aclresult;
127 
128  /*
129  * User must have connect privilege for target database or have privileges
130  * of pg_read_all_stats
131  */
132  aclresult = object_aclcheck(DatabaseRelationId, dbOid, GetUserId(), ACL_CONNECT);
133  if (aclresult != ACLCHECK_OK &&
134  !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
135  {
136  aclcheck_error(aclresult, OBJECT_DATABASE,
137  get_database_name(dbOid));
138  }
139 
140  /* Shared storage in pg_global is not counted */
141 
142  /* Include pg_default storage */
143  snprintf(pathname, sizeof(pathname), "base/%u", dbOid);
144  totalsize = db_dir_size(pathname);
145 
146  /* Scan the non-default tablespaces */
147  snprintf(dirpath, MAXPGPATH, "pg_tblspc");
148  dirdesc = AllocateDir(dirpath);
149 
150  while ((direntry = ReadDir(dirdesc, dirpath)) != NULL)
151  {
153 
154  if (strcmp(direntry->d_name, ".") == 0 ||
155  strcmp(direntry->d_name, "..") == 0)
156  continue;
157 
158  snprintf(pathname, sizeof(pathname), "pg_tblspc/%s/%s/%u",
159  direntry->d_name, TABLESPACE_VERSION_DIRECTORY, dbOid);
160  totalsize += db_dir_size(pathname);
161  }
162 
163  FreeDir(dirdesc);
164 
165  return totalsize;
166 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4961
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2669
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3760
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3084
static int64 db_dir_size(const char *path)
Definition: dbsize.c:75
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2854
int FreeDir(DIR *dir)
Definition: fd.c:2906
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2788
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
Oid GetUserId(void)
Definition: miscinit.c:509
@ OBJECT_DATABASE
Definition: parsenodes.h:2129
#define ACL_CONNECT
Definition: parsenodes.h:94
#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 452 of file dbsize.c.

453 {
454  int64 size = 0;
455 
456  /*
457  * Aggregate all indexes on the given relation
458  */
459  if (rel->rd_rel->relhasindex)
460  {
461  List *index_oids = RelationGetIndexList(rel);
462  ListCell *cell;
463 
464  foreach(cell, index_oids)
465  {
466  Oid idxOid = lfirst_oid(cell);
467  Relation idxRel;
468  ForkNumber forkNum;
469 
470  idxRel = relation_open(idxOid, AccessShareLock);
471 
472  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
473  size += calculate_relation_size(&(idxRel->rd_locator),
474  idxRel->rd_backend,
475  forkNum);
476 
478  }
479 
480  list_free(index_oids);
481  }
482 
483  return size;
484 }
static int64 calculate_relation_size(RelFileLocator *rfn, BackendId backend, ForkNumber forknum)
Definition: dbsize.c:309
void list_free(List *list)
Definition: list.c:1545
#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:4740
ForkNumber
Definition: relpath.h:48
#define MAX_FORKNUM
Definition: relpath.h:62
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
Definition: pg_list.h:54
BackendId 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(), and RelationGetIndexList().

Referenced by calculate_total_relation_size(), and pg_indexes_size().

◆ calculate_relation_size()

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

Definition at line 309 of file dbsize.c.

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

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

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

Referenced by calculate_total_relation_size(), and pg_table_size().

◆ calculate_tablespace_size()

static int64 calculate_tablespace_size ( Oid  tblspcOid)
static

Definition at line 203 of file dbsize.c.

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

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

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

Referenced by calculate_table_size().

◆ calculate_total_relation_size()

static int64 calculate_total_relation_size ( Relation  rel)
static

Definition at line 529 of file dbsize.c.

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

References calculate_indexes_size(), and calculate_table_size().

Referenced by pg_total_relation_size().

◆ db_dir_size()

static int64 db_dir_size ( const char *  path)
static

Definition at line 75 of file dbsize.c.

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

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

636 {
637  Datum d = NumericGetDatum(n);
638  Datum zero;
639  Datum one;
640  Datum two;
641  Datum result;
642 
646 
648  d = DirectFunctionCall2(numeric_add, d, one);
649  else
650  d = DirectFunctionCall2(numeric_sub, d, one);
651 
652  result = DirectFunctionCall2(numeric_div_trunc, d, two);
653  return DatumGetNumeric(result);
654 }
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition: numeric.c:2924
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4232
Datum numeric_ge(PG_FUNCTION_ARGS)
Definition: numeric.c:2459
Datum numeric_div_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:3258
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2847
#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 616 of file dbsize.c.

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

609 {
610  Datum d = NumericGetDatum(n);
611 
613 }
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:806
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 657 of file dbsize.c.

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

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

184 {
186  Oid dbOid = get_database_oid(NameStr(*dbName), false);
187  int64 size;
188 
189  size = calculate_database_size(dbOid);
190 
191  if (size == 0)
192  PG_RETURN_NULL();
193 
194  PG_RETURN_INT64(size);
195 }
#define NameStr(name)
Definition: c.h:735
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3037
static int64 calculate_database_size(Oid dbOid)
Definition: dbsize.c:119
#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:730

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

◆ pg_database_size_oid()

Datum pg_database_size_oid ( PG_FUNCTION_ARGS  )

Definition at line 169 of file dbsize.c.

170 {
171  Oid dbOid = PG_GETARG_OID(0);
172  int64 size;
173 
174  size = calculate_database_size(dbOid);
175 
176  if (size == 0)
177  PG_RETURN_NULL();
178 
179  PG_RETURN_INT64(size);
180 }
#define PG_GETARG_OID(n)
Definition: fmgr.h:275

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

◆ pg_filenode_relation()

Datum pg_filenode_relation ( PG_FUNCTION_ARGS  )

Definition at line 924 of file dbsize.c.

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

507 {
508  Oid relOid = PG_GETARG_OID(0);
509  Relation rel;
510  int64 size;
511 
512  rel = try_relation_open(relOid, AccessShareLock);
513 
514  if (rel == NULL)
515  PG_RETURN_NULL();
516 
517  size = calculate_indexes_size(rel);
518 
520 
521  PG_RETURN_INT64(size);
522 }
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89

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

◆ pg_relation_filenode()

Datum pg_relation_filenode ( PG_FUNCTION_ARGS  )

Definition at line 876 of file dbsize.c.

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

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

◆ pg_relation_filepath()

Datum pg_relation_filepath ( PG_FUNCTION_ARGS  )

Definition at line 948 of file dbsize.c.

949 {
950  Oid relid = PG_GETARG_OID(0);
951  HeapTuple tuple;
952  Form_pg_class relform;
953  RelFileLocator rlocator;
954  BackendId backend;
955  char *path;
956 
957  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
958  if (!HeapTupleIsValid(tuple))
959  PG_RETURN_NULL();
960  relform = (Form_pg_class) GETSTRUCT(tuple);
961 
962  if (RELKIND_HAS_STORAGE(relform->relkind))
963  {
964  /* This logic should match RelationInitPhysicalAddr */
965  if (relform->reltablespace)
966  rlocator.spcOid = relform->reltablespace;
967  else
968  rlocator.spcOid = MyDatabaseTableSpace;
969  if (rlocator.spcOid == GLOBALTABLESPACE_OID)
970  rlocator.dbOid = InvalidOid;
971  else
972  rlocator.dbOid = MyDatabaseId;
973  if (relform->relfilenode)
974  rlocator.relNumber = relform->relfilenode;
975  else /* Consult the relation mapper */
976  rlocator.relNumber = RelationMapOidToFilenumber(relid,
977  relform->relisshared);
978  }
979  else
980  {
981  /* no storage, return NULL */
982  rlocator.relNumber = InvalidRelFileNumber;
983  /* some compilers generate warnings without these next two lines */
984  rlocator.dbOid = InvalidOid;
985  rlocator.spcOid = InvalidOid;
986  }
987 
988  if (!RelFileNumberIsValid(rlocator.relNumber))
989  {
990  ReleaseSysCache(tuple);
991  PG_RETURN_NULL();
992  }
993 
994  /* Determine owning backend. */
995  switch (relform->relpersistence)
996  {
997  case RELPERSISTENCE_UNLOGGED:
998  case RELPERSISTENCE_PERMANENT:
999  backend = InvalidBackendId;
1000  break;
1001  case RELPERSISTENCE_TEMP:
1002  if (isTempOrTempToastNamespace(relform->relnamespace))
1003  backend = BackendIdForTempRelations();
1004  else
1005  {
1006  /* Do it the hard way. */
1007  backend = GetTempNamespaceBackendId(relform->relnamespace);
1008  Assert(backend != InvalidBackendId);
1009  }
1010  break;
1011  default:
1012  elog(ERROR, "invalid relpersistence: %c", relform->relpersistence);
1013  backend = InvalidBackendId; /* placate compiler */
1014  break;
1015  }
1016 
1017  ReleaseSysCache(tuple);
1018 
1019  path = relpathbackend(rlocator, backend, MAIN_FORKNUM);
1020 
1022 }
int BackendId
Definition: backendid.h:21
#define BackendIdForTempRelations()
Definition: backendid.h:34
#define InvalidBackendId
Definition: backendid.h:23
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
Oid MyDatabaseId
Definition: globals.c:89
Assert(fmt[strlen(fmt) - 1] !='\n')
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3206
int GetTempNamespaceBackendId(Oid namespaceId)
Definition: namespace.c:3299
#define InvalidOid
Definition: postgres_ext.h:36
@ MAIN_FORKNUM
Definition: relpath.h:50
RelFileNumber relNumber
text * cstring_to_text(const char *s)
Definition: varlena.c:182

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

◆ pg_relation_size()

Datum pg_relation_size ( PG_FUNCTION_ARGS  )

Definition at line 347 of file dbsize.c.

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

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(), text_to_cstring(), and try_relation_open().

◆ pg_size_bytes()

Datum pg_size_bytes ( PG_FUNCTION_ARGS  )

Definition at line 710 of file dbsize.c.

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

571 {
572  int64 size = PG_GETARG_INT64(0);
573  char buf[64];
574  const struct size_pretty_unit *unit;
575 
576  for (unit = size_pretty_units; unit->name != NULL; unit++)
577  {
578  uint8 bits;
579 
580  /* use this unit if there are no more units or we're below the limit */
581  if (unit[1].name == NULL || i64abs(size) < unit->limit)
582  {
583  if (unit->round)
584  size = half_rounded(size);
585 
586  snprintf(buf, sizeof(buf), INT64_FORMAT " %s", size, unit->name);
587  break;
588  }
589 
590  /*
591  * Determine the number of bits to use to build the divisor. We may
592  * need to use 1 bit less than the difference between this and the
593  * next unit if the next unit uses half rounding. Or we may need to
594  * shift an extra bit if this unit uses half rounding and the next one
595  * does not. We use division rather than shifting right by this
596  * number of bits to ensure positive and negative values are rounded
597  * in the same way.
598  */
599  bits = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
600  + (unit->round == true));
601  size /= ((int64) 1) << bits;
602  }
603 
605 }
#define INT64_FORMAT
Definition: c.h:537
unsigned char uint8
Definition: c.h:493
#define i64abs(i)
Definition: c.h:1317
#define half_rounded(x)
Definition: dbsize.c:36
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
static char * buf
Definition: pg_test_fsync.c:67
uint32 limit
Definition: dbsize.c:42
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_pretty_units, snprintf, and size_pretty_unit::unitbits.

◆ pg_size_pretty_numeric()

Datum pg_size_pretty_numeric ( PG_FUNCTION_ARGS  )

Definition at line 669 of file dbsize.c.

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

◆ pg_table_size()

Datum pg_table_size ( PG_FUNCTION_ARGS  )

Definition at line 487 of file dbsize.c.

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

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

◆ pg_tablespace_size_name()

Datum pg_tablespace_size_name ( PG_FUNCTION_ARGS  )

Definition at line 287 of file dbsize.c.

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

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

◆ pg_tablespace_size_oid()

Datum pg_tablespace_size_oid ( PG_FUNCTION_ARGS  )

Definition at line 273 of file dbsize.c.

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

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

◆ pg_total_relation_size()

Datum pg_total_relation_size ( PG_FUNCTION_ARGS  )

Definition at line 548 of file dbsize.c.

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

References AccessShareLock, calculate_total_relation_size(), PG_GETARG_OID, PG_RETURN_INT64, PG_RETURN_NULL, relation_close(), 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().