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-2025, 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"
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"
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 */
49static 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 */
68 {"B", 0},
69 {NULL}
70};
71
72/* Return physical size of directory contents, or 0 if dir doesn't exist */
73static int64
74db_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
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 */
117static 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 {
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 */
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), "%s/%s/%s/%u",
159 totalsize += db_dir_size(pathname);
160 }
161
162 FreeDir(dirdesc);
163
164 return totalsize;
165}
166
167Datum
169{
170 Oid dbOid = PG_GETARG_OID(0);
171 int64 size;
172
173 /*
174 * Not needed for correctness, but avoid non-user-facing error message
175 * later if the database doesn't exist.
176 */
177 if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(dbOid)))
179 errcode(ERRCODE_UNDEFINED_OBJECT),
180 errmsg("database with OID %u does not exist", dbOid));
181
183
184 if (size == 0)
186
188}
189
190Datum
192{
194 Oid dbOid = get_database_oid(NameStr(*dbName), false);
195 int64 size;
196
198
199 if (size == 0)
201
203}
204
205
206/*
207 * Calculate total size of tablespace. Returns -1 if the tablespace directory
208 * cannot be found.
209 */
210static int64
212{
213 char tblspcPath[MAXPGPATH];
214 char pathname[MAXPGPATH * 2];
215 int64 totalsize = 0;
216 DIR *dirdesc;
217 struct dirent *direntry;
218 AclResult aclresult;
219
220 /*
221 * User must have privileges of pg_read_all_stats or have CREATE privilege
222 * for target tablespace, either explicitly granted or implicitly because
223 * it is default for current database.
224 */
225 if (tblspcOid != MyDatabaseTableSpace &&
226 !has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
227 {
228 aclresult = object_aclcheck(TableSpaceRelationId, tblspcOid, GetUserId(), ACL_CREATE);
229 if (aclresult != ACLCHECK_OK)
231 get_tablespace_name(tblspcOid));
232 }
233
234 if (tblspcOid == DEFAULTTABLESPACE_OID)
235 snprintf(tblspcPath, MAXPGPATH, "base");
236 else if (tblspcOid == GLOBALTABLESPACE_OID)
237 snprintf(tblspcPath, MAXPGPATH, "global");
238 else
239 snprintf(tblspcPath, MAXPGPATH, "%s/%u/%s", PG_TBLSPC_DIR, tblspcOid,
241
242 dirdesc = AllocateDir(tblspcPath);
243
244 if (!dirdesc)
245 return -1;
246
247 while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL)
248 {
249 struct stat fst;
250
252
253 if (strcmp(direntry->d_name, ".") == 0 ||
254 strcmp(direntry->d_name, "..") == 0)
255 continue;
256
257 snprintf(pathname, sizeof(pathname), "%s/%s", tblspcPath, direntry->d_name);
258
259 if (stat(pathname, &fst) < 0)
260 {
261 if (errno == ENOENT)
262 continue;
263 else
266 errmsg("could not stat file \"%s\": %m", pathname)));
267 }
268
269 if (S_ISDIR(fst.st_mode))
270 totalsize += db_dir_size(pathname);
271
272 totalsize += fst.st_size;
273 }
274
275 FreeDir(dirdesc);
276
277 return totalsize;
278}
279
280Datum
282{
283 Oid tblspcOid = PG_GETARG_OID(0);
284 int64 size;
285
286 /*
287 * Not needed for correctness, but avoid non-user-facing error message
288 * later if the tablespace doesn't exist.
289 */
290 if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tblspcOid)))
292 errcode(ERRCODE_UNDEFINED_OBJECT),
293 errmsg("tablespace with OID %u does not exist", tblspcOid));
294
295 size = calculate_tablespace_size(tblspcOid);
296
297 if (size < 0)
299
301}
302
303Datum
305{
306 Name tblspcName = PG_GETARG_NAME(0);
307 Oid tblspcOid = get_tablespace_oid(NameStr(*tblspcName), false);
308 int64 size;
309
310 size = calculate_tablespace_size(tblspcOid);
311
312 if (size < 0)
314
316}
317
318
319/*
320 * calculate size of (one fork of) a relation
321 *
322 * Note: we can safely apply this to temp tables of other sessions, so there
323 * is no check here or at the call sites for that.
324 */
325static int64
327{
328 int64 totalsize = 0;
329 char *relationpath;
330 char pathname[MAXPGPATH];
331 unsigned int segcount = 0;
332
333 relationpath = relpathbackend(*rfn, backend, forknum);
334
335 for (segcount = 0;; segcount++)
336 {
337 struct stat fst;
338
340
341 if (segcount == 0)
342 snprintf(pathname, MAXPGPATH, "%s",
343 relationpath);
344 else
345 snprintf(pathname, MAXPGPATH, "%s.%u",
346 relationpath, segcount);
347
348 if (stat(pathname, &fst) < 0)
349 {
350 if (errno == ENOENT)
351 break;
352 else
355 errmsg("could not stat file \"%s\": %m", pathname)));
356 }
357 totalsize += fst.st_size;
358 }
359
360 return totalsize;
361}
362
363Datum
365{
366 Oid relOid = PG_GETARG_OID(0);
367 text *forkName = PG_GETARG_TEXT_PP(1);
368 Relation rel;
369 int64 size;
370
371 rel = try_relation_open(relOid, AccessShareLock);
372
373 /*
374 * Before 9.2, we used to throw an error if the relation didn't exist, but
375 * that makes queries like "SELECT pg_relation_size(oid) FROM pg_class"
376 * less robust, because while we scan pg_class with an MVCC snapshot,
377 * someone else might drop the table. It's better to return NULL for
378 * already-dropped tables than throw an error and abort the whole query.
379 */
380 if (rel == NULL)
382
385
387
389}
390
391/*
392 * Calculate total on-disk size of a TOAST relation, including its indexes.
393 * Must not be applied to non-TOAST relations.
394 */
395static int64
397{
398 int64 size = 0;
399 Relation toastRel;
400 ForkNumber forkNum;
401 ListCell *lc;
402 List *indexlist;
403
404 toastRel = relation_open(toastrelid, AccessShareLock);
405
406 /* toast heap size, including FSM and VM size */
407 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
409 toastRel->rd_backend, forkNum);
410
411 /* toast index size, including FSM and VM size */
412 indexlist = RelationGetIndexList(toastRel);
413
414 /* Size is calculated using all the indexes available */
415 foreach(lc, indexlist)
416 {
417 Relation toastIdxRel;
418
419 toastIdxRel = relation_open(lfirst_oid(lc),
421 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
422 size += calculate_relation_size(&(toastIdxRel->rd_locator),
423 toastIdxRel->rd_backend, forkNum);
424
425 relation_close(toastIdxRel, AccessShareLock);
426 }
427 list_free(indexlist);
429
430 return size;
431}
432
433/*
434 * Calculate total on-disk size of a given table,
435 * including FSM and VM, plus TOAST table if any.
436 * Indexes other than the TOAST table's index are not included.
437 *
438 * Note that this also behaves sanely if applied to an index or toast table;
439 * those won't have attached toast tables, but they can have multiple forks.
440 */
441static int64
443{
444 int64 size = 0;
445 ForkNumber forkNum;
446
447 /*
448 * heap size, including FSM and VM
449 */
450 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
452 forkNum);
453
454 /*
455 * Size of toast relation
456 */
457 if (OidIsValid(rel->rd_rel->reltoastrelid))
458 size += calculate_toast_table_size(rel->rd_rel->reltoastrelid);
459
460 return size;
461}
462
463/*
464 * Calculate total on-disk size of all indexes attached to the given table.
465 *
466 * Can be applied safely to an index, but you'll just get zero.
467 */
468static int64
470{
471 int64 size = 0;
472
473 /*
474 * Aggregate all indexes on the given relation
475 */
476 if (rel->rd_rel->relhasindex)
477 {
478 List *index_oids = RelationGetIndexList(rel);
479 ListCell *cell;
480
481 foreach(cell, index_oids)
482 {
483 Oid idxOid = lfirst_oid(cell);
484 Relation idxRel;
485 ForkNumber forkNum;
486
487 idxRel = relation_open(idxOid, AccessShareLock);
488
489 for (forkNum = 0; forkNum <= MAX_FORKNUM; forkNum++)
491 idxRel->rd_backend,
492 forkNum);
493
495 }
496
497 list_free(index_oids);
498 }
499
500 return size;
501}
502
503Datum
505{
506 Oid relOid = PG_GETARG_OID(0);
507 Relation rel;
508 int64 size;
509
510 rel = try_relation_open(relOid, AccessShareLock);
511
512 if (rel == NULL)
514
516
518
520}
521
522Datum
524{
525 Oid relOid = PG_GETARG_OID(0);
526 Relation rel;
527 int64 size;
528
529 rel = try_relation_open(relOid, AccessShareLock);
530
531 if (rel == NULL)
533
535
537
539}
540
541/*
542 * Compute the on-disk size of all files for the relation,
543 * including heap data, index data, toast data, FSM, VM.
544 */
545static int64
547{
548 int64 size;
549
550 /*
551 * Aggregate the table size, this includes size of the heap, toast and
552 * toast index with free space and visibility map
553 */
555
556 /*
557 * Add size of all attached indexes as well
558 */
560
561 return size;
562}
563
564Datum
566{
567 Oid relOid = PG_GETARG_OID(0);
568 Relation rel;
569 int64 size;
570
571 rel = try_relation_open(relOid, AccessShareLock);
572
573 if (rel == NULL)
575
577
579
581}
582
583/*
584 * formatting with size units
585 */
586Datum
588{
590 char buf[64];
591 const struct size_pretty_unit *unit;
592
593 for (unit = size_pretty_units; unit->name != NULL; unit++)
594 {
595 uint8 bits;
596 uint64 abs_size = size < 0 ? 0 - (uint64) size : (uint64) size;
597
598 /*
599 * Use this unit if there are no more units or the absolute size is
600 * below the limit for the current unit.
601 */
602 if (unit[1].name == NULL || abs_size < unit->limit)
603 {
604 if (unit->round)
606
607 snprintf(buf, sizeof(buf), INT64_FORMAT " %s", size, unit->name);
608 break;
609 }
610
611 /*
612 * Determine the number of bits to use to build the divisor. We may
613 * need to use 1 bit less than the difference between this and the
614 * next unit if the next unit uses half rounding. Or we may need to
615 * shift an extra bit if this unit uses half rounding and the next one
616 * does not. We use division rather than shifting right by this
617 * number of bits to ensure positive and negative values are rounded
618 * in the same way.
619 */
620 bits = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
621 + (unit->round == true));
622 size /= ((int64) 1) << bits;
623 }
624
626}
627
628static char *
630{
631 Datum d = NumericGetDatum(n);
632
634}
635
636static bool
638{
639 Datum da = NumericGetDatum(a);
640 Datum db = NumericGetDatum(b);
641
643}
644
645static Numeric
647{
648 Datum d = NumericGetDatum(n);
649 Datum result;
650
651 result = DirectFunctionCall1(numeric_abs, d);
652 return DatumGetNumeric(result);
653}
654
655static Numeric
657{
658 Datum d = NumericGetDatum(n);
659 Datum zero;
660 Datum one;
661 Datum two;
662 Datum result;
663
667
669 d = DirectFunctionCall2(numeric_add, d, one);
670 else
671 d = DirectFunctionCall2(numeric_sub, d, one);
672
673 result = DirectFunctionCall2(numeric_div_trunc, d, two);
674 return DatumGetNumeric(result);
675}
676
677static Numeric
679{
680 Datum d = NumericGetDatum(n);
681 Datum divisor_numeric;
682 Datum result;
683
684 divisor_numeric = NumericGetDatum(int64_to_numeric(divisor));
685 result = DirectFunctionCall2(numeric_div_trunc, d, divisor_numeric);
686 return DatumGetNumeric(result);
687}
688
689Datum
691{
693 char *result = NULL;
694 const struct size_pretty_unit *unit;
695
696 for (unit = size_pretty_units; unit->name != NULL; unit++)
697 {
698 unsigned int shiftby;
699
700 /* use this unit if there are no more units or we're below the limit */
701 if (unit[1].name == NULL ||
703 int64_to_numeric(unit->limit)))
704 {
705 if (unit->round)
707
708 result = psprintf("%s %s", numeric_to_cstring(size), unit->name);
709 break;
710 }
711
712 /*
713 * Determine the number of bits to use to build the divisor. We may
714 * need to use 1 bit less than the difference between this and the
715 * next unit if the next unit uses half rounding. Or we may need to
716 * shift an extra bit if this unit uses half rounding and the next one
717 * does not.
718 */
719 shiftby = (unit[1].unitbits - unit->unitbits - (unit[1].round == true)
720 + (unit->round == true));
721 size = numeric_truncated_divide(size, ((int64) 1) << shiftby);
722 }
723
725}
726
727/*
728 * Convert a human-readable size to a size in bytes
729 */
730Datum
732{
734 char *str,
735 *strptr,
736 *endptr;
737 char saved_char;
738 Numeric num;
739 int64 result;
740 bool have_digits = false;
741
743
744 /* Skip leading whitespace */
745 strptr = str;
746 while (isspace((unsigned char) *strptr))
747 strptr++;
748
749 /* Check that we have a valid number and determine where it ends */
750 endptr = strptr;
751
752 /* Part (1): sign */
753 if (*endptr == '-' || *endptr == '+')
754 endptr++;
755
756 /* Part (2): main digit string */
757 if (isdigit((unsigned char) *endptr))
758 {
759 have_digits = true;
760 do
761 endptr++;
762 while (isdigit((unsigned char) *endptr));
763 }
764
765 /* Part (3): optional decimal point and fractional digits */
766 if (*endptr == '.')
767 {
768 endptr++;
769 if (isdigit((unsigned char) *endptr))
770 {
771 have_digits = true;
772 do
773 endptr++;
774 while (isdigit((unsigned char) *endptr));
775 }
776 }
777
778 /* Complain if we don't have a valid number at this point */
779 if (!have_digits)
781 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
782 errmsg("invalid size: \"%s\"", str)));
783
784 /* Part (4): optional exponent */
785 if (*endptr == 'e' || *endptr == 'E')
786 {
787 long exponent;
788 char *cp;
789
790 /*
791 * Note we might one day support EB units, so if what follows 'E'
792 * isn't a number, just treat it all as a unit to be parsed.
793 */
794 exponent = strtol(endptr + 1, &cp, 10);
795 (void) exponent; /* Silence -Wunused-result warnings */
796 if (cp > endptr + 1)
797 endptr = cp;
798 }
799
800 /*
801 * Parse the number, saving the next character, which may be the first
802 * character of the unit string.
803 */
804 saved_char = *endptr;
805 *endptr = '\0';
806
808 CStringGetDatum(strptr),
810 Int32GetDatum(-1)));
811
812 *endptr = saved_char;
813
814 /* Skip whitespace between number and unit */
815 strptr = endptr;
816 while (isspace((unsigned char) *strptr))
817 strptr++;
818
819 /* Handle possible unit */
820 if (*strptr != '\0')
821 {
822 const struct size_pretty_unit *unit;
823 int64 multiplier = 0;
824
825 /* Trim any trailing whitespace */
826 endptr = str + VARSIZE_ANY_EXHDR(arg) - 1;
827
828 while (isspace((unsigned char) *endptr))
829 endptr--;
830
831 endptr++;
832 *endptr = '\0';
833
834 for (unit = size_pretty_units; unit->name != NULL; unit++)
835 {
836 /* Parse the unit case-insensitively */
837 if (pg_strcasecmp(strptr, unit->name) == 0)
838 break;
839 }
840
841 /* If not found, look in table of aliases */
842 if (unit->name == NULL)
843 {
844 for (const struct size_bytes_unit_alias *a = size_bytes_aliases; a->alias != NULL; a++)
845 {
846 if (pg_strcasecmp(strptr, a->alias) == 0)
847 {
848 unit = &size_pretty_units[a->unit_index];
849 break;
850 }
851 }
852 }
853
854 /* Verify we found a valid unit in the loop above */
855 if (unit->name == NULL)
857 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
858 errmsg("invalid size: \"%s\"", text_to_cstring(arg)),
859 errdetail("Invalid size unit: \"%s\".", strptr),
860 errhint("Valid units are \"bytes\", \"B\", \"kB\", \"MB\", \"GB\", \"TB\", and \"PB\".")));
861
862 multiplier = ((int64) 1) << unit->unitbits;
863
864 if (multiplier > 1)
865 {
866 Numeric mul_num;
867
868 mul_num = int64_to_numeric(multiplier);
869
871 NumericGetDatum(mul_num),
872 NumericGetDatum(num)));
873 }
874 }
875
877 NumericGetDatum(num)));
878
879 PG_RETURN_INT64(result);
880}
881
882/*
883 * Get the filenode of a relation
884 *
885 * This is expected to be used in queries like
886 * SELECT pg_relation_filenode(oid) FROM pg_class;
887 * That leads to a couple of choices. We work from the pg_class row alone
888 * rather than actually opening each relation, for efficiency. We don't
889 * fail if we can't find the relation --- some rows might be visible in
890 * the query's MVCC snapshot even though the relations have been dropped.
891 * (Note: we could avoid using the catcache, but there's little point
892 * because the relation mapper also works "in the now".) We also don't
893 * fail if the relation doesn't have storage. In all these cases it
894 * seems better to quietly return NULL.
895 */
896Datum
898{
899 Oid relid = PG_GETARG_OID(0);
900 RelFileNumber result;
901 HeapTuple tuple;
902 Form_pg_class relform;
903
904 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
905 if (!HeapTupleIsValid(tuple))
907 relform = (Form_pg_class) GETSTRUCT(tuple);
908
909 if (RELKIND_HAS_STORAGE(relform->relkind))
910 {
911 if (relform->relfilenode)
912 result = relform->relfilenode;
913 else /* Consult the relation mapper */
914 result = RelationMapOidToFilenumber(relid,
915 relform->relisshared);
916 }
917 else
918 {
919 /* no storage, return NULL */
920 result = InvalidRelFileNumber;
921 }
922
923 ReleaseSysCache(tuple);
924
925 if (!RelFileNumberIsValid(result))
927
928 PG_RETURN_OID(result);
929}
930
931/*
932 * Get the relation via (reltablespace, relfilenumber)
933 *
934 * This is expected to be used when somebody wants to match an individual file
935 * on the filesystem back to its table. That's not trivially possible via
936 * pg_class, because that doesn't contain the relfilenumbers of shared and nailed
937 * tables.
938 *
939 * We don't fail but return NULL if we cannot find a mapping.
940 *
941 * InvalidOid can be passed instead of the current database's default
942 * tablespace.
943 */
944Datum
946{
947 Oid reltablespace = PG_GETARG_OID(0);
948 RelFileNumber relfilenumber = PG_GETARG_OID(1);
949 Oid heaprel;
950
951 /* test needed so RelidByRelfilenumber doesn't misbehave */
952 if (!RelFileNumberIsValid(relfilenumber))
954
955 heaprel = RelidByRelfilenumber(reltablespace, relfilenumber);
956
957 if (!OidIsValid(heaprel))
959 else
960 PG_RETURN_OID(heaprel);
961}
962
963/*
964 * Get the pathname (relative to $PGDATA) of a relation
965 *
966 * See comments for pg_relation_filenode.
967 */
968Datum
970{
971 Oid relid = PG_GETARG_OID(0);
972 HeapTuple tuple;
973 Form_pg_class relform;
974 RelFileLocator rlocator;
975 ProcNumber backend;
976 char *path;
977
978 tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
979 if (!HeapTupleIsValid(tuple))
981 relform = (Form_pg_class) GETSTRUCT(tuple);
982
983 if (RELKIND_HAS_STORAGE(relform->relkind))
984 {
985 /* This logic should match RelationInitPhysicalAddr */
986 if (relform->reltablespace)
987 rlocator.spcOid = relform->reltablespace;
988 else
989 rlocator.spcOid = MyDatabaseTableSpace;
990 if (rlocator.spcOid == GLOBALTABLESPACE_OID)
991 rlocator.dbOid = InvalidOid;
992 else
993 rlocator.dbOid = MyDatabaseId;
994 if (relform->relfilenode)
995 rlocator.relNumber = relform->relfilenode;
996 else /* Consult the relation mapper */
997 rlocator.relNumber = RelationMapOidToFilenumber(relid,
998 relform->relisshared);
999 }
1000 else
1001 {
1002 /* no storage, return NULL */
1004 /* some compilers generate warnings without these next two lines */
1005 rlocator.dbOid = InvalidOid;
1006 rlocator.spcOid = InvalidOid;
1007 }
1008
1009 if (!RelFileNumberIsValid(rlocator.relNumber))
1010 {
1011 ReleaseSysCache(tuple);
1013 }
1014
1015 /* Determine owning backend. */
1016 switch (relform->relpersistence)
1017 {
1018 case RELPERSISTENCE_UNLOGGED:
1019 case RELPERSISTENCE_PERMANENT:
1020 backend = INVALID_PROC_NUMBER;
1021 break;
1022 case RELPERSISTENCE_TEMP:
1023 if (isTempOrTempToastNamespace(relform->relnamespace))
1024 backend = ProcNumberForTempRelations();
1025 else
1026 {
1027 /* Do it the hard way. */
1028 backend = GetTempNamespaceProcNumber(relform->relnamespace);
1029 Assert(backend != INVALID_PROC_NUMBER);
1030 }
1031 break;
1032 default:
1033 elog(ERROR, "invalid relpersistence: %c", relform->relpersistence);
1034 backend = INVALID_PROC_NUMBER; /* placate compiler */
1035 break;
1036 }
1037
1038 ReleaseSysCache(tuple);
1039
1040 path = relpathbackend(rlocator, backend, MAIN_FORKNUM);
1041
1043}
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3804
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:3043
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4401
Datum numeric_int8(PG_FUNCTION_ARGS)
Definition: numeric.c:4653
Datum numeric_ge(PG_FUNCTION_ARGS)
Definition: numeric.c:2578
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:816
Datum numeric_div_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:3377
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:637
Datum numeric_lt(PG_FUNCTION_ARGS)
Definition: numeric.c:2593
Datum numeric_add(PG_FUNCTION_ARGS)
Definition: numeric.c:2966
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1393
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3121
#define NameStr(name)
Definition: c.h:703
uint8_t uint8
Definition: c.h:486
#define INT64_FORMAT
Definition: c.h:506
#define Assert(condition)
Definition: c.h:815
int64_t int64
Definition: c.h:485
uint64_t uint64
Definition: c.h:489
uint32_t uint32
Definition: c.h:488
#define OidIsValid(objectId)
Definition: c.h:732
Oid get_database_oid(const char *dbname, bool missing_ok)
Definition: dbcommands.c:3140
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3187
static int64 calculate_total_relation_size(Relation rel)
Definition: dbsize.c:546
static char * numeric_to_cstring(Numeric n)
Definition: dbsize.c:629
static bool numeric_is_less(Numeric a, Numeric b)
Definition: dbsize.c:637
Datum pg_indexes_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:523
Datum pg_size_bytes(PG_FUNCTION_ARGS)
Definition: dbsize.c:731
static Numeric numeric_truncated_divide(Numeric n, int64 divisor)
Definition: dbsize.c:678
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
Datum pg_total_relation_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:565
Datum pg_tablespace_size_name(PG_FUNCTION_ARGS)
Definition: dbsize.c:304
static int64 calculate_tablespace_size(Oid tblspcOid)
Definition: dbsize.c:211
Datum pg_size_pretty_numeric(PG_FUNCTION_ARGS)
Definition: dbsize.c:690
Datum pg_relation_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:364
static int64 calculate_indexes_size(Relation rel)
Definition: dbsize.c:469
static int64 db_dir_size(const char *path)
Definition: dbsize.c:74
Datum pg_database_size_name(PG_FUNCTION_ARGS)
Definition: dbsize.c:191
static Numeric numeric_absolute(Numeric n)
Definition: dbsize.c:646
#define half_rounded(x)
Definition: dbsize.c:35
Datum pg_size_pretty(PG_FUNCTION_ARGS)
Definition: dbsize.c:587
static int64 calculate_database_size(Oid dbOid)
Definition: dbsize.c:118
Datum pg_table_size(PG_FUNCTION_ARGS)
Definition: dbsize.c:504
Datum pg_tablespace_size_oid(PG_FUNCTION_ARGS)
Definition: dbsize.c:281
static Numeric numeric_half_rounded(Numeric n)
Definition: dbsize.c:656
Datum pg_relation_filenode(PG_FUNCTION_ARGS)
Definition: dbsize.c:897
Datum pg_filenode_relation(PG_FUNCTION_ARGS)
Definition: dbsize.c:945
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:326
Datum pg_relation_filepath(PG_FUNCTION_ARGS)
Definition: dbsize.c:969
static int64 calculate_toast_table_size(Oid toastrelid)
Definition: dbsize.c:396
static int64 calculate_table_size(Relation rel)
Definition: dbsize.c:442
int errcode_for_file_access(void)
Definition: elog.c:876
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:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
int FreeDir(DIR *dir)
Definition: fd.c:2983
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2931
#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:643
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
#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:645
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
Oid MyDatabaseTableSpace
Definition: globals.c:95
Oid MyDatabaseId
Definition: globals.c:93
const char * str
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:653
int b
Definition: isn.c:69
int a
Definition: isn.c:68
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:517
bool isTempOrTempToastNamespace(Oid namespaceId)
Definition: namespace.c:3673
ProcNumber GetTempNamespaceProcNumber(Oid namespaceId)
Definition: namespace.c:3766
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:2354
@ OBJECT_DATABASE
Definition: parsenodes.h:2321
#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:72
static 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:95
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:390
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static char * DatumGetCString(Datum X)
Definition: postgres.h:340
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
int ProcNumber
Definition: procnumber.h:24
#define ProcNumberForTempRelations()
Definition: procnumber.h:40
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
List * RelationGetIndexList(Relation relation)
Definition: relcache.c:4756
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:56
@ MAIN_FORKNUM
Definition: relpath.h:58
#define MAX_FORKNUM
Definition: relpath.h:70
#define InvalidRelFileNumber
Definition: relpath.h:26
#define relpathbackend(rlocator, backend, forknum)
Definition: relpath.h:93
#define PG_TBLSPC_DIR
Definition: relpath.h:41
#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:698
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:263
unsigned short st_mode
Definition: win32_port.h:258
Definition: c.h:644
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
text * cstring_to_text(const char *s)
Definition: varlena.c:184
char * text_to_cstring(const text *t)
Definition: varlena.c:217
const char * name
#define stat
Definition: win32_port.h:274
#define S_ISDIR(m)
Definition: win32_port.h:315