YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

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