00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "postgres_fe.h"
00011
00012 #include <unistd.h>
00013 #ifdef HAVE_GETOPT_H
00014 #include <getopt.h>
00015 #endif
00016
00017 extern char *optarg;
00018
00019 #include "libpq-fe.h"
00020
00021
00022 typedef struct
00023 {
00024 char **array;
00025 int num;
00026 int alloc;
00027 } eary;
00028
00029
00030 struct options
00031 {
00032 eary *tables;
00033 eary *oids;
00034 eary *filenodes;
00035
00036 bool quiet;
00037 bool systables;
00038 bool indexes;
00039 bool nodb;
00040 bool extended;
00041 bool tablespaces;
00042
00043 char *dbname;
00044 char *hostname;
00045 char *port;
00046 char *username;
00047 const char *progname;
00048 };
00049
00050
00051 static void help(const char *progname);
00052 void get_opts(int, char **, struct options *);
00053 void add_one_elt(char *eltname, eary *eary);
00054 char *get_comma_elts(eary *eary);
00055 PGconn *sql_conn(struct options *);
00056 int sql_exec(PGconn *, const char *sql, bool quiet);
00057 void sql_exec_dumpalldbs(PGconn *, struct options *);
00058 void sql_exec_dumpalltables(PGconn *, struct options *);
00059 void sql_exec_searchtables(PGconn *, struct options *);
00060 void sql_exec_dumpalltbspc(PGconn *, struct options *);
00061
00062
00063 void
00064 get_opts(int argc, char **argv, struct options * my_opts)
00065 {
00066 int c;
00067 const char *progname;
00068
00069 progname = get_progname(argv[0]);
00070
00071
00072 my_opts->quiet = false;
00073 my_opts->systables = false;
00074 my_opts->indexes = false;
00075 my_opts->nodb = false;
00076 my_opts->extended = false;
00077 my_opts->tablespaces = false;
00078 my_opts->dbname = NULL;
00079 my_opts->hostname = NULL;
00080 my_opts->port = NULL;
00081 my_opts->username = NULL;
00082 my_opts->progname = progname;
00083
00084 if (argc > 1)
00085 {
00086 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
00087 {
00088 help(progname);
00089 exit(0);
00090 }
00091 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
00092 {
00093 puts("oid2name (PostgreSQL) " PG_VERSION);
00094 exit(0);
00095 }
00096 }
00097
00098
00099 while ((c = getopt(argc, argv, "H:p:U:d:t:o:f:qSxish")) != -1)
00100 {
00101 switch (c)
00102 {
00103
00104 case 'd':
00105 my_opts->dbname = pg_strdup(optarg);
00106 break;
00107
00108
00109 case 't':
00110 add_one_elt(optarg, my_opts->tables);
00111 break;
00112
00113
00114 case 'o':
00115 add_one_elt(optarg, my_opts->oids);
00116 break;
00117
00118
00119 case 'f':
00120 add_one_elt(optarg, my_opts->filenodes);
00121 break;
00122
00123
00124 case 'q':
00125 my_opts->quiet = true;
00126 break;
00127
00128
00129 case 'H':
00130 my_opts->hostname = pg_strdup(optarg);
00131 break;
00132
00133
00134 case 'p':
00135 my_opts->port = pg_strdup(optarg);
00136 break;
00137
00138
00139 case 'U':
00140 my_opts->username = pg_strdup(optarg);
00141 break;
00142
00143
00144 case 'S':
00145 my_opts->systables = true;
00146 break;
00147
00148
00149 case 'i':
00150 my_opts->indexes = true;
00151 break;
00152
00153
00154 case 'x':
00155 my_opts->extended = true;
00156 break;
00157
00158
00159 case 's':
00160 my_opts->tablespaces = true;
00161 break;
00162
00163 case 'h':
00164 help(progname);
00165 exit(0);
00166 break;
00167
00168 default:
00169 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
00170 exit(1);
00171 }
00172 }
00173 }
00174
00175 static void
00176 help(const char *progname)
00177 {
00178 printf("%s helps examining the file structure used by PostgreSQL.\n\n"
00179 "Usage:\n"
00180 " %s [OPTION]...\n"
00181 "\nOptions:\n"
00182 " -d DBNAME database to connect to\n"
00183 " -f FILENODE show info for table with given file node\n"
00184 " -H HOSTNAME database server host or socket directory\n"
00185 " -i show indexes and sequences too\n"
00186 " -o OID show info for table with given OID\n"
00187 " -p PORT database server port number\n"
00188 " -q quiet (don't show headers)\n"
00189 " -s show all tablespaces\n"
00190 " -S show system objects too\n"
00191 " -t TABLE show info for named table\n"
00192 " -U NAME connect as specified database user\n"
00193 " -V, --version output version information, then exit\n"
00194 " -x extended (show additional columns)\n"
00195 " -?, --help show this help, then exit\n"
00196 "\nThe default action is to show all database OIDs.\n\n"
00197 "Report bugs to <[email protected]>.\n",
00198 progname, progname);
00199 }
00200
00201
00202
00203
00204
00205
00206 void
00207 add_one_elt(char *eltname, eary *eary)
00208 {
00209 if (eary->alloc == 0)
00210 {
00211 eary ->alloc = 8;
00212 eary ->array = (char **) pg_malloc(8 * sizeof(char *));
00213 }
00214 else if (eary->num >= eary->alloc)
00215 {
00216 eary ->alloc *= 2;
00217 eary ->array = (char **) pg_realloc(eary->array,
00218 eary->alloc * sizeof(char *));
00219 }
00220
00221 eary ->array[eary->num] = pg_strdup(eltname);
00222 eary ->num++;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232 char *
00233 get_comma_elts(eary *eary)
00234 {
00235 char *ret,
00236 *ptr;
00237 int i,
00238 length = 0;
00239
00240 if (eary->num == 0)
00241 return pg_strdup("");
00242
00243
00244
00245
00246
00247 for (i = 0; i < eary->num; i++)
00248 length += strlen(eary->array[i]);
00249
00250 ret = (char *) pg_malloc(length * 2 + 4 * eary->num);
00251 ptr = ret;
00252
00253 for (i = 0; i < eary->num; i++)
00254 {
00255 if (i != 0)
00256 sprintf(ptr++, ",");
00257 sprintf(ptr++, "'");
00258 ptr += PQescapeString(ptr, eary->array[i], strlen(eary->array[i]));
00259 sprintf(ptr++, "'");
00260 }
00261
00262 return ret;
00263 }
00264
00265
00266 PGconn *
00267 sql_conn(struct options * my_opts)
00268 {
00269 PGconn *conn;
00270 char *password = NULL;
00271 bool new_pass;
00272
00273
00274
00275
00276
00277 do
00278 {
00279 #define PARAMS_ARRAY_SIZE 7
00280
00281 const char *keywords[PARAMS_ARRAY_SIZE];
00282 const char *values[PARAMS_ARRAY_SIZE];
00283
00284 keywords[0] = "host";
00285 values[0] = my_opts->hostname;
00286 keywords[1] = "port";
00287 values[1] = my_opts->port;
00288 keywords[2] = "user";
00289 values[2] = my_opts->username;
00290 keywords[3] = "password";
00291 values[3] = password;
00292 keywords[4] = "dbname";
00293 values[4] = my_opts->dbname;
00294 keywords[5] = "fallback_application_name";
00295 values[5] = my_opts->progname;
00296 keywords[6] = NULL;
00297 values[6] = NULL;
00298
00299 new_pass = false;
00300 conn = PQconnectdbParams(keywords, values, true);
00301
00302 if (!conn)
00303 {
00304 fprintf(stderr, "%s: could not connect to database %s\n",
00305 "oid2name", my_opts->dbname);
00306 exit(1);
00307 }
00308
00309 if (PQstatus(conn) == CONNECTION_BAD &&
00310 PQconnectionNeedsPassword(conn) &&
00311 password == NULL)
00312 {
00313 PQfinish(conn);
00314 password = simple_prompt("Password: ", 100, false);
00315 new_pass = true;
00316 }
00317 } while (new_pass);
00318
00319 if (password)
00320 free(password);
00321
00322
00323 if (PQstatus(conn) == CONNECTION_BAD)
00324 {
00325 fprintf(stderr, "%s: could not connect to database %s: %s",
00326 "oid2name", my_opts->dbname, PQerrorMessage(conn));
00327 PQfinish(conn);
00328 exit(1);
00329 }
00330
00331
00332 return conn;
00333 }
00334
00335
00336
00337
00338 int
00339 sql_exec(PGconn *conn, const char *todo, bool quiet)
00340 {
00341 PGresult *res;
00342
00343 int nfields;
00344 int nrows;
00345 int i,
00346 j,
00347 l;
00348 int *length;
00349 char *pad;
00350
00351
00352 res = PQexec(conn, todo);
00353
00354
00355 if (!res || PQresultStatus(res) > 2)
00356 {
00357 fprintf(stderr, "oid2name: query failed: %s\n", PQerrorMessage(conn));
00358 fprintf(stderr, "oid2name: query was: %s\n", todo);
00359
00360 PQclear(res);
00361 PQfinish(conn);
00362 exit(-1);
00363 }
00364
00365
00366 nrows = PQntuples(res);
00367 nfields = PQnfields(res);
00368
00369
00370 length = (int *) pg_malloc(sizeof(int) * nfields);
00371 for (j = 0; j < nfields; j++)
00372 length[j] = strlen(PQfname(res, j));
00373
00374 for (i = 0; i < nrows; i++)
00375 {
00376 for (j = 0; j < nfields; j++)
00377 {
00378 l = strlen(PQgetvalue(res, i, j));
00379 if (l > length[j])
00380 length[j] = strlen(PQgetvalue(res, i, j));
00381 }
00382 }
00383
00384
00385 if (!quiet)
00386 {
00387 for (j = 0, l = 0; j < nfields; j++)
00388 {
00389 fprintf(stdout, "%*s", length[j] + 2, PQfname(res, j));
00390 l += length[j] + 2;
00391 }
00392 fprintf(stdout, "\n");
00393 pad = (char *) pg_malloc(l + 1);
00394 MemSet(pad, '-', l);
00395 pad[l] = '\0';
00396 fprintf(stdout, "%s\n", pad);
00397 free(pad);
00398 }
00399
00400
00401 for (i = 0; i < nrows; i++)
00402 {
00403 for (j = 0; j < nfields; j++)
00404 fprintf(stdout, "%*s", length[j] + 2, PQgetvalue(res, i, j));
00405 fprintf(stdout, "\n");
00406 }
00407
00408
00409 PQclear(res);
00410 free(length);
00411
00412 return 0;
00413 }
00414
00415
00416
00417
00418 void
00419 sql_exec_dumpalldbs(PGconn *conn, struct options * opts)
00420 {
00421 char todo[1024];
00422
00423
00424 snprintf(todo, sizeof(todo),
00425 "SELECT d.oid AS \"Oid\", datname AS \"Database Name\", "
00426 "spcname AS \"Tablespace\" FROM pg_catalog.pg_database d JOIN pg_catalog.pg_tablespace t ON "
00427 "(dattablespace = t.oid) ORDER BY 2");
00428
00429 sql_exec(conn, todo, opts->quiet);
00430 }
00431
00432
00433
00434
00435 void
00436 sql_exec_dumpalltables(PGconn *conn, struct options * opts)
00437 {
00438 char todo[1024];
00439 char *addfields = ",c.oid AS \"Oid\", nspname AS \"Schema\", spcname as \"Tablespace\" ";
00440
00441 snprintf(todo, sizeof(todo),
00442 "SELECT pg_catalog.pg_relation_filenode(c.oid) as \"Filenode\", relname as \"Table Name\" %s "
00443 "FROM pg_class c "
00444 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
00445 " LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),"
00446 " pg_catalog.pg_tablespace t "
00447 "WHERE relkind IN ('r', 'm'%s%s) AND "
00448 " %s"
00449 " t.oid = CASE"
00450 " WHEN reltablespace <> 0 THEN reltablespace"
00451 " ELSE dattablespace"
00452 " END "
00453 "ORDER BY relname",
00454 opts->extended ? addfields : "",
00455 opts->indexes ? ", 'i', 'S'" : "",
00456 opts->systables ? ", 't'" : "",
00457 opts->systables ? "" : "n.nspname NOT IN ('pg_catalog', 'information_schema') AND n.nspname !~ '^pg_toast' AND");
00458
00459 sql_exec(conn, todo, opts->quiet);
00460 }
00461
00462
00463
00464
00465
00466 void
00467 sql_exec_searchtables(PGconn *conn, struct options * opts)
00468 {
00469 char *todo;
00470 char *qualifiers,
00471 *ptr;
00472 char *comma_oids,
00473 *comma_filenodes,
00474 *comma_tables;
00475 bool written = false;
00476 char *addfields = ",c.oid AS \"Oid\", nspname AS \"Schema\", spcname as \"Tablespace\" ";
00477
00478
00479 comma_oids = get_comma_elts(opts->oids);
00480 comma_tables = get_comma_elts(opts->tables);
00481 comma_filenodes = get_comma_elts(opts->filenodes);
00482
00483
00484 qualifiers = (char *) pg_malloc(strlen(comma_oids) + strlen(comma_tables) +
00485 strlen(comma_filenodes) + 80);
00486 ptr = qualifiers;
00487
00488 if (opts->oids->num > 0)
00489 {
00490 ptr += sprintf(ptr, "c.oid IN (%s)", comma_oids);
00491 written = true;
00492 }
00493 if (opts->filenodes->num > 0)
00494 {
00495 if (written)
00496 ptr += sprintf(ptr, " OR ");
00497 ptr += sprintf(ptr, "pg_catalog.pg_relation_filenode(c.oid) IN (%s)", comma_filenodes);
00498 written = true;
00499 }
00500 if (opts->tables->num > 0)
00501 {
00502 if (written)
00503 ptr += sprintf(ptr, " OR ");
00504 sprintf(ptr, "c.relname ~~ ANY (ARRAY[%s])", comma_tables);
00505 }
00506 free(comma_oids);
00507 free(comma_tables);
00508 free(comma_filenodes);
00509
00510
00511 todo = (char *) pg_malloc(650 + strlen(qualifiers));
00512 snprintf(todo, 650 + strlen(qualifiers),
00513 "SELECT pg_catalog.pg_relation_filenode(c.oid) as \"Filenode\", relname as \"Table Name\" %s\n"
00514 "FROM pg_catalog.pg_class c \n"
00515 " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace \n"
00516 " LEFT JOIN pg_catalog.pg_database d ON d.datname = pg_catalog.current_database(),\n"
00517 " pg_catalog.pg_tablespace t \n"
00518 "WHERE relkind IN ('r', 'm', 'i', 'S', 't') AND \n"
00519 " t.oid = CASE\n"
00520 " WHEN reltablespace <> 0 THEN reltablespace\n"
00521 " ELSE dattablespace\n"
00522 " END AND \n"
00523 " (%s) \n"
00524 "ORDER BY relname\n",
00525 opts->extended ? addfields : "",
00526 qualifiers);
00527
00528 free(qualifiers);
00529
00530 sql_exec(conn, todo, opts->quiet);
00531 }
00532
00533 void
00534 sql_exec_dumpalltbspc(PGconn *conn, struct options * opts)
00535 {
00536 char todo[1024];
00537
00538 snprintf(todo, sizeof(todo),
00539 "SELECT oid AS \"Oid\", spcname as \"Tablespace Name\"\n"
00540 "FROM pg_catalog.pg_tablespace");
00541
00542 sql_exec(conn, todo, opts->quiet);
00543 }
00544
00545 int
00546 main(int argc, char **argv)
00547 {
00548 struct options *my_opts;
00549 PGconn *pgconn;
00550
00551 my_opts = (struct options *) pg_malloc(sizeof(struct options));
00552
00553 my_opts->oids = (eary *) pg_malloc(sizeof(eary));
00554 my_opts->tables = (eary *) pg_malloc(sizeof(eary));
00555 my_opts->filenodes = (eary *) pg_malloc(sizeof(eary));
00556
00557 my_opts->oids->num = my_opts->oids->alloc = 0;
00558 my_opts->tables->num = my_opts->tables->alloc = 0;
00559 my_opts->filenodes->num = my_opts->filenodes->alloc = 0;
00560
00561
00562 get_opts(argc, argv, my_opts);
00563
00564 if (my_opts->dbname == NULL)
00565 {
00566 my_opts->dbname = "postgres";
00567 my_opts->nodb = true;
00568 }
00569 pgconn = sql_conn(my_opts);
00570
00571
00572 if (my_opts->tablespaces)
00573 {
00574 if (!my_opts->quiet)
00575 printf("All tablespaces:\n");
00576 sql_exec_dumpalltbspc(pgconn, my_opts);
00577
00578 PQfinish(pgconn);
00579 exit(0);
00580 }
00581
00582
00583 if (my_opts->oids->num > 0 ||
00584 my_opts->tables->num > 0 ||
00585 my_opts->filenodes->num > 0)
00586 {
00587 if (!my_opts->quiet)
00588 printf("From database \"%s\":\n", my_opts->dbname);
00589 sql_exec_searchtables(pgconn, my_opts);
00590
00591 PQfinish(pgconn);
00592 exit(0);
00593 }
00594
00595
00596 if (my_opts->dbname && !my_opts->nodb)
00597 {
00598 if (!my_opts->quiet)
00599 printf("From database \"%s\":\n", my_opts->dbname);
00600 sql_exec_dumpalltables(pgconn, my_opts);
00601
00602 PQfinish(pgconn);
00603 exit(0);
00604 }
00605
00606
00607 if (!my_opts->quiet)
00608 printf("All databases:\n");
00609 sql_exec_dumpalldbs(pgconn, my_opts);
00610
00611 PQfinish(pgconn);
00612 return 0;
00613 }