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-2024, 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/namespace.h"
19 #include "catalog/pg_authid.h"
20 #include "catalog/pg_database.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/relfilenumbermap.h"
31 #include "utils/relmapper.h"
32 #include "utils/syscache.h"
33 
34 /* Divide by two and round away from zero */
35 #define half_rounded(x) (((x) + ((x) < 0 ? -1 : 1)) / 2)
36 
37 /* Units used in pg_size_pretty functions. All units must be powers of 2 */
39 {
40  const char *name; /* bytes, kB, MB, GB etc */
41  uint32 limit; /* upper limit, prior to half rounding after
42  * converting to this unit. */
43  bool round; /* do half rounding for this unit */
44  uint8 unitbits; /* (1 << unitbits) bytes to make 1 of this
45  * unit */
46 };
47 
48 /* When adding units here also update the docs and the error message in pg_size_bytes */
49 static const struct size_pretty_unit size_pretty_units[] = {
50  {"bytes", 10 * 1024, false, 0},
51  {"kB", 20 * 1024 - 1, true, 10},
52  {"MB", 20 * 1024 - 1, true, 20},
53  {"GB", 20 * 1024 - 1, true, 30},
54  {"TB", 20 * 1024 - 1, true, 40},
55  {"PB", 20 * 1024 - 1, true, 50},
56  {NULL, 0, false, 0}
57 };
58 
59 /* Additional unit aliases accepted by pg_size_bytes */
61 {
62  const char *alias;
63  int unit_index; /* corresponding size_pretty_units element */
64 };
65 
66 /* When adding units here also update the docs and the error message in pg_size_bytes */
67 static const struct size_bytes_unit_alias size_bytes_aliases[] = {
68  {"B", 0},
69  {NULL}
70 };
71 
72 /* Return physical size of directory contents, or 0 if dir doesn't exist */
73 static int64
74 db_dir_size(const char *path)
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 }
113 
114 /*
115  * calculate size of database in all tablespaces
116  */
117 static int64
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 }
166 
167 Datum
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 }
180 
181 Datum
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 }
195 
196 
197 /*
198  * Calculate total size of tablespace. Returns -1 if the tablespace directory
199  * cannot be found.
200  */
201 static int64
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 }
270 
271 Datum
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 }
284 
285 Datum
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 }
299 
300 
301 /*
302  * calculate size of (one fork of) a relation
303  *
304  * Note: we can safely apply this to temp tables of other sessions, so there
305  * is no check here or at the call sites for that.
306  */
307 static int64
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 }
344 
345 Datum
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 }
372 
373 /*
374  * Calculate total on-disk size of a TOAST relation, including its indexes.
375  * Must not be applied to non-TOAST relations.
376  */
377 static int64
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 }
414 
415 /*
416  * Calculate total on-disk size of a given table,
417  * including FSM and VM, plus TOAST table if any.
418  * Indexes other than the TOAST table's index are not included.
419  *
420  * Note that this also behaves sanely if applied to an index or toast table;
421  * those won't have attached toast tables, but they can have multiple forks.
422  */
423 static int64
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 }
444 
445 /*
446  * Calculate total on-disk size of all indexes attached to the given table.
447  *
448  * Can be applied safely to an index, but you'll just get zero.
449  */
450 static int64
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 }
484 
485 Datum
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 }
503 
504 Datum
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 }
522 
523 /*
524  * Compute the on-disk size of all files for the relation,
525  * including heap data, index data, toast data, FSM, VM.
526  */
527 static int64
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 }
545 
546 Datum
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 }
564 
565 /*
566  * formatting with size units
567  */
568 Datum
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 }
605 
606 static char *
608 {
609  Datum d = NumericGetDatum(n);
610 
612 }
613 
614 static bool
616 {
617  Datum da = NumericGetDatum(a);
618  Datum db = NumericGetDatum(b);
619 
621 }
622 
623 static Numeric
625 {
626  Datum d = NumericGetDatum(n);
627  Datum result;
628 
629  result = DirectFunctionCall1(numeric_abs, d);
630  return DatumGetNumeric(result);
631 }
632 
633 static Numeric
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 }
654 
655 static Numeric
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 }
666 
667 Datum
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 }
704 
705 /*
706  * Convert a human-readable size to a size in bytes
707  */
708 Datum
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 }
859 
860 /*
861  * Get the filenode of a relation
862  *
863  * This is expected to be used in queries like
864  * SELECT pg_relation_filenode(oid) FROM pg_class;
865  * That leads to a couple of choices. We work from the pg_class row alone
866  * rather than actually opening each relation, for efficiency. We don't
867  * fail if we can't find the relation --- some rows might be visible in
868  * the query's MVCC snapshot even though the relations have been dropped.
869  * (Note: we could avoid using the catcache, but there's little point
870  * because the relation mapper also works "in the now".) We also don't
871  * fail if the relation doesn't have storage. In all these cases it
872  * seems better to quietly return NULL.
873  */
874 Datum
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 }
908 
909 /*
910  * Get the relation via (reltablespace, relfilenumber)
911  *
912  * This is expected to be used when somebody wants to match an individual file
913  * on the filesystem back to its table. That's not trivially possible via
914  * pg_class, because that doesn't contain the relfilenumbers of shared and nailed
915  * tables.
916  *
917  * We don't fail but return NULL if we cannot find a mapping.
918  *
919  * InvalidOid can be passed instead of the current database's default
920  * tablespace.
921  */
922 Datum
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 }
940 
941 /*
942  * Get the pathname (relative to $PGDATA) of a relation
943  *
944  * See comments for pg_relation_filenode.
945  */
946 Datum
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 }
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:2702
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3890
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1472
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1426
Datum numeric_sub(PG_FUNCTION_ARGS)
Definition: numeric.c:2925
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4283
Datum numeric_int8(PG_FUNCTION_ARGS)
Definition: numeric.c:4535
Datum numeric_ge(PG_FUNCTION_ARGS)
Definition: numeric.c:2460
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:807
Datum numeric_div_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:3259
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:628
Datum numeric_lt(PG_FUNCTION_ARGS)
Definition: numeric.c:2475
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2848
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1384
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3003
#define NameStr(name)
Definition: c.h:746
unsigned int uint32
Definition: c.h:506
#define INT64_FORMAT
Definition: c.h:548
#define Assert(condition)
Definition: c.h:858
unsigned char uint8
Definition: c.h:504
#define OidIsValid(objectId)
Definition: c.h:775
#define i64abs(i)
Definition: c.h:1307
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3154
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3107
static int64 calculate_total_relation_size(Relation rel)
Definition: dbsize.c:528
static bool numeric_is_less(Numeric a, Numeric b)
Definition: dbsize.c:615
Datum pg_indexes_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:505
Datum pg_size_bytes(PG_FUNCTION_ARGS)
Definition: dbsize.c:709
static Numeric numeric_truncated_divide(Numeric n, int64 divisor)
Definition: dbsize.c:656
static const struct size_bytes_unit_alias size_bytes_aliases[]
Definition: dbsize.c:67
Datum pg_database_size_oid(PG_FUNCTION_ARGS)
Definition: dbsize.c:168
static char * numeric_to_cstring(Numeric n)
Definition: dbsize.c:607
Datum pg_total_relation_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:547
Datum pg_tablespace_size_name(PG_FUNCTION_ARGS)
Definition: dbsize.c:286
static int64 calculate_tablespace_size(Oid tblspcOid)
Definition: dbsize.c:202
Datum pg_size_pretty_numeric(PG_FUNCTION_ARGS)
Definition: dbsize.c:668
Datum pg_relation_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:346
static int64 calculate_indexes_size(Relation rel)
Definition: dbsize.c:451
static int64 db_dir_size(const char *path)
Definition: dbsize.c:74
Datum pg_database_size_name(PG_FUNCTION_ARGS)
Definition: dbsize.c:182
static Numeric numeric_absolute(Numeric n)
Definition: dbsize.c:624
#define half_rounded(x)
Definition: dbsize.c:35
Datum pg_size_pretty(PG_FUNCTION_ARGS)
Definition: dbsize.c:569
static int64 calculate_database_size(Oid dbOid)
Definition: dbsize.c:118
Datum pg_table_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:486
Datum pg_tablespace_size_oid(PG_FUNCTION_ARGS)
Definition: dbsize.c:272
static Numeric numeric_half_rounded(Numeric n)
Definition: dbsize.c:634
Datum pg_relation_filenode(PG_FUNCTION_ARGS)
Definition: dbsize.c:875
Datum pg_filenode_relation(PG_FUNCTION_ARGS)
Definition: dbsize.c:923
static const struct size_pretty_unit size_pretty_units[]
Definition: dbsize.c:49
static int64 calculate_relation_size(RelFileLocator *rfn, ProcNumber backend, ForkNumber forknum)
Definition: dbsize.c:308
Datum pg_relation_filepath(PG_FUNCTION_ARGS)
Definition: dbsize.c:947
static int64 calculate_toast_table_size(Oid toastrelid)
Definition: dbsize.c:378
static int64 calculate_table_size(Relation rel)
Definition: dbsize.c:424
int errcode_for_file_access(void)
Definition: elog.c:880
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:857
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
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 PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
Oid MyDatabaseTableSpace
Definition: globals.c:93
Oid MyDatabaseId
Definition: globals.c:91
const char * str
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
int b
Definition: isn.c:70
int a
Definition: isn.c:69
void list_free(List *list)
Definition: list.c:1546
#define AccessShareLock
Definition: lockdefs.h:36
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid GetUserId(void)
Definition: miscinit.c:514
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3658
ProcNumber GetTempNamespaceProcNumber(Oid namespaceId)
Definition: namespace.c:3751
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:61
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:78
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:73
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2303
@ OBJECT_DATABASE
Definition: parsenodes.h:2270
#define ACL_CONNECT
Definition: parsenodes.h:87
#define ACL_CREATE
Definition: parsenodes.h:85
void * arg
FormData_pg_class * Form_pg_class
Definition: pg_class.h:153
#define MAXPGPATH
static char * filename
Definition: pg_dumpall.c:119
#define lfirst_oid(lc)
Definition: pg_list.h:174
static char * buf
Definition: pg_test_fsync.c:73
const char * dbName
Definition: pgbench.c:297
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
#define snprintf
Definition: port.h:238
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:385
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
#define ProcNumberForTempRelations()
Definition: proc.h:320
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
int ProcNumber
Definition: procnumber.h:24
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4760
Oid RelidByRelfilenumber(Oid reltablespace, RelFileNumber relfilenumber)
RelFileNumber RelationMapOidToFilenumber(Oid relationId, bool shared)
Definition: relmapper.c:165
ForkNumber forkname_to_number(const char *forkName)
Definition: relpath.c:50
Oid RelFileNumber
Definition: relpath.h:25
ForkNumber
Definition: relpath.h:48
@ MAIN_FORKNUM
Definition: relpath.h:50
#define MAX_FORKNUM
Definition: relpath.h:62
#define InvalidRelFileNumber
Definition: relpath.h:26
#define relpathbackend(rlocator, backend, forknum)
Definition: relpath.h:85
#define TABLESPACE_VERSION_DIRECTORY
Definition: relpath.h:33
#define RelFileNumberIsValid(relnumber)
Definition: relpath.h:27
static pg_noinline void Size size
Definition: slab.c:607
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation try_relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:88
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
Definition: dirent.c:26
Definition: pg_list.h:54
RelFileNumber relNumber
ProcNumber rd_backend
Definition: rel.h:60
RelFileLocator rd_locator
Definition: rel.h:57
Form_pg_class rd_rel
Definition: rel.h:111
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15
Definition: c.h:741
const char * alias
Definition: dbsize.c:62
const char * name
Definition: dbsize.c:40
uint8 unitbits
Definition: dbsize.c:44
uint32 limit
Definition: dbsize.c:41
__int64 st_size
Definition: win32_port.h:273
unsigned short st_mode
Definition: win32_port.h:268
Definition: c.h:687
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:266
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:218
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
char * text_to_cstring(const text *t)
Definition: varlena.c:217
text * cstring_to_text(const char *s)
Definition: varlena.c:184
const char * name
#define stat
Definition: win32_port.h:284
#define S_ISDIR(m)
Definition: win32_port.h:325