diff --git a/contrib/oid2name/README.oid2name b/contrib/oid2name/README.oid2name index abd13987242..ea9f48b43fb 100644 --- a/contrib/oid2name/README.oid2name +++ b/contrib/oid2name/README.oid2name @@ -1,126 +1,180 @@ -This utility allows administrators to view the file structure used by -PostgreSQL. Databases are placed in directories based on their OIDs in -pg_database, and the tables in that directory are named by original -OIDs, stored in pg_class.relfilenode. Oid2name connects to the database -and extracts the OID and table name information. +This utility allows administrators to examine the file structure used by +PostgreSQL. ---------------------------------------------------------------------------- +Databases are placed in directories named after their OIDs in pg_database, +and the table files within a database's directory are named by "filenode" +numbers, which are stored in pg_class.relfilenode. -It can be used in four ways: +Note that while a table's filenode often matches its OID, this is *not* +necessarily the case; some operations, like TRUNCATE, REINDEX, CLUSTER +and some forms of ALTER TABLE, can change the filenode while preserving +the OID. Avoid assuming that filenode and table OID are the same. +When a table exceeds 1Gb, it is divided into gigabyte-sized "segments". +The first segment's file name is the same as the filenode; subsequent +segments are named filenode.1, filenode.2, etc. -oid2name +Tablespaces make the scenario more complicated. Each non-default +tablespace has a symlink inside the pg_tblspc directory, which points to +the physical tablespace directory (as specified in its CREATE TABLESPACE +command). The symlink is named after the tablespace's OID. Inside the +physical tablespace directory there is another directory for each database +that has elements in the tablespace, named after the database's OID. +Tables within that directory follow the filenode naming scheme. The +"pg_default" tablespace is not addressed via pg_tblspc, but corresponds to +$PGDATA/base. - This will connect to the template1 database and display all databases - in the system: +Oid2name connects to the database and extracts OID, filenode, and table +name information. You can also have it show database OIDs and tablespace +OIDs. - $ oid2name - All databases: - --------------------------------- - 18720 = test1 - 1 = template1 - 18719 = template0 - 18721 = test - 18735 = postgres - 18736 = cssi +When displaying specific tables, you can select which tables to show by +using -o, -f and -t. The first switch takes an OID, the second takes +a filenode, and the third takes a tablename (actually, it's a LIKE +pattern, so you can use things like "foo%"). Note that you can use as many +of these switches as you like, and the listing will include all objects +matched by any of the switches. Also note that these switches can only +show objects in the database given in -d. +If you don't give any of -o, -f or -t it will dump all the tables in the +database given in -d. If you don't give -d, it will show a database +listing. Alternatively you can give -s to get a tablespace listing. -oid2name -d test [-x] - - This connects to the database test and shows all tables and their OIDs: - - $ oid2name -d test - All tables from database "test": - --------------------------------- - 18766 = dns - 18737 = ips - 18722 = testdate - - -oid2name -d test -o 18737 -oid2name -d test -t testdate - - This will connect to the database test and display the table name for oid - 18737 and the oid for table name testdate respectively: - - $ oid2name -d test -o 18737 - Tablename of oid 18737 from database "test": - --------------------------------- - 18737 = ips - - - $ oid2name -d test -t testdate - Oid of table testdate from database "test": - --------------------------------- - 18722 = testdate - -Keep in mind tables over one gigabyte will be split into separate files -with numeric file extensions. +Additional switches: + -i include indexes and sequences in the database listing. + -x display more information about each object shown: + tablespace name, schema name, OID. + -S also show system objects + (those in information_schema, pg_toast and pg_catalog schemas) + -q don't display headers + (useful for scripting) --------------------------------------------------------------------------- Sample session: -$ cd /u/pg/data/base $ oid2name All databases: ---------------------------------- -16817 = test2 -16578 = x -16756 = test -1 = template1 -16569 = template0 -16818 = test3 -16811 = floattest + Oid Database Name Tablespace +---------------------------------- + 17228 alvherre pg_default + 17255 regression pg_default + 17227 template0 pg_default + 1 template1 pg_default -$ cd 16756 -$ ls 1873* -18730 18731 18732 18735 18736 18737 18738 18739 +$ oid2name -s +All tablespaces: + Oid Tablespace Name +------------------------- + 1663 pg_default + 1664 pg_global + 155151 fastdisk + 155152 bigdisk -$ oid2name -d test -o 18737 -Tablename of oid 18737 from database "test": ---------------------------------- -18737 = ips +$ cd $PGDATA/17228 -$ oid2name -d test -t ips -Oid of table ips from database "test": ---------------------------------- -18737 = ips +$ # get top 10 db objects in the default tablespace, ordered by size +$ ls -lS * | head -10 +-rw------- 1 alvherre alvherre 136536064 sep 14 09:51 155173 +-rw------- 1 alvherre alvherre 17965056 sep 14 09:51 1155291 +-rw------- 1 alvherre alvherre 1204224 sep 14 09:51 16717 +-rw------- 1 alvherre alvherre 581632 sep 6 17:51 1255 +-rw------- 1 alvherre alvherre 237568 sep 14 09:50 16674 +-rw------- 1 alvherre alvherre 212992 sep 14 09:51 1249 +-rw------- 1 alvherre alvherre 204800 sep 14 09:51 16684 +-rw------- 1 alvherre alvherre 196608 sep 14 09:50 16700 +-rw------- 1 alvherre alvherre 163840 sep 14 09:50 16699 +-rw------- 1 alvherre alvherre 122880 sep 6 17:51 16751 + +$ oid2name -d alvherre -f 155173 +From database "alvherre": + Filenode Table Name +---------------------- + 155173 accounts + +$ # you can ask for more than one object +$ oid2name -d alvherre -f 155173 -f 1155291 +From database "alvherre": + Filenode Table Name +------------------------- + 155173 accounts + 1155291 accounts_pkey + +$ # you can also mix the options, and have more details +$ oid2name -d alvherre -t accounts -f 1155291 -x +From database "alvherre": + Filenode Table Name Oid Schema Tablespace +------------------------------------------------------ + 155173 accounts 155173 public pg_default + 1155291 accounts_pkey 1155291 public pg_default $ # show disk space for every db object -$ du * | while read SIZE OID +$ du [0-9]* | +> while read SIZE FILENODE > do -> echo "$SIZE `oid2name -q -d test -o $OID`" +> echo "$SIZE `oid2name -q -d alvherre -i -f $FILENODE`" > done -24 18737 = ips -36 18722 = cities +16 1155287 branches_pkey +16 1155289 tellers_pkey +17561 1155291 accounts_pkey ... -$ # same as above, but sort by largest first -$ du * | while read SIZE OID +$ # same, but sort by size +$ du [0-9]* | sort -rn | while read SIZE FN > do -> echo "$SIZE `oid2name -q -d test -o $OID`" -> done | -> sort -rn -2048 19324 = bigtable -1950 23903 = customers +> echo "$SIZE `oid2name -q -d alvherre -f $FN`" +> done +133466 155173 accounts +17561 1155291 accounts_pkey +1177 16717 pg_proc_proname_args_nsp_index ... -$ # show disk usage per database -$ cd /u/pg/data/base -$ du -s * | -> while read SIZE OID -> do -> echo "$SIZE `aspg oid2name -q | grep ^$OID' '`" -> done | -> sort -rn -2256 18721 = test -2135 18735 = postgres -.. +$ # If you want to see what's in tablespaces, use the pg_tblspc directory +$ cd $PGDATA/pg_tblspc +$ oid2name -s +All tablespaces: + Oid Tablespace Name +------------------------- + 1663 pg_default + 1664 pg_global + 155151 fastdisk + 155152 bigdisk -This can be done in psql with: +$ # what databases have objects in tablespace "fastdisk"? +$ ls -d 155151/* +155151/17228/ 155151/PG_VERSION -test=> SELECT relpages, relfilenode, relname FROM pg_class ORDER BY relpages DESC; +$ # Oh, what was database 17228 again? +$ oid2name +All databases: + Oid Database Name Tablespace +---------------------------------- + 17228 alvherre pg_default + 17255 regression pg_default + 17227 template0 pg_default + 1 template1 pg_default + +$ # Let's see what objects does this database have in the tablespace. +$ cd 155151/17228 +$ ls -l +total 0 +-rw------- 1 postgres postgres 0 sep 13 23:20 155156 + +$ # OK, this is a pretty small table ... but which one is it? +$ oid2name -d alvherre -f 155156 +From database "alvherre": + Filenode Table Name +---------------------- + 155156 foo + +$ # end of sample session. + +--------------------------------------------------------------------------- + +You can also get approximate size data for each object using psql. For +example, + +SELECT relpages, relfilenode, relname FROM pg_class ORDER BY relpages DESC; Each page is typically 8k. Relpages is updated by VACUUM. diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c index 564448fe008..7186a7abd7f 100644 --- a/contrib/oid2name/oid2name.c +++ b/contrib/oid2name/oid2name.c @@ -1,9 +1,9 @@ /* - oid2name; a postgresql 7.1 (+?) app to map OIDs on the filesystem - to table and database names. - - b. palmer, bpalmer@crimelabs.net 1-17-2001 - + * oid2name, a PostgreSQL app to map OIDs on the filesystem + * to table and database names. + * + * Originally by + * B. Palmer, bpalmer@crimelabs.net 1-17-2001 */ #include "postgres_fe.h" @@ -14,41 +14,46 @@ #include "libpq-fe.h" +/* an extensible array to keep track of elements to show */ +typedef struct +{ + char **array; + int num; + int alloc; +} eary; + /* these are the opts structures for command line params */ struct options { - int getdatabase; - int gettable; - int getoid; + eary *tables; + eary *oids; + eary *filenodes; - int quiet; + bool quiet; + bool systables; + bool indexes; + bool nodb; + bool extended; + bool tablespaces; - int systables; - - int remotehost; - int remoteport; - int remoteuser; - int remotepass; - - int _oid; - char _dbname[128]; - char _tbname[128]; - - char _hostname[128]; - char _port[6]; - char _username[128]; - char _password[128]; + char *dbname; + char *hostname; + char *port; + char *username; + char *password; }; /* function prototypes */ void get_opts(int, char **, struct options *); -PGconn *sql_conn(const char *, struct options *); -void sql_exec_error(int); -int sql_exec(PGconn *, const char *, int); -void sql_exec_dumpdb(PGconn *); -void sql_exec_dumptable(PGconn *, int); -void sql_exec_searchtable(PGconn *, const char *); -void sql_exec_searchoid(PGconn *, int); +void *myalloc(size_t size); +void add_one_elt(char *eltname, eary *eary); +char *get_comma_elts(eary *eary); +PGconn *sql_conn(struct options *); +int sql_exec(PGconn *, const char *sql, bool quiet); +void sql_exec_dumpalldbs(PGconn *, struct options *); +void sql_exec_dumpalltables(PGconn *, struct options *); +void sql_exec_searchtables(PGconn *, struct options *); +void sql_exec_dumpalltbspc(PGconn *, struct options *); /* function to parse command line options and check for some usage errors. */ void @@ -57,239 +62,237 @@ get_opts(int argc, char **argv, struct options * my_opts) int c; /* set the defaults */ - my_opts->getdatabase = 0; - my_opts->gettable = 0; - my_opts->getoid = 0; - - my_opts->quiet = 0; - - my_opts->systables = 0; - - my_opts->remotehost = 0; - my_opts->remoteport = 0; - my_opts->remoteuser = 0; - my_opts->remotepass = 0; + my_opts->quiet = false; + my_opts->systables = false; + my_opts->indexes = false; + my_opts->nodb = false; + my_opts->extended = false; + my_opts->tablespaces = false; /* get opts */ - while ((c = getopt(argc, argv, "H:p:U:P:d:t:o:qxh?")) != -1) + while ((c = getopt(argc, argv, "H:p:U:P:d:t:o:f:qSxish?")) != -1) { switch (c) { /* specify the database */ case 'd': - my_opts->getdatabase = 1; - sscanf(optarg, "%s", my_opts->_dbname); + my_opts->dbname = (char *) myalloc(strlen(optarg)); + sscanf(optarg, "%s", my_opts->dbname); break; - /* specify the table name */ + /* specify one tablename to show */ case 't': - /* make sure we set the database first */ - if (!my_opts->getdatabase) - { - fprintf(stderr, "You must specify a database to dump from.\n"); - exit(1); - } - /* make sure we don't try to do a -o also */ - if (my_opts->getoid) - { - fprintf(stderr, "You can only specify either oid or table\n"); - exit(1); - } - - my_opts->gettable = 1; - sscanf(optarg, "%s", my_opts->_tbname); - + add_one_elt(optarg, my_opts->tables); break; - /* specify the oid int */ + /* specify one Oid to show */ case 'o': - /* make sure we set the database first */ - if (!my_opts->getdatabase) - { - fprintf(stderr, "You must specify a database to dump from.\n"); - exit(1); - } - /* make sure we don't try to do a -t also */ - if (my_opts->gettable) - { - fprintf(stderr, "You can only specify either oid or table\n"); - exit(1); - } - - my_opts->getoid = 1; - sscanf(optarg, "%i", &my_opts->_oid); - + add_one_elt(optarg, my_opts->oids); break; + /* specify one filenode to show*/ + case 'f': + add_one_elt(optarg, my_opts->filenodes); + break; + + /* don't show headers */ case 'q': - my_opts->quiet = 1; + my_opts->quiet = true; break; /* host to connect to */ case 'H': - my_opts->remotehost = 1; - sscanf(optarg, "%s", my_opts->_hostname); + my_opts->hostname = (char *) myalloc(strlen(optarg)); + sscanf(optarg, "%s", my_opts->hostname); break; /* port to connect to on remote host */ case 'p': - my_opts->remoteport = 1; - sscanf(optarg, "%s", my_opts->_port); + my_opts->port = (char *) myalloc(strlen(optarg)); + sscanf(optarg, "%s", my_opts->port); break; /* username */ case 'U': - my_opts->remoteuser = 1; - sscanf(optarg, "%s", my_opts->_username); + my_opts->username = (char *) myalloc(strlen(optarg)); + sscanf(optarg, "%s", my_opts->username); break; /* password */ case 'P': - my_opts->remotepass = 1; - sscanf(optarg, "%s", my_opts->_password); + my_opts->password = (char *) myalloc(strlen(optarg)); + sscanf(optarg, "%s", my_opts->password); break; /* display system tables */ + case 'S': + my_opts->systables = true; + break; + + /* also display indexes */ + case 'i': + my_opts->indexes = true; + break; + + /* display extra columns */ case 'x': - my_opts->systables = 1; + my_opts->extended = true; + break; + + /* dump tablespaces only */ + case 's': + my_opts->tablespaces = true; break; /* help! (ugly in code for easier editing) */ case '?': case 'h': - fprintf(stderr, "\ -Usage: oid2name [-d database [-x] ] [-t table | -o oid]\n\ - default action display all databases\n\ - -d database database to oid2name\n\ - -x display system tables\n\ - -t table | -o oid search for table name (-t) or\n\ - oid (-o) in -d database\n\ - -q quiet\n\ - -H host connect to remote host\n\ - -p port host port to connect to\n\ - -U username username to connect with\n\ - -P password password for username\n\ -"); + fprintf(stderr, +"Usage: oid2name [-s|-d database] [-S][-i][-q][-x] [-t table|-o oid|-f file] ...\n" +" default action show all database Oids\n" +" -d database database to connect to\n" +" -s show all tablespaces\n" +" -S show system objects too\n" +" -i show indexes and sequences too\n" +" -x extended (show additional columns)\n" +" -q quiet (don't show headers)\n" +" -t