Commit e8f69be0 authored by Philip Warner's avatar Philip Warner

- Support for BLOB output from pg_dump and input via pg_restore

- 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 fixes
parent 0143d391
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
# #
# Copyright (c) 1994, Regents of the University of California # Copyright (c) 1994, Regents of the University of California
# #
# $Header: /cvsroot/pgsql/src/bin/pg_dump/Makefile,v 1.19 2000/07/04 19:52:00 petere Exp $ # $Header: /cvsroot/pgsql/src/bin/pg_dump/Makefile,v 1.20 2000/07/21 11:40:08 pjw Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -12,8 +12,8 @@ subdir = src/bin/pg_dump ...@@ -12,8 +12,8 @@ subdir = src/bin/pg_dump
top_builddir = ../../.. top_builddir = ../../..
include ../../Makefile.global include ../../Makefile.global
OBJS= pg_backup_archiver.o pg_backup_custom.o pg_backup_files.o \ OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o pg_backup_files.o \
pg_backup_plain_text.o $(STRDUP) pg_backup_null.o pg_backup_tar.o $(STRDUP)
CFLAGS+= -I$(LIBPQDIR) CFLAGS+= -I$(LIBPQDIR)
LIBS+= -lz LIBS+= -lz
......
Notes on pg_dump Notes on pg_dump
================ ================
pg_dump, by default, still outputs text files. 1. pg_dump, by default, still outputs text files.
pg_dumpall forces all pg_dump output to be text, since it also outputs text into the same output stream. 2. pg_dumpall forces all pg_dump output to be text, since it also outputs text into the same output stream.
The plain text output format can not be used as input into pg_restore. 3. The plain text output format can not be used as input into pg_restore.
4. pg_dump now dumps the items in a modified OID order to try to improve relaibility of default restores.
To dump a database into the next custom format, type: To dump a database into the next custom format, type:
pg_dump <db-name> -Fc > <backup-file> pg_dump <db-name> -Fc > <backup-file>
or, in TAR format
pg_dump <db-name> -Ft > <backup-file>
To restore, try To restore, try
To list contents: To list contents:
...@@ -53,7 +59,37 @@ or, simply: ...@@ -53,7 +59,37 @@ or, simply:
pg_restore backup.bck --use=toc.lis | psql newdbname pg_restore backup.bck --use=toc.lis | psql newdbname
Philip Warner, 3-Jul-2000 BLOBs
=====
To dump blobs you must use the custom archive format (-Fc) or TAR format (-Ft), and specify the
--blobs qualifier to the pg_dump command.
To restore blobs you must use a direct database connection (--db=db-to-restore-to).
eg.
pg_dump --blob -Fc db-to-backup -f backup.bck
pg_restore backup.bck --db=db-to-restore-into
TAR
===
The TAR archive that pg_dump creates currently has a blank username & group for the files,
but should be otherwise valid. It also includes a 'restore.sql' script which is there for
the benefit of humans. It is never used by pg_restore.
Note: the TAR format archive can only be used as input into pg_restore if it is in TAR form.
(ie. you should not extract the files then expect pg_restore to work).
You can extract, edit, and tar the files again, and it should work, but the 'toc'
file should go at the start, the data files be in the order they are used, and
the BLOB files at the end.
Philip Warner, 16-Jul-2000
pjw@rhyme.com.au pjw@rhyme.com.au
......
...@@ -30,12 +30,15 @@ ...@@ -30,12 +30,15 @@
#define PG_BACKUP__ #define PG_BACKUP__
#include "postgres.h"
#include "libpq-fe.h"
typedef enum _archiveFormat { typedef enum _archiveFormat {
archUnknown = 0, archUnknown = 0,
archCustom = 1, archCustom = 1,
archFiles = 2, archFiles = 2,
archTar = 3, archTar = 3,
archPlainText = 4 archNull = 4
} ArchiveFormat; } ArchiveFormat;
/* /*
...@@ -43,7 +46,8 @@ typedef enum _archiveFormat { ...@@ -43,7 +46,8 @@ typedef enum _archiveFormat {
* time this gives us some abstraction and type checking. * time this gives us some abstraction and type checking.
*/ */
typedef struct _Archive { typedef struct _Archive {
/* Nothing here */ int verbose;
/* The rest is private */
} Archive; } Archive;
typedef int (*DataDumperPtr)(Archive* AH, char* oid, void* userArg); typedef int (*DataDumperPtr)(Archive* AH, char* oid, void* userArg);
...@@ -73,6 +77,13 @@ typedef struct _restoreOptions { ...@@ -73,6 +77,13 @@ typedef struct _restoreOptions {
char *tableNames; char *tableNames;
char *triggerNames; char *triggerNames;
int useDB;
char *dbname;
char *pgport;
char *pghost;
int ignoreVersion;
int requirePassword;
int *idWanted; int *idWanted;
int limitToList; int limitToList;
int compression; int compression;
...@@ -83,24 +94,42 @@ typedef struct _restoreOptions { ...@@ -83,24 +94,42 @@ typedef struct _restoreOptions {
* Main archiver interface. * 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 */ /* Called to add a TOC entry */
extern void ArchiveEntry(Archive* AH, const char* oid, const char* name, extern void ArchiveEntry(Archive* AH, const char* oid, const char* name,
const char* desc, const char* (deps[]), const char* defn, const char* desc, const char* (deps[]), const char* defn,
const char* dropStmt, const char* owner, const char* dropStmt, const char* copyStmt, const char* owner,
DataDumperPtr dumpFn, void* dumpArg); DataDumperPtr dumpFn, void* dumpArg);
/* Called to write *data* to the archive */ /* Called to write *data* to the archive */
extern int WriteData(Archive* AH, const void* data, int dLen); 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 CloseArchive(Archive* AH);
extern void RestoreArchive(Archive* AH, RestoreOptions *ropt); extern void RestoreArchive(Archive* AH, RestoreOptions *ropt);
/* Open an existing archive */ /* Open an existing archive */
extern Archive* OpenArchive(const char* FileSpec, ArchiveFormat fmt); extern Archive* OpenArchive(const char* FileSpec, const ArchiveFormat fmt);
/* Create a new archive */ /* Create a new archive */
extern Archive* CreateArchive(const char* FileSpec, ArchiveFormat fmt, int compression); extern Archive* CreateArchive(const char* FileSpec, const ArchiveFormat fmt,
const int compression);
/* The --list option */ /* The --list option */
extern void PrintTOCSummary(Archive* AH, RestoreOptions *ropt); extern void PrintTOCSummary(Archive* AH, RestoreOptions *ropt);
......
This diff is collapsed.
...@@ -29,6 +29,10 @@ ...@@ -29,6 +29,10 @@
#define __PG_BACKUP_ARCHIVE__ #define __PG_BACKUP_ARCHIVE__
#include <stdio.h> #include <stdio.h>
#include <time.h>
#include "postgres.h"
#include "pqexpbuffer.h"
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
#include <zlib.h> #include <zlib.h>
...@@ -51,15 +55,23 @@ typedef z_stream *z_streamp; ...@@ -51,15 +55,23 @@ typedef z_stream *z_streamp;
#endif #endif
#include "pg_backup.h" #include "pg_backup.h"
#include "libpq-fe.h"
#define K_VERS_MAJOR 1 #define K_VERS_MAJOR 1
#define K_VERS_MINOR 2 #define K_VERS_MINOR 4
#define K_VERS_REV 2 #define K_VERS_REV 3
/* Data block types */
#define BLK_DATA 1
#define BLK_BLOB 2
#define BLK_BLOBS 3
/* Some important version numbers (checked in code) */ /* Some important version numbers (checked in code) */
#define K_VERS_1_0 (( (1 * 256 + 0) * 256 + 0) * 256 + 0) #define K_VERS_1_0 (( (1 * 256 + 0) * 256 + 0) * 256 + 0)
#define K_VERS_1_2 (( (1 * 256 + 2) * 256 + 0) * 256 + 0) #define K_VERS_1_2 (( (1 * 256 + 2) * 256 + 0) * 256 + 0) /* Allow No ZLIB */
#define K_VERS_MAX (( (1 * 256 + 2) * 256 + 255) * 256 + 0) #define K_VERS_1_3 (( (1 * 256 + 3) * 256 + 0) * 256 + 0) /* BLOBs */
#define K_VERS_1_4 (( (1 * 256 + 4) * 256 + 0) * 256 + 0) /* Date & name in header */
#define K_VERS_MAX (( (1 * 256 + 4) * 256 + 255) * 256 + 0)
struct _archiveHandle; struct _archiveHandle;
struct _tocEntry; struct _tocEntry;
...@@ -72,6 +84,11 @@ typedef void (*StartDataPtr) (struct _archiveHandle* AH, struct _tocEntry* te); ...@@ -72,6 +84,11 @@ typedef void (*StartDataPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
typedef int (*WriteDataPtr) (struct _archiveHandle* AH, const void* data, int dLen); typedef int (*WriteDataPtr) (struct _archiveHandle* AH, const void* data, int dLen);
typedef void (*EndDataPtr) (struct _archiveHandle* AH, struct _tocEntry* te); typedef void (*EndDataPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
typedef void (*StartBlobsPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
typedef void (*StartBlobPtr) (struct _archiveHandle* AH, struct _tocEntry* te, int oid);
typedef void (*EndBlobPtr) (struct _archiveHandle* AH, struct _tocEntry* te, int oid);
typedef void (*EndBlobsPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
typedef int (*WriteBytePtr) (struct _archiveHandle* AH, const int i); typedef int (*WriteBytePtr) (struct _archiveHandle* AH, const int i);
typedef int (*ReadBytePtr) (struct _archiveHandle* AH); typedef int (*ReadBytePtr) (struct _archiveHandle* AH);
typedef int (*WriteBufPtr) (struct _archiveHandle* AH, const void* c, int len); typedef int (*WriteBufPtr) (struct _archiveHandle* AH, const void* c, int len);
...@@ -83,6 +100,8 @@ typedef void (*PrintExtraTocPtr) (struct _archiveHandle* AH, struct _tocEntry* t ...@@ -83,6 +100,8 @@ typedef void (*PrintExtraTocPtr) (struct _archiveHandle* AH, struct _tocEntry* t
typedef void (*PrintTocDataPtr) (struct _archiveHandle* AH, struct _tocEntry* te, typedef void (*PrintTocDataPtr) (struct _archiveHandle* AH, struct _tocEntry* te,
RestoreOptions *ropt); RestoreOptions *ropt);
typedef int (*CustomOutPtr) (struct _archiveHandle* AH, const void* buf, int len);
typedef int (*TocSortCompareFn) (const void* te1, const void *te2); typedef int (*TocSortCompareFn) (const void* te1, const void *te2);
typedef enum _archiveMode { typedef enum _archiveMode {
...@@ -95,16 +114,44 @@ typedef struct _outputContext { ...@@ -95,16 +114,44 @@ typedef struct _outputContext {
int gzOut; int gzOut;
} OutputContext; } OutputContext;
typedef enum {
SQL_SCAN = 0,
SQL_IN_SQL_COMMENT,
SQL_IN_EXT_COMMENT,
SQL_IN_QUOTE} sqlparseState;
typedef struct {
int backSlash;
sqlparseState state;
char lastChar;
char quoteChar;
} sqlparseInfo;
typedef struct _archiveHandle { typedef struct _archiveHandle {
Archive public; /* Public part of archive */
char vmaj; /* Version of file */ char vmaj; /* Version of file */
char vmin; char vmin;
char vrev; char vrev;
int version; /* Conveniently formatted version */ int version; /* Conveniently formatted version */
int debugLevel; /* Not used. Intended for logging */
int intSize; /* Size of an integer in the archive */ int intSize; /* Size of an integer in the archive */
ArchiveFormat format; /* Archive format */ ArchiveFormat format; /* Archive format */
sqlparseInfo sqlparse;
PQExpBuffer sqlBuf;
time_t createDate; /* Date archive created */
/*
* Fields used when discovering header.
* A format can always get the previous read bytes from here...
*/
int readHeader; /* Used if file header has been read already */ int readHeader; /* Used if file header has been read already */
char *lookahead; /* Buffer used when reading header to discover format */
int lookaheadSize; /* Size of allocated buffer */
int lookaheadLen; /* Length of data in lookahead */
int lookaheadPos; /* Current read position in lookahead buffer */
ArchiveEntryPtr ArchiveEntryPtr; /* Called for each metadata object */ ArchiveEntryPtr ArchiveEntryPtr; /* Called for each metadata object */
StartDataPtr StartDataPtr; /* Called when table data is about to be dumped */ StartDataPtr StartDataPtr; /* Called when table data is about to be dumped */
...@@ -121,6 +168,28 @@ typedef struct _archiveHandle { ...@@ -121,6 +168,28 @@ typedef struct _archiveHandle {
PrintExtraTocPtr PrintExtraTocPtr; /* Extra TOC info for format */ PrintExtraTocPtr PrintExtraTocPtr; /* Extra TOC info for format */
PrintTocDataPtr PrintTocDataPtr; PrintTocDataPtr PrintTocDataPtr;
StartBlobsPtr StartBlobsPtr;
EndBlobsPtr EndBlobsPtr;
StartBlobPtr StartBlobPtr;
EndBlobPtr EndBlobPtr;
CustomOutPtr CustomOutPtr; /* Alternate script output routine */
/* Stuff for direct DB connection */
char username[100];
char *dbname; /* Name of db for connection */
char *archdbname; /* DB name *read* from archive */
char *pghost;
char *pgport;
PGconn *connection;
int connectToDB; /* Flag to indicate if direct DB connection is required */
int pgCopyIn; /* Currently in libpq 'COPY IN' mode. */
PQExpBuffer pgCopyBuf; /* Left-over data from incomplete lines in COPY IN */
int loFd; /* BLOB fd */
int writingBlob; /* Flag */
int createdBlobXref; /* Flag */
int lastID; /* Last internal ID for a TOC entry */ int lastID; /* Last internal ID for a TOC entry */
char* fSpec; /* Archive File Spec */ char* fSpec; /* Archive File Spec */
FILE *FH; /* General purpose file handle */ FILE *FH; /* General purpose file handle */
...@@ -135,6 +204,7 @@ typedef struct _archiveHandle { ...@@ -135,6 +204,7 @@ typedef struct _archiveHandle {
ArchiveMode mode; /* File mode - r or w */ ArchiveMode mode; /* File mode - r or w */
void* formatData; /* Header data specific to file format */ void* formatData; /* Header data specific to file format */
RestoreOptions *ropt; /* Used to check restore options in ahwrite etc */
} ArchiveHandle; } ArchiveHandle;
typedef struct _tocEntry { typedef struct _tocEntry {
...@@ -148,6 +218,7 @@ typedef struct _tocEntry { ...@@ -148,6 +218,7 @@ typedef struct _tocEntry {
char* desc; char* desc;
char* defn; char* defn;
char* dropStmt; char* dropStmt;
char* copyStmt;
char* owner; char* owner;
char** depOid; char** depOid;
int printed; /* Indicates if entry defn has been dumped */ int printed; /* Indicates if entry defn has been dumped */
...@@ -159,7 +230,8 @@ typedef struct _tocEntry { ...@@ -159,7 +230,8 @@ typedef struct _tocEntry {
} TocEntry; } TocEntry;
extern void die_horribly(const char *fmt, ...); /* Used everywhere */
extern void die_horribly(ArchiveHandle *AH, const char *fmt, ...);
extern void WriteTOC(ArchiveHandle* AH); extern void WriteTOC(ArchiveHandle* AH);
extern void ReadTOC(ArchiveHandle* AH); extern void ReadTOC(ArchiveHandle* AH);
...@@ -180,9 +252,15 @@ extern int ReadInt(ArchiveHandle* AH); ...@@ -180,9 +252,15 @@ extern int ReadInt(ArchiveHandle* AH);
extern char* ReadStr(ArchiveHandle* AH); extern char* ReadStr(ArchiveHandle* AH);
extern int WriteStr(ArchiveHandle* AH, char* s); extern int WriteStr(ArchiveHandle* AH, char* s);
extern void StartRestoreBlob(ArchiveHandle* AH, int oid);
extern void EndRestoreBlob(ArchiveHandle* AH, int oid);
extern void InitArchiveFmt_Custom(ArchiveHandle* AH); extern void InitArchiveFmt_Custom(ArchiveHandle* AH);
extern void InitArchiveFmt_Files(ArchiveHandle* AH); extern void InitArchiveFmt_Files(ArchiveHandle* AH);
extern void InitArchiveFmt_PlainText(ArchiveHandle* AH); extern void InitArchiveFmt_Null(ArchiveHandle* AH);
extern void InitArchiveFmt_Tar(ArchiveHandle* AH);
extern int isValidTarHeader(char *header);
extern OutputContext SetOutput(ArchiveHandle* AH, char *filename, int compression); extern OutputContext SetOutput(ArchiveHandle* AH, char *filename, int compression);
extern void ResetOutput(ArchiveHandle* AH, OutputContext savedContext); extern void ResetOutput(ArchiveHandle* AH, OutputContext savedContext);
...@@ -190,4 +268,6 @@ extern void ResetOutput(ArchiveHandle* AH, OutputContext savedContext); ...@@ -190,4 +268,6 @@ extern void ResetOutput(ArchiveHandle* AH, OutputContext savedContext);
int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle* AH); int ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle* AH);
int ahprintf(ArchiveHandle* AH, const char *fmt, ...); int ahprintf(ArchiveHandle* AH, const char *fmt, ...);
void ahlog(ArchiveHandle* AH, int level, const char *fmt, ...);
#endif #endif
This diff is collapsed.
...@@ -47,10 +47,17 @@ static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te); ...@@ -47,10 +47,17 @@ static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te);
static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te); static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te);
static void _PrintExtraToc(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 { typedef struct {
int hasSeek; int hasSeek;
int filePos; int filePos;
FILE *blobToc;
} lclContext; } lclContext;
typedef struct { typedef struct {
...@@ -62,6 +69,10 @@ typedef struct { ...@@ -62,6 +69,10 @@ typedef struct {
char *filename; char *filename;
} lclTocEntry; } lclTocEntry;
static char* progname = "Archiver(files)";
static void _LoadBlobs(ArchiveHandle* AH, RestoreOptions *ropt);
static void _getBlobTocEntry(ArchiveHandle* AH, int *oid, char *fname);
/* /*
* Initializer * Initializer
*/ */
...@@ -84,6 +95,11 @@ void InitArchiveFmt_Files(ArchiveHandle* AH) ...@@ -84,6 +95,11 @@ void InitArchiveFmt_Files(ArchiveHandle* AH)
AH->WriteExtraTocPtr = _WriteExtraToc; AH->WriteExtraTocPtr = _WriteExtraToc;
AH->PrintExtraTocPtr = _PrintExtraToc; AH->PrintExtraTocPtr = _PrintExtraToc;
AH->StartBlobsPtr = _StartBlobs;
AH->StartBlobPtr = _StartBlob;
AH->EndBlobPtr = _EndBlob;
AH->EndBlobsPtr = _EndBlobs;
/* /*
* Set up some special context used in compressing data. * Set up some special context used in compressing data.
*/ */
...@@ -95,6 +111,13 @@ void InitArchiveFmt_Files(ArchiveHandle* AH) ...@@ -95,6 +111,13 @@ void InitArchiveFmt_Files(ArchiveHandle* AH)
* Now open the TOC file * Now open the TOC file
*/ */
if (AH->mode == archModeWrite) { 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) { if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
AH->FH = fopen(AH->fSpec, PG_BINARY_W); AH->FH = fopen(AH->fSpec, PG_BINARY_W);
} else { } else {
...@@ -107,7 +130,8 @@ void InitArchiveFmt_Files(ArchiveHandle* AH) ...@@ -107,7 +130,8 @@ void InitArchiveFmt_Files(ArchiveHandle* AH)
} }
} else { } else { /* Read Mode */
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) { if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
AH->FH = fopen(AH->fSpec, PG_BINARY_R); AH->FH = fopen(AH->fSpec, PG_BINARY_R);
} else { } else {
...@@ -129,7 +153,7 @@ void InitArchiveFmt_Files(ArchiveHandle* AH) ...@@ -129,7 +153,7 @@ void InitArchiveFmt_Files(ArchiveHandle* AH)
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te) static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te)
{ {
lclTocEntry* ctx; lclTocEntry* ctx;
char fn[1024]; char fn[K_STD_BUF_SIZE];
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry)); ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry));
if (te->dataDumper) { if (te->dataDumper) {
...@@ -218,35 +242,98 @@ static void _EndData(ArchiveHandle* AH, TocEntry* te) ...@@ -218,35 +242,98 @@ static void _EndData(ArchiveHandle* AH, TocEntry* te)
} }
/* /*
* Print data for a given TOC entry * Print data for a given file
*/ */
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt) static void _PrintFileData(ArchiveHandle* AH, char *filename, RestoreOptions *ropt)
{ {
lclTocEntry* tctx = (lclTocEntry*) te->formatData;
char buf[4096]; char buf[4096];
int cnt; int cnt;
if (!tctx->filename) if (!filename)
return; return;
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
AH->FH = gzopen(tctx->filename,"rb"); AH->FH = gzopen(filename,"rb");
#else #else
AH->FH = fopen(tctx->filename,PG_BINARY_R); AH->FH = fopen(filename,PG_BINARY_R);
#endif #endif
ahprintf(AH, "--\n-- Data for TOC Entry ID %d (OID %s) %s %s\n--\n\n", while ( (cnt = GZREAD(buf, 1, 4095, AH->FH)) > 0) {
te->id, te->oid, te->desc, te->name); buf[cnt] = '\0';
while ( (cnt = GZREAD(buf, 1, 4096, AH->FH)) > 0) {
ahwrite(buf, 1, cnt, AH); ahwrite(buf, 1, cnt, AH);
} }
GZCLOSE(AH->FH); 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, " ");
ahprintf(AH, "\n\n"); 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) static int _WriteByte(ArchiveHandle* AH, const int i)
{ {
lclContext* ctx = (lclContext*)AH->formatData; lclContext* ctx = (lclContext*)AH->formatData;
...@@ -284,6 +371,7 @@ static int _ReadBuf(ArchiveHandle* AH, void* buf, int len) ...@@ -284,6 +371,7 @@ static int _ReadBuf(ArchiveHandle* AH, void* buf, int len)
{ {
lclContext* ctx = (lclContext*)AH->formatData; lclContext* ctx = (lclContext*)AH->formatData;
int res; int res;
res = fread(buf, 1, len, AH->FH); res = fread(buf, 1, len, AH->FH);
ctx->filePos += res; ctx->filePos += res;
return res; return res;
...@@ -301,3 +389,95 @@ static void _CloseArchive(ArchiveHandle* AH) ...@@ -301,3 +389,95 @@ static void _CloseArchive(ArchiveHandle* AH)
AH->FH = NULL; 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);
}
This diff is collapsed.
...@@ -84,19 +84,24 @@ typedef struct option optType; ...@@ -84,19 +84,24 @@ typedef struct option optType;
struct option cmdopts[] = { struct option cmdopts[] = {
{ "clean", 0, NULL, 'c' }, { "clean", 0, NULL, 'c' },
{ "data-only", 0, NULL, 'a' }, { "data-only", 0, NULL, 'a' },
{ "dbname", 1, NULL, 'd' },
{ "file", 1, NULL, 'f' }, { "file", 1, NULL, 'f' },
{ "format", 1, NULL, 'F' }, { "format", 1, NULL, 'F' },
{ "function", 2, NULL, 'p' }, { "function", 2, NULL, 'P' },
{ "index", 2, NULL, 'i'}, { "host", 1, NULL, 'h' },
{ "ignore-version", 0, NULL, 'i'},
{ "index", 2, NULL, 'I'},
{ "list", 0, NULL, 'l'}, { "list", 0, NULL, 'l'},
{ "no-acl", 0, NULL, 'x' }, { "no-acl", 0, NULL, 'x' },
{ "port", 1, NULL, 'p' },
{ "oid-order", 0, NULL, 'o'}, { "oid-order", 0, NULL, 'o'},
{ "orig-order", 0, NULL, 'O' }, { "orig-order", 0, NULL, 'O' },
{ "password", 0, NULL, 'u' },
{ "rearrange", 0, NULL, 'r'}, { "rearrange", 0, NULL, 'r'},
{ "schema-only", 0, NULL, 's' }, { "schema-only", 0, NULL, 's' },
{ "table", 2, NULL, 't'}, { "table", 2, NULL, 't'},
{ "trigger", 2, NULL, 'T' }, { "trigger", 2, NULL, 'T' },
{ "use-list", 1, NULL, 'u'}, { "use-list", 1, NULL, 'U'},
{ "verbose", 0, NULL, 'v' }, { "verbose", 0, NULL, 'v' },
{ NULL, 0, NULL, 0} { NULL, 0, NULL, 0}
}; };
...@@ -115,9 +120,9 @@ int main(int argc, char **argv) ...@@ -115,9 +120,9 @@ int main(int argc, char **argv)
progname = *argv; progname = *argv;
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
while ((c = getopt_long(argc, argv, "acf:F:i:loOp:st:T:u:vx", cmdopts, NULL)) != EOF) while ((c = getopt_long(argc, argv, "acd:f:F:h:i:loOp:st:T:u:U:vx", cmdopts, NULL)) != EOF)
#else #else
while ((c = getopt(argc, argv, "acf:F:i:loOp:st:T:u:vx")) != -1) while ((c = getopt(argc, argv, "acd:f:F:h:i:loOp:st:T:u:U:vx")) != -1)
#endif #endif
{ {
switch (c) switch (c)
...@@ -129,6 +134,13 @@ int main(int argc, char **argv) ...@@ -129,6 +134,13 @@ int main(int argc, char **argv)
* create */ * create */
opts->dropSchema = 1; opts->dropSchema = 1;
break; break;
case 'd':
if (strlen(optarg) != 0)
{
opts->dbname = strdup(optarg);
opts->useDB = 1;
}
break;
case 'f': /* output file name */ case 'f': /* output file name */
opts->filename = strdup(optarg); opts->filename = strdup(optarg);
break; break;
...@@ -136,22 +148,32 @@ int main(int argc, char **argv) ...@@ -136,22 +148,32 @@ int main(int argc, char **argv)
if (strlen(optarg) != 0) if (strlen(optarg) != 0)
opts->formatName = strdup(optarg); opts->formatName = strdup(optarg);
break; break;
case 'h':
if (strlen(optarg) != 0)
opts->pghost = strdup(optarg);
break;
case 'i':
opts->ignoreVersion = 1;
break;
case 'o': case 'o':
opts->oidOrder = 1; opts->oidOrder = 1;
break; break;
case 'O': case 'O':
opts->origOrder = 1; opts->origOrder = 1;
break; break;
case 'p':
if (strlen(optarg) != 0)
opts->pgport = strdup(optarg);
break;
case 'r': case 'r':
opts->rearrange = 1; opts->rearrange = 1;
break; break;
case 'P': /* Function */
case 'p': /* Function */
opts->selTypes = 1; opts->selTypes = 1;
opts->selFunction = 1; opts->selFunction = 1;
opts->functionNames = _cleanupName(optarg); opts->functionNames = _cleanupName(optarg);
break; break;
case 'i': /* Index */ case 'I': /* Index */
opts->selTypes = 1; opts->selTypes = 1;
opts->selIndex = 1; opts->selIndex = 1;
opts->indexNames = _cleanupName(optarg); opts->indexNames = _cleanupName(optarg);
...@@ -173,7 +195,11 @@ int main(int argc, char **argv) ...@@ -173,7 +195,11 @@ int main(int argc, char **argv)
opts->tocSummary = 1; opts->tocSummary = 1;
break; break;
case 'u': /* input TOC summary file name */ case 'u':
opts->requirePassword = 1;
break;
case 'U': /* input TOC summary file name */
opts->tocFile = strdup(optarg); opts->tocFile = strdup(optarg);
break; break;
...@@ -209,14 +235,23 @@ int main(int argc, char **argv) ...@@ -209,14 +235,23 @@ int main(int argc, char **argv)
opts->format = archFiles; opts->format = archFiles;
break; break;
case 't':
case 'T':
opts->format = archTar;
break;
default: default:
fprintf(stderr, "%s: Unknown archive format '%s', please specify 'f' or 'c'\n", progname, opts->formatName); fprintf(stderr, "%s: Unknown archive format '%s', please specify 't' or 'c'\n",
progname, opts->formatName);
exit (1); exit (1);
} }
} }
AH = OpenArchive(fileSpec, opts->format); AH = OpenArchive(fileSpec, opts->format);
/* Let the archiver know how noisy to be */
AH->verbose = opts->verbose;
if (opts->tocFile) if (opts->tocFile)
SortTocFromFile(AH, opts); SortTocFromFile(AH, opts);
...@@ -226,7 +261,9 @@ int main(int argc, char **argv) ...@@ -226,7 +261,9 @@ int main(int argc, char **argv)
SortTocByID(AH); SortTocByID(AH);
if (opts->rearrange) { if (opts->rearrange) {
MoveToStart(AH, "<Init>");
MoveToEnd(AH, "TABLE DATA"); MoveToEnd(AH, "TABLE DATA");
MoveToEnd(AH, "BLOBS");
MoveToEnd(AH, "INDEX"); MoveToEnd(AH, "INDEX");
MoveToEnd(AH, "TRIGGER"); MoveToEnd(AH, "TRIGGER");
MoveToEnd(AH, "RULE"); MoveToEnd(AH, "RULE");
...@@ -250,39 +287,48 @@ static void usage(const char *progname) ...@@ -250,39 +287,48 @@ static void usage(const char *progname)
fprintf(stderr, fprintf(stderr,
"usage: %s [options] [backup file]\n" "usage: %s [options] [backup file]\n"
" -a, --data-only \t dump out only the data, no schema\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" " -c, --clean \t clean(drop) schema prior to create\n"
" -f filename \t script output filename\n" " -f filename \t script output filename\n"
" -F, --format {c|f} \t specify backup file format\n" " -F, --format {c|f} \t specify backup file format\n"
" -p, --function[=name] \t dump functions or named function\n" " -h, --host <hostname> \t server host name\n"
" -i, --index[=name] \t dump indexes or named index\n" " -i, --index[=name] \t dump indexes or named index\n"
" -l, --list \t dump summarized TOC for this file\n" " -l, --list \t dump summarized TOC for this file\n"
" -o, --oid-order \t dump in oid order\n" " -o, --oid-order \t dump in oid order\n"
" -O, --orig-order \t dump in original dump 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" " -r, --rearrange \t rearrange output to put indexes etc at end\n"
" -s, --schema-only \t dump out only the schema, no data\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 [table], --table[=table] \t dump for this table only\n"
" -T, --trigger[=name] \t dump triggers or named trigger\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" " -u, --password \t use password authentication\n"
" -v \t verbose\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" " -x, --no-acl \t skip dumping of ACLs (grant/revoke)\n"
, progname); , progname);
#else #else
fprintf(stderr, fprintf(stderr,
"usage: %s [options] [backup file]\n" "usage: %s [options] [backup file]\n"
" -a \t dump out only the data, no schema\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" " -c \t clean(drop) schema prior to create\n"
" -f filename NOT IMPLEMENTED \t script output filename\n" " -f filename NOT IMPLEMENTED \t script output filename\n"
" -F {c|f} \t specify backup file format\n" " -F {c|f} \t specify backup file format\n"
" -p name \t dump functions or named function\n" " -h, <hostname> \t server host name\n"
" -i name \t dump indexes or named index\n" " -i name \t dump indexes or named index\n"
" -l \t dump summarized TOC for this file\n" " -l \t dump summarized TOC for this file\n"
" -o \t dump in oid order\n" " -o \t dump in oid order\n"
" -O \t dump in original dump 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" " -r \t rearrange output to put indexes etc at end\n"
" -s \t dump out only the schema, no data\n" " -s \t dump out only the schema, no data\n"
" -t name \t dump for this table only\n" " -t name \t dump for this table only\n"
" -T name \t dump triggers or named trigger\n" " -T name \t dump triggers or named trigger\n"
" -u filename \t use specified TOC for ordering output from this file\n" " -u \t use password authentication\n"
" -U filename \t use specified TOC for ordering output from this file\n"
" -v \t verbose\n" " -v \t verbose\n"
" -x \t skip dumping of ACLs (grant/revoke)\n" " -x \t skip dumping of ACLs (grant/revoke)\n"
, progname); , progname);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment