mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
- 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
This commit is contained in:
parent
0143d391c6
commit
e8f69be054
@ -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
|
|||||||
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
|
||||||
|
@ -1,17 +1,23 @@
|
|||||||
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:
|
|||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,125 +1,154 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* pg_backup.h
|
* pg_backup.h
|
||||||
*
|
*
|
||||||
* Public interface to the pg_dump archiver routines.
|
* Public interface to the pg_dump archiver routines.
|
||||||
*
|
*
|
||||||
* See the headers to pg_restore for more details.
|
* See the headers to pg_restore for more details.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000, Philip Warner
|
* Copyright (c) 2000, Philip Warner
|
||||||
* Rights are granted to use this software in any way so long
|
* Rights are granted to use this software in any way so long
|
||||||
* as this notice is not removed.
|
* as this notice is not removed.
|
||||||
*
|
*
|
||||||
* The author is not responsible for loss or damages that may
|
* The author is not responsible for loss or damages that may
|
||||||
* result from it's use.
|
* result from it's use.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
*
|
*
|
||||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
|
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
|
||||||
*
|
*
|
||||||
* Initial version.
|
* Initial version.
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PG_BACKUP__
|
#ifndef PG_BACKUP__
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "c.h"
|
#include "c.h"
|
||||||
|
|
||||||
#define PG_BACKUP__
|
#define PG_BACKUP__
|
||||||
|
|
||||||
typedef enum _archiveFormat {
|
#include "postgres.h"
|
||||||
archUnknown = 0,
|
#include "libpq-fe.h"
|
||||||
archCustom = 1,
|
|
||||||
archFiles = 2,
|
typedef enum _archiveFormat {
|
||||||
archTar = 3,
|
archUnknown = 0,
|
||||||
archPlainText = 4
|
archCustom = 1,
|
||||||
} ArchiveFormat;
|
archFiles = 2,
|
||||||
|
archTar = 3,
|
||||||
/*
|
archNull = 4
|
||||||
* We may want to have so user-readbale data, but in the mean
|
} ArchiveFormat;
|
||||||
* time this gives us some abstraction and type checking.
|
|
||||||
*/
|
/*
|
||||||
typedef struct _Archive {
|
* We may want to have so user-readbale data, but in the mean
|
||||||
/* Nothing here */
|
* time this gives us some abstraction and type checking.
|
||||||
} Archive;
|
*/
|
||||||
|
typedef struct _Archive {
|
||||||
typedef int (*DataDumperPtr)(Archive* AH, char* oid, void* userArg);
|
int verbose;
|
||||||
|
/* The rest is private */
|
||||||
typedef struct _restoreOptions {
|
} Archive;
|
||||||
int dataOnly;
|
|
||||||
int dropSchema;
|
typedef int (*DataDumperPtr)(Archive* AH, char* oid, void* userArg);
|
||||||
char *filename;
|
|
||||||
int schemaOnly;
|
typedef struct _restoreOptions {
|
||||||
int verbose;
|
int dataOnly;
|
||||||
int aclsSkip;
|
int dropSchema;
|
||||||
int tocSummary;
|
char *filename;
|
||||||
char *tocFile;
|
int schemaOnly;
|
||||||
int oidOrder;
|
int verbose;
|
||||||
int origOrder;
|
int aclsSkip;
|
||||||
int rearrange;
|
int tocSummary;
|
||||||
int format;
|
char *tocFile;
|
||||||
char *formatName;
|
int oidOrder;
|
||||||
|
int origOrder;
|
||||||
int selTypes;
|
int rearrange;
|
||||||
int selIndex;
|
int format;
|
||||||
int selFunction;
|
char *formatName;
|
||||||
int selTrigger;
|
|
||||||
int selTable;
|
int selTypes;
|
||||||
char *indexNames;
|
int selIndex;
|
||||||
char *functionNames;
|
int selFunction;
|
||||||
char *tableNames;
|
int selTrigger;
|
||||||
char *triggerNames;
|
int selTable;
|
||||||
|
char *indexNames;
|
||||||
int *idWanted;
|
char *functionNames;
|
||||||
int limitToList;
|
char *tableNames;
|
||||||
int compression;
|
char *triggerNames;
|
||||||
|
|
||||||
} RestoreOptions;
|
int useDB;
|
||||||
|
char *dbname;
|
||||||
/*
|
char *pgport;
|
||||||
* Main archiver interface.
|
char *pghost;
|
||||||
*/
|
int ignoreVersion;
|
||||||
|
int requirePassword;
|
||||||
/* Called to add a TOC entry */
|
|
||||||
extern void ArchiveEntry(Archive* AH, const char* oid, const char* name,
|
int *idWanted;
|
||||||
const char* desc, const char* (deps[]), const char* defn,
|
int limitToList;
|
||||||
const char* dropStmt, const char* owner,
|
int compression;
|
||||||
DataDumperPtr dumpFn, void* dumpArg);
|
|
||||||
|
} RestoreOptions;
|
||||||
/* Called to write *data* to the archive */
|
|
||||||
extern int WriteData(Archive* AH, const void* data, int dLen);
|
/*
|
||||||
|
* Main archiver interface.
|
||||||
extern void CloseArchive(Archive* AH);
|
*/
|
||||||
|
|
||||||
extern void RestoreArchive(Archive* AH, RestoreOptions *ropt);
|
extern void exit_horribly(Archive *AH, const char *fmt, ...);
|
||||||
|
|
||||||
/* Open an existing archive */
|
/* Lets the archibe know we have a DB connection to shutdown if it dies */
|
||||||
extern Archive* OpenArchive(const char* FileSpec, ArchiveFormat fmt);
|
|
||||||
|
PGconn* ConnectDatabase(Archive *AH,
|
||||||
/* Create a new archive */
|
const char* dbname,
|
||||||
extern Archive* CreateArchive(const char* FileSpec, ArchiveFormat fmt, int compression);
|
const char* pghost,
|
||||||
|
const char* pgport,
|
||||||
/* The --list option */
|
const int reqPwd,
|
||||||
extern void PrintTOCSummary(Archive* AH, RestoreOptions *ropt);
|
const int ignoreVersion);
|
||||||
|
|
||||||
extern RestoreOptions* NewRestoreOptions(void);
|
|
||||||
|
/* Called to add a TOC entry */
|
||||||
/* Rearrange TOC entries */
|
extern void ArchiveEntry(Archive* AH, const char* oid, const char* name,
|
||||||
extern void MoveToStart(Archive* AH, char *oType);
|
const char* desc, const char* (deps[]), const char* defn,
|
||||||
extern void MoveToEnd(Archive* AH, char *oType);
|
const char* dropStmt, const char* copyStmt, const char* owner,
|
||||||
extern void SortTocByOID(Archive* AH);
|
DataDumperPtr dumpFn, void* dumpArg);
|
||||||
extern void SortTocByID(Archive* AH);
|
|
||||||
extern void SortTocFromFile(Archive* AH, RestoreOptions *ropt);
|
/* Called to write *data* to the archive */
|
||||||
|
extern int WriteData(Archive* AH, const void* data, int dLen);
|
||||||
/* Convenience functions used only when writing DATA */
|
|
||||||
extern int archputs(const char *s, Archive* AH);
|
//extern int StartBlobs(Archive* AH);
|
||||||
extern int archputc(const char c, Archive* AH);
|
//extern int EndBlobs(Archive* AH);
|
||||||
extern int archprintf(Archive* AH, const char *fmt, ...);
|
extern int StartBlob(Archive* AH, int oid);
|
||||||
|
extern int EndBlob(Archive* AH, int oid);
|
||||||
#endif
|
|
||||||
|
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
@ -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;
|
|||||||
#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,10 +84,15 @@ 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 int (*WriteBytePtr) (struct _archiveHandle* AH, const int i);
|
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 (*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);
|
||||||
typedef int (*ReadBufPtr) (struct _archiveHandle* AH, void* buf, int len);
|
typedef int (*ReadBufPtr) (struct _archiveHandle* AH, void* buf, int len);
|
||||||
typedef void (*SaveArchivePtr) (struct _archiveHandle* AH);
|
typedef void (*SaveArchivePtr) (struct _archiveHandle* AH);
|
||||||
typedef void (*WriteExtraTocPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
|
typedef void (*WriteExtraTocPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
|
||||||
typedef void (*ReadExtraTocPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
|
typedef void (*ReadExtraTocPtr) (struct _archiveHandle* AH, struct _tocEntry* te);
|
||||||
@ -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 {
|
|||||||
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,11 +168,33 @@ typedef struct _archiveHandle {
|
|||||||
PrintExtraTocPtr PrintExtraTocPtr; /* Extra TOC info for format */
|
PrintExtraTocPtr PrintExtraTocPtr; /* Extra TOC info for format */
|
||||||
PrintTocDataPtr PrintTocDataPtr;
|
PrintTocDataPtr PrintTocDataPtr;
|
||||||
|
|
||||||
int lastID; /* Last internal ID for a TOC entry */
|
StartBlobsPtr StartBlobsPtr;
|
||||||
char* fSpec; /* Archive File Spec */
|
EndBlobsPtr EndBlobsPtr;
|
||||||
FILE *FH; /* General purpose file handle */
|
StartBlobPtr StartBlobPtr;
|
||||||
void *OF;
|
EndBlobPtr EndBlobPtr;
|
||||||
int gzOut; /* Output file */
|
|
||||||
|
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 */
|
||||||
|
char* fSpec; /* Archive File Spec */
|
||||||
|
FILE *FH; /* General purpose file handle */
|
||||||
|
void *OF;
|
||||||
|
int gzOut; /* Output file */
|
||||||
|
|
||||||
struct _tocEntry* toc; /* List of TOC entries */
|
struct _tocEntry* toc; /* List of TOC entries */
|
||||||
int tocCount; /* Number of TOC entries */
|
int tocCount; /* Number of TOC entries */
|
||||||
@ -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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
} 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);
|
||||||
@ -175,19 +247,27 @@ extern int TocIDRequired(ArchiveHandle* AH, int id, RestoreOptions *ropt);
|
|||||||
* Mandatory routines for each supported format
|
* Mandatory routines for each supported format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int WriteInt(ArchiveHandle* AH, int i);
|
extern int WriteInt(ArchiveHandle* AH, int i);
|
||||||
extern int ReadInt(ArchiveHandle* AH);
|
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 InitArchiveFmt_Custom(ArchiveHandle* AH);
|
extern void StartRestoreBlob(ArchiveHandle* AH, int oid);
|
||||||
extern void InitArchiveFmt_Files(ArchiveHandle* AH);
|
extern void EndRestoreBlob(ArchiveHandle* AH, int oid);
|
||||||
extern void InitArchiveFmt_PlainText(ArchiveHandle* AH);
|
|
||||||
|
extern void InitArchiveFmt_Custom(ArchiveHandle* AH);
|
||||||
|
extern void InitArchiveFmt_Files(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);
|
||||||
|
|
||||||
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
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,303 +1,483 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* pg_backup_files.c
|
* pg_backup_files.c
|
||||||
*
|
*
|
||||||
* This file is copied from the 'custom' format file, but dumps data into
|
* This file is copied from the 'custom' format file, but dumps data into
|
||||||
* separate files, and the TOC into the 'main' file.
|
* separate files, and the TOC into the 'main' file.
|
||||||
*
|
*
|
||||||
* IT IS FOR DEMONSTRATION PURPOSES ONLY.
|
* IT IS FOR DEMONSTRATION PURPOSES ONLY.
|
||||||
*
|
*
|
||||||
* (and could probably be used as a basis for writing a tar file)
|
* (and could probably be used as a basis for writing a tar file)
|
||||||
*
|
*
|
||||||
* See the headers to pg_restore for more details.
|
* See the headers to pg_restore for more details.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000, Philip Warner
|
* Copyright (c) 2000, Philip Warner
|
||||||
* Rights are granted to use this software in any way so long
|
* Rights are granted to use this software in any way so long
|
||||||
* as this notice is not removed.
|
* as this notice is not removed.
|
||||||
*
|
*
|
||||||
* The author is not responsible for loss or damages that may
|
* The author is not responsible for loss or damages that may
|
||||||
* result from it's use.
|
* result from it's use.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
*
|
*
|
||||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
|
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
|
||||||
*
|
*
|
||||||
* Initial version.
|
* Initial version.
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "pg_backup.h"
|
#include "pg_backup.h"
|
||||||
#include "pg_backup_archiver.h"
|
#include "pg_backup_archiver.h"
|
||||||
|
|
||||||
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te);
|
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te);
|
||||||
static void _StartData(ArchiveHandle* AH, TocEntry* te);
|
static void _StartData(ArchiveHandle* AH, TocEntry* te);
|
||||||
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen);
|
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen);
|
||||||
static void _EndData(ArchiveHandle* AH, TocEntry* te);
|
static void _EndData(ArchiveHandle* AH, TocEntry* te);
|
||||||
static int _WriteByte(ArchiveHandle* AH, const int i);
|
static int _WriteByte(ArchiveHandle* AH, const int i);
|
||||||
static int _ReadByte(ArchiveHandle* );
|
static int _ReadByte(ArchiveHandle* );
|
||||||
static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len);
|
static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len);
|
||||||
static int _ReadBuf(ArchiveHandle* AH, void* buf, int len);
|
static int _ReadBuf(ArchiveHandle* AH, void* buf, int len);
|
||||||
static void _CloseArchive(ArchiveHandle* AH);
|
static void _CloseArchive(ArchiveHandle* AH);
|
||||||
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt);
|
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt);
|
||||||
static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te);
|
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);
|
||||||
typedef struct {
|
static void _StartBlob(ArchiveHandle* AH, TocEntry* te, int oid);
|
||||||
int hasSeek;
|
static void _EndBlob(ArchiveHandle* AH, TocEntry* te, int oid);
|
||||||
int filePos;
|
static void _EndBlobs(ArchiveHandle* AH, TocEntry* te);
|
||||||
} lclContext;
|
|
||||||
|
#define K_STD_BUF_SIZE 1024
|
||||||
typedef struct {
|
|
||||||
#ifdef HAVE_LIBZ
|
typedef struct {
|
||||||
gzFile *FH;
|
int hasSeek;
|
||||||
#else
|
int filePos;
|
||||||
FILE *FH;
|
FILE *blobToc;
|
||||||
#endif
|
} lclContext;
|
||||||
char *filename;
|
|
||||||
} lclTocEntry;
|
typedef struct {
|
||||||
|
#ifdef HAVE_LIBZ
|
||||||
/*
|
gzFile *FH;
|
||||||
* Initializer
|
#else
|
||||||
*/
|
FILE *FH;
|
||||||
void InitArchiveFmt_Files(ArchiveHandle* AH)
|
#endif
|
||||||
{
|
char *filename;
|
||||||
lclContext* ctx;
|
} lclTocEntry;
|
||||||
|
|
||||||
/* Assuming static functions, this can be copied for each format. */
|
static char* progname = "Archiver(files)";
|
||||||
AH->ArchiveEntryPtr = _ArchiveEntry;
|
static void _LoadBlobs(ArchiveHandle* AH, RestoreOptions *ropt);
|
||||||
AH->StartDataPtr = _StartData;
|
static void _getBlobTocEntry(ArchiveHandle* AH, int *oid, char *fname);
|
||||||
AH->WriteDataPtr = _WriteData;
|
|
||||||
AH->EndDataPtr = _EndData;
|
/*
|
||||||
AH->WriteBytePtr = _WriteByte;
|
* Initializer
|
||||||
AH->ReadBytePtr = _ReadByte;
|
*/
|
||||||
AH->WriteBufPtr = _WriteBuf;
|
void InitArchiveFmt_Files(ArchiveHandle* AH)
|
||||||
AH->ReadBufPtr = _ReadBuf;
|
{
|
||||||
AH->ClosePtr = _CloseArchive;
|
lclContext* ctx;
|
||||||
AH->PrintTocDataPtr = _PrintTocData;
|
|
||||||
AH->ReadExtraTocPtr = _ReadExtraToc;
|
/* Assuming static functions, this can be copied for each format. */
|
||||||
AH->WriteExtraTocPtr = _WriteExtraToc;
|
AH->ArchiveEntryPtr = _ArchiveEntry;
|
||||||
AH->PrintExtraTocPtr = _PrintExtraToc;
|
AH->StartDataPtr = _StartData;
|
||||||
|
AH->WriteDataPtr = _WriteData;
|
||||||
/*
|
AH->EndDataPtr = _EndData;
|
||||||
* Set up some special context used in compressing data.
|
AH->WriteBytePtr = _WriteByte;
|
||||||
*/
|
AH->ReadBytePtr = _ReadByte;
|
||||||
ctx = (lclContext*)malloc(sizeof(lclContext));
|
AH->WriteBufPtr = _WriteBuf;
|
||||||
AH->formatData = (void*)ctx;
|
AH->ReadBufPtr = _ReadBuf;
|
||||||
ctx->filePos = 0;
|
AH->ClosePtr = _CloseArchive;
|
||||||
|
AH->PrintTocDataPtr = _PrintTocData;
|
||||||
/*
|
AH->ReadExtraTocPtr = _ReadExtraToc;
|
||||||
* Now open the TOC file
|
AH->WriteExtraTocPtr = _WriteExtraToc;
|
||||||
*/
|
AH->PrintExtraTocPtr = _PrintExtraToc;
|
||||||
if (AH->mode == archModeWrite) {
|
|
||||||
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
|
AH->StartBlobsPtr = _StartBlobs;
|
||||||
AH->FH = fopen(AH->fSpec, PG_BINARY_W);
|
AH->StartBlobPtr = _StartBlob;
|
||||||
} else {
|
AH->EndBlobPtr = _EndBlob;
|
||||||
AH->FH = stdout;
|
AH->EndBlobsPtr = _EndBlobs;
|
||||||
}
|
|
||||||
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
|
/*
|
||||||
|
* Set up some special context used in compressing data.
|
||||||
if (AH->compression < 0 || AH->compression > 9) {
|
*/
|
||||||
AH->compression = Z_DEFAULT_COMPRESSION;
|
ctx = (lclContext*)malloc(sizeof(lclContext));
|
||||||
}
|
AH->formatData = (void*)ctx;
|
||||||
|
ctx->filePos = 0;
|
||||||
|
|
||||||
} else {
|
/*
|
||||||
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
|
* Now open the TOC file
|
||||||
AH->FH = fopen(AH->fSpec, PG_BINARY_R);
|
*/
|
||||||
} else {
|
if (AH->mode == archModeWrite) {
|
||||||
AH->FH = stdin;
|
|
||||||
}
|
fprintf(stderr, "\n*************************************************************\n"
|
||||||
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
|
"* WARNING: This format is for demonstration purposes. It is *\n"
|
||||||
|
"* not intended for general use. Files will be dumped *\n"
|
||||||
ReadHead(AH);
|
"* into the current working directory. *\n"
|
||||||
ReadToc(AH);
|
"***************************************************************\n\n");
|
||||||
fclose(AH->FH); /* Nothing else in the file... */
|
|
||||||
}
|
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
|
||||||
|
AH->FH = fopen(AH->fSpec, PG_BINARY_W);
|
||||||
}
|
} else {
|
||||||
|
AH->FH = stdout;
|
||||||
/*
|
}
|
||||||
* - Start a new TOC entry
|
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
|
||||||
* Setup the output file name.
|
|
||||||
*/
|
if (AH->compression < 0 || AH->compression > 9) {
|
||||||
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te)
|
AH->compression = Z_DEFAULT_COMPRESSION;
|
||||||
{
|
}
|
||||||
lclTocEntry* ctx;
|
|
||||||
char fn[1024];
|
|
||||||
|
} else { /* Read Mode */
|
||||||
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry));
|
|
||||||
if (te->dataDumper) {
|
if (AH->fSpec && strcmp(AH->fSpec,"") != 0) {
|
||||||
#ifdef HAVE_LIBZ
|
AH->FH = fopen(AH->fSpec, PG_BINARY_R);
|
||||||
if (AH->compression == 0) {
|
} else {
|
||||||
sprintf(fn, "%d.dat", te->id);
|
AH->FH = stdin;
|
||||||
} else {
|
}
|
||||||
sprintf(fn, "%d.dat.gz", te->id);
|
ctx->hasSeek = (fseek(AH->FH, 0, SEEK_CUR) == 0);
|
||||||
}
|
|
||||||
#else
|
ReadHead(AH);
|
||||||
sprintf(fn, "%d.dat", te->id);
|
ReadToc(AH);
|
||||||
#endif
|
fclose(AH->FH); /* Nothing else in the file... */
|
||||||
ctx->filename = strdup(fn);
|
}
|
||||||
} else {
|
|
||||||
ctx->filename = NULL;
|
}
|
||||||
ctx->FH = NULL;
|
|
||||||
}
|
/*
|
||||||
te->formatData = (void*)ctx;
|
* - Start a new TOC entry
|
||||||
}
|
* Setup the output file name.
|
||||||
|
*/
|
||||||
static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te)
|
static void _ArchiveEntry(ArchiveHandle* AH, TocEntry* te)
|
||||||
{
|
{
|
||||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData;
|
lclTocEntry* ctx;
|
||||||
|
char fn[K_STD_BUF_SIZE];
|
||||||
if (ctx->filename) {
|
|
||||||
WriteStr(AH, ctx->filename);
|
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry));
|
||||||
} else {
|
if (te->dataDumper) {
|
||||||
WriteStr(AH, "");
|
#ifdef HAVE_LIBZ
|
||||||
}
|
if (AH->compression == 0) {
|
||||||
}
|
sprintf(fn, "%d.dat", te->id);
|
||||||
|
} else {
|
||||||
static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te)
|
sprintf(fn, "%d.dat.gz", te->id);
|
||||||
{
|
}
|
||||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData;
|
#else
|
||||||
|
sprintf(fn, "%d.dat", te->id);
|
||||||
if (ctx == NULL) {
|
#endif
|
||||||
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry));
|
ctx->filename = strdup(fn);
|
||||||
te->formatData = (void*)ctx;
|
} else {
|
||||||
}
|
ctx->filename = NULL;
|
||||||
|
ctx->FH = NULL;
|
||||||
ctx->filename = ReadStr(AH);
|
}
|
||||||
if (strlen(ctx->filename) == 0) {
|
te->formatData = (void*)ctx;
|
||||||
free(ctx->filename);
|
}
|
||||||
ctx->filename = NULL;
|
|
||||||
}
|
static void _WriteExtraToc(ArchiveHandle* AH, TocEntry* te)
|
||||||
ctx->FH = NULL;
|
{
|
||||||
}
|
lclTocEntry* ctx = (lclTocEntry*)te->formatData;
|
||||||
|
|
||||||
static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te)
|
if (ctx->filename) {
|
||||||
{
|
WriteStr(AH, ctx->filename);
|
||||||
lclTocEntry* ctx = (lclTocEntry*)te->formatData;
|
} else {
|
||||||
|
WriteStr(AH, "");
|
||||||
ahprintf(AH, "-- File: %s\n", ctx->filename);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _StartData(ArchiveHandle* AH, TocEntry* te)
|
static void _ReadExtraToc(ArchiveHandle* AH, TocEntry* te)
|
||||||
{
|
{
|
||||||
lclTocEntry* tctx = (lclTocEntry*)te->formatData;
|
lclTocEntry* ctx = (lclTocEntry*)te->formatData;
|
||||||
char fmode[10];
|
|
||||||
|
if (ctx == NULL) {
|
||||||
sprintf(fmode, "wb%d", AH->compression);
|
ctx = (lclTocEntry*)malloc(sizeof(lclTocEntry));
|
||||||
|
te->formatData = (void*)ctx;
|
||||||
#ifdef HAVE_LIBZ
|
}
|
||||||
tctx->FH = gzopen(tctx->filename, fmode);
|
|
||||||
#else
|
ctx->filename = ReadStr(AH);
|
||||||
tctx->FH = fopen(tctx->filename, PG_BINARY_W);
|
if (strlen(ctx->filename) == 0) {
|
||||||
#endif
|
free(ctx->filename);
|
||||||
}
|
ctx->filename = NULL;
|
||||||
|
}
|
||||||
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen)
|
ctx->FH = NULL;
|
||||||
{
|
}
|
||||||
lclTocEntry* tctx = (lclTocEntry*)AH->currToc->formatData;
|
|
||||||
|
static void _PrintExtraToc(ArchiveHandle* AH, TocEntry* te)
|
||||||
GZWRITE((void*)data, 1, dLen, tctx->FH);
|
{
|
||||||
|
lclTocEntry* ctx = (lclTocEntry*)te->formatData;
|
||||||
return dLen;
|
|
||||||
}
|
ahprintf(AH, "-- File: %s\n", ctx->filename);
|
||||||
|
}
|
||||||
static void _EndData(ArchiveHandle* AH, TocEntry* te)
|
|
||||||
{
|
static void _StartData(ArchiveHandle* AH, TocEntry* te)
|
||||||
lclTocEntry* tctx = (lclTocEntry*) te->formatData;
|
{
|
||||||
|
lclTocEntry* tctx = (lclTocEntry*)te->formatData;
|
||||||
/* Close the file */
|
char fmode[10];
|
||||||
GZCLOSE(tctx->FH);
|
|
||||||
tctx->FH = NULL;
|
sprintf(fmode, "wb%d", AH->compression);
|
||||||
}
|
|
||||||
|
#ifdef HAVE_LIBZ
|
||||||
/*
|
tctx->FH = gzopen(tctx->filename, fmode);
|
||||||
* Print data for a given TOC entry
|
#else
|
||||||
*/
|
tctx->FH = fopen(tctx->filename, PG_BINARY_W);
|
||||||
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt)
|
#endif
|
||||||
{
|
}
|
||||||
lclTocEntry* tctx = (lclTocEntry*) te->formatData;
|
|
||||||
char buf[4096];
|
static int _WriteData(ArchiveHandle* AH, const void* data, int dLen)
|
||||||
int cnt;
|
{
|
||||||
|
lclTocEntry* tctx = (lclTocEntry*)AH->currToc->formatData;
|
||||||
if (!tctx->filename)
|
|
||||||
return;
|
GZWRITE((void*)data, 1, dLen, tctx->FH);
|
||||||
|
|
||||||
#ifdef HAVE_LIBZ
|
return dLen;
|
||||||
AH->FH = gzopen(tctx->filename,"rb");
|
}
|
||||||
#else
|
|
||||||
AH->FH = fopen(tctx->filename,PG_BINARY_R);
|
static void _EndData(ArchiveHandle* AH, TocEntry* te)
|
||||||
#endif
|
{
|
||||||
|
lclTocEntry* tctx = (lclTocEntry*) te->formatData;
|
||||||
ahprintf(AH, "--\n-- Data for TOC Entry ID %d (OID %s) %s %s\n--\n\n",
|
|
||||||
te->id, te->oid, te->desc, te->name);
|
/* Close the file */
|
||||||
|
GZCLOSE(tctx->FH);
|
||||||
while ( (cnt = GZREAD(buf, 1, 4096, AH->FH)) > 0) {
|
tctx->FH = NULL;
|
||||||
ahwrite(buf, 1, cnt, AH);
|
}
|
||||||
}
|
|
||||||
|
/*
|
||||||
GZCLOSE(AH->FH);
|
* Print data for a given file
|
||||||
|
*/
|
||||||
ahprintf(AH, "\n\n");
|
static void _PrintFileData(ArchiveHandle* AH, char *filename, RestoreOptions *ropt)
|
||||||
}
|
{
|
||||||
|
char buf[4096];
|
||||||
static int _WriteByte(ArchiveHandle* AH, const int i)
|
int cnt;
|
||||||
{
|
|
||||||
lclContext* ctx = (lclContext*)AH->formatData;
|
if (!filename)
|
||||||
int res;
|
return;
|
||||||
|
|
||||||
res = fputc(i, AH->FH);
|
#ifdef HAVE_LIBZ
|
||||||
if (res != EOF) {
|
AH->FH = gzopen(filename,"rb");
|
||||||
ctx->filePos += 1;
|
#else
|
||||||
}
|
AH->FH = fopen(filename,PG_BINARY_R);
|
||||||
return res;
|
#endif
|
||||||
}
|
|
||||||
|
while ( (cnt = GZREAD(buf, 1, 4095, AH->FH)) > 0) {
|
||||||
static int _ReadByte(ArchiveHandle* AH)
|
buf[cnt] = '\0';
|
||||||
{
|
ahwrite(buf, 1, cnt, AH);
|
||||||
lclContext* ctx = (lclContext*)AH->formatData;
|
}
|
||||||
int res;
|
|
||||||
|
GZCLOSE(AH->FH);
|
||||||
res = fgetc(AH->FH);
|
}
|
||||||
if (res != EOF) {
|
|
||||||
ctx->filePos += 1;
|
|
||||||
}
|
/*
|
||||||
return res;
|
* Print data for a given TOC entry
|
||||||
}
|
*/
|
||||||
|
static void _PrintTocData(ArchiveHandle* AH, TocEntry* te, RestoreOptions *ropt)
|
||||||
static int _WriteBuf(ArchiveHandle* AH, const void* buf, int len)
|
{
|
||||||
{
|
lclTocEntry* tctx = (lclTocEntry*) te->formatData;
|
||||||
lclContext* ctx = (lclContext*)AH->formatData;
|
|
||||||
int res;
|
if (!tctx->filename)
|
||||||
res = fwrite(buf, 1, len, AH->FH);
|
return;
|
||||||
ctx->filePos += res;
|
|
||||||
return res;
|
if (strcmp(te->desc, "BLOBS") == 0)
|
||||||
}
|
_LoadBlobs(AH, ropt);
|
||||||
|
else
|
||||||
static int _ReadBuf(ArchiveHandle* AH, void* buf, int len)
|
{
|
||||||
{
|
_PrintFileData(AH, tctx->filename, ropt);
|
||||||
lclContext* ctx = (lclContext*)AH->formatData;
|
}
|
||||||
int res;
|
}
|
||||||
res = fread(buf, 1, len, AH->FH);
|
|
||||||
ctx->filePos += res;
|
static void _getBlobTocEntry(ArchiveHandle* AH, int *oid, char fname[K_STD_BUF_SIZE])
|
||||||
return res;
|
{
|
||||||
}
|
lclContext* ctx = (lclContext*)AH->formatData;
|
||||||
|
char blobTe[K_STD_BUF_SIZE];
|
||||||
static void _CloseArchive(ArchiveHandle* AH)
|
int fpos;
|
||||||
{
|
int eos;
|
||||||
if (AH->mode == archModeWrite) {
|
|
||||||
WriteHead(AH);
|
if (fgets(&blobTe[0], K_STD_BUF_SIZE - 1, ctx->blobToc) != NULL)
|
||||||
WriteToc(AH);
|
{
|
||||||
fclose(AH->FH);
|
*oid = atoi(blobTe);
|
||||||
WriteDataChunks(AH);
|
|
||||||
}
|
fpos = strcspn(blobTe, " ");
|
||||||
|
|
||||||
AH->FH = NULL;
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.159 2000/07/17 03:05:20 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.160 2000/07/21 11:40:08 pjw Exp $
|
||||||
*
|
*
|
||||||
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
|
* Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
|
||||||
*
|
*
|
||||||
@ -61,12 +61,19 @@
|
|||||||
* - Added a -Z option for compression level on compressed formats
|
* - Added a -Z option for compression level on compressed formats
|
||||||
* - Restored '-f' in usage output
|
* - Restored '-f' in usage output
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*
|
||||||
|
* Modifications - 17-Jul-2000 - Philip Warner pjw@rhyme.com.au
|
||||||
|
* - Support for BLOB output.
|
||||||
|
* - Sort archive by OID, put some items at end (out of OID order)
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <unistd.h> /* for getopt() */
|
#include <unistd.h> /* for getopt() */
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "pg_backup.h"
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
@ -84,6 +91,7 @@
|
|||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
|
||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
|
#include <libpq/libpq-fs.h>
|
||||||
#ifndef HAVE_STRDUP
|
#ifndef HAVE_STRDUP
|
||||||
#include "strdup.h"
|
#include "strdup.h"
|
||||||
#endif
|
#endif
|
||||||
@ -109,6 +117,9 @@ static void setMaxOid(Archive *fout);
|
|||||||
static void AddAcl(char *aclbuf, const char *keyword);
|
static void AddAcl(char *aclbuf, const char *keyword);
|
||||||
static char *GetPrivileges(const char *s);
|
static char *GetPrivileges(const char *s);
|
||||||
|
|
||||||
|
static int dumpBlobs(Archive *AH, char*, void*);
|
||||||
|
|
||||||
|
|
||||||
extern char *optarg;
|
extern char *optarg;
|
||||||
extern int optind,
|
extern int optind,
|
||||||
opterr;
|
opterr;
|
||||||
@ -268,14 +279,26 @@ dumpClasses_nodumpData(Archive *fout, char* oid, void *dctxv)
|
|||||||
|
|
||||||
if (oids == true)
|
if (oids == true)
|
||||||
{
|
{
|
||||||
archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
|
/*
|
||||||
fmtId(classname, force_quotes));
|
* archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
|
||||||
|
* fmtId(classname, force_quotes));
|
||||||
|
*
|
||||||
|
* - Not used as of V1.3 (needs to be in ArchiveEntry call)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
|
sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
|
||||||
fmtId(classname, force_quotes));
|
fmtId(classname, force_quotes));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname, force_quotes));
|
/*
|
||||||
|
*archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname, force_quotes));
|
||||||
|
*
|
||||||
|
* - Not used as of V1.3 (needs to be in ArchiveEntry call)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
|
sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
|
||||||
}
|
}
|
||||||
res = PQexec(g_conn, query);
|
res = PQexec(g_conn, query);
|
||||||
@ -452,19 +475,28 @@ dumpClasses_dumpData(Archive *fout, char* oid, void *dctxv)
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
|
dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
|
||||||
const char *onlytable, const bool oids)
|
const char *onlytable, const bool oids, const bool force_quotes)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
char *all_only;
|
char *all_only;
|
||||||
DataDumperPtr dumpFn;
|
DataDumperPtr dumpFn;
|
||||||
DumpContext *dumpCtx;
|
DumpContext *dumpCtx;
|
||||||
|
char *oidsPart;
|
||||||
|
char copyBuf[512];
|
||||||
|
char *copyStmt;
|
||||||
|
|
||||||
if (onlytable == NULL)
|
if (onlytable == NULL)
|
||||||
all_only = "all";
|
all_only = "all";
|
||||||
else
|
else
|
||||||
all_only = "only";
|
all_only = "only";
|
||||||
|
|
||||||
|
if (oids == true)
|
||||||
|
oidsPart = "WITH OIDS ";
|
||||||
|
else
|
||||||
|
oidsPart = "";
|
||||||
|
|
||||||
|
|
||||||
if (g_verbose)
|
if (g_verbose)
|
||||||
fprintf(stderr, "%s dumping out the contents of %s %d table%s/sequence%s %s\n",
|
fprintf(stderr, "%s dumping out the contents of %s %d table%s/sequence%s %s\n",
|
||||||
g_comment_start, all_only,
|
g_comment_start, all_only,
|
||||||
@ -514,112 +546,28 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
|
|||||||
dumpCtx->tblidx = i;
|
dumpCtx->tblidx = i;
|
||||||
dumpCtx->oids = oids;
|
dumpCtx->oids = oids;
|
||||||
|
|
||||||
if (!dumpData)
|
if (!dumpData) /* Dump/restore using COPY */
|
||||||
|
{
|
||||||
dumpFn = dumpClasses_nodumpData;
|
dumpFn = dumpClasses_nodumpData;
|
||||||
/* dumpClasses_nodumpData(fout, classname, oids); */
|
/* dumpClasses_nodumpData(fout, classname, oids); */
|
||||||
else
|
sprintf(copyBuf, "COPY %s %s FROM stdin;\n", fmtId(tblinfo[i].relname, force_quotes),
|
||||||
|
oidsPart);
|
||||||
|
copyStmt = copyBuf;
|
||||||
|
}
|
||||||
|
else /* Restore using INSERT */
|
||||||
|
{
|
||||||
dumpFn = dumpClasses_dumpData;
|
dumpFn = dumpClasses_dumpData;
|
||||||
/* dumpClasses_dumpData(fout, classname); */
|
/* dumpClasses_dumpData(fout, classname); */
|
||||||
|
copyStmt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
|
ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
|
||||||
"TABLE DATA", NULL, "", "", tblinfo[i].usename,
|
"TABLE DATA", NULL, "", "", copyStmt, tblinfo[i].usename,
|
||||||
dumpFn, dumpCtx);
|
dumpFn, dumpCtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
prompt_for_password(char *username, char *password)
|
|
||||||
{
|
|
||||||
char buf[512];
|
|
||||||
int length;
|
|
||||||
|
|
||||||
#ifdef HAVE_TERMIOS_H
|
|
||||||
struct termios t_orig,
|
|
||||||
t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
fprintf(stderr, "Username: ");
|
|
||||||
fflush(stderr);
|
|
||||||
fgets(username, 100, stdin);
|
|
||||||
length = strlen(username);
|
|
||||||
/* skip rest of the line */
|
|
||||||
if (length > 0 && username[length - 1] != '\n')
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
fgets(buf, 512, stdin);
|
|
||||||
} while (buf[strlen(buf) - 1] != '\n');
|
|
||||||
}
|
|
||||||
if (length > 0 && username[length - 1] == '\n')
|
|
||||||
username[length - 1] = '\0';
|
|
||||||
|
|
||||||
#ifdef HAVE_TERMIOS_H
|
|
||||||
tcgetattr(0, &t);
|
|
||||||
t_orig = t;
|
|
||||||
t.c_lflag &= ~ECHO;
|
|
||||||
tcsetattr(0, TCSADRAIN, &t);
|
|
||||||
#endif
|
|
||||||
fprintf(stderr, "Password: ");
|
|
||||||
fflush(stderr);
|
|
||||||
fgets(password, 100, stdin);
|
|
||||||
#ifdef HAVE_TERMIOS_H
|
|
||||||
tcsetattr(0, TCSADRAIN, &t_orig);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
length = strlen(password);
|
|
||||||
/* skip rest of the line */
|
|
||||||
if (length > 0 && password[length - 1] != '\n')
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
fgets(buf, 512, stdin);
|
|
||||||
} while (buf[strlen(buf) - 1] != '\n');
|
|
||||||
}
|
|
||||||
if (length > 0 && password[length - 1] == '\n')
|
|
||||||
password[length - 1] = '\0';
|
|
||||||
|
|
||||||
fprintf(stderr, "\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
check_database_version(bool ignoreVersion)
|
|
||||||
{
|
|
||||||
PGresult *res;
|
|
||||||
double myversion;
|
|
||||||
const char *remoteversion_str;
|
|
||||||
double remoteversion;
|
|
||||||
|
|
||||||
myversion = strtod(PG_VERSION, NULL);
|
|
||||||
res = PQexec(g_conn, "SELECT version()");
|
|
||||||
if (!res ||
|
|
||||||
PQresultStatus(res) != PGRES_TUPLES_OK ||
|
|
||||||
PQntuples(res) != 1)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "check_database_version(): command failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
|
|
||||||
exit_nicely(g_conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteversion_str = PQgetvalue(res, 0, 0);
|
|
||||||
remoteversion = strtod(remoteversion_str + 11, NULL);
|
|
||||||
if (myversion != remoteversion)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Database version: %s\npg_dump version: %s\n",
|
|
||||||
remoteversion_str, PG_VERSION);
|
|
||||||
if (ignoreVersion)
|
|
||||||
fprintf(stderr, "Proceeding despite version mismatch.\n");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Aborting because of version mismatch.\n"
|
|
||||||
"Use --ignore-version if you think it's safe to proceed anyway.\n");
|
|
||||||
exit_nicely(g_conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PQclear(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -634,20 +582,19 @@ main(int argc, char **argv)
|
|||||||
bool oids = false;
|
bool oids = false;
|
||||||
TableInfo *tblinfo;
|
TableInfo *tblinfo;
|
||||||
int numTables;
|
int numTables;
|
||||||
char connect_string[512] = "";
|
|
||||||
char tmp_string[128];
|
|
||||||
char username[100];
|
|
||||||
char password[100];
|
|
||||||
bool use_password = false;
|
bool use_password = false;
|
||||||
int compressLevel = -1;
|
int compressLevel = -1;
|
||||||
bool ignore_version = false;
|
bool ignore_version = false;
|
||||||
int plainText = 0;
|
int plainText = 0;
|
||||||
int outputClean = 0;
|
int outputClean = 0;
|
||||||
|
int outputBlobs = 0;
|
||||||
|
|
||||||
RestoreOptions *ropt;
|
RestoreOptions *ropt;
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"data-only", no_argument, NULL, 'a'},
|
{"data-only", no_argument, NULL, 'a'},
|
||||||
|
{"blobs", no_argument, NULL, 'b' },
|
||||||
{"clean", no_argument, NULL, 'c'},
|
{"clean", no_argument, NULL, 'c'},
|
||||||
{"file", required_argument, NULL, 'f'},
|
{"file", required_argument, NULL, 'f'},
|
||||||
{"format", required_argument, NULL, 'F'},
|
{"format", required_argument, NULL, 'F'},
|
||||||
@ -686,6 +633,12 @@ main(int argc, char **argv)
|
|||||||
else
|
else
|
||||||
progname = strrchr(argv[0], SEP_CHAR) + 1;
|
progname = strrchr(argv[0], SEP_CHAR) + 1;
|
||||||
|
|
||||||
|
/* Set defaulty options based on progname */
|
||||||
|
if (strcmp(progname, "pg_backup") == 0)
|
||||||
|
{
|
||||||
|
format = "c";
|
||||||
|
outputBlobs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
while ((c = getopt_long(argc, argv, "acdDf:F:h:inNop:st:uvxzZ:V?", long_options, &optindex)) != -1)
|
while ((c = getopt_long(argc, argv, "acdDf:F:h:inNop:st:uvxzZ:V?", long_options, &optindex)) != -1)
|
||||||
@ -698,6 +651,10 @@ main(int argc, char **argv)
|
|||||||
case 'a': /* Dump data only */
|
case 'a': /* Dump data only */
|
||||||
dataOnly = true;
|
dataOnly = true;
|
||||||
break;
|
break;
|
||||||
|
case 'b': /* Dump blobs */
|
||||||
|
outputBlobs = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'c': /* clean (i.e., drop) schema prior to
|
case 'c': /* clean (i.e., drop) schema prior to
|
||||||
* create */
|
* create */
|
||||||
outputClean = 1;
|
outputClean = 1;
|
||||||
@ -843,7 +800,12 @@ main(int argc, char **argv)
|
|||||||
case 'p':
|
case 'p':
|
||||||
case 'P':
|
case 'P':
|
||||||
plainText = 1;
|
plainText = 1;
|
||||||
g_fout = CreateArchive(filename, archPlainText, 0);
|
g_fout = CreateArchive(filename, archNull, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
g_fout = CreateArchive(filename, archTar, compressLevel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -860,53 +822,13 @@ main(int argc, char **argv)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find database */
|
/* Let the archiver know how noisy to be */
|
||||||
if (!(dbname = argv[optind]) &&
|
g_fout->verbose = g_verbose;
|
||||||
!(dbname = getenv("PGDATABASE")))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: no database name specified\n", progname);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
|
dbname = argv[optind];
|
||||||
if (pghost != NULL)
|
|
||||||
{
|
|
||||||
sprintf(tmp_string, "host=%s ", pghost);
|
|
||||||
strcat(connect_string, tmp_string);
|
|
||||||
}
|
|
||||||
if (pgport != NULL)
|
|
||||||
{
|
|
||||||
sprintf(tmp_string, "port=%s ", pgport);
|
|
||||||
strcat(connect_string, tmp_string);
|
|
||||||
}
|
|
||||||
if (dbname != NULL)
|
|
||||||
{
|
|
||||||
sprintf(tmp_string, "dbname=%s ", dbname);
|
|
||||||
strcat(connect_string, tmp_string);
|
|
||||||
}
|
|
||||||
if (use_password)
|
|
||||||
{
|
|
||||||
prompt_for_password(username, password);
|
|
||||||
strcat(connect_string, "authtype=password ");
|
|
||||||
sprintf(tmp_string, "user=%s ", username);
|
|
||||||
strcat(connect_string, tmp_string);
|
|
||||||
sprintf(tmp_string, "password=%s ", password);
|
|
||||||
strcat(connect_string, tmp_string);
|
|
||||||
MemSet(tmp_string, 0, sizeof(tmp_string));
|
|
||||||
MemSet(password, 0, sizeof(password));
|
|
||||||
}
|
|
||||||
g_conn = PQconnectdb(connect_string);
|
|
||||||
MemSet(connect_string, 0, sizeof(connect_string));
|
|
||||||
/* check to see that the backend connection was successfully made */
|
|
||||||
if (PQstatus(g_conn) == CONNECTION_BAD)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
|
|
||||||
fprintf(stderr, "%s\n", PQerrorMessage(g_conn));
|
|
||||||
exit_nicely(g_conn);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* check for version mismatch */
|
/* Open the database using the Archiver, so it knows about it. Errors mean death */
|
||||||
check_database_version(ignore_version);
|
g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, use_password, ignore_version);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start serializable transaction to dump consistent data
|
* Start serializable transaction to dump consistent data
|
||||||
@ -916,17 +838,15 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
res = PQexec(g_conn, "begin");
|
res = PQexec(g_conn, "begin");
|
||||||
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
{
|
exit_horribly(g_fout, "BEGIN command failed. Explanation from backend: '%s'.\n",
|
||||||
fprintf(stderr, "BEGIN command failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
|
PQerrorMessage(g_conn));
|
||||||
exit_nicely(g_conn);
|
|
||||||
}
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
res = PQexec(g_conn, "set transaction isolation level serializable");
|
res = PQexec(g_conn, "set transaction isolation level serializable");
|
||||||
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
{
|
exit_horribly(g_fout, "SET TRANSACTION command failed. Explanation from backend: '%s'.\n",
|
||||||
fprintf(stderr, "SET TRANSACTION command failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
|
PQerrorMessage(g_conn));
|
||||||
exit_nicely(g_conn);
|
|
||||||
}
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -941,7 +861,12 @@ main(int argc, char **argv)
|
|||||||
tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip, oids, schemaOnly, dataOnly);
|
tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip, oids, schemaOnly, dataOnly);
|
||||||
|
|
||||||
if (!schemaOnly)
|
if (!schemaOnly)
|
||||||
dumpClasses(tblinfo, numTables, g_fout, tablename, oids);
|
{
|
||||||
|
dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputBlobs)
|
||||||
|
ArchiveEntry(g_fout, "0", "BLOBS", "BLOBS", NULL, "", "", "", "", dumpBlobs, 0);
|
||||||
|
|
||||||
if (!dataOnly) /* dump indexes and triggers at the end
|
if (!dataOnly) /* dump indexes and triggers at the end
|
||||||
* for performance */
|
* for performance */
|
||||||
@ -951,6 +876,15 @@ main(int argc, char **argv)
|
|||||||
dumpRules(g_fout, tablename, tblinfo, numTables);
|
dumpRules(g_fout, tablename, tblinfo, numTables);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now sort the output nicely */
|
||||||
|
SortTocByOID(g_fout);
|
||||||
|
MoveToEnd(g_fout, "TABLE DATA");
|
||||||
|
MoveToEnd(g_fout, "BLOBS");
|
||||||
|
MoveToEnd(g_fout, "INDEX");
|
||||||
|
MoveToEnd(g_fout, "TRIGGER");
|
||||||
|
MoveToEnd(g_fout, "RULE");
|
||||||
|
MoveToEnd(g_fout, "ACL");
|
||||||
|
|
||||||
if (plainText)
|
if (plainText)
|
||||||
{
|
{
|
||||||
ropt = NewRestoreOptions();
|
ropt = NewRestoreOptions();
|
||||||
@ -973,6 +907,92 @@ main(int argc, char **argv)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dumpBlobs:
|
||||||
|
* dump all blobs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define loBufSize 16384
|
||||||
|
#define loFetchSize 1000
|
||||||
|
|
||||||
|
static int
|
||||||
|
dumpBlobs(Archive *AH, char* junkOid, void *junkVal)
|
||||||
|
{
|
||||||
|
PQExpBuffer oidQry = createPQExpBuffer();
|
||||||
|
PQExpBuffer oidFetchQry = createPQExpBuffer();
|
||||||
|
PGresult *res;
|
||||||
|
int i;
|
||||||
|
int loFd;
|
||||||
|
char buf[loBufSize];
|
||||||
|
int cnt;
|
||||||
|
int blobOid;
|
||||||
|
|
||||||
|
if (g_verbose)
|
||||||
|
fprintf(stderr, "%s saving BLOBs\n", g_comment_start);
|
||||||
|
|
||||||
|
/* Cursor to get all BLOB tables */
|
||||||
|
appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l'");
|
||||||
|
|
||||||
|
res = PQexec(g_conn, oidQry->data);
|
||||||
|
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "dumpBlobs(): Declare Cursor failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
|
||||||
|
exit_nicely(g_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetch for cursor */
|
||||||
|
appendPQExpBuffer(oidFetchQry, "Fetch %d in blobOid", loFetchSize);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Do a fetch */
|
||||||
|
PQclear(res);
|
||||||
|
res = PQexec(g_conn, oidFetchQry->data);
|
||||||
|
|
||||||
|
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "dumpBlobs(): Fetch Cursor failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
|
||||||
|
exit_nicely(g_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the tuples, if any */
|
||||||
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
|
{
|
||||||
|
blobOid = atoi(PQgetvalue(res, i, 0));
|
||||||
|
/* Open the BLOB */
|
||||||
|
loFd = lo_open(g_conn, blobOid, INV_READ);
|
||||||
|
if (loFd == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "dumpBlobs(): Could not open large object. "
|
||||||
|
"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
|
||||||
|
exit_nicely(g_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
StartBlob(AH, blobOid);
|
||||||
|
|
||||||
|
/* Now read it in chunks, sending data to archive */
|
||||||
|
do {
|
||||||
|
cnt = lo_read(g_conn, loFd, buf, loBufSize);
|
||||||
|
if (cnt < 0) {
|
||||||
|
fprintf(stderr, "dumpBlobs(): Error reading large object. "
|
||||||
|
" Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
|
||||||
|
exit_nicely(g_conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteData(AH, buf, cnt);
|
||||||
|
|
||||||
|
} while (cnt > 0);
|
||||||
|
|
||||||
|
lo_close(g_conn, loFd);
|
||||||
|
|
||||||
|
EndBlob(AH, blobOid);
|
||||||
|
|
||||||
|
}
|
||||||
|
} while (PQntuples(res) > 0);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* getTypes:
|
* getTypes:
|
||||||
* read all base types in the system catalogs and return them in the
|
* read all base types in the system catalogs and return them in the
|
||||||
@ -2409,7 +2429,7 @@ dumpComment(Archive *fout, const char *target, const char *oid)
|
|||||||
target, checkForQuote(PQgetvalue(res, 0, i_description)));
|
target, checkForQuote(PQgetvalue(res, 0, i_description)));
|
||||||
|
|
||||||
ArchiveEntry(fout, oid, target, "COMMENT", NULL, query->data, "" /*Del*/,
|
ArchiveEntry(fout, oid, target, "COMMENT", NULL, query->data, "" /*Del*/,
|
||||||
"" /*Owner*/, NULL, NULL);
|
"" /* Copy */, "" /*Owner*/, NULL, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2542,7 +2562,7 @@ dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
|
|||||||
appendPQExpBuffer(q, ");\n");
|
appendPQExpBuffer(q, ");\n");
|
||||||
|
|
||||||
ArchiveEntry(fout, tinfo[i].oid, fmtId(tinfo[i].typname, force_quotes), "TYPE", NULL,
|
ArchiveEntry(fout, tinfo[i].oid, fmtId(tinfo[i].typname, force_quotes), "TYPE", NULL,
|
||||||
q->data, delq->data, tinfo[i].usename, NULL, NULL);
|
q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
|
||||||
|
|
||||||
/*** Dump Type Comments ***/
|
/*** Dump Type Comments ***/
|
||||||
|
|
||||||
@ -2629,7 +2649,7 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
|
|||||||
lancompiler);
|
lancompiler);
|
||||||
|
|
||||||
ArchiveEntry(fout, PQgetvalue(res, i, i_oid), lanname, "PROCEDURAL LANGUAGE",
|
ArchiveEntry(fout, PQgetvalue(res, i, i_oid), lanname, "PROCEDURAL LANGUAGE",
|
||||||
NULL, defqry->data, delqry->data, "", NULL, NULL);
|
NULL, defqry->data, delqry->data, "", "", NULL, NULL);
|
||||||
|
|
||||||
free(lanname);
|
free(lanname);
|
||||||
free(lancompiler);
|
free(lancompiler);
|
||||||
@ -2669,8 +2689,8 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
|
|||||||
PQExpBuffer fn = createPQExpBuffer();
|
PQExpBuffer fn = createPQExpBuffer();
|
||||||
PQExpBuffer delqry = createPQExpBuffer();
|
PQExpBuffer delqry = createPQExpBuffer();
|
||||||
PQExpBuffer fnlist = createPQExpBuffer();
|
PQExpBuffer fnlist = createPQExpBuffer();
|
||||||
PQExpBuffer asPart = createPQExpBuffer();
|
|
||||||
int j;
|
int j;
|
||||||
|
PQExpBuffer asPart = createPQExpBuffer();
|
||||||
char func_lang[NAMEDATALEN + 1];
|
char func_lang[NAMEDATALEN + 1];
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
int nlangs;
|
int nlangs;
|
||||||
@ -2703,7 +2723,7 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
|
|||||||
|
|
||||||
i_lanname = PQfnumber(res, "lanname");
|
i_lanname = PQfnumber(res, "lanname");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See backend/commands/define.c for details of how the 'AS' clause
|
* See backend/commands/define.c for details of how the 'AS' clause
|
||||||
* is used.
|
* is used.
|
||||||
*/
|
*/
|
||||||
@ -2751,7 +2771,7 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
|
|||||||
asPart->data, func_lang);
|
asPart->data, func_lang);
|
||||||
|
|
||||||
ArchiveEntry(fout, finfo[i].oid, fn->data, "FUNCTION", NULL, q->data, delqry->data,
|
ArchiveEntry(fout, finfo[i].oid, fn->data, "FUNCTION", NULL, q->data, delqry->data,
|
||||||
finfo[i].usename, NULL, NULL);
|
"", finfo[i].usename, NULL, NULL);
|
||||||
|
|
||||||
/*** Dump Function Comments ***/
|
/*** Dump Function Comments ***/
|
||||||
|
|
||||||
@ -2870,7 +2890,7 @@ dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
|
|||||||
sort2->data);
|
sort2->data);
|
||||||
|
|
||||||
ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
|
ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
|
||||||
q->data, delq->data, oprinfo[i].usename, NULL, NULL);
|
q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2927,7 +2947,7 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
|
|||||||
details->data);
|
details->data);
|
||||||
|
|
||||||
ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
|
ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
|
||||||
q->data, delq->data, agginfo[i].usename, NULL, NULL);
|
q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
|
||||||
|
|
||||||
/*** Dump Aggregate Comments ***/
|
/*** Dump Aggregate Comments ***/
|
||||||
|
|
||||||
@ -3096,7 +3116,7 @@ dumpACL(Archive *fout, TableInfo tbinfo)
|
|||||||
|
|
||||||
free(aclbuf);
|
free(aclbuf);
|
||||||
|
|
||||||
ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "ACL", NULL, sql, "", "", NULL, NULL);
|
ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "ACL", NULL, sql, "", "", "", NULL, NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3274,7 +3294,7 @@ dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
|
|||||||
|
|
||||||
if (!dataOnly) {
|
if (!dataOnly) {
|
||||||
ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
|
ArchiveEntry(fout, tblinfo[i].oid, fmtId(tblinfo[i].relname, false),
|
||||||
"TABLE", NULL, q->data, delq->data, tblinfo[i].usename,
|
"TABLE", NULL, q->data, delq->data, "", tblinfo[i].usename,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3468,7 +3488,7 @@ dumpIndices(Archive *fout, IndInfo *indinfo, int numIndices,
|
|||||||
/* Dump Index Comments */
|
/* Dump Index Comments */
|
||||||
|
|
||||||
ArchiveEntry(fout, tblinfo[tableInd].oid, id1->data, "INDEX", NULL, q->data, delq->data,
|
ArchiveEntry(fout, tblinfo[tableInd].oid, id1->data, "INDEX", NULL, q->data, delq->data,
|
||||||
tblinfo[tableInd].usename, NULL, NULL);
|
"", tblinfo[tableInd].usename, NULL, NULL);
|
||||||
|
|
||||||
resetPQExpBuffer(q);
|
resetPQExpBuffer(q);
|
||||||
appendPQExpBuffer(q, "INDEX %s", id1->data);
|
appendPQExpBuffer(q, "INDEX %s", id1->data);
|
||||||
@ -3599,7 +3619,7 @@ setMaxOid(Archive *fout)
|
|||||||
pos = pos + snprintf(sql+pos, 1024-pos, "\\.\n");
|
pos = pos + snprintf(sql+pos, 1024-pos, "\\.\n");
|
||||||
pos = pos + snprintf(sql+pos, 1024-pos, "DROP TABLE pg_dump_oid;\n");
|
pos = pos + snprintf(sql+pos, 1024-pos, "DROP TABLE pg_dump_oid;\n");
|
||||||
|
|
||||||
ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "","", NULL, NULL);
|
ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3750,7 +3770,7 @@ dumpSequence(Archive *fout, TableInfo tbinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArchiveEntry(fout, tbinfo.oid, fmtId(tbinfo.relname, force_quotes), "SEQUENCE", NULL,
|
ArchiveEntry(fout, tbinfo.oid, fmtId(tbinfo.relname, force_quotes), "SEQUENCE", NULL,
|
||||||
query->data, delqry->data, tbinfo.usename, NULL, NULL);
|
query->data, delqry->data, "", tbinfo.usename, NULL, NULL);
|
||||||
|
|
||||||
/* Dump Sequence Comments */
|
/* Dump Sequence Comments */
|
||||||
|
|
||||||
@ -3779,7 +3799,7 @@ dumpTriggers(Archive *fout, const char *tablename,
|
|||||||
for (j = 0; j < tblinfo[i].ntrig; j++)
|
for (j = 0; j < tblinfo[i].ntrig; j++)
|
||||||
{
|
{
|
||||||
ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
|
ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
|
||||||
"TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "",
|
"TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "",
|
||||||
tblinfo[i].usename, NULL, NULL);
|
tblinfo[i].usename, NULL, NULL);
|
||||||
dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid);
|
dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid);
|
||||||
}
|
}
|
||||||
@ -3846,7 +3866,7 @@ dumpRules(Archive *fout, const char *tablename,
|
|||||||
|
|
||||||
ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
|
ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
|
||||||
"RULE", NULL, PQgetvalue(res, i, i_definition),
|
"RULE", NULL, PQgetvalue(res, i, i_definition),
|
||||||
"", "", NULL, NULL);
|
"", "", "", NULL, NULL);
|
||||||
|
|
||||||
/* Dump rule comments */
|
/* Dump rule comments */
|
||||||
|
|
||||||
|
@ -1,325 +1,371 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* pg_restore.c
|
* pg_restore.c
|
||||||
* pg_restore is an utility extracting postgres database definitions
|
* pg_restore is an utility extracting postgres database definitions
|
||||||
* from a backup archive created by pg_dump using the archiver
|
* from a backup archive created by pg_dump using the archiver
|
||||||
* interface.
|
* interface.
|
||||||
*
|
*
|
||||||
* pg_restore will read the backup archive and
|
* pg_restore will read the backup archive and
|
||||||
* dump out a script that reproduces
|
* dump out a script that reproduces
|
||||||
* the schema of the database in terms of
|
* the schema of the database in terms of
|
||||||
* user-defined types
|
* user-defined types
|
||||||
* user-defined functions
|
* user-defined functions
|
||||||
* tables
|
* tables
|
||||||
* indices
|
* indices
|
||||||
* aggregates
|
* aggregates
|
||||||
* operators
|
* operators
|
||||||
* ACL - grant/revoke
|
* ACL - grant/revoke
|
||||||
*
|
*
|
||||||
* the output script is SQL that is understood by PostgreSQL
|
* the output script is SQL that is understood by PostgreSQL
|
||||||
*
|
*
|
||||||
* Basic process in a restore operation is:
|
* Basic process in a restore operation is:
|
||||||
*
|
*
|
||||||
* Open the Archive and read the TOC.
|
* Open the Archive and read the TOC.
|
||||||
* Set flags in TOC entries, and *maybe* reorder them.
|
* Set flags in TOC entries, and *maybe* reorder them.
|
||||||
* Generate script to stdout
|
* Generate script to stdout
|
||||||
* Exit
|
* Exit
|
||||||
*
|
*
|
||||||
* Copyright (c) 2000, Philip Warner
|
* Copyright (c) 2000, Philip Warner
|
||||||
* Rights are granted to use this software in any way so long
|
* Rights are granted to use this software in any way so long
|
||||||
* as this notice is not removed.
|
* as this notice is not removed.
|
||||||
*
|
*
|
||||||
* The author is not responsible for loss or damages that may
|
* The author is not responsible for loss or damages that may
|
||||||
* result from it's use.
|
* result from it's use.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
*
|
*
|
||||||
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
|
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
|
||||||
*
|
*
|
||||||
* Initial version. Command processing taken from original pg_dump.
|
* Initial version. Command processing taken from original pg_dump.
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "access/htup.h"
|
#include "access/htup.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "catalog/pg_language.h"
|
#include "catalog/pg_language.h"
|
||||||
#include "catalog/pg_index.h"
|
#include "catalog/pg_index.h"
|
||||||
#include "catalog/pg_trigger.h"
|
#include "catalog/pg_trigger.h"
|
||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pg_backup.h"
|
#include "pg_backup.h"
|
||||||
|
|
||||||
#ifndef HAVE_STRDUP
|
#ifndef HAVE_STRDUP
|
||||||
#include "strdup.h"
|
#include "strdup.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_TERMIOS_H
|
#ifdef HAVE_TERMIOS_H
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Forward decls */
|
/* Forward decls */
|
||||||
static void usage(const char *progname);
|
static void usage(const char *progname);
|
||||||
static char* _cleanupName(char* name);
|
static char* _cleanupName(char* name);
|
||||||
|
|
||||||
typedef struct option optType;
|
typedef struct option optType;
|
||||||
|
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
struct option cmdopts[] = {
|
struct option cmdopts[] = {
|
||||||
{ "clean", 0, NULL, 'c' },
|
{ "clean", 0, NULL, 'c' },
|
||||||
{ "data-only", 0, NULL, 'a' },
|
{ "data-only", 0, NULL, 'a' },
|
||||||
{ "file", 1, NULL, 'f' },
|
{ "dbname", 1, NULL, 'd' },
|
||||||
{ "format", 1, NULL, 'F' },
|
{ "file", 1, NULL, 'f' },
|
||||||
{ "function", 2, NULL, 'p' },
|
{ "format", 1, NULL, 'F' },
|
||||||
{ "index", 2, NULL, 'i'},
|
{ "function", 2, NULL, 'P' },
|
||||||
{ "list", 0, NULL, 'l'},
|
{ "host", 1, NULL, 'h' },
|
||||||
{ "no-acl", 0, NULL, 'x' },
|
{ "ignore-version", 0, NULL, 'i'},
|
||||||
{ "oid-order", 0, NULL, 'o'},
|
{ "index", 2, NULL, 'I'},
|
||||||
{ "orig-order", 0, NULL, 'O' },
|
{ "list", 0, NULL, 'l'},
|
||||||
{ "rearrange", 0, NULL, 'r'},
|
{ "no-acl", 0, NULL, 'x' },
|
||||||
{ "schema-only", 0, NULL, 's' },
|
{ "port", 1, NULL, 'p' },
|
||||||
{ "table", 2, NULL, 't'},
|
{ "oid-order", 0, NULL, 'o'},
|
||||||
{ "trigger", 2, NULL, 'T' },
|
{ "orig-order", 0, NULL, 'O' },
|
||||||
{ "use-list", 1, NULL, 'u'},
|
{ "password", 0, NULL, 'u' },
|
||||||
{ "verbose", 0, NULL, 'v' },
|
{ "rearrange", 0, NULL, 'r'},
|
||||||
{ NULL, 0, NULL, 0}
|
{ "schema-only", 0, NULL, 's' },
|
||||||
};
|
{ "table", 2, NULL, 't'},
|
||||||
#endif
|
{ "trigger", 2, NULL, 'T' },
|
||||||
|
{ "use-list", 1, NULL, 'U'},
|
||||||
int main(int argc, char **argv)
|
{ "verbose", 0, NULL, 'v' },
|
||||||
{
|
{ NULL, 0, NULL, 0}
|
||||||
RestoreOptions *opts;
|
};
|
||||||
char *progname;
|
#endif
|
||||||
int c;
|
|
||||||
Archive* AH;
|
int main(int argc, char **argv)
|
||||||
char *fileSpec = NULL;
|
{
|
||||||
|
RestoreOptions *opts;
|
||||||
opts = NewRestoreOptions();
|
char *progname;
|
||||||
|
int c;
|
||||||
progname = *argv;
|
Archive* AH;
|
||||||
|
char *fileSpec = NULL;
|
||||||
#ifdef HAVE_GETOPT_LONG
|
|
||||||
while ((c = getopt_long(argc, argv, "acf:F:i:loOp:st:T:u:vx", cmdopts, NULL)) != EOF)
|
opts = NewRestoreOptions();
|
||||||
#else
|
|
||||||
while ((c = getopt(argc, argv, "acf:F:i:loOp:st:T:u:vx")) != -1)
|
progname = *argv;
|
||||||
#endif
|
|
||||||
{
|
#ifdef HAVE_GETOPT_LONG
|
||||||
switch (c)
|
while ((c = getopt_long(argc, argv, "acd:f:F:h:i:loOp:st:T:u:U:vx", cmdopts, NULL)) != EOF)
|
||||||
{
|
#else
|
||||||
case 'a': /* Dump data only */
|
while ((c = getopt(argc, argv, "acd:f:F:h:i:loOp:st:T:u:U:vx")) != -1)
|
||||||
opts->dataOnly = 1;
|
#endif
|
||||||
break;
|
{
|
||||||
case 'c': /* clean (i.e., drop) schema prior to
|
switch (c)
|
||||||
* create */
|
{
|
||||||
opts->dropSchema = 1;
|
case 'a': /* Dump data only */
|
||||||
break;
|
opts->dataOnly = 1;
|
||||||
case 'f': /* output file name */
|
break;
|
||||||
opts->filename = strdup(optarg);
|
case 'c': /* clean (i.e., drop) schema prior to
|
||||||
break;
|
* create */
|
||||||
case 'F':
|
opts->dropSchema = 1;
|
||||||
if (strlen(optarg) != 0)
|
break;
|
||||||
opts->formatName = strdup(optarg);
|
case 'd':
|
||||||
break;
|
if (strlen(optarg) != 0)
|
||||||
case 'o':
|
{
|
||||||
opts->oidOrder = 1;
|
opts->dbname = strdup(optarg);
|
||||||
break;
|
opts->useDB = 1;
|
||||||
case 'O':
|
}
|
||||||
opts->origOrder = 1;
|
break;
|
||||||
break;
|
case 'f': /* output file name */
|
||||||
case 'r':
|
opts->filename = strdup(optarg);
|
||||||
opts->rearrange = 1;
|
break;
|
||||||
break;
|
case 'F':
|
||||||
|
if (strlen(optarg) != 0)
|
||||||
case 'p': /* Function */
|
opts->formatName = strdup(optarg);
|
||||||
opts->selTypes = 1;
|
break;
|
||||||
opts->selFunction = 1;
|
case 'h':
|
||||||
opts->functionNames = _cleanupName(optarg);
|
if (strlen(optarg) != 0)
|
||||||
break;
|
opts->pghost = strdup(optarg);
|
||||||
case 'i': /* Index */
|
break;
|
||||||
opts->selTypes = 1;
|
case 'i':
|
||||||
opts->selIndex = 1;
|
opts->ignoreVersion = 1;
|
||||||
opts->indexNames = _cleanupName(optarg);
|
break;
|
||||||
break;
|
case 'o':
|
||||||
case 'T': /* Trigger */
|
opts->oidOrder = 1;
|
||||||
opts->selTypes = 1;
|
break;
|
||||||
opts->selTrigger = 1;
|
case 'O':
|
||||||
opts->triggerNames = _cleanupName(optarg);
|
opts->origOrder = 1;
|
||||||
break;
|
break;
|
||||||
case 's': /* dump schema only */
|
case 'p':
|
||||||
opts->schemaOnly = 1;
|
if (strlen(optarg) != 0)
|
||||||
break;
|
opts->pgport = strdup(optarg);
|
||||||
case 't': /* Dump data for this table only */
|
break;
|
||||||
opts->selTypes = 1;
|
case 'r':
|
||||||
opts->selTable = 1;
|
opts->rearrange = 1;
|
||||||
opts->tableNames = _cleanupName(optarg);
|
break;
|
||||||
break;
|
case 'P': /* Function */
|
||||||
case 'l': /* Dump the TOC summary */
|
opts->selTypes = 1;
|
||||||
opts->tocSummary = 1;
|
opts->selFunction = 1;
|
||||||
break;
|
opts->functionNames = _cleanupName(optarg);
|
||||||
|
break;
|
||||||
case 'u': /* input TOC summary file name */
|
case 'I': /* Index */
|
||||||
opts->tocFile = strdup(optarg);
|
opts->selTypes = 1;
|
||||||
break;
|
opts->selIndex = 1;
|
||||||
|
opts->indexNames = _cleanupName(optarg);
|
||||||
case 'v': /* verbose */
|
break;
|
||||||
opts->verbose = 1;
|
case 'T': /* Trigger */
|
||||||
break;
|
opts->selTypes = 1;
|
||||||
case 'x': /* skip ACL dump */
|
opts->selTrigger = 1;
|
||||||
opts->aclsSkip = 1;
|
opts->triggerNames = _cleanupName(optarg);
|
||||||
break;
|
break;
|
||||||
default:
|
case 's': /* dump schema only */
|
||||||
usage(progname);
|
opts->schemaOnly = 1;
|
||||||
break;
|
break;
|
||||||
}
|
case 't': /* Dump data for this table only */
|
||||||
}
|
opts->selTypes = 1;
|
||||||
|
opts->selTable = 1;
|
||||||
if (optind < argc) {
|
opts->tableNames = _cleanupName(optarg);
|
||||||
fileSpec = argv[optind];
|
break;
|
||||||
} else {
|
case 'l': /* Dump the TOC summary */
|
||||||
fileSpec = NULL;
|
opts->tocSummary = 1;
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (opts->formatName) {
|
case 'u':
|
||||||
|
opts->requirePassword = 1;
|
||||||
switch (opts->formatName[0]) {
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'U': /* input TOC summary file name */
|
||||||
case 'C':
|
opts->tocFile = strdup(optarg);
|
||||||
opts->format = archCustom;
|
break;
|
||||||
break;
|
|
||||||
|
case 'v': /* verbose */
|
||||||
case 'f':
|
opts->verbose = 1;
|
||||||
case 'F':
|
break;
|
||||||
opts->format = archFiles;
|
case 'x': /* skip ACL dump */
|
||||||
break;
|
opts->aclsSkip = 1;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "%s: Unknown archive format '%s', please specify 'f' or 'c'\n", progname, opts->formatName);
|
usage(progname);
|
||||||
exit (1);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AH = OpenArchive(fileSpec, opts->format);
|
if (optind < argc) {
|
||||||
|
fileSpec = argv[optind];
|
||||||
if (opts->tocFile)
|
} else {
|
||||||
SortTocFromFile(AH, opts);
|
fileSpec = NULL;
|
||||||
|
}
|
||||||
if (opts->oidOrder)
|
|
||||||
SortTocByOID(AH);
|
if (opts->formatName) {
|
||||||
else if (opts->origOrder)
|
|
||||||
SortTocByID(AH);
|
switch (opts->formatName[0]) {
|
||||||
|
|
||||||
if (opts->rearrange) {
|
case 'c':
|
||||||
MoveToEnd(AH, "TABLE DATA");
|
case 'C':
|
||||||
MoveToEnd(AH, "INDEX");
|
opts->format = archCustom;
|
||||||
MoveToEnd(AH, "TRIGGER");
|
break;
|
||||||
MoveToEnd(AH, "RULE");
|
|
||||||
MoveToEnd(AH, "ACL");
|
case 'f':
|
||||||
}
|
case 'F':
|
||||||
|
opts->format = archFiles;
|
||||||
if (opts->tocSummary) {
|
break;
|
||||||
PrintTOCSummary(AH, opts);
|
|
||||||
} else {
|
case 't':
|
||||||
RestoreArchive(AH, opts);
|
case 'T':
|
||||||
}
|
opts->format = archTar;
|
||||||
|
break;
|
||||||
CloseArchive(AH);
|
|
||||||
|
default:
|
||||||
return 1;
|
fprintf(stderr, "%s: Unknown archive format '%s', please specify 't' or 'c'\n",
|
||||||
}
|
progname, opts->formatName);
|
||||||
|
exit (1);
|
||||||
static void usage(const char *progname)
|
}
|
||||||
{
|
}
|
||||||
#ifdef HAVE_GETOPT_LONG
|
|
||||||
fprintf(stderr,
|
AH = OpenArchive(fileSpec, opts->format);
|
||||||
"usage: %s [options] [backup file]\n"
|
|
||||||
" -a, --data-only \t dump out only the data, no schema\n"
|
/* Let the archiver know how noisy to be */
|
||||||
" -c, --clean \t clean(drop) schema prior to create\n"
|
AH->verbose = opts->verbose;
|
||||||
" -f filename \t script output filename\n"
|
|
||||||
" -F, --format {c|f} \t specify backup file format\n"
|
if (opts->tocFile)
|
||||||
" -p, --function[=name] \t dump functions or named function\n"
|
SortTocFromFile(AH, opts);
|
||||||
" -i, --index[=name] \t dump indexes or named index\n"
|
|
||||||
" -l, --list \t dump summarized TOC for this file\n"
|
if (opts->oidOrder)
|
||||||
" -o, --oid-order \t dump in oid order\n"
|
SortTocByOID(AH);
|
||||||
" -O, --orig-order \t dump in original dump order\n"
|
else if (opts->origOrder)
|
||||||
" -r, --rearrange \t rearrange output to put indexes etc at end\n"
|
SortTocByID(AH);
|
||||||
" -s, --schema-only \t dump out only the schema, no data\n"
|
|
||||||
" -t [table], --table[=table] \t dump for this table only\n"
|
if (opts->rearrange) {
|
||||||
" -T, --trigger[=name] \t dump triggers or named trigger\n"
|
MoveToStart(AH, "<Init>");
|
||||||
" -u, --use-list filename \t use specified TOC for ordering output from this file\n"
|
MoveToEnd(AH, "TABLE DATA");
|
||||||
" -v \t verbose\n"
|
MoveToEnd(AH, "BLOBS");
|
||||||
" -x, --no-acl \t skip dumping of ACLs (grant/revoke)\n"
|
MoveToEnd(AH, "INDEX");
|
||||||
, progname);
|
MoveToEnd(AH, "TRIGGER");
|
||||||
#else
|
MoveToEnd(AH, "RULE");
|
||||||
fprintf(stderr,
|
MoveToEnd(AH, "ACL");
|
||||||
"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"
|
if (opts->tocSummary) {
|
||||||
" -f filename NOT IMPLEMENTED \t script output filename\n"
|
PrintTOCSummary(AH, opts);
|
||||||
" -F {c|f} \t specify backup file format\n"
|
} else {
|
||||||
" -p name \t dump functions or named function\n"
|
RestoreArchive(AH, opts);
|
||||||
" -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"
|
CloseArchive(AH);
|
||||||
" -O \t dump in original dump order\n"
|
|
||||||
" -r \t rearrange output to put indexes etc at end\n"
|
return 1;
|
||||||
" -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"
|
static void usage(const char *progname)
|
||||||
" -u filename \t use specified TOC for ordering output from this file\n"
|
{
|
||||||
" -v \t verbose\n"
|
#ifdef HAVE_GETOPT_LONG
|
||||||
" -x \t skip dumping of ACLs (grant/revoke)\n"
|
fprintf(stderr,
|
||||||
, progname);
|
"usage: %s [options] [backup file]\n"
|
||||||
#endif
|
" -a, --data-only \t dump out only the data, no schema\n"
|
||||||
fprintf(stderr,
|
" -d, --dbname <name> \t specify database name\n"
|
||||||
"\nIf [backup file] is not supplied, then standard input "
|
" -c, --clean \t clean(drop) schema prior to create\n"
|
||||||
"is used.\n");
|
" -f filename \t script output filename\n"
|
||||||
fprintf(stderr, "\n");
|
" -F, --format {c|f} \t specify backup file format\n"
|
||||||
|
" -h, --host <hostname> \t server host name\n"
|
||||||
exit(1);
|
" -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"
|
||||||
static char* _cleanupName(char* name)
|
" -O, --orig-order \t dump in original dump order\n"
|
||||||
{
|
" -p, --port <port> \t server port number\n"
|
||||||
int i;
|
" -P, --function[=name] \t dump functions or named function\n"
|
||||||
|
" -r, --rearrange \t rearrange output to put indexes etc at end\n"
|
||||||
if (!name)
|
" -s, --schema-only \t dump out only the schema, no data\n"
|
||||||
return NULL;
|
" -t [table], --table[=table] \t dump for this table only\n"
|
||||||
|
" -T, --trigger[=name] \t dump triggers or named trigger\n"
|
||||||
if (strlen(name) == 0)
|
" -u, --password \t use password authentication\n"
|
||||||
return NULL;
|
" -U, --use-list filename \t use specified TOC for ordering output from this file\n"
|
||||||
|
" -v, --verbose \t verbose\n"
|
||||||
name = strdup(name);
|
" -x, --no-acl \t skip dumping of ACLs (grant/revoke)\n"
|
||||||
|
, progname);
|
||||||
if (name[0] == '"')
|
|
||||||
{
|
#else
|
||||||
strcpy(name, &name[1]);
|
fprintf(stderr,
|
||||||
if (*(name + strlen(name) - 1) == '"')
|
"usage: %s [options] [backup file]\n"
|
||||||
*(name + strlen(name) - 1) = '\0';
|
" -a \t dump out only the data, no schema\n"
|
||||||
}
|
" -d, <name> \t specify database name\n"
|
||||||
/* otherwise, convert table name to lowercase... */
|
" -c \t clean(drop) schema prior to create\n"
|
||||||
else
|
" -f filename NOT IMPLEMENTED \t script output filename\n"
|
||||||
{
|
" -F {c|f} \t specify backup file format\n"
|
||||||
for (i = 0; name[i]; i++)
|
" -h, <hostname> \t server host name\n"
|
||||||
if (isascii((unsigned char) name[i]) && isupper(name[i]))
|
" -i name \t dump indexes or named index\n"
|
||||||
name[i] = tolower(name[i]);
|
" -l \t dump summarized TOC for this file\n"
|
||||||
}
|
" -o \t dump in oid order\n"
|
||||||
return name;
|
" -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…
x
Reference in New Issue
Block a user