int main(int argc, char** argv) { int c, i, optindex; static struct option long_options[] = { {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"username", required_argument, NULL, 'U'}, {"help", no_argument, NULL, '?'}, {NULL, 0, NULL, 0} }; if (argc == 1 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-?")) help(); while ((c = getopt_long(argc, argv, "h:p:U:", long_options, &optindex)) != -1) { switch (c) { case 'h': /* host for tranlsting oids */ pghost = optarg; break; case 'p': /* port for translating oids */ pgport = optarg; break; case 'U': /* username for translating oids */ username = optarg; break; default: fprintf(stderr, "Try \"changetrackingdump --help\" for more information.\n"); exit(1); } } if(pghost) { conn = DBConnect(pghost, pgport, "template1", username); } dbQry = createPQExpBuffer(); for (i = optind; i < argc; i++) { char *fname = argv[i]; logFd = open(fname, O_RDONLY | PG_BINARY, 0); if (logFd < 0) { perror(fname); continue; } dumpChangeTracking(fname); } exit_gracefuly(0); /* just to avoid a warning */ return 0; }
/* * Atempt to get the name of relation and copy to relName * (if there's a database connection and the reloid changed) * Copy a string with oid if not found */ static void getRelName(uint32 relid) { resetPQExpBuffer(dbQry); if((conn) && (lastDbConn) && (lastRelOid != relid)) { PQclear(res); /* Try the relfilenode and oid just in case the filenode has changed If it has changed more than once we can't translate it's name */ appendPQExpBuffer(dbQry, "SELECT relname, oid FROM pg_class WHERE relfilenode = %i OR oid = %i", relid, relid); res = PQexec(lastDbConn, dbQry->data); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "SELECT FAILED: %s", PQerrorMessage(conn)); PQclear(res); exit_gracefuly(1); } resetPQExpBuffer(dbQry); lastRelOid = relid; if(PQntuples(res) > 0) { strcpy(relName, PQgetvalue(res, 0, 0)); /* copy the oid since it could be different from relfilenode */ lastRelOid = (uint32) atoi(PQgetvalue(res, 0, 1)); return; } } else if(lastRelOid == relid) return; /* Didn't find the name, return string with oid */ sprintf(relName, "%u", relid); return; }
/* * Atempt to get the name of database (if there's a database connection) */ static void getDbName(uint32 db) { resetPQExpBuffer(dbQry); if((conn) && (lastDbOid != db)) { PQclear(res); appendPQExpBuffer(dbQry, "SELECT datname FROM pg_database WHERE oid = %i", db); res = PQexec(conn, dbQry->data); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "SELECT FAILED: %s", PQerrorMessage(conn)); PQclear(res); exit_gracefuly(1); } resetPQExpBuffer(dbQry); lastDbOid = db; if(PQntuples(res) > 0) { strcpy(dbName, PQgetvalue(res, 0, 0)); // Database changed makes new connection PQfinish(lastDbConn); lastDbConn = DBConnect(pghost, pgport, dbName, username); return; } } else if(lastDbOid == db) return; /* Didn't find the name, return string with oid */ sprintf(dbName, "%u", db); return; }
/* * Atempt to read the name of tablespace into lastSpcName * (if there's a database connection and the oid changed since lastSpcOid) */ static void getSpaceName(uint32 space) { resetPQExpBuffer(dbQry); if((conn) && (lastSpcOid != space)) { PQclear(res); appendPQExpBuffer(dbQry, "SELECT spcname FROM pg_tablespace WHERE oid = %i", space); res = PQexec(conn, dbQry->data); if (PQresultStatus(res) != PGRES_TUPLES_OK) { fprintf(stderr, "SELECT FAILED: %s", PQerrorMessage(conn)); PQclear(res); exit_gracefuly(1); } resetPQExpBuffer(dbQry); lastSpcOid = space; if(PQntuples(res) > 0) { strcpy(spaceName, PQgetvalue(res, 0, 0)); return; } } else if(lastSpcOid == space) return; /* Didn't find the name, return string with oid */ sprintf(spaceName, "%u", space); return; }
/* * Open a database connection */ static PGconn * DBConnect(const char *host, const char *port, char *database, const char *user) { char *password = NULL; char *password_prompt = NULL; bool need_pass; PGconn *conn = NULL; /* loop until we have a password if requested by backend */ do { need_pass = false; conn = PQsetdbLogin(host, port, NULL, NULL, database, user, password); if (PQstatus(conn) == CONNECTION_BAD && strcmp(PQerrorMessage(conn), PQnoPasswordSupplied) == 0 && !feof(stdin)) { PQfinish(conn); need_pass = true; free(password); password = NULL; printf("\nPassword: "******"Connection to database failed: %s", PQerrorMessage(conn)); exit_gracefuly(1); } if (password) free(password); return conn; }
int main(int argc, char** argv) { int c, i, optindex; bool oid2name = false; bool oid2name_gen = false; char *pghost = NULL; /* connection host */ char *pgport = NULL; /* connection port */ char *pguser = NULL; /* connection username */ char *dbname = NULL; /* connection database name */ char *oid2name_file = NULL; static struct option long_options[] = { {"transactions", no_argument, NULL, 't'}, {"statements", no_argument, NULL, 's'}, {"stats", no_argument, NULL, 'S'}, {"hide-timestamps", no_argument, NULL, 'T'}, {"rmid", required_argument, NULL, 'r'}, {"oid2name", no_argument, NULL, 'n'}, {"gen_oid2name", no_argument, NULL, 'g'}, {"xid", required_argument, NULL, 'x'}, {"host", required_argument, NULL, 'h'}, {"port", required_argument, NULL, 'p'}, {"user", required_argument, NULL, 'U'}, {"dbname", required_argument, NULL, 'd'}, {"file", required_argument, NULL, 'f'}, {"help", no_argument, NULL, '?'}, {NULL, 0, NULL, 0} }; if (argc == 1 || !strcmp(argv[1], "--help") || !strcmp(argv[1], "-?")) help(); pghost = strdup("localhost"); pgport = strdup("5432"); pguser = getenv("USER"); dbname = strdup("postgres"); oid2name_file = strdup(DATADIR "/contrib/" OID2NAME_FILE); while ((c = getopt_long(argc, argv, "sStTngr:x:h:p:U:d:f:", long_options, &optindex)) != -1) { switch (c) { case 's': /* show statements */ statements = true; break; case 'S': /* show statistics */ enable_stats = true; enable_rmgr_dump(false); break; case 't': transactions = true; /* show only transactions */ break; case 'T': /* hide timestamps (used for testing) */ hideTimestamps = true; break; case 'n': oid2name = true; break; case 'g': oid2name_gen = true; break; case 'r': /* output only rmid passed */ rmid = atoi(optarg); break; case 'x': /* output only xid passed */ xid = atoi(optarg); break; case 'h': /* host for tranlsting oids */ pghost = optarg; break; case 'p': /* port for translating oids */ pgport = optarg; break; case 'U': /* username for translating oids */ pguser = optarg; break; case 'd': /* database name for translating oids */ dbname = optarg; break; case 'f': oid2name_file = optarg; break; default: fprintf(stderr, "Try \"xlogdump --help\" for more information.\n"); exit(1); } } if (statements && transactions) { fprintf(stderr, "options \"statements\" (-s) and \"transactions\" (-t) cannot be used together\n"); exit(1); } if (rmid>=0 && transactions) { fprintf(stderr, "options \"rmid\" (-r) and \"transactions\" (-t) cannot be used together\n"); exit(1); } if (oid2name) { if ( !oid2name_from_file(oid2name_file) ) { /* if not found in share/contrib, read from the cwd. */ oid2name_from_file(OID2NAME_FILE); } if ( !DBConnect(pghost, pgport, dbname, pguser) ) fprintf(stderr, "WARNING: Database connection to lookup the system catalog is not available.\n"); } /* * Generate an oid2name cache file. */ if (oid2name_gen) { if ( !DBConnect(pghost, pgport, dbname, pguser) ) exit_gracefuly(1); if (oid2name_to_file("oid2name.out")) { printf("oid2name.out successfully created.\n"); } exit_gracefuly(0); } for (i = optind; i < argc; i++) { char *fname = argv[i]; logFd = open(fname, O_RDONLY | PG_BINARY, 0); if (logFd < 0) { perror(fname); continue; } dumpXLog(fname); } if (enable_stats) print_xlog_stats(); exit_gracefuly(0); /* just to avoid a warning */ return 0; }