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