mirror of https://github.com/postgres/postgres
- Support for direct DB connection in pg_restore - Fixes in support for --insert flag - pg_dump now outputs in modified OID order - various other bug fixesREL7_1_STABLE
parent
0143d391c6
commit
e8f69be054
@ -1,125 +1,154 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_backup.h |
||||
* |
||||
* Public interface to the pg_dump archiver routines. |
||||
* |
||||
* See the headers to pg_restore for more details. |
||||
* |
||||
* Copyright (c) 2000, Philip Warner |
||||
* Rights are granted to use this software in any way so long |
||||
* as this notice is not removed. |
||||
* |
||||
* The author is not responsible for loss or damages that may |
||||
* result from it's use. |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* |
||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au |
||||
* |
||||
* Initial version.
|
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#ifndef PG_BACKUP__ |
||||
|
||||
#include "config.h" |
||||
#include "c.h" |
||||
|
||||
#define PG_BACKUP__ |
||||
|
||||
typedef enum _archiveFormat { |
||||
archUnknown = 0, |
||||
archCustom = 1, |
||||
archFiles = 2, |
||||
archTar = 3, |
||||
archPlainText = 4 |
||||
} ArchiveFormat; |
||||
|
||||
/*
|
||||
* We may want to have so user-readbale data, but in the mean |
||||
* time this gives us some abstraction and type checking. |
||||
*/ |
||||
typedef struct _Archive { |
||||
/* Nothing here */ |
||||
} Archive; |
||||
|
||||
typedef int (*DataDumperPtr)(Archive* AH, char* oid, void* userArg); |
||||
|
||||
typedef struct _restoreOptions { |
||||
int dataOnly; |
||||
int dropSchema; |
||||
char *filename; |
||||
int schemaOnly; |
||||
int verbose; |
||||
int aclsSkip; |
||||
int tocSummary; |
||||
char *tocFile; |
||||
int oidOrder; |
||||
int origOrder; |
||||
int rearrange; |
||||
int format; |
||||
char *formatName; |
||||
|
||||
int selTypes; |
||||
int selIndex; |
||||
int selFunction; |
||||
int selTrigger; |
||||
int selTable; |
||||
char *indexNames; |
||||
char *functionNames; |
||||
char *tableNames; |
||||
char *triggerNames; |
||||
|
||||
int *idWanted; |
||||
int limitToList; |
||||
int compression; |
||||
|
||||
} RestoreOptions; |
||||
|
||||
/*
|
||||
* Main archiver interface. |
||||
*/ |
||||
|
||||
/* Called to add a TOC entry */ |
||||
extern void ArchiveEntry(Archive* AH, const char* oid, const char* name, |
||||
const char* desc, const char* (deps[]), const char* defn, |
||||
const char* dropStmt, const char* owner,
|
||||
DataDumperPtr dumpFn, void* dumpArg); |
||||
|
||||
/* Called to write *data* to the archive */ |
||||
extern int WriteData(Archive* AH, const void* data, int dLen); |
||||
|
||||
extern void CloseArchive(Archive* AH); |
||||
|
||||
extern void RestoreArchive(Archive* AH, RestoreOptions *ropt); |
||||
|
||||
/* Open an existing archive */ |
||||
extern Archive* OpenArchive(const char* FileSpec, ArchiveFormat fmt); |
||||
|
||||
/* Create a new archive */ |
||||
extern Archive* CreateArchive(const char* FileSpec, ArchiveFormat fmt, int compression); |
||||
|
||||
/* The --list option */ |
||||
extern void PrintTOCSummary(Archive* AH, RestoreOptions *ropt); |
||||
|
||||
extern RestoreOptions* NewRestoreOptions(void); |
||||
|
||||
/* Rearrange TOC entries */ |
||||
extern void MoveToStart(Archive* AH, char *oType); |
||||
extern void MoveToEnd(Archive* AH, char *oType);
|
||||
extern void SortTocByOID(Archive* AH); |
||||
extern void SortTocByID(Archive* AH); |
||||
extern void SortTocFromFile(Archive* AH, RestoreOptions *ropt); |
||||
|
||||
/* Convenience functions used only when writing DATA */ |
||||
extern int archputs(const char *s, Archive* AH); |
||||
extern int archputc(const char c, Archive* AH); |
||||
extern int archprintf(Archive* AH, const char *fmt, ...); |
||||
|
||||
#endif |
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_backup.h |
||||
* |
||||
* Public interface to the pg_dump archiver routines. |
||||
* |
||||
* See the headers to pg_restore for more details. |
||||
* |
||||
* Copyright (c) 2000, Philip Warner |
||||
* Rights are granted to use this software in any way so long |
||||
* as this notice is not removed. |
||||
* |
||||
* The author is not responsible for loss or damages that may |
||||
* result from it's use. |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* |
||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au |
||||
* |
||||
* Initial version.
|
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#ifndef PG_BACKUP__ |
||||
|
||||
#include "config.h" |
||||
#include "c.h" |
||||
|
||||
#define PG_BACKUP__ |
||||
|
||||
#include "postgres.h" |
||||
#include "libpq-fe.h" |
||||
|
||||
typedef enum _archiveFormat { |
||||
archUnknown = 0, |
||||
archCustom = 1, |
||||
archFiles = 2, |
||||
archTar = 3, |
||||
archNull = 4 |
||||
} ArchiveFormat; |
||||
|
||||
/*
|
||||
* We may want to have so user-readbale data, but in the mean |
||||
* time this gives us some abstraction and type checking. |
||||
*/ |
||||
typedef struct _Archive { |
||||
int verbose; |
||||
/* The rest is private */ |
||||
} Archive; |
||||
|
||||
typedef int (*DataDumperPtr)(Archive* AH, char* oid, void* userArg); |
||||
|
||||
typedef struct _restoreOptions { |
||||
int dataOnly; |
||||
int dropSchema; |
||||
char *filename; |
||||
int schemaOnly; |
||||
int verbose; |
||||
int aclsSkip; |
||||
int tocSummary; |
||||
char *tocFile; |
||||
int oidOrder; |
||||
int origOrder; |
||||
int rearrange; |
||||
int format; |
||||
char *formatName; |
||||
|
||||
int selTypes; |
||||
int selIndex; |
||||
int selFunction; |
||||
int selTrigger; |
||||
int selTable; |
||||
char *indexNames; |
||||
char *functionNames; |
||||
char *tableNames; |
||||
char *triggerNames; |
||||
|
||||
int useDB; |
||||
char *dbname; |
||||
char *pgport; |
||||
char *pghost; |
||||
int ignoreVersion; |
||||
int requirePassword; |
||||
|
||||
int *idWanted; |
||||
int limitToList; |
||||
int compression; |
||||
|
||||
} RestoreOptions; |
||||
|
||||
/*
|
||||
* Main archiver interface. |
||||
*/ |
||||
|
||||
extern void exit_horribly(Archive *AH, const char *fmt, ...); |
||||
|
||||
/* Lets the archibe know we have a DB connection to shutdown if it dies */ |
||||
|
||||
PGconn* ConnectDatabase(Archive *AH, |
||||
const char* dbname, |
||||
const char* pghost, |
||||
const char* pgport, |
||||
const int reqPwd, |
||||
const int ignoreVersion); |
||||
|
||||
|
||||
/* Called to add a TOC entry */ |
||||
extern void ArchiveEntry(Archive* AH, const char* oid, const char* name, |
||||
const char* desc, const char* (deps[]), const char* defn, |
||||
const char* dropStmt, const char* copyStmt, const char* owner,
|
||||
DataDumperPtr dumpFn, void* dumpArg); |
||||
|
||||
/* Called to write *data* to the archive */ |
||||
extern int WriteData(Archive* AH, const void* data, int dLen); |
||||
|
||||
//extern int StartBlobs(Archive* AH);
|
||||
//extern int EndBlobs(Archive* AH);
|
||||
extern int StartBlob(Archive* AH, int oid); |
||||
extern int EndBlob(Archive* AH, int oid); |
||||
|
||||
extern void CloseArchive(Archive* AH); |
||||
|
||||
extern void RestoreArchive(Archive* AH, RestoreOptions *ropt); |
||||
|
||||
/* Open an existing archive */ |
||||
extern Archive* OpenArchive(const char* FileSpec, const ArchiveFormat fmt); |
||||
|
||||
/* Create a new archive */ |
||||
extern Archive* CreateArchive(const char* FileSpec, const ArchiveFormat fmt,
|
||||
const int compression); |
||||
|
||||
/* The --list option */ |
||||
extern void PrintTOCSummary(Archive* AH, RestoreOptions *ropt); |
||||
|
||||
extern RestoreOptions* NewRestoreOptions(void); |
||||
|
||||
/* Rearrange TOC entries */ |
||||
extern void MoveToStart(Archive* AH, char *oType); |
||||
extern void MoveToEnd(Archive* AH, char *oType);
|
||||
extern void SortTocByOID(Archive* AH); |
||||
extern void SortTocByID(Archive* AH); |
||||
extern void SortTocFromFile(Archive* AH, RestoreOptions *ropt); |
||||
|
||||
/* Convenience functions used only when writing DATA */ |
||||
extern int archputs(const char *s, Archive* AH); |
||||
extern int archputc(const char c, Archive* AH); |
||||
extern int archprintf(Archive* AH, const char *fmt, ...); |
||||
|
||||
#endif |
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,303 +1,483 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_backup_files.c |
||||
* |
||||
* This file is copied from the 'custom' format file, but dumps data into |
||||
* separate files, and the TOC into the 'main' file. |
||||
* |
||||
* IT IS FOR DEMONSTRATION PURPOSES ONLY. |
||||
* |
||||
* (and could probably be used as a basis for writing a tar file) |
||||
* |
||||
* See the headers to pg_restore for more details. |
||||
* |
||||
* Copyright (c) 2000, Philip Warner |
||||
* Rights are granted to use this software in any way so long |
||||
* as this notice is not removed. |
||||
* |
||||
* The author is not responsible for loss or damages that may |
||||
* result from it's use. |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* |
||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au |
||||
* |
||||
* Initial version.
|
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "pg_backup.h" |
||||
#include "pg_backup_archiver.h" |
||||
|
||||
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te); |
||||
static void _StartData(ArchiveHandle* AH, TocEntry* te); |
||||
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen); |
||||
static void _EndData(ArchiveHandle* AH, TocEntry* te); |
||||
static int _WriteByte(ArchiveHandle* AH, const int i); |
||||
static int _ReadByte(ArchiveHandle* ); |
||||
static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len); |
||||
static int _ReadBuf(ArchiveHandle* AH, void* buf, int len); |
||||
static void _CloseArchive(ArchiveHandle* AH); |
||||
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt); |
||||
static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te); |
||||
static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te); |
||||
static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te); |
||||
|
||||
|
||||
typedef struct { |
||||
int hasSeek; |
||||
int filePos; |
||||
} lclContext; |
||||
|
||||
typedef struct { |
||||
#ifdef HAVE_LIBZ |
||||
gzFile *FH; |
||||
#else |
||||
FILE *FH; |
||||
#endif |
||||
char *filename; |
||||
} lclTocEntry; |
||||
|
||||
/*
|
||||
* Initializer |
||||
*/ |
||||
void InitArchiveFmt_Files(ArchiveHandle* AH)
|
||||
{ |
||||
lclContext* ctx; |
||||
|
||||
/* Assuming static functions, this can be copied for each format. */ |
||||
AH->ArchiveEntryPtr = _ArchiveEntry; |
||||
AH->StartDataPtr = _StartData; |
||||
AH->WriteDataPtr = _WriteData; |
||||
AH->EndDataPtr = _EndData; |
||||
AH->WriteBytePtr = _WriteByte; |
||||
AH->ReadBytePtr = _ReadByte; |
||||
AH->WriteBufPtr = _WriteBuf; |
||||
AH->ReadBufPtr = _ReadBuf; |
||||
AH->ClosePtr = _CloseArchive; |
||||
AH->PrintTocDataPtr = _PrintTocData; |
||||
AH->ReadExtraTocPtr = _ReadExtraToc; |
||||
AH->WriteExtraTocPtr = _WriteExtraToc; |
||||
AH->PrintExtraTocPtr = _PrintExtraToc; |
||||
|
||||
/*
|
||||
* Set up some special context used in compressing data. |
||||
*/ |
||||
ctx = (lclContext*)malloc(sizeof(lclContext)); |
||||
AH->formatData = (void*)ctx; |
||||
ctx->filePos = 0; |
||||
|
||||
/*
|
||||
* Now open the TOC file |
||||
*/ |
||||
if (AH->mode == archModeWrite) { |
||||
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) { |
||||
AH->FH = fopen(AH->fSpec, PG_BINARY_W); |
||||
} else { |
||||
AH->FH = stdout; |
||||
} |
||||
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0); |
||||
|
||||
if (AH->compression < 0 || AH->compression > 9) { |
||||
AH->compression = Z_DEFAULT_COMPRESSION; |
||||
} |
||||
|
||||
|
||||
} else { |
||||
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) { |
||||
AH->FH = fopen(AH->fSpec, PG_BINARY_R); |
||||
} else { |
||||
AH->FH = stdin; |
||||
} |
||||
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0); |
||||
|
||||
ReadHead(AH); |
||||
ReadToc(AH); |
||||
fclose(AH->FH); /* Nothing else in the file... */ |
||||
} |
||||
|
||||
} |
||||
|
||||
/*
|
||||
* - Start a new TOC entry |
||||
* Setup the output file name. |
||||
*/ |
||||
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te)
|
||||
{ |
||||
lclTocEntry* ctx; |
||||
char fn[1024]; |
||||
|
||||
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry)); |
||||
if (te->dataDumper) { |
||||
#ifdef HAVE_LIBZ |
||||
if (AH->compression == 0) { |
||||
sprintf(fn, "%d.dat", te->id); |
||||
} else { |
||||
sprintf(fn, "%d.dat.gz", te->id); |
||||
} |
||||
#else |
||||
sprintf(fn, "%d.dat", te->id); |
||||
#endif |
||||
ctx->filename = strdup(fn); |
||||
} else { |
||||
ctx->filename = NULL; |
||||
ctx->FH = NULL; |
||||
} |
||||
te->formatData = (void*)ctx; |
||||
} |
||||
|
||||
static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData; |
||||
|
||||
if (ctx->filename) { |
||||
WriteStr(AH, ctx->filename); |
||||
} else { |
||||
WriteStr(AH, ""); |
||||
} |
||||
} |
||||
|
||||
static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData; |
||||
|
||||
if (ctx == NULL) { |
||||
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry)); |
||||
te->formatData = (void*)ctx; |
||||
} |
||||
|
||||
ctx->filename = ReadStr(AH); |
||||
if (strlen(ctx->filename) == 0) { |
||||
free(ctx->filename); |
||||
ctx->filename = NULL; |
||||
} |
||||
ctx->FH = NULL; |
||||
} |
||||
|
||||
static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData; |
||||
|
||||
ahprintf(AH, "-- File: %s\n", ctx->filename); |
||||
} |
||||
|
||||
static void _StartData(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*)te->formatData; |
||||
char fmode[10]; |
||||
|
||||
sprintf(fmode, "wb%d", AH->compression); |
||||
|
||||
#ifdef HAVE_LIBZ |
||||
tctx->FH = gzopen(tctx->filename, fmode); |
||||
#else |
||||
tctx->FH = fopen(tctx->filename, PG_BINARY_W); |
||||
#endif |
||||
} |
||||
|
||||
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*)AH->currToc->formatData; |
||||
|
||||
GZWRITE((void*)data, 1, dLen, tctx->FH); |
||||
|
||||
return dLen; |
||||
} |
||||
|
||||
static void _EndData(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*) te->formatData; |
||||
|
||||
/* Close the file */ |
||||
GZCLOSE(tctx->FH); |
||||
tctx->FH = NULL; |
||||
} |
||||
|
||||
/*
|
||||
* Print data for a given TOC entry |
||||
*/ |
||||
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*) te->formatData; |
||||
char buf[4096]; |
||||
int cnt; |
||||
|
||||
if (!tctx->filename)
|
||||
return; |
||||
|
||||
#ifdef HAVE_LIBZ |
||||
AH->FH = gzopen(tctx->filename,"rb"); |
||||
#else |
||||
AH->FH = fopen(tctx->filename,PG_BINARY_R); |
||||
#endif |
||||
|
||||
ahprintf(AH, "--\n-- Data for TOC Entry ID %d (OID %s) %s %s\n--\n\n", |
||||
te->id, te->oid, te->desc, te->name); |
||||
|
||||
while ( (cnt = GZREAD(buf, 1, 4096, AH->FH)) > 0) { |
||||
ahwrite(buf, 1, cnt, AH); |
||||
} |
||||
|
||||
GZCLOSE(AH->FH); |
||||
|
||||
ahprintf(AH, "\n\n"); |
||||
} |
||||
|
||||
static int _WriteByte(ArchiveHandle* AH, const int i) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
|
||||
res = fputc(i, AH->FH); |
||||
if (res != EOF) { |
||||
ctx->filePos += 1; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
static int _ReadByte(ArchiveHandle* AH) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
|
||||
res = fgetc(AH->FH); |
||||
if (res != EOF) { |
||||
ctx->filePos += 1; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
res = fwrite(buf, 1, len, AH->FH); |
||||
ctx->filePos += res; |
||||
return res; |
||||
} |
||||
|
||||
static int _ReadBuf(ArchiveHandle* AH, void* buf, int len) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
res = fread(buf, 1, len, AH->FH); |
||||
ctx->filePos += res; |
||||
return res; |
||||
} |
||||
|
||||
static void _CloseArchive(ArchiveHandle* AH) |
||||
{ |
||||
if (AH->mode == archModeWrite) { |
||||
WriteHead(AH); |
||||
WriteToc(AH); |
||||
fclose(AH->FH); |
||||
WriteDataChunks(AH); |
||||
} |
||||
|
||||
AH->FH = NULL;
|
||||
} |
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_backup_files.c |
||||
* |
||||
* This file is copied from the 'custom' format file, but dumps data into |
||||
* separate files, and the TOC into the 'main' file. |
||||
* |
||||
* IT IS FOR DEMONSTRATION PURPOSES ONLY. |
||||
* |
||||
* (and could probably be used as a basis for writing a tar file) |
||||
* |
||||
* See the headers to pg_restore for more details. |
||||
* |
||||
* Copyright (c) 2000, Philip Warner |
||||
* Rights are granted to use this software in any way so long |
||||
* as this notice is not removed. |
||||
* |
||||
* The author is not responsible for loss or damages that may |
||||
* result from it's use. |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* |
||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au |
||||
* |
||||
* Initial version.
|
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include "pg_backup.h" |
||||
#include "pg_backup_archiver.h" |
||||
|
||||
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te); |
||||
static void _StartData(ArchiveHandle* AH, TocEntry* te); |
||||
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen); |
||||
static void _EndData(ArchiveHandle* AH, TocEntry* te); |
||||
static int _WriteByte(ArchiveHandle* AH, const int i); |
||||
static int _ReadByte(ArchiveHandle* ); |
||||
static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len); |
||||
static int _ReadBuf(ArchiveHandle* AH, void* buf, int len); |
||||
static void _CloseArchive(ArchiveHandle* AH); |
||||
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt); |
||||
static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te); |
||||
static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te); |
||||
static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te); |
||||
|
||||
static void _StartBlobs(ArchiveHandle* AH, TocEntry* te); |
||||
static void _StartBlob(ArchiveHandle* AH, TocEntry* te, int oid); |
||||
static void _EndBlob(ArchiveHandle* AH, TocEntry* te, int oid); |
||||
static void _EndBlobs(ArchiveHandle* AH, TocEntry* te); |
||||
|
||||
#define K_STD_BUF_SIZE 1024 |
||||
|
||||
typedef struct { |
||||
int hasSeek; |
||||
int filePos; |
||||
FILE *blobToc; |
||||
} lclContext; |
||||
|
||||
typedef struct { |
||||
#ifdef HAVE_LIBZ |
||||
gzFile *FH; |
||||
#else |
||||
FILE *FH; |
||||
#endif |
||||
char *filename; |
||||
} lclTocEntry; |
||||
|
||||
static char* progname = "Archiver(files)"; |
||||
static void _LoadBlobs(ArchiveHandle* AH, RestoreOptions *ropt); |
||||
static void _getBlobTocEntry(ArchiveHandle* AH, int *oid, char *fname); |
||||
|
||||
/*
|
||||
* Initializer |
||||
*/ |
||||
void InitArchiveFmt_Files(ArchiveHandle* AH)
|
||||
{ |
||||
lclContext* ctx; |
||||
|
||||
/* Assuming static functions, this can be copied for each format. */ |
||||
AH->ArchiveEntryPtr = _ArchiveEntry; |
||||
AH->StartDataPtr = _StartData; |
||||
AH->WriteDataPtr = _WriteData; |
||||
AH->EndDataPtr = _EndData; |
||||
AH->WriteBytePtr = _WriteByte; |
||||
AH->ReadBytePtr = _ReadByte; |
||||
AH->WriteBufPtr = _WriteBuf; |
||||
AH->ReadBufPtr = _ReadBuf; |
||||
AH->ClosePtr = _CloseArchive; |
||||
AH->PrintTocDataPtr = _PrintTocData; |
||||
AH->ReadExtraTocPtr = _ReadExtraToc; |
||||
AH->WriteExtraTocPtr = _WriteExtraToc; |
||||
AH->PrintExtraTocPtr = _PrintExtraToc; |
||||
|
||||
AH->StartBlobsPtr = _StartBlobs; |
||||
AH->StartBlobPtr = _StartBlob; |
||||
AH->EndBlobPtr = _EndBlob; |
||||
AH->EndBlobsPtr = _EndBlobs; |
||||
|
||||
/*
|
||||
* Set up some special context used in compressing data. |
||||
*/ |
||||
ctx = (lclContext*)malloc(sizeof(lclContext)); |
||||
AH->formatData = (void*)ctx; |
||||
ctx->filePos = 0; |
||||
|
||||
/*
|
||||
* Now open the TOC file |
||||
*/ |
||||
if (AH->mode == archModeWrite) { |
||||
|
||||
fprintf(stderr, "\n*************************************************************\n" |
||||
"* WARNING: This format is for demonstration purposes. It is *\n" |
||||
"* not intended for general use. Files will be dumped *\n" |
||||
"* into the current working directory. *\n" |
||||
"***************************************************************\n\n"); |
||||
|
||||
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) { |
||||
AH->FH = fopen(AH->fSpec, PG_BINARY_W); |
||||
} else { |
||||
AH->FH = stdout; |
||||
} |
||||
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0); |
||||
|
||||
if (AH->compression < 0 || AH->compression > 9) { |
||||
AH->compression = Z_DEFAULT_COMPRESSION; |
||||
} |
||||
|
||||
|
||||
} else { /* Read Mode */ |
||||
|
||||
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) { |
||||
AH->FH = fopen(AH->fSpec, PG_BINARY_R); |
||||
} else { |
||||
AH->FH = stdin; |
||||
} |
||||
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0); |
||||
|
||||
ReadHead(AH); |
||||
ReadToc(AH); |
||||
fclose(AH->FH); /* Nothing else in the file... */ |
||||
} |
||||
|
||||
} |
||||
|
||||
/*
|
||||
* - Start a new TOC entry |
||||
* Setup the output file name. |
||||
*/ |
||||
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te)
|
||||
{ |
||||
lclTocEntry* ctx; |
||||
char fn[K_STD_BUF_SIZE]; |
||||
|
||||
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry)); |
||||
if (te->dataDumper) { |
||||
#ifdef HAVE_LIBZ |
||||
if (AH->compression == 0) { |
||||
sprintf(fn, "%d.dat", te->id); |
||||
} else { |
||||
sprintf(fn, "%d.dat.gz", te->id); |
||||
} |
||||
#else |
||||
sprintf(fn, "%d.dat", te->id); |
||||
#endif |
||||
ctx->filename = strdup(fn); |
||||
} else { |
||||
ctx->filename = NULL; |
||||
ctx->FH = NULL; |
||||
} |
||||
te->formatData = (void*)ctx; |
||||
} |
||||
|
||||
static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData; |
||||
|
||||
if (ctx->filename) { |
||||
WriteStr(AH, ctx->filename); |
||||
} else { |
||||
WriteStr(AH, ""); |
||||
} |
||||
} |
||||
|
||||
static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData; |
||||
|
||||
if (ctx == NULL) { |
||||
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry)); |
||||
te->formatData = (void*)ctx; |
||||
} |
||||
|
||||
ctx->filename = ReadStr(AH); |
||||
if (strlen(ctx->filename) == 0) { |
||||
free(ctx->filename); |
||||
ctx->filename = NULL; |
||||
} |
||||
ctx->FH = NULL; |
||||
} |
||||
|
||||
static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData; |
||||
|
||||
ahprintf(AH, "-- File: %s\n", ctx->filename); |
||||
} |
||||
|
||||
static void _StartData(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*)te->formatData; |
||||
char fmode[10]; |
||||
|
||||
sprintf(fmode, "wb%d", AH->compression); |
||||
|
||||
#ifdef HAVE_LIBZ |
||||
tctx->FH = gzopen(tctx->filename, fmode); |
||||
#else |
||||
tctx->FH = fopen(tctx->filename, PG_BINARY_W); |
||||
#endif |
||||
} |
||||
|
||||
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*)AH->currToc->formatData; |
||||
|
||||
GZWRITE((void*)data, 1, dLen, tctx->FH); |
||||
|
||||
return dLen; |
||||
} |
||||
|
||||
static void _EndData(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*) te->formatData; |
||||
|
||||
/* Close the file */ |
||||
GZCLOSE(tctx->FH); |
||||
tctx->FH = NULL; |
||||
} |
||||
|
||||
/*
|
||||
* Print data for a given file
|
||||
*/ |
||||
static void _PrintFileData(ArchiveHandle* AH, char *filename, RestoreOptions *ropt) |
||||
{ |
||||
char buf[4096]; |
||||
int cnt; |
||||
|
||||
if (!filename)
|
||||
return; |
||||
|
||||
#ifdef HAVE_LIBZ |
||||
AH->FH = gzopen(filename,"rb"); |
||||
#else |
||||
AH->FH = fopen(filename,PG_BINARY_R); |
||||
#endif |
||||
|
||||
while ( (cnt = GZREAD(buf, 1, 4095, AH->FH)) > 0) { |
||||
buf[cnt] = '\0'; |
||||
ahwrite(buf, 1, cnt, AH); |
||||
} |
||||
|
||||
GZCLOSE(AH->FH); |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* Print data for a given TOC entry |
||||
*/ |
||||
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*) te->formatData; |
||||
|
||||
if (!tctx->filename)
|
||||
return; |
||||
|
||||
if (strcmp(te->desc, "BLOBS") == 0) |
||||
_LoadBlobs(AH, ropt); |
||||
else |
||||
{ |
||||
_PrintFileData(AH, tctx->filename, ropt); |
||||
} |
||||
} |
||||
|
||||
static void _getBlobTocEntry(ArchiveHandle* AH, int *oid, char fname[K_STD_BUF_SIZE]) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
char blobTe[K_STD_BUF_SIZE]; |
||||
int fpos; |
||||
int eos; |
||||
|
||||
if (fgets(&blobTe[0], K_STD_BUF_SIZE - 1, ctx->blobToc) != NULL) |
||||
{ |
||||
*oid = atoi(blobTe); |
||||
|
||||
fpos = strcspn(blobTe, " "); |
||||
|
||||
strncpy(fname, &blobTe[fpos+1], K_STD_BUF_SIZE - 1); |
||||
|
||||
eos = strlen(fname)-1; |
||||
|
||||
if (fname[eos] == '\n') |
||||
fname[eos] = '\0'; |
||||
|
||||
} else { |
||||
|
||||
*oid = 0; |
||||
fname[0] = '\0'; |
||||
} |
||||
} |
||||
|
||||
static void _LoadBlobs(ArchiveHandle* AH, RestoreOptions *ropt) |
||||
{ |
||||
int oid; |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
char fname[K_STD_BUF_SIZE]; |
||||
|
||||
ctx->blobToc = fopen("blobs.toc", PG_BINARY_R); |
||||
|
||||
_getBlobTocEntry(AH, &oid, fname); |
||||
|
||||
while(oid != 0) |
||||
{ |
||||
StartRestoreBlob(AH, oid); |
||||
_PrintFileData(AH, fname, ropt); |
||||
EndRestoreBlob(AH, oid); |
||||
_getBlobTocEntry(AH, &oid, fname); |
||||
} |
||||
|
||||
fclose(ctx->blobToc); |
||||
} |
||||
|
||||
|
||||
static int _WriteByte(ArchiveHandle* AH, const int i) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
|
||||
res = fputc(i, AH->FH); |
||||
if (res != EOF) { |
||||
ctx->filePos += 1; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
static int _ReadByte(ArchiveHandle* AH) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
|
||||
res = fgetc(AH->FH); |
||||
if (res != EOF) { |
||||
ctx->filePos += 1; |
||||
} |
||||
return res; |
||||
} |
||||
|
||||
static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
res = fwrite(buf, 1, len, AH->FH); |
||||
ctx->filePos += res; |
||||
return res; |
||||
} |
||||
|
||||
static int _ReadBuf(ArchiveHandle* AH, void* buf, int len) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
int res; |
||||
|
||||
res = fread(buf, 1, len, AH->FH); |
||||
ctx->filePos += res; |
||||
return res; |
||||
} |
||||
|
||||
static void _CloseArchive(ArchiveHandle* AH) |
||||
{ |
||||
if (AH->mode == archModeWrite) { |
||||
WriteHead(AH); |
||||
WriteToc(AH); |
||||
fclose(AH->FH); |
||||
WriteDataChunks(AH); |
||||
} |
||||
|
||||
AH->FH = NULL;
|
||||
} |
||||
|
||||
|
||||
|
||||
/*
|
||||
* BLOB support |
||||
*/ |
||||
|
||||
/*
|
||||
* Called by the archiver when starting to save all BLOB DATA (not schema).
|
||||
* This routine should save whatever format-specific information is needed |
||||
* to read the BLOBs back into memory.
|
||||
* |
||||
* It is called just prior to the dumper's DataDumper routine. |
||||
* |
||||
* Optional, but strongly recommended. |
||||
* |
||||
*/ |
||||
static void _StartBlobs(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
char fname[K_STD_BUF_SIZE]; |
||||
|
||||
sprintf(fname, "blobs.toc"); |
||||
ctx->blobToc = fopen(fname, PG_BINARY_W); |
||||
|
||||
} |
||||
|
||||
/*
|
||||
* Called by the archiver when the dumper calls StartBlob. |
||||
* |
||||
* Mandatory. |
||||
* |
||||
* Must save the passed OID for retrieval at restore-time. |
||||
*/ |
||||
static void _StartBlob(ArchiveHandle* AH, TocEntry* te, int oid) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
lclTocEntry* tctx = (lclTocEntry*)te->formatData; |
||||
char fmode[10]; |
||||
char fname[255]; |
||||
char *sfx; |
||||
|
||||
if (oid == 0)
|
||||
die_horribly(AH, "%s: illegal OID for BLOB (%d)\n", progname, oid); |
||||
|
||||
if (AH->compression != 0) |
||||
sfx = ".gz"; |
||||
else |
||||
sfx = ""; |
||||
|
||||
sprintf(fmode, "wb%d", AH->compression); |
||||
sprintf(fname, "blob_%d.dat%s", oid, sfx); |
||||
|
||||
fprintf(ctx->blobToc, "%d %s\n", oid, fname); |
||||
|
||||
#ifdef HAVE_LIBZ |
||||
tctx->FH = gzopen(fname, fmode); |
||||
#else |
||||
tctx->FH = fopen(fname, PG_BINARY_W); |
||||
#endif |
||||
|
||||
} |
||||
|
||||
/*
|
||||
* Called by the archiver when the dumper calls EndBlob. |
||||
* |
||||
* Optional. |
||||
* |
||||
*/ |
||||
static void _EndBlob(ArchiveHandle* AH, TocEntry* te, int oid) |
||||
{ |
||||
lclTocEntry* tctx = (lclTocEntry*)te->formatData; |
||||
|
||||
GZCLOSE(tctx->FH); |
||||
} |
||||
|
||||
/*
|
||||
* Called by the archiver when finishing saving all BLOB DATA.
|
||||
* |
||||
* Optional. |
||||
* |
||||
*/ |
||||
static void _EndBlobs(ArchiveHandle* AH, TocEntry* te) |
||||
{ |
||||
lclContext* ctx = (lclContext*)AH->formatData; |
||||
/* Write out a fake zero OID to mark end-of-blobs. */ |
||||
/* WriteInt(AH, 0); */ |
||||
|
||||
fclose(ctx->blobToc); |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
@ -1,325 +1,371 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_restore.c |
||||
* pg_restore is an utility extracting postgres database definitions |
||||
* from a backup archive created by pg_dump using the archiver
|
||||
* interface. |
||||
* |
||||
* pg_restore will read the backup archive and |
||||
* dump out a script that reproduces |
||||
* the schema of the database in terms of |
||||
* user-defined types |
||||
* user-defined functions |
||||
* tables |
||||
* indices |
||||
* aggregates |
||||
* operators |
||||
* ACL - grant/revoke |
||||
* |
||||
* the output script is SQL that is understood by PostgreSQL |
||||
* |
||||
* Basic process in a restore operation is: |
||||
*
|
||||
* Open the Archive and read the TOC. |
||||
* Set flags in TOC entries, and *maybe* reorder them. |
||||
* Generate script to stdout |
||||
* Exit |
||||
* |
||||
* Copyright (c) 2000, Philip Warner |
||||
* Rights are granted to use this software in any way so long |
||||
* as this notice is not removed. |
||||
* |
||||
* The author is not responsible for loss or damages that may |
||||
* result from it's use. |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* |
||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au |
||||
* |
||||
* Initial version. Command processing taken from original pg_dump. |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
|
||||
|
||||
/*
|
||||
#include "postgres.h" |
||||
#include "access/htup.h" |
||||
#include "catalog/pg_type.h" |
||||
#include "catalog/pg_language.h" |
||||
#include "catalog/pg_index.h" |
||||
#include "catalog/pg_trigger.h" |
||||
#include "libpq-fe.h" |
||||
*/ |
||||
|
||||
#include "pg_backup.h" |
||||
|
||||
#ifndef HAVE_STRDUP |
||||
#include "strdup.h" |
||||
#endif |
||||
|
||||
#ifdef HAVE_TERMIOS_H |
||||
#include <termios.h> |
||||
#endif |
||||
|
||||
#ifdef HAVE_GETOPT_H |
||||
#include <getopt.h> |
||||
#else |
||||
#include <unistd.h> |
||||
#endif |
||||
|
||||
/* Forward decls */ |
||||
static void usage(const char *progname); |
||||
static char* _cleanupName(char* name); |
||||
|
||||
typedef struct option optType; |
||||
|
||||
#ifdef HAVE_GETOPT_H |
||||
struct option cmdopts[] = {
|
||||
{ "clean", 0, NULL, 'c' }, |
||||
{ "data-only", 0, NULL, 'a' }, |
||||
{ "file", 1, NULL, 'f' }, |
||||
{ "format", 1, NULL, 'F' }, |
||||
{ "function", 2, NULL, 'p' }, |
||||
{ "index", 2, NULL, 'i'}, |
||||
{ "list", 0, NULL, 'l'}, |
||||
{ "no-acl", 0, NULL, 'x' }, |
||||
{ "oid-order", 0, NULL, 'o'}, |
||||
{ "orig-order", 0, NULL, 'O' }, |
||||
{ "rearrange", 0, NULL, 'r'}, |
||||
{ "schema-only", 0, NULL, 's' }, |
||||
{ "table", 2, NULL, 't'}, |
||||
{ "trigger", 2, NULL, 'T' }, |
||||
{ "use-list", 1, NULL, 'u'}, |
||||
{ "verbose", 0, NULL, 'v' }, |
||||
{ NULL, 0, NULL, 0} |
||||
}; |
||||
#endif |
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
RestoreOptions *opts; |
||||
char *progname; |
||||
int c; |
||||
Archive* AH; |
||||
char *fileSpec = NULL; |
||||
|
||||
opts = NewRestoreOptions(); |
||||
|
||||
progname = *argv; |
||||
|
||||
#ifdef HAVE_GETOPT_LONG |
||||
while ((c = getopt_long(argc, argv, "acf:F:i:loOp:st:T:u:vx", cmdopts, NULL)) != EOF) |
||||
#else |
||||
while ((c = getopt(argc, argv, "acf:F:i:loOp:st:T:u:vx")) != -1) |
||||
#endif |
||||
{ |
||||
switch (c) |
||||
{ |
||||
case 'a': /* Dump data only */ |
||||
opts->dataOnly = 1; |
||||
break; |
||||
case 'c': /* clean (i.e., drop) schema prior to
|
||||
* create */ |
||||
opts->dropSchema = 1; |
||||
break; |
||||
case 'f': /* output file name */ |
||||
opts->filename = strdup(optarg); |
||||
break; |
||||
case 'F': |
||||
if (strlen(optarg) != 0)
|
||||
opts->formatName = strdup(optarg); |
||||
break; |
||||
case 'o': |
||||
opts->oidOrder = 1; |
||||
break; |
||||
case 'O': |
||||
opts->origOrder = 1; |
||||
break; |
||||
case 'r': |
||||
opts->rearrange = 1; |
||||
break; |
||||
|
||||
case 'p': /* Function */ |
||||
opts->selTypes = 1; |
||||
opts->selFunction = 1; |
||||
opts->functionNames = _cleanupName(optarg); |
||||
break; |
||||
case 'i': /* Index */ |
||||
opts->selTypes = 1; |
||||
opts->selIndex = 1; |
||||
opts->indexNames = _cleanupName(optarg); |
||||
break; |
||||
case 'T': /* Trigger */ |
||||
opts->selTypes = 1; |
||||
opts->selTrigger = 1; |
||||
opts->triggerNames = _cleanupName(optarg); |
||||
break; |
||||
case 's': /* dump schema only */ |
||||
opts->schemaOnly = 1; |
||||
break; |
||||
case 't': /* Dump data for this table only */ |
||||
opts->selTypes = 1; |
||||
opts->selTable = 1; |
||||
opts->tableNames = _cleanupName(optarg); |
||||
break; |
||||
case 'l': /* Dump the TOC summary */ |
||||
opts->tocSummary = 1; |
||||
break; |
||||
|
||||
case 'u': /* input TOC summary file name */ |
||||
opts->tocFile = strdup(optarg); |
||||
break; |
||||
|
||||
case 'v': /* verbose */ |
||||
opts->verbose = 1; |
||||
break; |
||||
case 'x': /* skip ACL dump */ |
||||
opts->aclsSkip = 1; |
||||
break; |
||||
default: |
||||
usage(progname); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (optind < argc) { |
||||
fileSpec = argv[optind]; |
||||
} else { |
||||
fileSpec = NULL; |
||||
} |
||||
|
||||
if (opts->formatName) {
|
||||
|
||||
switch (opts->formatName[0]) { |
||||
|
||||
case 'c': |
||||
case 'C': |
||||
opts->format = archCustom; |
||||
break; |
||||
|
||||
case 'f': |
||||
case 'F': |
||||
opts->format = archFiles; |
||||
break; |
||||
|
||||
default: |
||||
fprintf(stderr, "%s: Unknown archive format '%s', please specify 'f' or 'c'\n", progname, opts->formatName); |
||||
exit (1); |
||||
} |
||||
} |
||||
|
||||
AH = OpenArchive(fileSpec, opts->format); |
||||
|
||||
if (opts->tocFile) |
||||
SortTocFromFile(AH, opts); |
||||
|
||||
if (opts->oidOrder) |
||||
SortTocByOID(AH); |
||||
else if (opts->origOrder) |
||||
SortTocByID(AH); |
||||
|
||||
if (opts->rearrange) { |
||||
MoveToEnd(AH, "TABLE DATA"); |
||||
MoveToEnd(AH, "INDEX"); |
||||
MoveToEnd(AH, "TRIGGER"); |
||||
MoveToEnd(AH, "RULE"); |
||||
MoveToEnd(AH, "ACL"); |
||||
} |
||||
|
||||
if (opts->tocSummary) { |
||||
PrintTOCSummary(AH, opts); |
||||
} else { |
||||
RestoreArchive(AH, opts); |
||||
} |
||||
|
||||
CloseArchive(AH); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
static void usage(const char *progname) |
||||
{ |
||||
#ifdef HAVE_GETOPT_LONG |
||||
fprintf(stderr, |
||||
"usage: %s [options] [backup file]\n" |
||||
" -a, --data-only \t dump out only the data, no schema\n" |
||||
" -c, --clean \t clean(drop) schema prior to create\n" |
||||
" -f filename \t script output filename\n" |
||||
" -F, --format {c|f} \t specify backup file format\n" |
||||
" -p, --function[=name] \t dump functions or named function\n" |
||||
" -i, --index[=name] \t dump indexes or named index\n" |
||||
" -l, --list \t dump summarized TOC for this file\n" |
||||
" -o, --oid-order \t dump in oid order\n" |
||||
" -O, --orig-order \t dump in original dump order\n" |
||||
" -r, --rearrange \t rearrange output to put indexes etc at end\n" |
||||
" -s, --schema-only \t dump out only the schema, no data\n" |
||||
" -t [table], --table[=table] \t dump for this table only\n" |
||||
" -T, --trigger[=name] \t dump triggers or named trigger\n" |
||||
" -u, --use-list filename \t use specified TOC for ordering output from this file\n" |
||||
" -v \t verbose\n" |
||||
" -x, --no-acl \t skip dumping of ACLs (grant/revoke)\n" |
||||
, progname); |
||||
#else |
||||
fprintf(stderr, |
||||
"usage: %s [options] [backup file]\n" |
||||
" -a \t dump out only the data, no schema\n" |
||||
" -c \t clean(drop) schema prior to create\n" |
||||
" -f filename NOT IMPLEMENTED \t script output filename\n" |
||||
" -F {c|f} \t specify backup file format\n" |
||||
" -p name \t dump functions or named function\n" |
||||
" -i name \t dump indexes or named index\n" |
||||
" -l \t dump summarized TOC for this file\n" |
||||
" -o \t dump in oid order\n" |
||||
" -O \t dump in original dump order\n" |
||||
" -r \t rearrange output to put indexes etc at end\n" |
||||
" -s \t dump out only the schema, no data\n" |
||||
" -t name \t dump for this table only\n" |
||||
" -T name \t dump triggers or named trigger\n" |
||||
" -u filename \t use specified TOC for ordering output from this file\n" |
||||
" -v \t verbose\n" |
||||
" -x \t skip dumping of ACLs (grant/revoke)\n" |
||||
, progname); |
||||
#endif |
||||
fprintf(stderr, |
||||
"\nIf [backup file] is not supplied, then standard input " |
||||
"is used.\n"); |
||||
fprintf(stderr, "\n"); |
||||
|
||||
exit(1); |
||||
} |
||||
|
||||
static char* _cleanupName(char* name) |
||||
{ |
||||
int i; |
||||
|
||||
if (!name) |
||||
return NULL; |
||||
|
||||
if (strlen(name) == 0) |
||||
return NULL; |
||||
|
||||
name = strdup(name); |
||||
|
||||
if (name[0] == '"') |
||||
{ |
||||
strcpy(name, &name[1]); |
||||
if (*(name + strlen(name) - 1) == '"') |
||||
*(name + strlen(name) - 1) = '\0'; |
||||
} |
||||
/* otherwise, convert table name to lowercase... */ |
||||
else |
||||
{ |
||||
for (i = 0; name[i]; i++) |
||||
if (isascii((unsigned char) name[i]) && isupper(name[i])) |
||||
name[i] = tolower(name[i]); |
||||
} |
||||
return name; |
||||
} |
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* pg_restore.c |
||||
* pg_restore is an utility extracting postgres database definitions |
||||
* from a backup archive created by pg_dump using the archiver
|
||||
* interface. |
||||
* |
||||
* pg_restore will read the backup archive and |
||||
* dump out a script that reproduces |
||||
* the schema of the database in terms of |
||||
* user-defined types |
||||
* user-defined functions |
||||
* tables |
||||
* indices |
||||
* aggregates |
||||
* operators |
||||
* ACL - grant/revoke |
||||
* |
||||
* the output script is SQL that is understood by PostgreSQL |
||||
* |
||||
* Basic process in a restore operation is: |
||||
*
|
||||
* Open the Archive and read the TOC. |
||||
* Set flags in TOC entries, and *maybe* reorder them. |
||||
* Generate script to stdout |
||||
* Exit |
||||
* |
||||
* Copyright (c) 2000, Philip Warner |
||||
* Rights are granted to use this software in any way so long |
||||
* as this notice is not removed. |
||||
* |
||||
* The author is not responsible for loss or damages that may |
||||
* result from it's use. |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* |
||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au |
||||
* |
||||
* Initial version. Command processing taken from original pg_dump. |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
|
||||
|
||||
/*
|
||||
#include "postgres.h" |
||||
#include "access/htup.h" |
||||
#include "catalog/pg_type.h" |
||||
#include "catalog/pg_language.h" |
||||
#include "catalog/pg_index.h" |
||||
#include "catalog/pg_trigger.h" |
||||
#include "libpq-fe.h" |
||||
*/ |
||||
|
||||
#include "pg_backup.h" |
||||
|
||||
#ifndef HAVE_STRDUP |
||||
#include "strdup.h" |
||||
#endif |
||||
|
||||
#ifdef HAVE_TERMIOS_H |
||||
#include <termios.h> |
||||
#endif |
||||
|
||||
#ifdef HAVE_GETOPT_H |
||||
#include <getopt.h> |
||||
#else |
||||
#include <unistd.h> |
||||
#endif |
||||
|
||||
/* Forward decls */ |
||||
static void usage(const char *progname); |
||||
static char* _cleanupName(char* name); |
||||
|
||||
typedef struct option optType; |
||||
|
||||
#ifdef HAVE_GETOPT_H |
||||
struct option cmdopts[] = {
|
||||
{ "clean", 0, NULL, 'c' }, |
||||
{ "data-only", 0, NULL, 'a' }, |
||||
{ "dbname", 1, NULL, 'd' }, |
||||
{ "file", 1, NULL, 'f' }, |
||||
{ "format", 1, NULL, 'F' }, |
||||
{ "function", 2, NULL, 'P' }, |
||||
{ "host", 1, NULL, 'h' }, |
||||
{ "ignore-version", 0, NULL, 'i'}, |
||||
{ "index", 2, NULL, 'I'}, |
||||
{ "list", 0, NULL, 'l'}, |
||||
{ "no-acl", 0, NULL, 'x' }, |
||||
{ "port", 1, NULL, 'p' }, |
||||
{ "oid-order", 0, NULL, 'o'}, |
||||
{ "orig-order", 0, NULL, 'O' }, |
||||
{ "password", 0, NULL, 'u' }, |
||||
{ "rearrange", 0, NULL, 'r'}, |
||||
{ "schema-only", 0, NULL, 's' }, |
||||
{ "table", 2, NULL, 't'}, |
||||
{ "trigger", 2, NULL, 'T' }, |
||||
{ "use-list", 1, NULL, 'U'}, |
||||
{ "verbose", 0, NULL, 'v' }, |
||||
{ NULL, 0, NULL, 0} |
||||
}; |
||||
#endif |
||||
|
||||
int main(int argc, char **argv) |
||||
{ |
||||
RestoreOptions *opts; |
||||
char *progname; |
||||
int c; |
||||
Archive* AH; |
||||
char *fileSpec = NULL; |
||||
|
||||
opts = NewRestoreOptions(); |
||||
|
||||
progname = *argv; |
||||
|
||||
#ifdef HAVE_GETOPT_LONG |
||||
while ((c = getopt_long(argc, argv, "acd:f:F:h:i:loOp:st:T:u:U:vx", cmdopts, NULL)) != EOF) |
||||
#else |
||||
while ((c = getopt(argc, argv, "acd:f:F:h:i:loOp:st:T:u:U:vx")) != -1) |
||||
#endif |
||||
{ |
||||
switch (c) |
||||
{ |
||||
case 'a': /* Dump data only */ |
||||
opts->dataOnly = 1; |
||||
break; |
||||
case 'c': /* clean (i.e., drop) schema prior to
|
||||
* create */ |
||||
opts->dropSchema = 1; |
||||
break; |
||||
case 'd': |
||||
if (strlen(optarg) != 0) |
||||
{ |
||||
opts->dbname = strdup(optarg); |
||||
opts->useDB = 1; |
||||
} |
||||
break; |
||||
case 'f': /* output file name */ |
||||
opts->filename = strdup(optarg); |
||||
break; |
||||
case 'F': |
||||
if (strlen(optarg) != 0)
|
||||
opts->formatName = strdup(optarg); |
||||
break; |
||||
case 'h': |
||||
if (strlen(optarg) != 0) |
||||
opts->pghost = strdup(optarg); |
||||
break; |
||||
case 'i': |
||||
opts->ignoreVersion = 1; |
||||
break; |
||||
case 'o': |
||||
opts->oidOrder = 1; |
||||
break; |
||||
case 'O': |
||||
opts->origOrder = 1; |
||||
break; |
||||
case 'p': |
||||
if (strlen(optarg) != 0) |
||||
opts->pgport = strdup(optarg); |
||||
break; |
||||
case 'r': |
||||
opts->rearrange = 1; |
||||
break; |
||||
case 'P': /* Function */ |
||||
opts->selTypes = 1; |
||||
opts->selFunction = 1; |
||||
opts->functionNames = _cleanupName(optarg); |
||||
break; |
||||
case 'I': /* Index */ |
||||
opts->selTypes = 1; |
||||
opts->selIndex = 1; |
||||
opts->indexNames = _cleanupName(optarg); |
||||
break; |
||||
case 'T': /* Trigger */ |
||||
opts->selTypes = 1; |
||||
opts->selTrigger = 1; |
||||
opts->triggerNames = _cleanupName(optarg); |
||||
break; |
||||
case 's': /* dump schema only */ |
||||
opts->schemaOnly = 1; |
||||
break; |
||||
case 't': /* Dump data for this table only */ |
||||
opts->selTypes = 1; |
||||
opts->selTable = 1; |
||||
opts->tableNames = _cleanupName(optarg); |
||||
break; |
||||
case 'l': /* Dump the TOC summary */ |
||||
opts->tocSummary = 1; |
||||
break; |
||||
|
||||
case 'u': |
||||
opts->requirePassword = 1; |
||||
break; |
||||
|
||||
case 'U': /* input TOC summary file name */ |
||||
opts->tocFile = strdup(optarg); |
||||
break; |
||||
|
||||
case 'v': /* verbose */ |
||||
opts->verbose = 1; |
||||
break; |
||||
case 'x': /* skip ACL dump */ |
||||
opts->aclsSkip = 1; |
||||
break; |
||||
default: |
||||
usage(progname); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (optind < argc) { |
||||
fileSpec = argv[optind]; |
||||
} else { |
||||
fileSpec = NULL; |
||||
} |
||||
|
||||
if (opts->formatName) {
|
||||
|
||||
switch (opts->formatName[0]) { |
||||
|
||||
case 'c': |
||||
case 'C': |
||||
opts->format = archCustom; |
||||
break; |
||||
|
||||
case 'f': |
||||
case 'F': |
||||
opts->format = archFiles; |
||||
break; |
||||
|
||||
case 't': |
||||
case 'T': |
||||
opts->format = archTar; |
||||
break; |
||||
|
||||
default: |
||||
fprintf(stderr, "%s: Unknown archive format '%s', please specify 't' or 'c'\n", |
||||
progname, opts->formatName); |
||||
exit (1); |
||||
} |
||||
} |
||||
|
||||
AH = OpenArchive(fileSpec, opts->format); |
||||
|
||||
/* Let the archiver know how noisy to be */ |
||||
AH->verbose = opts->verbose; |
||||
|
||||
if (opts->tocFile) |
||||
SortTocFromFile(AH, opts); |
||||
|
||||
if (opts->oidOrder) |
||||
SortTocByOID(AH); |
||||
else if (opts->origOrder) |
||||
SortTocByID(AH); |
||||
|
||||
if (opts->rearrange) { |
||||
MoveToStart(AH, "<Init>"); |
||||
MoveToEnd(AH, "TABLE DATA"); |
||||
MoveToEnd(AH, "BLOBS"); |
||||
MoveToEnd(AH, "INDEX"); |
||||
MoveToEnd(AH, "TRIGGER"); |
||||
MoveToEnd(AH, "RULE"); |
||||
MoveToEnd(AH, "ACL"); |
||||
} |
||||
|
||||
if (opts->tocSummary) { |
||||
PrintTOCSummary(AH, opts); |
||||
} else { |
||||
RestoreArchive(AH, opts); |
||||
} |
||||
|
||||
CloseArchive(AH); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
static void usage(const char *progname) |
||||
{ |
||||
#ifdef HAVE_GETOPT_LONG |
||||
fprintf(stderr, |
||||
"usage: %s [options] [backup file]\n" |
||||
" -a, --data-only \t dump out only the data, no schema\n" |
||||
" -d, --dbname <name> \t specify database name\n" |
||||
" -c, --clean \t clean(drop) schema prior to create\n" |
||||
" -f filename \t script output filename\n" |
||||
" -F, --format {c|f} \t specify backup file format\n" |
||||
" -h, --host <hostname> \t server host name\n" |
||||
" -i, --index[=name] \t dump indexes or named index\n" |
||||
" -l, --list \t dump summarized TOC for this file\n" |
||||
" -o, --oid-order \t dump in oid order\n" |
||||
" -O, --orig-order \t dump in original dump order\n" |
||||
" -p, --port <port> \t server port number\n" |
||||
" -P, --function[=name] \t dump functions or named function\n" |
||||
" -r, --rearrange \t rearrange output to put indexes etc at end\n" |
||||
" -s, --schema-only \t dump out only the schema, no data\n" |
||||
" -t [table], --table[=table] \t dump for this table only\n" |
||||
" -T, --trigger[=name] \t dump triggers or named trigger\n" |
||||
" -u, --password \t use password authentication\n" |
||||
" -U, --use-list filename \t use specified TOC for ordering output from this file\n" |
||||
" -v, --verbose \t verbose\n" |
||||
" -x, --no-acl \t skip dumping of ACLs (grant/revoke)\n" |
||||
, progname); |
||||
|
||||
#else |
||||
fprintf(stderr, |
||||
"usage: %s [options] [backup file]\n" |
||||
" -a \t dump out only the data, no schema\n" |
||||
" -d, <name> \t specify database name\n" |
||||
" -c \t clean(drop) schema prior to create\n" |
||||
" -f filename NOT IMPLEMENTED \t script output filename\n" |
||||
" -F {c|f} \t specify backup file format\n" |
||||
" -h, <hostname> \t server host name\n" |
||||
" -i name \t dump indexes or named index\n" |
||||
" -l \t dump summarized TOC for this file\n" |
||||
" -o \t dump in oid order\n" |
||||
" -O \t dump in original dump order\n" |
||||
" -p <port> \t server port number\n" |
||||
" -P name \t dump functions or named function\n" |
||||
" -r \t rearrange output to put indexes etc at end\n" |
||||
" -s \t dump out only the schema, no data\n" |
||||
" -t name \t dump for this table only\n" |
||||
" -T name \t dump triggers or named trigger\n" |
||||
" -u \t use password authentication\n" |
||||
" -U filename \t use specified TOC for ordering output from this file\n" |
||||
" -v \t verbose\n" |
||||
" -x \t skip dumping of ACLs (grant/revoke)\n" |
||||
, progname); |
||||
#endif |
||||
fprintf(stderr, |
||||
"\nIf [backup file] is not supplied, then standard input " |
||||
"is used.\n"); |
||||
fprintf(stderr, "\n"); |
||||
|
||||
exit(1); |
||||
} |
||||
|
||||
static char* _cleanupName(char* name) |
||||
{ |
||||
int i; |
||||
|
||||
if (!name) |
||||
return NULL; |
||||
|
||||
if (strlen(name) == 0) |
||||
return NULL; |
||||
|
||||
name = strdup(name); |
||||
|
||||
if (name[0] == '"') |
||||
{ |
||||
strcpy(name, &name[1]); |
||||
if (*(name + strlen(name) - 1) == '"') |
||||
*(name + strlen(name) - 1) = '\0'; |
||||
} |
||||
/* otherwise, convert table name to lowercase... */ |
||||
else |
||||
{ |
||||
for (i = 0; name[i]; i++) |
||||
if (isascii((unsigned char) name[i]) && isupper(name[i])) |
||||
name[i] = tolower(name[i]); |
||||
} |
||||
return name; |
||||
} |
||||
|
||||
|
||||
Loading…
Reference in new issue