/* 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 */ #include "postgres_fe.h" #include #ifdef HAVE_GETOPT_H #include #endif #include "libpq-fe.h" /* these are the opts structures for command line params */ struct options { int getdatabase; int gettable; int getoid; 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]; }; /* 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); /* fuction to parse command line options and check for some usage errors. */ void 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->systables = 0; my_opts->remotehost = 0; my_opts->remoteport = 0; my_opts->remoteuser = 0; my_opts->remotepass = 0; /* get opts */ while ((c = getopt(argc, argv, "H:p:U:P:d:t:o:xh?")) != -1) { switch (c) { /* specify the database */ case 'd': my_opts->getdatabase = 1; sscanf(optarg, "%s", my_opts->_dbname); break; /* specify the table name */ case 't': /* make sure we set the database first */ if (!my_opts->getdatabase) { fprintf(stderr, "Sorry, but 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, "Sorry, you can only specify either oid or table\n"); exit(1); } my_opts->gettable = 1; sscanf(optarg, "%s", my_opts->_tbname); break; /* specify the oid int */ case 'o': /* make sure we set the database first */ if (!my_opts->getdatabase) { fprintf(stderr, "Sorry, but 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, "Sorry, you can only specify either oid or table\n"); exit(1); } my_opts->getoid = 1; sscanf(optarg, "%i", &my_opts->_oid); break; /* host to connect to */ case 'H': my_opts->remotehost = 1; 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); break; /* username */ case 'U': my_opts->remoteuser = 1; sscanf(optarg, "%s", my_opts->_username); break; /* password */ case 'P': my_opts->remotepass = 1; sscanf(optarg, "%s", my_opts->_password); break; /* display system tables */ case 'x': my_opts->systables = 1; break; /* help! (ugly in code for easier editing) */ case '?': case 'h': fprintf(stderr, "\n\ Usage: pg_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\ -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\n\ "); exit(1); break; } } } /* establish connection with database. */ PGconn * sql_conn(const char *dbName, struct options * my_opts) { char *pghost, *pgport; char *pgoptions, *pgtty; char *pguser, *pgpass; PGconn *conn; pghost = NULL; pgport = NULL; pgoptions = NULL; /* special options to start up the backend * server */ pgtty = NULL; /* debugging tty for the backend server */ pguser = NULL; pgpass = NULL; /* override the NULLs with the user params if passed */ if (my_opts->remotehost) { pghost = (char *) malloc(128); sscanf(my_opts->_hostname, "%s", pghost); } if (my_opts->remoteport) { pgport = (char *) malloc(6); sscanf(my_opts->_port, "%s", pgport); } if (my_opts->remoteuser) { pguser = (char *) malloc(128); sscanf(my_opts->_username, "%s", pguser); } if (my_opts->remotepass) { pgpass = (char *) malloc(128); sscanf(my_opts->_password, "%s", pgpass); } /* login */ conn = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName, pguser, pgpass); /* deal with errors */ if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database '%s' failed.\n", dbName); fprintf(stderr, "%s", PQerrorMessage(conn)); PQfinish(conn); exit(1); } /* free data structures: not strictly necessary */ if (pghost != NULL) free(pghost); if (pgport != NULL) free(pgport); if (pguser != NULL) free(pguser); if (pgpass != NULL) free(pgpass); /* return the conn if good */ return conn; } /* If the sql_ command has an error, this function looks up the error number and prints it out. */ void sql_exec_error(int error_number) { fprintf(stderr, "Error number %i.\n", error_number); switch (error_number) { case 3: fprintf(stderr, "Error: PGRES_COPY_OUT\n"); break; case 4: fprintf(stderr, "Error: PGRES_COPY_IN\n"); break; case 5: fprintf(stderr, "Error: PGRES_BAD_RESPONCE\n"); break; case 6: fprintf(stderr, "Error: PGRES_NONFATAL_ERROR\n"); break; case 7: fprintf(stderr, "Error: PGRES_FATAL_ERROR\n"); break; } } /* actual code to make call to the database and print the output data */ int sql_exec(PGconn *conn, const char *todo, int match) { PGresult *res; int numbfields; int error_number; int i, len; /* make the call */ res = PQexec(conn, todo); /* check and deal with errors */ if (!res || PQresultStatus(res) > 2) { error_number = PQresultStatus(res); fprintf(stderr, "There was an error in the SQL command:\n%s\n", todo); sql_exec_error(error_number); fprintf(stderr, "PQerrorMessage = %s\n", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); exit(-1); } /* get the number of fields */ numbfields = PQntuples(res); /* if we only expect 1 and there mode than, return -2 */ if (match == 1 && numbfields > 1) return -2; /* return -1 if there aren't any returns */ if (match == 1 && numbfields < 1) return -1; /* for each row, dump the information */ for (i = 0; i < numbfields; i++) { len = strlen(PQgetvalue(res, i, 0)); fprintf(stdout, "%-6s = %s\n", PQgetvalue(res, i, 0), PQgetvalue(res, i, 1)); } /* clean the PGconn once done */ PQclear(res); return 0; } /* dump all databases known by the system table */ void sql_exec_dumpdb(PGconn *conn) { char todo[1024]; /* get the oid and database name from the system pg_database table */ sprintf(todo, "select oid,datname from pg_database"); sql_exec(conn, todo, 0); } /* display all tables in whatever db we are connected to. don't display the system tables by default */ void sql_exec_dumptable(PGconn *conn, int systables) { char todo[1024]; /* don't exclude the systables if this is set */ if (systables == 1) sprintf(todo, "select relfilenode,relname from pg_class order by relname"); else sprintf(todo, "select relfilenode,relname from pg_class where relname not like 'pg_%%' order by relname"); sql_exec(conn, todo, 0); } /* display the oid for a given tablename for whatever db we are connected to. do we want to allow %bar% in the search? Not now. */ void sql_exec_searchtable(PGconn *conn, const char *tablename) { int returnvalue; char todo[1024]; /* get the oid and tablename where the name matches tablename */ sprintf(todo, "select relfilenode,relname from pg_class where relname = '%s'", tablename); returnvalue = sql_exec(conn, todo, 1); /* deal with the return errors */ if (returnvalue == -1) printf("No tables with that name found\n"); if (returnvalue == -2) printf("VERY scary: more than one table with that name found!!\n"); } /* same as above */ void sql_exec_searchoid(PGconn *conn, int oid) { int returnvalue; char todo[1024]; sprintf(todo, "select relfilenode,relname from pg_class where oid = %i", oid); returnvalue = sql_exec(conn, todo, 1); if (returnvalue == -1) printf("No tables with that oid found\n"); if (returnvalue == -2) printf("VERY scary: more than one table with that oid found!!\n"); } int main(int argc, char **argv) { struct options *my_opts; PGconn *pgconn; my_opts = (struct options *) malloc(sizeof(struct options)); /* parse the opts */ get_opts(argc, argv, my_opts); /* display all the tables in the database */ if (my_opts->getdatabase & my_opts->gettable) { printf("Oid of table %s from database \"%s\":\n", my_opts->_tbname, my_opts->_dbname); printf("_______________________________\n"); pgconn = sql_conn(my_opts->_dbname, my_opts); sql_exec_searchtable(pgconn, my_opts->_tbname); PQfinish(pgconn); exit(1); } /* search for the tablename of the given OID */ if (my_opts->getdatabase & my_opts->getoid) { printf("Tablename of oid %i from database \"%s\":\n", my_opts->_oid, my_opts->_dbname); printf("---------------------------------\n"); pgconn = sql_conn(my_opts->_dbname, my_opts); sql_exec_searchoid(pgconn, my_opts->_oid); PQfinish(pgconn); exit(1); } /* search for the oid for the given tablename */ if (my_opts->getdatabase) { printf("All tables from database \"%s\":\n", my_opts->_dbname); printf("---------------------------------\n"); pgconn = sql_conn(my_opts->_dbname, my_opts); sql_exec_dumptable(pgconn, my_opts->systables); PQfinish(pgconn); exit(1); } /* display all the databases for the server we are connected to.. */ printf("All databases:\n"); printf("---------------------------------\n"); pgconn = sql_conn("template1", my_opts); sql_exec_dumpdb(pgconn); PQfinish(pgconn); exit(0); }