PostgreSQL Source Code  git master
dbsize.c
Go to the documentation of this file.
1 /*
2  * dbsize.c
3  * Database object size functions, and related inquiries
4  *
5  * Copyright (c) 2002-2020, PostgreSQL Global Development Group
6  *
7  * IDENTIFICATION
8  * src/backend/utils/adt/dbsize.c
9  *
10  */
11 
12 #include "postgres.h"
13 
14 #include <sys/stat.h>
15 
16 #include "access/htup_details.h"
17 #include "access/relation.h"
18 #include "catalog/catalog.h"
19 #include "catalog/namespace.h"
20 #include "catalog/pg_authid.h"
21 #include "catalog/pg_tablespace.h"
22 #include "commands/dbcommands.h"
23 #include "commands/tablespace.h"
24 #include "miscadmin.h"
25 #include "storage/fd.h"
26 #include "utils/acl.h"
27 #include "utils/builtins.h"
28 #include "utils/numeric.h"
29 #include "utils/rel.h"
30 #include "utils/relfilenodemap.h"
31 #include "utils/relmapper.h"
32 #include "utils/syscache.h"
33 
34 /* Divide by two and round towards positive infinity. */
35 #define half_rounded(x) (((x) + ((x) < 0 ? 0 : 1)) / 2)
36 
37 /* Return physical size of directory contents, or 0 if dir doesn't exist */
38 static int64
39 db_dir_size(const char *path)
40 {
41  int64 dirsize = 0;
42  struct dirent *direntry;
43  DIR *dirdesc;
44  char filename[MAXPGPATH * 2];
45 
46  dirdesc = AllocateDir(path);
47 
48  if (!dirdesc)
49  return 0;
50 
51  while ((direntry = ReadDir(dirdesc, path)) != NULL)
52  {
53  struct stat fst;
54 
56 
57  if (strcmp(direntry->d_name, ".") == 0 ||
58  strcmp(direntry->d_name, "..") == 0)
59  continue;
60 
61  snprintf(filename, sizeof(filename), "%s/%s", path, direntry->d_name);
62 
63  if (stat(filename, &fst) < 0)
64  {
65  if (errno == ENOENT)
66  continue;
67  else
68  ereport(ERROR,
70  errmsg("could not stat file \"%s\": %m", filename)));
71  }
72  dirsize += fst.st_size;
73  }
74 
75  FreeDir(dirdesc);
76  return dirsize;
77 }
78 
79 /*
80  * calculate size of database in all tablespaces
81  */
82 static int64
84 {
85  int64 totalsize;
86  DIR *dirdesc;
87  struct dirent *direntry;
88  char dirpath[MAXPGPATH];
89  char pathname[MAXPGPATH + 21 + sizeof(TABLESPACE_VERSION_DIRECTORY)];
90  AclResult aclresult;
91 
92  /*
93  * User must have connect privilege for target database or be a member of
94  * pg_read_all_stats
95  */
96  aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT);
97  if (aclresult != ACLCHECK_OK &&
98  !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
99  {
100  aclcheck_error(aclresult, OBJECT_DATABASE,
101  get_database_name(dbOid));
102  }
103 
104  /* Shared storage in pg_global is not counted */
105 
106  /* Include pg_default storage */
107  snprintf(pathname, sizeof(pathname), "base/%u", dbOid);
108  totalsize = db_dir_size(pathname);
109 
110  /* Scan the non-default tablespaces */
111  snprintf(dirpath, MAXPGPATH, "pg_tblspc");
112  dirdesc = AllocateDir(dirpath);
113 
114  while ((direntry = ReadDir(dirdesc, dirpath)) != NULL)
115  {
117 
118  if (strcmp(direntry->d_name, ".") == 0 ||
119  strcmp(direntry->d_name, "..") == 0)
120  continue;
121 
122  snprintf(pathname, sizeof(pathname), "pg_tblspc/%s/%s/%u",
123  direntry->d_name, TABLESPACE_VERSION_DIRECTORY, dbOid);
124  totalsize += db_dir_size(pathname);
125  }
126 
127  FreeDir(dirdesc);
128 
129  return totalsize;
130 }
131 
132 Datum
134 {
135  Oid dbOid = PG_GETARG_OID(0);
136  int64 size;
137 
138  size = calculate_database_size(dbOid);
139 
140  if (size == 0)
141  PG_RETURN_NULL();
142 
143  PG_RETURN_INT64(size);
144 }
145 
146 Datum
148 {
150  Oid dbOid = get_database_oid(NameStr(*dbName), false);
151  int64 size;
152 
153  size = calculate_database_size(dbOid);
154 
155  if (size == 0)
156  PG_RETURN_NULL();
157 
158  PG_RETURN_INT64(size);
159 }
160 
161 
162 /*
163  * Calculate total size of tablespace. Returns -1 if the tablespace directory
164  * cannot be found.
165  */
166 static int64
168 {
169  char tblspcPath[MAXPGPATH];
170  char pathname[MAXPGPATH * 2];
171  int64 totalsize = 0;
172  DIR *dirdesc;
173  struct dirent *direntry;
174  AclResult aclresult;
175 
176  /*
177  * User must be a member of pg_read_all_stats or have CREATE privilege for
178  * target tablespace, either explicitly granted or implicitly because it
179  * is default for current database.
180  */
181  if (tblspcOid != MyDatabaseTableSpace &&
182  !is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS))
183  {
184  aclresult = pg_tablespace_aclcheck(tblspcOid, GetUserId(), ACL_CREATE);
185  if (aclresult != ACLCHECK_OK)
187  get_tablespace_name(tblspcOid));
188  }
189 
190  if (tblspcOid == DEFAULTTABLESPACE_OID)
191  snprintf(tblspcPath, MAXPGPATH, "base");
192  else if (tblspcOid == GLOBALTABLESPACE_OID)
193  snprintf(tblspcPath, MAXPGPATH, "global");
194  else
195  snprintf(tblspcPath, MAXPGPATH, "pg_tblspc/%u/%s", tblspcOid,
197 
198  dirdesc = AllocateDir(tblspcPath);
199 
200  if (!dirdesc)
201  return -1;
202 
203  while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL)
204  {
205  struct stat fst;
206 
208 
209  if (strcmp(direntry->d_name, ".") == 0 ||
210  strcmp(direntry->d_name, "..") == 0)
211  continue;
212 
213  snprintf(pathname, sizeof(pathname), "%s/%s", tblspcPath, direntry->d_name);
214 
215  if (stat(pathname, &fst) < 0)
216  {
217  if (errno == ENOENT)
218  continue;
219  else
220  ereport(ERROR,
222  errmsg("could not stat file \"%s\": %m", pathname)));
223  }
224 
225  if (S_ISDIR(fst.st_mode))
226  totalsize += db_dir_size(pathname);
227 
228  totalsize += fst.st_size;
229  }
230 
231  FreeDir(dirdesc);
232 
233  return totalsize;
234 }
235 
236 Datum
238 {
239  Oid tblspcOid = PG_GETARG_OID(0);
240  int64 size;
241 
242  size = calculate_tablespace_size(tblspcOid);
243 
244  if (size < 0)
245  PG_RETURN_NULL();
246 
247  PG_RETURN_INT64(size);
248 }
249 
250 Datum
252 {
253  Name tblspcName = PG_GETARG_NAME(0);
254  Oid tblspcOid = get_tablespace_oid(NameStr(*tblspcName), false);
255  int64 size;
256 
257  size = calculate_tablespace_size(tblspcOid);
258 
259  if (size < 0)
260  PG_RETURN_NULL();
261 
262  PG_RETURN_INT64(size);
263 }
264 
265 
266 /*
267  * calculate size of (one fork of) a relation
268  *
269  * Note: we can safely apply this to temp tables of other sessions, so there
270  * is no check here or at the call sites for that.
271  */
272 static int64
274 {
275  int64 totalsize = 0;
276  char *relationpath;
277  char pathname[MAXPGPATH];
278  unsigned int segcount = 0;
279 
280  relationpath = relpathbackend(*rfn, backend, forknum);
281 
282  for (segcount = 0;; segcount++)
283  {
284  struct stat fst;
285 
287 
288  if (segcount == 0)
289  snprintf(pathname, MAXPGPATH, "%s",
290  relationpath);
291  else
292  snprintf(pathname, MAXPGPATH, "%s.%u",
293  relationpath, segcount);
294 
295  if (stat(pathname, &fst) < 0)
296  {
297  if (errno == ENOENT)
298  break;
299  else
300  ereport(ERROR,
302  errmsg("could not stat file \"%s\": %m", pathname)));
303  }
304  totalsize += fst.st_size;
305  }
306 
307  return totalsize;
308 }
309 
310 Datum
312 {
313  Oid relOid = PG_GETARG_OID(0);
314  text *forkName = PG_GETARG_TEXT_PP(1);
315  Relation rel;
316  int64 size;
317 
318  rel = try_relation_open(relOid, AccessShareLock);
319 
320  /*
321  * Before 9.2, we used to throw an error if the relation didn't exist, but
322  * that makes queries like "SELECT pg_relation_size(oid) FROM pg_class"
323  * less robust, because while we scan pg_class with an MVCC snapshot,
324  * someone else might drop the table. It's better to return NULL for
325  * already-dropped tables than throw an error and abort the whole query.
326  */
327  if (rel == NULL)
328  PG_RETURN_NULL();
329 
330  size = calculate_relation_size(&(rel->rd_node), rel->rd_backend,
332 
334 
335  PG_RETURN_INT64(size);
336 }
337 
338 /*
339  * Calculate total on-disk size of a TOAST relation, including its indexes.
340  * Must not be applied to non-TOAST relations.
341  */
342 static int64
344 {
345  int64 size = 0;
346  Relation toastRel;
347  ForkNumber forkNum;
348  ListCell *lc;
349  List *indexlist;
350 
351  toastRel = relation_open(toastrelid, AccessShareLock);
352 
353  /* toast heap size, including FSM and VM size */
354  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
355  size += calculate_relation_size(&(toastRel->rd_node),
356  toastRel->rd_backend, forkNum);
357 
358  /* toast index size, including FSM and VM size */
359  indexlist = RelationGetIndexList(toastRel);
360 
361  /* Size is calculated using all the indexes available */
362  foreach(lc, indexlist)
363  {
364  Relation toastIdxRel;
365 
366  toastIdxRel = relation_open(lfirst_oid(lc),
368  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
369  size += calculate_relation_size(&(toastIdxRel->rd_node),
370  toastIdxRel->rd_backend, forkNum);
371 
372  relation_close(toastIdxRel, AccessShareLock);
373  }
374  list_free(indexlist);
375  relation_close(toastRel, AccessShareLock);
376 
377  return size;
378 }
379 
380 /*
381  * Calculate total on-disk size of a given table,
382  * including FSM and VM, plus TOAST table if any.
383  * Indexes other than the TOAST table's index are not included.
384  *
385  * Note that this also behaves sanely if applied to an index or toast table;
386  * those won't have attached toast tables, but they can have multiple forks.
387  */
388 static int64
390 {
391  int64 size = 0;
392  ForkNumber forkNum;
393 
394  /*
395  * heap size, including FSM and VM
396  */
397  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
398  size += calculate_relation_size(&(rel->rd_node), rel->rd_backend,
399  forkNum);
400 
401  /*
402  * Size of toast relation
403  */
404  if (OidIsValid(rel->rd_rel->reltoastrelid))
405  size += calculate_toast_table_size(rel->rd_rel->reltoastrelid);
406 
407  return size;
408 }
409 
410 /*
411  * Calculate total on-disk size of all indexes attached to the given table.
412  *
413  * Can be applied safely to an index, but you'll just get zero.
414  */
415 static int64
417 {
418  int64 size = 0;
419 
420  /*
421  * Aggregate all indexes on the given relation
422  */
423  if (rel->rd_rel->relhasindex)
424  {
425  List *index_oids = RelationGetIndexList(rel);
426  ListCell *cell;
427 
428  foreach(cell, index_oids)
429  {
430  Oid idxOid = lfirst_oid(cell);
431  Relation idxRel;
432  ForkNumber forkNum;
433 
434  idxRel = relation_open(idxOid, AccessShareLock);
435 
436  for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
437  size += calculate_relation_size(&(idxRel->rd_node),
438  idxRel->rd_backend,
439  forkNum);
440 
442  }
443 
444  list_free(index_oids);
445  }
446 
447  return size;
448 }
449 
450 Datum
452 {
453  Oid relOid = PG_GETARG_OID(0);
454  Relation rel;
455  int64 size;
456 
457  rel = try_relation_open(relOid, AccessShareLock);
458 
459  if (rel == NULL)
460  PG_RETURN_NULL();
461 
462  size = calculate_table_size(rel);
463 
465 
466  PG_RETURN_INT64(size);
467 }
468 
469 Datum
471 {
472  Oid relOid = PG_GETARG_OID(0);
473  Relation rel;
474  int64 size;
475 
476  rel = try_relation_open(relOid, AccessShareLock);
477 
478  if (rel == NULL)
479  PG_RETURN_NULL();
480 
481  size = calculate_indexes_size(rel);
482 
484 
485  PG_RETURN_INT64(size);
486 }
487 
488 /*
489  * Compute the on-disk size of all files for the relation,
490  * including heap data, index data, toast data, FSM, VM.
491  */
492 static int64
494 {
495  int64 size;
496 
497  /*
498  * Aggregate the table size, this includes size of the heap, toast and
499  * toast index with free space and visibility map
500  */
501  size = calculate_table_size(rel);
502 
503  /*
504  * Add size of all attached indexes as well
505  */
506  size += calculate_indexes_size(rel);
507 
508  return size;
509 }
510 
511 Datum
513 {
514  Oid relOid = PG_GETARG_OID(0);
515  Relation rel;
516  int64 size;
517 
518  rel = try_relation_open(relOid, AccessShareLock);
519 
520  if (rel == NULL)
521  PG_RETURN_NULL();
522 
523  size = calculate_total_relation_size(rel);
524 
526 
527  PG_RETURN_INT64(size);
528 }
529 
530 /*
531  * formatting with size units
532  */
533 Datum
535 {
536  int64 size = PG_GETARG_INT64(0);
537  char buf[64];
538  int64 limit = 10 * 1024;
539  int64 limit2 = limit * 2 - 1;
540 
541  if (Abs(size) < limit)
542  snprintf(buf, sizeof(buf), INT64_FORMAT " bytes", size);
543  else
544  {
545  size >>= 9; /* keep one extra bit for rounding */
546  if (Abs(size) < limit2)
547  snprintf(buf, sizeof(buf), INT64_FORMAT " kB",
548  half_rounded(size));
549  else
550  {
551  size >>= 10;
552  if (Abs(size) < limit2)
553  snprintf(buf, sizeof(buf), INT64_FORMAT " MB",
554  half_rounded(size));
555  else
556  {
557  size >>= 10;
558  if (Abs(size) < limit2)
559  snprintf(buf, sizeof(buf), INT64_FORMAT " GB",
560  half_rounded(size));
561  else
562  {
563  size >>= 10;
564  snprintf(buf, sizeof(buf), INT64_FORMAT " TB",
565  half_rounded(size));
566  }
567  }
568  }
569  }
570 
572 }
573 
574 static char *
576 {
577  Datum d = NumericGetDatum(n);
578 
580 }
581 
582 static bool
584 {
585  Datum da = NumericGetDatum(a);
586  Datum db = NumericGetDatum(b);
587 
589 }
590 
591 static Numeric
593 {
594  Datum d = NumericGetDatum(n);
595  Datum result;
596 
597  result = DirectFunctionCall1(numeric_abs, d);
598  return DatumGetNumeric(result);
599 }
600 
601 static Numeric
603 {
604  Datum d = NumericGetDatum(n);
605  Datum zero;
606  Datum one;
607  Datum two;
608  Datum result;
609 
613 
615  d = DirectFunctionCall2(numeric_add, d, one);
616  else
617  d = DirectFunctionCall2(numeric_sub, d, one);
618 
619  result = DirectFunctionCall2(numeric_div_trunc, d, two);
620  return DatumGetNumeric(result);
621 }
622 
623 static Numeric
624 numeric_shift_right(Numeric n, unsigned count)
625 {
626  Datum d = NumericGetDatum(n);
627  Datum divisor_numeric;
628  Datum result;
629 
630  divisor_numeric = NumericGetDatum(int64_to_numeric(((int64) 1) << count));
631  result = DirectFunctionCall2(numeric_div_trunc, d, divisor_numeric);
632  return DatumGetNumeric(result);
633 }
634 
635 Datum
637 {
638  Numeric size = PG_GETARG_NUMERIC(0);
639  Numeric limit,
640  limit2;
641  char *result;
642 
643  limit = int64_to_numeric(10 * 1024);
644  limit2 = int64_to_numeric(10 * 1024 * 2 - 1);
645 
646  if (numeric_is_less(numeric_absolute(size), limit))
647  {
648  result = psprintf("%s bytes", numeric_to_cstring(size));
649  }
650  else
651  {
652  /* keep one extra bit for rounding */
653  /* size >>= 9 */
654  size = numeric_shift_right(size, 9);
655 
656  if (numeric_is_less(numeric_absolute(size), limit2))
657  {
658  size = numeric_half_rounded(size);
659  result = psprintf("%s kB", numeric_to_cstring(size));
660  }
661  else
662  {
663  /* size >>= 10 */
664  size = numeric_shift_right(size, 10);
665  if (numeric_is_less(numeric_absolute(size), limit2))
666  {
667  size = numeric_half_rounded(size);
668  result = psprintf("%s MB", numeric_to_cstring(size));
669  }
670  else
671  {
672  /* size >>= 10 */
673  size = numeric_shift_right(size, 10);
674 
675  if (numeric_is_less(numeric_absolute(size), limit2))
676  {
677  size = numeric_half_rounded(size);
678  result = psprintf("%s GB", numeric_to_cstring(size));
679  }
680  else
681  {
682  /* size >>= 10 */
683  size = numeric_shift_right(size, 10);
684  size = numeric_half_rounded(size);
685  result = psprintf("%s TB", numeric_to_cstring(size));
686  }
687  }
688  }
689  }
690 
692 }
693 
694 /*
695  * Convert a human-readable size to a size in bytes
696  */
697 Datum
699 {
700  text *arg = PG_GETARG_TEXT_PP(0);
701  char *str,
702  *strptr,
703  *endptr;
704  char saved_char;
705  Numeric num;
706  int64 result;
707  bool have_digits = false;
708 
709  str = text_to_cstring(arg);
710 
711  /* Skip leading whitespace */
712  strptr = str;
713  while (isspace((unsigned char) *strptr))
714  strptr++;
715 
716  /* Check that we have a valid number and determine where it ends */
717  endptr = strptr;
718 
719  /* Part (1): sign */
720  if (*endptr == '-' || *endptr == '+')
721  endptr++;
722 
723  /* Part (2): main digit string */
724  if (isdigit((unsigned char) *endptr))
725  {
726  have_digits = true;
727  do
728  endptr++;
729  while (isdigit((unsigned char) *endptr));
730  }
731 
732  /* Part (3): optional decimal point and fractional digits */
733  if (*endptr == '.')
734  {
735  endptr++;
736  if (isdigit((unsigned char) *endptr))
737  {
738  have_digits = true;
739  do
740  endptr++;
741  while (isdigit((unsigned char) *endptr));
742  }
743  }
744 
745  /* Complain if we don't have a valid number at this point */
746  if (!have_digits)
747  ereport(ERROR,
748  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
749  errmsg("invalid size: \"%s\"", str)));
750 
751  /* Part (4): optional exponent */
752  if (*endptr == 'e' || *endptr == 'E')
753  {
754  long exponent;
755  char *cp;
756 
757  /*
758  * Note we might one day support EB units, so if what follows 'E'
759  * isn't a number, just treat it all as a unit to be parsed.
760  */
761  exponent = strtol(endptr + 1, &cp, 10);
762  (void) exponent; /* Silence -Wunused-result warnings */
763  if (cp > endptr + 1)
764  endptr = cp;
765  }
766 
767  /*
768  * Parse the number, saving the next character, which may be the first
769  * character of the unit string.
770  */
771  saved_char = *endptr;
772  *endptr = '\0';
773 
775  CStringGetDatum(strptr),
777  Int32GetDatum(-1)));
778 
779  *endptr = saved_char;
780 
781  /* Skip whitespace between number and unit */
782  strptr = endptr;
783  while (isspace((unsigned char) *strptr))
784  strptr++;
785 
786  /* Handle possible unit */
787  if (*strptr != '\0')
788  {
789  int64 multiplier = 0;
790 
791  /* Trim any trailing whitespace */
792  endptr = str + VARSIZE_ANY_EXHDR(arg) - 1;
793 
794  while (isspace((unsigned char) *endptr))
795  endptr--;
796 
797  endptr++;
798  *endptr = '\0';
799 
800  /* Parse the unit case-insensitively */
801  if (pg_strcasecmp(strptr, "bytes") == 0)
802  multiplier = (int64) 1;
803  else if (pg_strcasecmp(strptr, "kb") == 0)
804  multiplier = (int64) 1024;
805  else if (pg_strcasecmp(strptr, "mb") == 0)
806  multiplier = ((int64) 1024) * 1024;
807 
808  else if (pg_strcasecmp(strptr, "gb") == 0)
809  multiplier = ((int64) 1024) * 1024 * 1024;
810 
811  else if (pg_strcasecmp(strptr, "tb") == 0)
812  multiplier = ((int64) 1024) * 1024 * 1024 * 1024;
813 
814  else
815  ereport(ERROR,
816  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
817  errmsg("invalid size: \"%s\"", text_to_cstring(arg)),
818  errdetail("Invalid size unit: \"%s\".", strptr),
819  errhint("Valid units are \"bytes\", \"kB\", \"MB\", \"GB\", and \"TB\".")));
820 
821  if (multiplier > 1)
822  {
823  Numeric mul_num;
824 
825  mul_num = int64_to_numeric(multiplier);
826 
828  NumericGetDatum(mul_num),
829  NumericGetDatum(num)));
830  }
831  }
832 
834  NumericGetDatum(num)));
835 
836  PG_RETURN_INT64(result);
837 }
838 
839 /*
840  * Get the filenode of a relation
841  *
842  * This is expected to be used in queries like
843  * SELECT pg_relation_filenode(oid) FROM pg_class;
844  * That leads to a couple of choices. We work from the pg_class row alone
845  * rather than actually opening each relation, for efficiency. We don't
846  * fail if we can't find the relation --- some rows might be visible in
847  * the query's MVCC snapshot even though the relations have been dropped.
848  * (Note: we could avoid using the catcache, but there's little point
849  * because the relation mapper also works "in the now".) We also don't
850  * fail if the relation doesn't have storage. In all these cases it
851  * seems better to quietly return NULL.
852  */
853 Datum
855 {
856  Oid relid = PG_GETARG_OID(0);
857  Oid result;
858  HeapTuple tuple;
859  Form_pg_class relform;
860 
861  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
862  if (!HeapTupleIsValid(tuple))
863  PG_RETURN_NULL();
864  relform = (Form_pg_class) GETSTRUCT(tuple);
865 
866  if (RELKIND_HAS_STORAGE(relform->relkind))
867  {
868  if (relform->relfilenode)
869  result = relform->relfilenode;
870  else /* Consult the relation mapper */
871  result = RelationMapOidToFilenode(relid,
872  relform->relisshared);
873  }
874  else
875  {
876  /* no storage, return NULL */
877  result = InvalidOid;
878  }
879 
880  ReleaseSysCache(tuple);
881 
882  if (!OidIsValid(result))
883  PG_RETURN_NULL();
884 
885  PG_RETURN_OID(result);
886 }
887 
888 /*
889  * Get the relation via (reltablespace, relfilenode)
890  *
891  * This is expected to be used when somebody wants to match an individual file
892  * on the filesystem back to its table. That's not trivially possible via
893  * pg_class, because that doesn't contain the relfilenodes of shared and nailed
894  * tables.
895  *
896  * We don't fail but return NULL if we cannot find a mapping.
897  *
898  * InvalidOid can be passed instead of the current database's default
899  * tablespace.
900  */
901 Datum
903 {
904  Oid reltablespace = PG_GETARG_OID(0);
905  Oid relfilenode = PG_GETARG_OID(1);
906  Oid heaprel = InvalidOid;
907 
908  heaprel = RelidByRelfilenode(reltablespace, relfilenode);
909 
910  if (!OidIsValid(heaprel))
911  PG_RETURN_NULL();
912  else
913  PG_RETURN_OID(heaprel);
914 }
915 
916 /*
917  * Get the pathname (relative to $PGDATA) of a relation
918  *
919  * See comments for pg_relation_filenode.
920  */
921 Datum
923 {
924  Oid relid = PG_GETARG_OID(0);
925  HeapTuple tuple;
926  Form_pg_class relform;
927  RelFileNode rnode;
928  BackendId backend;
929  char *path;
930 
931  tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
932  if (!HeapTupleIsValid(tuple))
933  PG_RETURN_NULL();
934  relform = (Form_pg_class) GETSTRUCT(tuple);
935 
936  if (RELKIND_HAS_STORAGE(relform->relkind))
937  {
938  /* This logic should match RelationInitPhysicalAddr */
939  if (relform->reltablespace)
940  rnode.spcNode = relform->reltablespace;
941  else
943  if (rnode.spcNode == GLOBALTABLESPACE_OID)
944  rnode.dbNode = InvalidOid;
945  else
946  rnode.dbNode = MyDatabaseId;
947  if (relform->relfilenode)
948  rnode.relNode = relform->relfilenode;
949  else /* Consult the relation mapper */
950  rnode.relNode = RelationMapOidToFilenode(relid,
951  relform->relisshared);
952  }
953  else
954  {
955  /* no storage, return NULL */
956  rnode.relNode = InvalidOid;
957  /* some compilers generate warnings without these next two lines */
958  rnode.dbNode = InvalidOid;
959  rnode.spcNode = InvalidOid;
960  }
961 
962  if (!OidIsValid(rnode.relNode))
963  {
964  ReleaseSysCache(tuple);
965  PG_RETURN_NULL();
966  }
967 
968  /* Determine owning backend. */
969  switch (relform->relpersistence)
970  {
971  case RELPERSISTENCE_UNLOGGED:
972  case RELPERSISTENCE_PERMANENT:
973  backend = InvalidBackendId;
974  break;
975  case RELPERSISTENCE_TEMP:
976  if (isTempOrTempToastNamespace(relform->relnamespace))
977  backend = BackendIdForTempRelations();
978  else
979  {
980  /* Do it the hard way. */
981  backend = GetTempNamespaceBackendId(relform->relnamespace);
982  Assert(backend != InvalidBackendId);
983  }
984  break;
985  default:
986  elog(ERROR, "invalid relpersistence: %c", relform->relpersistence);
987  backend = InvalidBackendId; /* placate compiler */
988  break;
989  }
990 
991  ReleaseSysCache(tuple);
992 
993  path = relpathbackend(rnode, backend, MAIN_FORKNUM);
994 
996 }
Datum pg_filenode_relation(PG_FUNCTION_ARGS)
Definition: dbsize.c:902
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1421
AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4637
int errhint(const char *fmt,...)
Definition: elog.c:1149
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static int64 calculate_total_relation_size(Relation rel)
Definition: dbsize.c:493
Datum pg_relation_filepath(PG_FUNCTION_ARGS)
Definition: dbsize.c:922
static int64 calculate_relation_size(RelFileNode *rfn, BackendId backend, ForkNumber forknum)
Definition: dbsize.c:273
Oid GetUserId(void)
Definition: miscinit.c:476
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3180
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define NumericGetDatum(X)
Definition: numeric.h:51
Oid RelidByRelfilenode(Oid reltablespace, Oid relfilenode)
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:739
#define AccessShareLock
Definition: lockdefs.h:36
Datum numeric_int8(PG_FUNCTION_ARGS)
Definition: numeric.c:4191
int errcode(int sqlerrcode)
Definition: elog.c:691
int GetTempNamespaceBackendId(Oid namespaceId)
Definition: namespace.c:3273
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:626
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
Form_pg_class rd_rel
Definition: rel.h:110
unsigned int Oid
Definition: postgres_ext.h:31
static Numeric numeric_shift_right(Numeric n, unsigned count)
Definition: dbsize.c:624
Definition: dirent.h:9
#define OidIsValid(objectId)
Definition: c.h:706
Datum numeric_div_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:3115
Datum pg_total_relation_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:512
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:50
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:89
Oid MyDatabaseTableSpace
Definition: globals.c:87
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define Abs(x)
Definition: c.h:988
Datum pg_relation_filenode(PG_FUNCTION_ARGS)
Definition: dbsize.c:854
static char * numeric_to_cstring(Numeric n)
Definition: dbsize.c:575
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
static Numeric numeric_absolute(Numeric n)
Definition: dbsize.c:592
Definition: dirent.c:25
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1258
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
#define DatumGetCString(X)
Definition: postgres.h:566
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define MAXPGPATH
#define DatumGetInt64(X)
Definition: postgres.h:607
#define half_rounded(x)
Definition: dbsize.c:35
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2155
Definition: c.h:671
#define BackendIdForTempRelations()
Definition: backendid.h:34
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:26
static char * buf
Definition: pg_test_fsync.c:68
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
static Numeric numeric_half_rounded(Numeric n)
Definition: dbsize.c:602
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4079
int errdetail(const char *fmt,...)
Definition: elog.c:1035
int errcode_for_file_access(void)
Definition: elog.c:714
#define CStringGetDatum(X)
Definition: postgres.h:578
#define DatumGetBool(X)
Definition: postgres.h:393
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2610
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:621
__int64 st_size
Definition: win32_port.h:265
static bool numeric_is_less(Numeric a, Numeric b)
Definition: dbsize.c:583
Datum pg_table_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:451
Datum pg_size_bytes(PG_FUNCTION_ARGS)
Definition: dbsize.c:698
static int64 calculate_table_size(Relation rel)
Definition: dbsize.c:389
#define ACL_CONNECT
Definition: parsenodes.h:86
ForkNumber
Definition: relpath.h:40
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:630
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1115
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:2866
Datum pg_database_size_name(PG_FUNCTION_ARGS)
Definition: dbsize.c:147
#define InvalidBackendId
Definition: backendid.h:23
AclResult
Definition: acl.h:177
Oid RelationMapOidToFilenode(Oid relationId, bool shared)
Definition: relmapper.c:159
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition: numeric.c:2788
int BackendId
Definition: backendid.h:21
unsigned short st_mode
Definition: win32_port.h:260
Oid MyDatabaseId
Definition: globals.c:85
Datum numeric_lt(PG_FUNCTION_ARGS)
Definition: numeric.c:2338
#define InvalidOid
Definition: postgres_ext.h:36
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:2108
Datum pg_size_pretty_numeric(PG_FUNCTION_ARGS)
Definition: dbsize.c:636
#define ereport(elevel,...)
Definition: elog.h:155
bool is_member_of_role(Oid member, Oid role)
Definition: acl.c:4916
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
static int64 calculate_toast_table_size(Oid toastrelid)
Definition: dbsize.c:343
static int64 calculate_database_size(Oid dbOid)
Definition: dbsize.c:83
RelFileNode rd_node
Definition: rel.h:55
text * cstring_to_text(const char *s)
Definition: varlena.c:188
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:52
#define DatumGetNumeric(X)
Definition: numeric.h:49
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:800
Datum pg_tablespace_size_name(PG_FUNCTION_ARGS)
Definition: dbsize.c:251
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2676
Datum pg_size_pretty(PG_FUNCTION_ARGS)
Definition: dbsize.c:534
Datum pg_indexes_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:470
#define MAX_FORKNUM
Definition: relpath.h:55
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4515
#define INT64_FORMAT
Definition: c.h:471
#define S_ISDIR(m)
Definition: win32_port.h:316
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
char * text_to_cstring(const text *t)
Definition: varlena.c:221
Datum pg_tablespace_size_oid(PG_FUNCTION_ARGS)
Definition: dbsize.c:237
#define Int32GetDatum(X)
Definition: postgres.h:479
static char * filename
Definition: pg_dumpall.c:91
Datum pg_database_size_oid(PG_FUNCTION_ARGS)
Definition: dbsize.c:133
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
char * dbName
Definition: pgbench.c:246
int errmsg(const char *fmt,...)
Definition: elog.c:902
static int64 calculate_tablespace_size(Oid tblspcOid)
Definition: dbsize.c:167
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1467
void list_free(List *list)
Definition: list.c:1376
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:677
void * arg
Definition: c.h:617
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
char d_name[MAX_PATH]
Definition: dirent.h:15
Datum numeric_ge(PG_FUNCTION_ARGS)
Definition: numeric.c:2323
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define relpathbackend(rnode, backend, forknum)
Definition: relpath.h:78
Definition: pg_list.h:50
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
#define snprintf
Definition: port.h:215
Datum pg_relation_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:311
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2711
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:628
#define PG_RETURN_NULL()
Definition: fmgr.h:345
int FreeDir(DIR *dir)
Definition: fd.c:2728
static int64 db_dir_size(const char *path)
Definition: dbsize.c:39
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
static int64 calculate_indexes_size(Relation rel)
Definition: dbsize.c:416
#define stat
Definition: win32_port.h:275
#define lfirst_oid(lc)
Definition: pg_list.h:171