]> granicus.if.org Git - postgresql/blob - contrib/dbsize/dbsize.c
dbsize modification to support tablespaces
[postgresql] / contrib / dbsize / dbsize.c
1 #include "postgres.h"
2
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6
7 #include "access/heapam.h"
8 #include "catalog/catalog.h"
9 #include "catalog/catname.h"
10 #include "catalog/namespace.h"
11 #include "catalog/pg_tablespace.h"
12 #include "commands/dbcommands.h"
13 #include "fmgr.h"
14 #include "storage/fd.h"
15 #include "utils/builtins.h"
16
17
18 static int64
19 get_tablespace_size(Oid dbid, Oid spcid, bool baddirOK);
20
21 static char *
22 psnprintf(size_t len, const char *fmt,...)
23 {
24         va_list         ap;
25         char       *buf;
26
27         buf = palloc(len);
28
29         va_start(ap, fmt);
30         vsnprintf(buf, len, fmt, ap);
31         va_end(ap);
32
33         return buf;
34 }
35
36
37
38 /*
39  * SQL function: database_size(name) returns bigint
40  */
41
42 PG_FUNCTION_INFO_V1(database_size);
43
44 Datum           database_size(PG_FUNCTION_ARGS);
45
46 Datum
47 database_size(PG_FUNCTION_ARGS)
48 {
49         Name            dbname = PG_GETARG_NAME(0);
50
51         Oid                     dbid;
52         int64           totalsize;
53 #ifdef SYMLINK
54         Relation                dbrel;
55         HeapScanDesc    scan;
56         HeapTuple               tuple;
57 #endif
58
59         dbid = get_database_oid(NameStr(*dbname));
60         if (!OidIsValid(dbid))
61                 ereport(ERROR,
62                                 (errcode(ERRCODE_UNDEFINED_DATABASE),
63                         errmsg("database \"%s\" does not exist", NameStr(*dbname))));
64
65 #ifdef SYMLINK 
66
67         dbrel = heap_openr(TableSpaceRelationName, AccessShareLock);    
68         scan = heap_beginscan(dbrel, SnapshotNow, 0, (ScanKey) NULL);
69
70         totalsize = 0;
71
72         while((tuple = heap_getnext(scan, ForwardScanDirection)))
73         {
74                 Oid spcid = HeapTupleGetOid(tuple);
75                 if(spcid != GLOBALTABLESPACE_OID)
76                         totalsize += get_tablespace_size(dbid, spcid, true);
77         }
78         heap_endscan(scan);
79         heap_close(dbrel, AccessShareLock);
80 #else
81         /* Same as always */
82         totalsize = get_tablespace_size(dbid, DEFAULTTABLESPACE_OID, false);
83 #endif
84
85         /*
86          * We need to keep in mind that we may not be called from the database
87          * whose size we're reporting so, we need to look in every tablespace
88          * to see if our database has data in there
89          */
90
91         PG_RETURN_INT64(totalsize);
92 }
93
94 static int64
95 get_tablespace_size(Oid dbid, Oid spcid, bool baddirOK)
96 {
97         char            *dbpath;
98         DIR                     *dirdesc;
99         struct dirent *direntry;
100         int64           totalsize;
101
102         dbpath = GetDatabasePath(dbid, spcid);
103
104         dirdesc = AllocateDir(dbpath);
105         if (!dirdesc)
106         {
107                 if(baddirOK)
108                         return 0;
109                 else
110                         ereport(ERROR,
111                                 (errcode_for_file_access(),
112                                  errmsg("could not open directory \"%s\": %m", dbpath)));
113         }
114         totalsize = 0;
115         for (;;)
116         {
117                 char       *fullname;
118                 struct stat statbuf;
119
120                 errno = 0;
121                 direntry = readdir(dirdesc);
122                 if (!direntry)
123                 {
124                         if (errno)
125                                 ereport(ERROR,
126                                                 (errcode_for_file_access(),
127                                                  errmsg("error reading directory: %m")));
128                         else
129                                 break;
130                 }
131
132                 fullname = psnprintf(strlen(dbpath) + 1 + strlen(direntry->d_name) + 1,
133                                                          "%s/%s", dbpath, direntry->d_name);
134                 if (stat(fullname, &statbuf) == -1)
135                         ereport(ERROR,
136                                         (errcode_for_file_access(),
137                                          errmsg("could not stat \"%s\": %m", fullname)));
138                 totalsize += statbuf.st_size;
139                 pfree(fullname);
140         }
141
142         FreeDir(dirdesc);
143         return (totalsize);
144 }
145
146 /*
147  * SQL function: relation_size(text) returns bigint
148  */
149
150 PG_FUNCTION_INFO_V1(relation_size);
151
152 Datum           relation_size(PG_FUNCTION_ARGS);
153
154 Datum
155 relation_size(PG_FUNCTION_ARGS)
156 {
157         text       *relname = PG_GETARG_TEXT_P(0);
158
159         RangeVar   *relrv;
160         Relation        relation;
161         Oid                     relnode;
162         int64           totalsize;
163         unsigned int segcount;
164
165         relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
166                                                                                                            "relation_size"));
167         relation = heap_openrv(relrv, AccessShareLock);
168
169         relnode = relation->rd_rel->relfilenode;
170
171         totalsize = 0;
172         segcount = 0;
173         for (;;)
174         {
175                 char       *fullname;
176                 struct stat statbuf;
177
178                 if (segcount == 0)
179                         fullname = psnprintf(25, "%u", (unsigned) relnode);
180                 else
181                         fullname = psnprintf(50, "%u.%u", (unsigned) relnode, segcount);
182
183                 if (stat(fullname, &statbuf) == -1)
184                 {
185                         if (errno == ENOENT)
186                                 break;
187                         else
188                                 ereport(ERROR,
189                                                 (errcode_for_file_access(),
190                                                  errmsg("could not stat \"%s\": %m", fullname)));
191                 }
192                 totalsize += statbuf.st_size;
193                 pfree(fullname);
194                 segcount++;
195         }
196
197         heap_close(relation, AccessShareLock);
198
199         PG_RETURN_INT64(totalsize);
200 }