~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to contrib/oid2name/oid2name.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * oid2name, a PostgreSQL app to map OIDs on the filesystem
 
3
 * to table and database names.
 
4
 *
 
5
 * Originally by
 
6
 * B. Palmer, bpalmer@crimelabs.net 1-17-2001
 
7
 *
 
8
 * contrib/oid2name/oid2name.c
 
9
 */
 
10
#include "postgres_fe.h"
 
11
 
 
12
#include <unistd.h>
 
13
#ifdef HAVE_GETOPT_H
 
14
#include <getopt.h>
 
15
#endif
 
16
 
 
17
extern char *optarg;
 
18
 
 
19
#include "libpq-fe.h"
 
20
 
 
21
/* an extensible array to keep track of elements to show */
 
22
typedef struct
 
23
{
 
24
        char      **array;
 
25
        int                     num;
 
26
        int                     alloc;
 
27
} eary;
 
28
 
 
29
/* these are the opts structures for command line params */
 
30
struct options
 
31
{
 
32
        eary       *tables;
 
33
        eary       *oids;
 
34
        eary       *filenodes;
 
35
 
 
36
        bool            quiet;
 
37
        bool            systables;
 
38
        bool            indexes;
 
39
        bool            nodb;
 
40
        bool            extended;
 
41
        bool            tablespaces;
 
42
 
 
43
        char       *dbname;
 
44
        char       *hostname;
 
45
        char       *port;
 
46
        char       *username;
 
47
};
 
48
 
 
49
/* function prototypes */
 
50
static void help(const char *progname);
 
51
void            get_opts(int, char **, struct options *);
 
52
void       *myalloc(size_t size);
 
53
char       *mystrdup(const char *str);
 
54
void            add_one_elt(char *eltname, eary *eary);
 
55
char       *get_comma_elts(eary *eary);
 
56
PGconn     *sql_conn(struct options *);
 
57
int                     sql_exec(PGconn *, const char *sql, bool quiet);
 
58
void            sql_exec_dumpalldbs(PGconn *, struct options *);
 
59
void            sql_exec_dumpalltables(PGconn *, struct options *);
 
60
void            sql_exec_searchtables(PGconn *, struct options *);
 
61
void            sql_exec_dumpalltbspc(PGconn *, struct options *);
 
62
 
 
63
/* function to parse command line options and check for some usage errors. */
 
64
void
 
65
get_opts(int argc, char **argv, struct options * my_opts)
 
66
{
 
67
        int                     c;
 
68
        const char *progname;
 
69
 
 
70
        progname = get_progname(argv[0]);
 
71
 
 
72
        /* set the defaults */
 
73
        my_opts->quiet = false;
 
74
        my_opts->systables = false;
 
75
        my_opts->indexes = false;
 
76
        my_opts->nodb = false;
 
77
        my_opts->extended = false;
 
78
        my_opts->tablespaces = false;
 
79
        my_opts->dbname = NULL;
 
80
        my_opts->hostname = NULL;
 
81
        my_opts->port = NULL;
 
82
        my_opts->username = NULL;
 
83
 
 
84
        if (argc > 1)
 
85
        {
 
86
                if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
 
87
                {
 
88
                        help(progname);
 
89
                        exit(0);
 
90
                }
 
91
                if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
 
92
                {
 
93
                        puts("oid2name (PostgreSQL) " PG_VERSION);
 
94
                        exit(0);
 
95
                }
 
96
        }
 
97
 
 
98
        /* get opts */
 
99
        while ((c = getopt(argc, argv, "H:p:U:d:t:o:f:qSxish")) != -1)
 
100
        {
 
101
                switch (c)
 
102
                {
 
103
                                /* specify the database */
 
104
                        case 'd':
 
105
                                my_opts->dbname = mystrdup(optarg);
 
106
                                break;
 
107
 
 
108
                                /* specify one tablename to show */
 
109
                        case 't':
 
110
                                add_one_elt(optarg, my_opts->tables);
 
111
                                break;
 
112
 
 
113
                                /* specify one Oid to show */
 
114
                        case 'o':
 
115
                                add_one_elt(optarg, my_opts->oids);
 
116
                                break;
 
117
 
 
118
                                /* specify one filenode to show */
 
119
                        case 'f':
 
120
                                add_one_elt(optarg, my_opts->filenodes);
 
121
                                break;
 
122
 
 
123
                                /* don't show headers */
 
124
                        case 'q':
 
125
                                my_opts->quiet = true;
 
126
                                break;
 
127
 
 
128
                                /* host to connect to */
 
129
                        case 'H':
 
130
                                my_opts->hostname = mystrdup(optarg);
 
131
                                break;
 
132
 
 
133
                                /* port to connect to on remote host */
 
134
                        case 'p':
 
135
                                my_opts->port = mystrdup(optarg);
 
136
                                break;
 
137
 
 
138
                                /* username */
 
139
                        case 'U':
 
140
                                my_opts->username = mystrdup(optarg);
 
141
                                break;
 
142
 
 
143
                                /* display system tables */
 
144
                        case 'S':
 
145
                                my_opts->systables = true;
 
146
                                break;
 
147
 
 
148
                                /* also display indexes */
 
149
                        case 'i':
 
150
                                my_opts->indexes = true;
 
151
                                break;
 
152
 
 
153
                                /* display extra columns */
 
154
                        case 'x':
 
155
                                my_opts->extended = true;
 
156
                                break;
 
157
 
 
158
                                /* dump tablespaces only */
 
159
                        case 's':
 
160
                                my_opts->tablespaces = true;
 
161
                                break;
 
162
 
 
163
                        case 'h':
 
164
                                help(progname);
 
165
                                exit(0);
 
166
                                break;
 
167
 
 
168
                        default:
 
169
                                fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
 
170
                                exit(1);
 
171
                }
 
172
        }
 
173
}
 
174
 
 
175
static void
 
176
help(const char *progname)
 
177
{
 
178
        printf("%s helps examining the file structure used by PostgreSQL.\n\n"
 
179
                   "Usage:\n"
 
180
                   "  %s [OPTIONS]...\n"
 
181
                   "\nOptions:\n"
 
182
                   "  -d DBNAME    database to connect to\n"
 
183
                   "  -f FILENODE  show info for table with given file node\n"
 
184
                   "  -H HOSTNAME  database server host or socket directory\n"
 
185
                   "  -i           show indexes and sequences too\n"
 
186
                   "  -o OID       show info for table with given OID\n"
 
187
                   "  -p PORT      database server port number\n"
 
188
                   "  -q           quiet (don't show headers)\n"
 
189
                   "  -s           show all tablespaces\n"
 
190
                   "  -S           show system objects too\n"
 
191
                   "  -t TABLE     show info for named table\n"
 
192
                   "  -U NAME      connect as specified database user\n"
 
193
                   "  -x           extended (show additional columns)\n"
 
194
                   "  --help       show this help, then exit\n"
 
195
                   "  --version    output version information, then exit\n"
 
196
                   "\nThe default action is to show all database OIDs.\n\n"
 
197
                   "Report bugs to <pgsql-bugs@postgresql.org>.\n",
 
198
                   progname, progname);
 
199
}
 
200
 
 
201
void *
 
202
myalloc(size_t size)
 
203
{
 
204
        void       *ptr = malloc(size);
 
205
 
 
206
        if (!ptr)
 
207
        {
 
208
                fprintf(stderr, "out of memory");
 
209
                exit(1);
 
210
        }
 
211
        return ptr;
 
212
}
 
213
 
 
214
char *
 
215
mystrdup(const char *str)
 
216
{
 
217
        char       *result = strdup(str);
 
218
 
 
219
        if (!result)
 
220
        {
 
221
                fprintf(stderr, "out of memory");
 
222
                exit(1);
 
223
        }
 
224
        return result;
 
225
}
 
226
 
 
227
/*
 
228
 * add_one_elt
 
229
 *
 
230
 * Add one element to a (possibly empty) eary struct.
 
231
 */
 
232
void
 
233
add_one_elt(char *eltname, eary *eary)
 
234
{
 
235
        if (eary->alloc == 0)
 
236
        {
 
237
                eary      ->alloc = 8;
 
238
                eary      ->array = (char **) myalloc(8 * sizeof(char *));
 
239
        }
 
240
        else if (eary->num >= eary->alloc)
 
241
        {
 
242
                eary      ->alloc *= 2;
 
243
                eary      ->array = (char **)
 
244
                realloc(eary->array, eary->alloc * sizeof(char *));
 
245
 
 
246
                if (!eary->array)
 
247
                {
 
248
                        fprintf(stderr, "out of memory");
 
249
                        exit(1);
 
250
                }
 
251
        }
 
252
 
 
253
        eary      ->array[eary->num] = mystrdup(eltname);
 
254
        eary      ->num++;
 
255
}
 
256
 
 
257
/*
 
258
 * get_comma_elts
 
259
 *
 
260
 * Return the elements of an eary as a (freshly allocated) single string, in
 
261
 * single quotes, separated by commas and properly escaped for insertion in an
 
262
 * SQL statement.
 
263
 */
 
264
char *
 
265
get_comma_elts(eary *eary)
 
266
{
 
267
        char       *ret,
 
268
                           *ptr;
 
269
        int                     i,
 
270
                                length = 0;
 
271
 
 
272
        if (eary->num == 0)
 
273
                return mystrdup("");
 
274
 
 
275
        /*
 
276
         * PQescapeString wants 2 * length + 1 bytes of breath space.  Add two
 
277
         * chars per element for the single quotes and one for the comma.
 
278
         */
 
279
        for (i = 0; i < eary->num; i++)
 
280
                length += strlen(eary->array[i]);
 
281
 
 
282
        ret = (char *) myalloc(length * 2 + 4 * eary->num);
 
283
        ptr = ret;
 
284
 
 
285
        for (i = 0; i < eary->num; i++)
 
286
        {
 
287
                if (i != 0)
 
288
                        sprintf(ptr++, ",");
 
289
                sprintf(ptr++, "'");
 
290
                ptr += PQescapeString(ptr, eary->array[i], strlen(eary->array[i]));
 
291
                sprintf(ptr++, "'");
 
292
        }
 
293
 
 
294
        return ret;
 
295
}
 
296
 
 
297
/* establish connection with database. */
 
298
PGconn *
 
299
sql_conn(struct options * my_opts)
 
300
{
 
301
        PGconn     *conn;
 
302
        char       *password = NULL;
 
303
        bool            new_pass;
 
304
 
 
305
        /*
 
306
         * Start the connection.  Loop until we have a password if requested by
 
307
         * backend.
 
308
         */
 
309
        do
 
310
        {
 
311
                new_pass = false;
 
312
                conn = PQsetdbLogin(my_opts->hostname,
 
313
                                                        my_opts->port,
 
314
                                                        NULL,           /* options */
 
315
                                                        NULL,           /* tty */
 
316
                                                        my_opts->dbname,
 
317
                                                        my_opts->username,
 
318
                                                        password);
 
319
                if (!conn)
 
320
                {
 
321
                        fprintf(stderr, "%s: could not connect to database %s\n",
 
322
                                        "oid2name", my_opts->dbname);
 
323
                        exit(1);
 
324
                }
 
325
 
 
326
                if (PQstatus(conn) == CONNECTION_BAD &&
 
327
                        PQconnectionNeedsPassword(conn) &&
 
328
                        password == NULL)
 
329
                {
 
330
                        PQfinish(conn);
 
331
                        password = simple_prompt("Password: ", 100, false);
 
332
                        new_pass = true;
 
333
                }
 
334
        } while (new_pass);
 
335
 
 
336
        if (password)
 
337
                free(password);
 
338
 
 
339
        /* check to see that the backend connection was successfully made */
 
340
        if (PQstatus(conn) == CONNECTION_BAD)
 
341
        {
 
342
                fprintf(stderr, "%s: could not connect to database %s: %s",
 
343
                                "oid2name", my_opts->dbname, PQerrorMessage(conn));
 
344
                PQfinish(conn);
 
345
                exit(1);
 
346
        }
 
347
 
 
348
        /* return the conn if good */
 
349
        return conn;
 
350
}
 
351
 
 
352
/*
 
353
 * Actual code to make call to the database and print the output data.
 
354
 */
 
355
int
 
356
sql_exec(PGconn *conn, const char *todo, bool quiet)
 
357
{
 
358
        PGresult   *res;
 
359
 
 
360
        int                     nfields;
 
361
        int                     nrows;
 
362
        int                     i,
 
363
                                j,
 
364
                                l;
 
365
        int                *length;
 
366
        char       *pad;
 
367
 
 
368
        /* make the call */
 
369
        res = PQexec(conn, todo);
 
370
 
 
371
        /* check and deal with errors */
 
372
        if (!res || PQresultStatus(res) > 2)
 
373
        {
 
374
                fprintf(stderr, "oid2name: query failed: %s\n", PQerrorMessage(conn));
 
375
                fprintf(stderr, "oid2name: query was: %s\n", todo);
 
376
 
 
377
                PQclear(res);
 
378
                PQfinish(conn);
 
379
                exit(-1);
 
380
        }
 
381
 
 
382
        /* get the number of fields */
 
383
        nrows = PQntuples(res);
 
384
        nfields = PQnfields(res);
 
385
 
 
386
        /* for each field, get the needed width */
 
387
        length = (int *) myalloc(sizeof(int) * nfields);
 
388
        for (j = 0; j < nfields; j++)
 
389
                length[j] = strlen(PQfname(res, j));
 
390
 
 
391
        for (i = 0; i < nrows; i++)
 
392
        {
 
393
                for (j = 0; j < nfields; j++)
 
394
                {
 
395
                        l = strlen(PQgetvalue(res, i, j));
 
396
                        if (l > length[j])
 
397
                                length[j] = strlen(PQgetvalue(res, i, j));
 
398
                }
 
399
        }
 
400
 
 
401
        /* print a header */
 
402
        if (!quiet)
 
403
        {
 
404
                for (j = 0, l = 0; j < nfields; j++)
 
405
                {
 
406
                        fprintf(stdout, "%*s", length[j] + 2, PQfname(res, j));
 
407
                        l += length[j] + 2;
 
408
                }
 
409
                fprintf(stdout, "\n");
 
410
                pad = (char *) myalloc(l + 1);
 
411
                MemSet(pad, '-', l);
 
412
                pad[l] = '\0';
 
413
                fprintf(stdout, "%s\n", pad);
 
414
                free(pad);
 
415
        }
 
416
 
 
417
        /* for each row, dump the information */
 
418
        for (i = 0; i < nrows; i++)
 
419
        {
 
420
                for (j = 0; j < nfields; j++)
 
421
                        fprintf(stdout, "%*s", length[j] + 2, PQgetvalue(res, i, j));
 
422
                fprintf(stdout, "\n");
 
423
        }
 
424
 
 
425
        /* cleanup */
 
426
        PQclear(res);
 
427
        free(length);
 
428
 
 
429
        return 0;
 
430
}
 
431
 
 
432
/*
 
433
 * Dump all databases.  There are no system objects to worry about.
 
434
 */
 
435
void
 
436
sql_exec_dumpalldbs(PGconn *conn, struct options * opts)
 
437
{
 
438
        char            todo[1024];
 
439
 
 
440
        /* get the oid and database name from the system pg_database table */
 
441
        snprintf(todo, sizeof(todo),
 
442
                         "SELECT d.oid AS \"Oid\", datname AS \"Database Name\", "
 
443
                         "spcname AS \"Tablespace\" FROM pg_catalog.pg_database d JOIN pg_catalog.pg_tablespace t ON "
 
444
                         "(dattablespace = t.oid) ORDER BY 2");
 
445
 
 
446
        sql_exec(conn, todo, opts->quiet);
 
447
}
 
448
 
 
449
/*
 
450
 * Dump all tables, indexes and sequences in the current database.
 
451
 */
 
452
void
 
453
sql_exec_dumpalltables(PGconn *conn, struct options * opts)
 
454
{
 
455
        char            todo[1024];
 
456
        char       *addfields = ",c.oid AS \"Oid\", nspname AS \"Schema\", spcname as \"Tablespace\" ";
 
457
 
 
458
        snprintf(todo, sizeof(todo),
 
459
                         "SELECT pg_catalog.pg_relation_filenode(c.oid) as \"Filenode\", relname as \"Table Name\" %s "
 
460
                         "FROM pg_class c "
 
461
                   "    LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
 
462
                         "      LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),"
 
463
                         "      pg_catalog.pg_tablespace t "
 
464
                         "WHERE relkind IN ('r'%s%s) AND "
 
465
                         "      %s"
 
466
                         "              t.oid = CASE"
 
467
                         "                      WHEN reltablespace <> 0 THEN reltablespace"
 
468
                         "                      ELSE dattablespace"
 
469
                         "              END "
 
470
                         "ORDER BY relname",
 
471
                         opts->extended ? addfields : "",
 
472
                         opts->indexes ? ", 'i', 'S'" : "",
 
473
                         opts->systables ? ", 't'" : "",
 
474
                         opts->systables ? "" : "n.nspname NOT IN ('pg_catalog', 'information_schema') AND n.nspname !~ '^pg_toast' AND");
 
475
 
 
476
        sql_exec(conn, todo, opts->quiet);
 
477
}
 
478
 
 
479
/*
 
480
 * Show oid, filenode, name, schema and tablespace for each of the
 
481
 * given objects in the current database.
 
482
 */
 
483
void
 
484
sql_exec_searchtables(PGconn *conn, struct options * opts)
 
485
{
 
486
        char       *todo;
 
487
        char       *qualifiers,
 
488
                           *ptr;
 
489
        char       *comma_oids,
 
490
                           *comma_filenodes,
 
491
                           *comma_tables;
 
492
        bool            written = false;
 
493
        char       *addfields = ",c.oid AS \"Oid\", nspname AS \"Schema\", spcname as \"Tablespace\" ";
 
494
 
 
495
        /* get tables qualifiers, whether names, filenodes, or OIDs */
 
496
        comma_oids = get_comma_elts(opts->oids);
 
497
        comma_tables = get_comma_elts(opts->tables);
 
498
        comma_filenodes = get_comma_elts(opts->filenodes);
 
499
 
 
500
        /* 80 extra chars for SQL expression */
 
501
        qualifiers = (char *) myalloc(strlen(comma_oids) + strlen(comma_tables) +
 
502
                                                                  strlen(comma_filenodes) + 80);
 
503
        ptr = qualifiers;
 
504
 
 
505
        if (opts->oids->num > 0)
 
506
        {
 
507
                ptr += sprintf(ptr, "c.oid IN (%s)", comma_oids);
 
508
                written = true;
 
509
        }
 
510
        if (opts->filenodes->num > 0)
 
511
        {
 
512
                if (written)
 
513
                        ptr += sprintf(ptr, " OR ");
 
514
                ptr += sprintf(ptr, "pg_catalog.pg_relation_filenode(c.oid) IN (%s)", comma_filenodes);
 
515
                written = true;
 
516
        }
 
517
        if (opts->tables->num > 0)
 
518
        {
 
519
                if (written)
 
520
                        ptr += sprintf(ptr, " OR ");
 
521
                sprintf(ptr, "c.relname ~~ ANY (ARRAY[%s])", comma_tables);
 
522
        }
 
523
        free(comma_oids);
 
524
        free(comma_tables);
 
525
        free(comma_filenodes);
 
526
 
 
527
        /* now build the query */
 
528
        todo = (char *) myalloc(650 + strlen(qualifiers));
 
529
        snprintf(todo, 650 + strlen(qualifiers),
 
530
                         "SELECT pg_catalog.pg_relation_filenode(c.oid) as \"Filenode\", relname as \"Table Name\" %s\n"
 
531
                         "FROM pg_catalog.pg_class c \n"
 
532
                 "      LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \n"
 
533
                         "      LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),\n"
 
534
                         "      pg_catalog.pg_tablespace t \n"
 
535
                         "WHERE relkind IN ('r', 'i', 'S', 't') AND \n"
 
536
                         "              t.oid = CASE\n"
 
537
                         "                      WHEN reltablespace <> 0 THEN reltablespace\n"
 
538
                         "                      ELSE dattablespace\n"
 
539
                         "              END AND \n"
 
540
                         "  (%s) \n"
 
541
                         "ORDER BY relname\n",
 
542
                         opts->extended ? addfields : "",
 
543
                         qualifiers);
 
544
 
 
545
        free(qualifiers);
 
546
 
 
547
        sql_exec(conn, todo, opts->quiet);
 
548
}
 
549
 
 
550
void
 
551
sql_exec_dumpalltbspc(PGconn *conn, struct options * opts)
 
552
{
 
553
        char            todo[1024];
 
554
 
 
555
        snprintf(todo, sizeof(todo),
 
556
                         "SELECT oid AS \"Oid\", spcname as \"Tablespace Name\"\n"
 
557
                         "FROM pg_catalog.pg_tablespace");
 
558
 
 
559
        sql_exec(conn, todo, opts->quiet);
 
560
}
 
561
 
 
562
int
 
563
main(int argc, char **argv)
 
564
{
 
565
        struct options *my_opts;
 
566
        PGconn     *pgconn;
 
567
 
 
568
        my_opts = (struct options *) myalloc(sizeof(struct options));
 
569
 
 
570
        my_opts->oids = (eary *) myalloc(sizeof(eary));
 
571
        my_opts->tables = (eary *) myalloc(sizeof(eary));
 
572
        my_opts->filenodes = (eary *) myalloc(sizeof(eary));
 
573
 
 
574
        my_opts->oids->num = my_opts->oids->alloc = 0;
 
575
        my_opts->tables->num = my_opts->tables->alloc = 0;
 
576
        my_opts->filenodes->num = my_opts->filenodes->alloc = 0;
 
577
 
 
578
        /* parse the opts */
 
579
        get_opts(argc, argv, my_opts);
 
580
 
 
581
        if (my_opts->dbname == NULL)
 
582
        {
 
583
                my_opts->dbname = "postgres";
 
584
                my_opts->nodb = true;
 
585
        }
 
586
        pgconn = sql_conn(my_opts);
 
587
 
 
588
        /* display only tablespaces */
 
589
        if (my_opts->tablespaces)
 
590
        {
 
591
                if (!my_opts->quiet)
 
592
                        printf("All tablespaces:\n");
 
593
                sql_exec_dumpalltbspc(pgconn, my_opts);
 
594
 
 
595
                PQfinish(pgconn);
 
596
                exit(0);
 
597
        }
 
598
 
 
599
        /* display the given elements in the database */
 
600
        if (my_opts->oids->num > 0 ||
 
601
                my_opts->tables->num > 0 ||
 
602
                my_opts->filenodes->num > 0)
 
603
        {
 
604
                if (!my_opts->quiet)
 
605
                        printf("From database \"%s\":\n", my_opts->dbname);
 
606
                sql_exec_searchtables(pgconn, my_opts);
 
607
 
 
608
                PQfinish(pgconn);
 
609
                exit(0);
 
610
        }
 
611
 
 
612
        /* no elements given; dump the given database */
 
613
        if (my_opts->dbname && !my_opts->nodb)
 
614
        {
 
615
                if (!my_opts->quiet)
 
616
                        printf("From database \"%s\":\n", my_opts->dbname);
 
617
                sql_exec_dumpalltables(pgconn, my_opts);
 
618
 
 
619
                PQfinish(pgconn);
 
620
                exit(0);
 
621
        }
 
622
 
 
623
        /* no database either; dump all databases */
 
624
        if (!my_opts->quiet)
 
625
                printf("All databases:\n");
 
626
        sql_exec_dumpalldbs(pgconn, my_opts);
 
627
 
 
628
        PQfinish(pgconn);
 
629
        return 0;
 
630
}