mirror of
https://github.com/postgres/postgres.git
synced 2025-11-16 15:02:33 +03:00
pg_dump can now dump large objects even in plain-text output mode, by
using the recently added lo_create() function. The restore logic in pg_restore is greatly simplified as well, since there's no need anymore to try to adjust database references to match a new set of blob OIDs.
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* pg_backup_null.c
|
||||
*
|
||||
* Implementation of an archive that is never saved; it is used by
|
||||
* pg_dump to output a plain text SQL script instead of save
|
||||
* pg_dump to output a plain text SQL script instead of saving
|
||||
* a real archive.
|
||||
*
|
||||
* See the headers to pg_restore for more details.
|
||||
@@ -17,7 +17,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.14 2003/12/08 16:39:05 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.15 2005/06/21 20:45:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -27,12 +27,21 @@
|
||||
|
||||
#include <unistd.h> /* for dup */
|
||||
|
||||
#include "libpq/libpq-fs.h"
|
||||
|
||||
|
||||
static size_t _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
|
||||
static size_t _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen);
|
||||
static void _EndData(ArchiveHandle *AH, TocEntry *te);
|
||||
static int _WriteByte(ArchiveHandle *AH, const int i);
|
||||
static size_t _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
|
||||
static void _CloseArchive(ArchiveHandle *AH);
|
||||
static void _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
|
||||
static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
|
||||
static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
|
||||
static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
|
||||
static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
|
||||
|
||||
|
||||
/*
|
||||
* Initializer
|
||||
@@ -48,6 +57,17 @@ InitArchiveFmt_Null(ArchiveHandle *AH)
|
||||
AH->ClosePtr = _CloseArchive;
|
||||
AH->PrintTocDataPtr = _PrintTocData;
|
||||
|
||||
AH->StartBlobsPtr = _StartBlobs;
|
||||
AH->StartBlobPtr = _StartBlob;
|
||||
AH->EndBlobPtr = _EndBlob;
|
||||
AH->EndBlobsPtr = _EndBlobs;
|
||||
|
||||
/* Initialize LO buffering */
|
||||
AH->lo_buf_size = LOBBUFSIZE;
|
||||
AH->lo_buf = (void *) malloc(LOBBUFSIZE);
|
||||
if (AH->lo_buf == NULL)
|
||||
die_horribly(AH, NULL, "out of memory\n");
|
||||
|
||||
/*
|
||||
* Now prevent reading...
|
||||
*/
|
||||
@@ -59,10 +79,8 @@ InitArchiveFmt_Null(ArchiveHandle *AH)
|
||||
* - Start a new TOC entry
|
||||
*/
|
||||
|
||||
/*------
|
||||
/*
|
||||
* Called by dumper via archiver from within a data dump routine
|
||||
* As at V1.3, this is only called for COPY FROM dfata, and BLOB data
|
||||
*------
|
||||
*/
|
||||
static size_t
|
||||
_WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
|
||||
@@ -72,12 +90,91 @@ _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
|
||||
return dLen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by dumper via archiver from within a data dump routine
|
||||
* We substitute this for _WriteData while emitting a BLOB
|
||||
*/
|
||||
static size_t
|
||||
_WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen)
|
||||
{
|
||||
if (dLen > 0)
|
||||
{
|
||||
unsigned char *str;
|
||||
size_t len;
|
||||
|
||||
str = PQescapeBytea((const unsigned char *) data, dLen, &len);
|
||||
if (!str)
|
||||
die_horribly(AH, NULL, "out of memory\n");
|
||||
|
||||
ahprintf(AH, "SELECT lowrite(0, '%s');\n", str);
|
||||
|
||||
free(str);
|
||||
}
|
||||
return dLen;
|
||||
}
|
||||
|
||||
static void
|
||||
_EndData(ArchiveHandle *AH, TocEntry *te)
|
||||
{
|
||||
ahprintf(AH, "\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
ahprintf(AH, "BEGIN;\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, Oid oid)
|
||||
{
|
||||
if (oid == 0)
|
||||
die_horribly(AH, NULL, "invalid OID for large object\n");
|
||||
|
||||
ahprintf(AH, "SELECT lo_open(lo_create(%u), %d);\n", oid, INV_WRITE);
|
||||
|
||||
AH->WriteDataPtr = _WriteBlobData;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by the archiver when the dumper calls EndBlob.
|
||||
*
|
||||
* Optional.
|
||||
*/
|
||||
static void
|
||||
_EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
|
||||
{
|
||||
AH->WriteDataPtr = _WriteData;
|
||||
ahprintf(AH, "SELECT lo_close(0);\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by the archiver when finishing saving all BLOB DATA.
|
||||
*
|
||||
* Optional.
|
||||
*/
|
||||
static void
|
||||
_EndBlobs(ArchiveHandle *AH, TocEntry *te)
|
||||
{
|
||||
ahprintf(AH, "COMMIT;\n\n");
|
||||
}
|
||||
|
||||
/*------
|
||||
* Called as part of a RestoreArchive call; for the NULL archive, this
|
||||
* just sends the data for a given TOC entry to the output.
|
||||
@@ -89,7 +186,15 @@ _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
|
||||
if (te->dataDumper)
|
||||
{
|
||||
AH->currToc = te;
|
||||
|
||||
if (strcmp(te->desc, "BLOBS") == 0)
|
||||
_StartBlobs(AH, te);
|
||||
|
||||
(*te->dataDumper) ((Archive *) AH, te->dataDumperArg);
|
||||
|
||||
if (strcmp(te->desc, "BLOBS") == 0)
|
||||
_EndBlobs(AH, te);
|
||||
|
||||
AH->currToc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user