*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
***************
*** 329,335 **** RestoreArchive(Archive *AHX, RestoreOptions *ropt)
  			AH->currentTE = te;
  
  			reqs = _tocEntryRequired(te, ropt, false /* needn't drop ACLs */ );
! 			if (((reqs & REQ_SCHEMA) != 0) && te->dropStmt)
  			{
  				/* We want the schema */
  				ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
--- 329,336 ----
  			AH->currentTE = te;
  
  			reqs = _tocEntryRequired(te, ropt, false /* needn't drop ACLs */ );
! 			if (((reqs & REQ_SCHEMA) != 0 ||
! 				 strcmp(te->desc, "LARGE OBJECT") == 0) && te->dropStmt)
  			{
  				/* We want the schema */
  				ahlog(AH, 1, "dropping %s %s\n", te->desc, te->tag);
***************
*** 448,454 **** restore_toc_entry(ArchiveHandle *AH, TocEntry *te,
  
  	defnDumped = false;
  
! 	if ((reqs & REQ_SCHEMA) != 0)		/* We want the schema */
  	{
  		ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);
  
--- 449,456 ----
  
  	defnDumped = false;
  
! 	if ((reqs & REQ_SCHEMA) != 0 &&				/* We want the schema */
! 		strcmp(te->desc, "LARGE OBJECT") != 0)	/* or large object */
  	{
  		ahlog(AH, 1, "creating %s %s\n", te->desc, te->tag);
  
***************
*** 519,525 **** restore_toc_entry(ArchiveHandle *AH, TocEntry *te,
  			{
  				_printTocEntry(AH, te, ropt, true, false);
  
! 				if (strcmp(te->desc, "BLOBS") == 0 ||
  					strcmp(te->desc, "BLOB COMMENTS") == 0)
  				{
  					ahlog(AH, 1, "restoring %s\n", te->desc);
--- 521,528 ----
  			{
  				_printTocEntry(AH, te, ropt, true, false);
  
! 				if (strcmp(te->desc, "LARGE OBJECT") == 0 ||
! 					strcmp(te->desc, "BLOBS") == 0 ||
  					strcmp(te->desc, "BLOB COMMENTS") == 0)
  				{
  					ahlog(AH, 1, "restoring %s\n", te->desc);
***************
*** 903,909 **** EndRestoreBlobs(ArchiveHandle *AH)
   * Called by a format handler to initiate restoration of a blob
   */
  void
! StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool drop)
  {
  	Oid			loOid;
  
--- 906,912 ----
   * Called by a format handler to initiate restoration of a blob
   */
  void
! StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool cleanup, bool compat)
  {
  	Oid			loOid;
  
***************
*** 914,938 **** StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool drop)
  
  	ahlog(AH, 2, "restoring large object with OID %u\n", oid);
  
! 	if (drop)
! 		DropBlobIfExists(AH, oid);
  
  	if (AH->connection)
  	{
! 		loOid = lo_create(AH->connection, oid);
! 		if (loOid == 0 || loOid != oid)
! 			die_horribly(AH, modulename, "could not create large object %u\n",
! 						 oid);
! 
  		AH->loFd = lo_open(AH->connection, oid, INV_WRITE);
  		if (AH->loFd == -1)
  			die_horribly(AH, modulename, "could not open large object\n");
  	}
! 	else
  	{
  		ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
  				 oid, INV_WRITE);
  	}
  
  	AH->writingBlob = 1;
  }
--- 917,947 ----
  
  	ahlog(AH, 2, "restoring large object with OID %u\n", oid);
  
! 	if (cleanup)
! 		CleanupBlobIfExists(AH, oid, compat);
  
  	if (AH->connection)
  	{
! 		if (compat)
! 		{
! 			loOid = lo_create(AH->connection, oid);
! 			if (loOid == 0 || loOid != oid)
! 				die_horribly(AH, modulename, "could not create large object %u\n", oid);
! 		}
  		AH->loFd = lo_open(AH->connection, oid, INV_WRITE);
  		if (AH->loFd == -1)
  			die_horribly(AH, modulename, "could not open large object\n");
  	}
! 	else if (compat)
  	{
  		ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
  				 oid, INV_WRITE);
  	}
+ 	else
+ 	{
+ 		ahprintf(AH, "SELECT pg_catalog.lo_open('%u', %d);\n",
+ 				 oid, INV_WRITE);
+ 	}
  
  	AH->writingBlob = 1;
  }
***************
*** 1940,1946 **** WriteDataChunks(ArchiveHandle *AH)
  			AH->currToc = te;
  			/* printf("Writing data for %d (%x)\n", te->id, te); */
  
! 			if (strcmp(te->desc, "BLOBS") == 0)
  			{
  				startPtr = AH->StartBlobsPtr;
  				endPtr = AH->EndBlobsPtr;
--- 1949,1956 ----
  			AH->currToc = te;
  			/* printf("Writing data for %d (%x)\n", te->id, te); */
  
! 			if (strcmp(te->desc, "BLOBS") == 0 ||
! 				strcmp(te->desc, "LARGE OBJECT") == 0)
  			{
  				startPtr = AH->StartBlobsPtr;
  				endPtr = AH->EndBlobsPtr;
***************
*** 2685,2690 **** _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
--- 2695,2707 ----
  		return;
  	}
  
+ 	/* objects named by just an identifier */
+ 	if (strcmp(type, "LARGE OBJECT") == 0)
+ 	{
+ 		appendPQExpBuffer(buf, "%s %s", type, te->tag);
+ 		return;
+ 	}
+ 
  	/*
  	 * These object types require additional decoration.  Fortunately, the
  	 * information needed is exactly what's in the DROP command.
***************
*** 2828,2833 **** _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
--- 2845,2851 ----
  			strcmp(te->desc, "DATABASE") == 0 ||
  			strcmp(te->desc, "DOMAIN") == 0 ||
  			strcmp(te->desc, "FUNCTION") == 0 ||
+ 			strcmp(te->desc, "LARGE OBJECT") == 0 ||
  			strcmp(te->desc, "OPERATOR") == 0 ||
  			strcmp(te->desc, "OPERATOR CLASS") == 0 ||
  			strcmp(te->desc, "OPERATOR FAMILY") == 0 ||
*** a/src/bin/pg_dump/pg_backup_archiver.h
--- b/src/bin/pg_dump/pg_backup_archiver.h
***************
*** 359,365 **** int			ReadOffset(ArchiveHandle *, pgoff_t *);
  size_t		WriteOffset(ArchiveHandle *, pgoff_t, int);
  
  extern void StartRestoreBlobs(ArchiveHandle *AH);
! extern void StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool drop);
  extern void EndRestoreBlob(ArchiveHandle *AH, Oid oid);
  extern void EndRestoreBlobs(ArchiveHandle *AH);
  
--- 359,365 ----
  size_t		WriteOffset(ArchiveHandle *, pgoff_t, int);
  
  extern void StartRestoreBlobs(ArchiveHandle *AH);
! extern void StartRestoreBlob(ArchiveHandle *AH, Oid oid, bool cleanup, bool compat);
  extern void EndRestoreBlob(ArchiveHandle *AH, Oid oid);
  extern void EndRestoreBlobs(ArchiveHandle *AH);
  
***************
*** 371,377 **** extern void InitArchiveFmt_Tar(ArchiveHandle *AH);
  extern bool isValidTarHeader(char *header);
  
  extern int	ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
! extern void	DropBlobIfExists(ArchiveHandle *AH, Oid oid);
  
  int			ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
  int			ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(printf, 2, 3)));
--- 371,377 ----
  extern bool isValidTarHeader(char *header);
  
  extern int	ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
! extern void	CleanupBlobIfExists(ArchiveHandle *AH, Oid oid, bool compat);
  
  int			ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
  int			ahprintf(ArchiveHandle *AH, const char *fmt,...) __attribute__((format(printf, 2, 3)));
*** a/src/bin/pg_dump/pg_backup_custom.c
--- b/src/bin/pg_dump/pg_backup_custom.c
***************
*** 54,60 **** 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);
! static void _LoadBlobs(ArchiveHandle *AH, bool drop);
  static void _Clone(ArchiveHandle *AH);
  static void _DeClone(ArchiveHandle *AH);
  
--- 54,60 ----
  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);
! static void _LoadBlobs(ArchiveHandle *AH, bool cleanup, bool compat);
  static void _Clone(ArchiveHandle *AH);
  static void _DeClone(ArchiveHandle *AH);
  
***************
*** 498,504 **** _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
  			break;
  
  		case BLK_BLOBS:
! 			_LoadBlobs(AH, ropt->dropSchema);
  			break;
  
  		default:				/* Always have a default */
--- 498,505 ----
  			break;
  
  		case BLK_BLOBS:
! 			_LoadBlobs(AH, ropt->dropSchema,
! 					   strcmp(te->desc, "BLOBS") == 0 ? true : false);
  			break;
  
  		default:				/* Always have a default */
***************
*** 619,625 **** _PrintData(ArchiveHandle *AH)
  }
  
  static void
! _LoadBlobs(ArchiveHandle *AH, bool drop)
  {
  	Oid			oid;
  
--- 620,626 ----
  }
  
  static void
! _LoadBlobs(ArchiveHandle *AH, bool cleanup, bool compat)
  {
  	Oid			oid;
  
***************
*** 628,634 **** _LoadBlobs(ArchiveHandle *AH, bool drop)
  	oid = ReadInt(AH);
  	while (oid != 0)
  	{
! 		StartRestoreBlob(AH, oid, drop);
  		_PrintData(AH);
  		EndRestoreBlob(AH, oid);
  		oid = ReadInt(AH);
--- 629,635 ----
  	oid = ReadInt(AH);
  	while (oid != 0)
  	{
! 		StartRestoreBlob(AH, oid, cleanup, compat);
  		_PrintData(AH);
  		EndRestoreBlob(AH, oid);
  		oid = ReadInt(AH);
*** a/src/bin/pg_dump/pg_backup_db.c
--- b/src/bin/pg_dump/pg_backup_db.c
***************
*** 12,17 ****
--- 12,18 ----
  
  #include "pg_backup_db.h"
  #include "dumputils.h"
+ #include "libpq/libpq-fs.h"
  
  #include <unistd.h>
  
***************
*** 653,672 **** CommitTransaction(ArchiveHandle *AH)
  }
  
  void
! DropBlobIfExists(ArchiveHandle *AH, Oid oid)
  {
! 	/* Call lo_unlink only if exists to avoid not-found error. */
! 	if (PQserverVersion(AH->connection) >= 80500)
! 	{
  		ahprintf(AH, "SELECT pg_catalog.lo_unlink(oid) "
! 					 "FROM pg_catalog.pg_largeobject_metadata "
! 					 "WHERE oid = %u;\n", oid);
! 	}
  	else
! 	{
! 		ahprintf(AH, "SELECT CASE WHEN EXISTS(SELECT 1 FROM pg_catalog.pg_largeobject WHERE loid = '%u') THEN pg_catalog.lo_unlink('%u') END;\n",
! 				 oid, oid);
! 	}
  }
  
  static bool
--- 654,674 ----
  }
  
  void
! CleanupBlobIfExists(ArchiveHandle *AH, Oid oid, bool compat)
  {
! 	if (AH->connection &&
! 		PQserverVersion(AH->connection) < 80500)
! 		die_horribly(AH, NULL,
! 					 "could not restore large object into older server");
! 
! 	if (compat)
  		ahprintf(AH, "SELECT pg_catalog.lo_unlink(oid) "
! 				 "FROM pg_catalog.pg_largeobject_metadata "
! 				 "WHERE oid = %u;\n", oid);
  	else
! 		ahprintf(AH, "SELECT pg_catalog.lo_truncate(pg_catalog.lo_open(oid, %d), 0) "
! 				 "FROM pg_catalog.pg_largeobject_metadata "
! 				 "WHERE oid = %u;\n", INV_READ, oid);
  }
  
  static bool
*** a/src/bin/pg_dump/pg_backup_files.c
--- b/src/bin/pg_dump/pg_backup_files.c
***************
*** 41,50 **** static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
  static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
  static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
  
- static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
  static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
  static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
- static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
  
  #define K_STD_BUF_SIZE 1024
  
--- 41,48 ----
***************
*** 67,72 **** typedef struct
--- 65,72 ----
  
  static const char *modulename = gettext_noop("file archiver");
  static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
+ static void _LoadLargeObject(ArchiveHandle *AH, TocEntry *te,
+ 							 RestoreOptions *ropt);
  static void _getBlobTocEntry(ArchiveHandle *AH, Oid *oid, char *fname);
  
  /*
***************
*** 93,102 **** InitArchiveFmt_Files(ArchiveHandle *AH)
  	AH->WriteExtraTocPtr = _WriteExtraToc;
  	AH->PrintExtraTocPtr = _PrintExtraToc;
  
! 	AH->StartBlobsPtr = _StartBlobs;
  	AH->StartBlobPtr = _StartBlob;
  	AH->EndBlobPtr = _EndBlob;
! 	AH->EndBlobsPtr = _EndBlobs;
  	AH->ClonePtr = NULL;
  	AH->DeClonePtr = NULL;
  
--- 93,102 ----
  	AH->WriteExtraTocPtr = _WriteExtraToc;
  	AH->PrintExtraTocPtr = _PrintExtraToc;
  
! 	AH->StartBlobsPtr = NULL;
  	AH->StartBlobPtr = _StartBlob;
  	AH->EndBlobPtr = _EndBlob;
! 	AH->EndBlobsPtr = NULL;
  	AH->ClonePtr = NULL;
  	AH->DeClonePtr = NULL;
  
***************
*** 331,336 **** _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
--- 331,338 ----
  
  	if (strcmp(te->desc, "BLOBS") == 0)
  		_LoadBlobs(AH, ropt);
+ 	else if (strcmp(te->desc, "LARGE OBJECT") == 0)
+ 		_LoadLargeObject(AH, te, ropt);
  	else
  		_PrintFileData(AH, tctx->filename, ropt);
  }
***************
*** 382,388 **** _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
  
  	while (oid != 0)
  	{
! 		StartRestoreBlob(AH, oid, ropt->dropSchema);
  		_PrintFileData(AH, fname, ropt);
  		EndRestoreBlob(AH, oid);
  		_getBlobTocEntry(AH, &oid, fname);
--- 384,390 ----
  
  	while (oid != 0)
  	{
! 		StartRestoreBlob(AH, oid, ropt->dropSchema, true);
  		_PrintFileData(AH, fname, ropt);
  		EndRestoreBlob(AH, oid);
  		_getBlobTocEntry(AH, &oid, fname);
***************
*** 394,399 **** _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
--- 396,418 ----
  	EndRestoreBlobs(AH);
  }
  
+ static void
+ _LoadLargeObject(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
+ {
+ 	Oid			oid = atooid(te->tag);
+ 	char		fname[K_STD_BUF_SIZE];
+ 
+ 	snprintf(fname, sizeof(fname), "blob_%u.dat%s",
+ 			 oid, (AH->compression ? ".gz" : ""));
+ 
+ 	StartRestoreBlobs(AH);
+ 
+ 	StartRestoreBlob(AH, oid, ropt->dropSchema, false);
+ 	_PrintFileData(AH, fname, ropt);
+ 	EndRestoreBlob(AH, oid);
+ 
+ 	EndRestoreBlobs(AH);
+ }
  
  static int
  _WriteByte(ArchiveHandle *AH, const int i)
***************
*** 468,496 **** _CloseArchive(ArchiveHandle *AH)
   */
  
  /*
-  * 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);
- 
- 	if (ctx->blobToc == NULL)
- 		die_horribly(AH, modulename,
- 		"could not open large object TOC for output: %s\n", strerror(errno));
- }
- 
- /*
   * Called by the archiver when the dumper calls StartBlob.
   *
   * Mandatory.
--- 487,492 ----
***************
*** 517,524 **** _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
  	sprintf(fmode, "wb%d", AH->compression);
  	sprintf(fname, "blob_%u.dat%s", oid, sfx);
  
- 	fprintf(ctx->blobToc, "%u %s\n", oid, fname);
- 
  #ifdef HAVE_LIBZ
  	tctx->FH = gzopen(fname, fmode);
  #else
--- 513,518 ----
***************
*** 543,562 **** _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
  	if (GZCLOSE(tctx->FH) != 0)
  		die_horribly(AH, modulename, "could not close large object file\n");
  }
- 
- /*
-  * 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); */
- 
- 	if (fclose(ctx->blobToc) != 0)
- 		die_horribly(AH, modulename, "could not close large object TOC file: %s\n", strerror(errno));
- }
--- 537,539 ----
*** a/src/bin/pg_dump/pg_backup_null.c
--- b/src/bin/pg_dump/pg_backup_null.c
***************
*** 147,160 **** _StartBlobs(ArchiveHandle *AH, TocEntry *te)
  static void
  _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
  {
  	if (oid == 0)
  		die_horribly(AH, NULL, "invalid OID for large object\n");
  
  	if (AH->ropt->dropSchema)
! 		DropBlobIfExists(AH, oid);
  
! 	ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
! 			 oid, INV_WRITE);
  
  	AH->WriteDataPtr = _WriteBlobData;
  }
--- 147,165 ----
  static void
  _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
  {
+ 	bool	compat = (strcmp(te->desc, "BLOBS") == 0 ? true : false);
+ 
  	if (oid == 0)
  		die_horribly(AH, NULL, "invalid OID for large object\n");
  
  	if (AH->ropt->dropSchema)
! 		CleanupBlobIfExists(AH, oid, compat);
  
! 	if (compat)
! 		ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
! 				 oid, INV_WRITE);
! 	else
! 		ahprintf(AH, "SELECT pg_catalog.lo_open(%u, %d);\n", oid, INV_WRITE);
  
  	AH->WriteDataPtr = _WriteBlobData;
  }
*** a/src/bin/pg_dump/pg_backup_tar.c
--- b/src/bin/pg_dump/pg_backup_tar.c
***************
*** 44,53 **** static void _WriteExtraToc(ArchiveHandle *AH, TocEntry *te);
  static void _ReadExtraToc(ArchiveHandle *AH, TocEntry *te);
  static void _PrintExtraToc(ArchiveHandle *AH, TocEntry *te);
  
- static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
  static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
  static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
- static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
  
  #define K_STD_BUF_SIZE 1024
  
--- 44,51 ----
***************
*** 101,106 **** typedef struct
--- 99,106 ----
  static const char *modulename = gettext_noop("tar archiver");
  
  static void _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt);
+ static void _LoadLargeObject(ArchiveHandle *AH, TocEntry *te,
+ 							 RestoreOptions *ropt);
  
  static TAR_MEMBER *tarOpen(ArchiveHandle *AH, const char *filename, char mode);
  static void tarClose(ArchiveHandle *AH, TAR_MEMBER *TH);
***************
*** 145,154 **** InitArchiveFmt_Tar(ArchiveHandle *AH)
  	AH->WriteExtraTocPtr = _WriteExtraToc;
  	AH->PrintExtraTocPtr = _PrintExtraToc;
  
! 	AH->StartBlobsPtr = _StartBlobs;
  	AH->StartBlobPtr = _StartBlob;
  	AH->EndBlobPtr = _EndBlob;
! 	AH->EndBlobsPtr = _EndBlobs;
  	AH->ClonePtr = NULL;
  	AH->DeClonePtr = NULL;
  
--- 145,154 ----
  	AH->WriteExtraTocPtr = _WriteExtraToc;
  	AH->PrintExtraTocPtr = _PrintExtraToc;
  
! 	AH->StartBlobsPtr = NULL;
  	AH->StartBlobPtr = _StartBlob;
  	AH->EndBlobPtr = _EndBlob;
! 	AH->EndBlobsPtr = NULL;
  	AH->ClonePtr = NULL;
  	AH->DeClonePtr = NULL;
  
***************
*** 697,702 **** _PrintTocData(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
--- 697,704 ----
  
  	if (strcmp(te->desc, "BLOBS") == 0)
  		_LoadBlobs(AH, ropt);
+ 	else if (strcmp(te->desc, "LARGE OBJECT") == 0)
+ 		_LoadLargeObject(AH, te, ropt);
  	else
  		_PrintFileData(AH, tctx->filename, ropt);
  }
***************
*** 725,731 **** _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
  			{
  				ahlog(AH, 1, "restoring large object OID %u\n", oid);
  
! 				StartRestoreBlob(AH, oid, ropt->dropSchema);
  
  				while ((cnt = tarRead(buf, 4095, th)) > 0)
  				{
--- 727,733 ----
  			{
  				ahlog(AH, 1, "restoring large object OID %u\n", oid);
  
! 				StartRestoreBlob(AH, oid, ropt->dropSchema, true);
  
  				while ((cnt = tarRead(buf, 4095, th)) > 0)
  				{
***************
*** 756,761 **** _LoadBlobs(ArchiveHandle *AH, RestoreOptions *ropt)
--- 758,796 ----
  	EndRestoreBlobs(AH);
  }
  
+ static void
+ _LoadLargeObject(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt)
+ {
+ 	Oid			oid = atooid(te->tag);
+ 	char		fname[K_STD_BUF_SIZE];
+ 	char		buf[4096];
+ 	TAR_MEMBER *th;
+ 	size_t		cnt;
+ 
+ 	StartRestoreBlobs(AH);
+ 
+ 	snprintf(fname, sizeof(fname), "blob_%u.dat", oid);
+ 
+ 	th = tarOpen(AH, fname, 'r');
+ 	if (th == NULL)
+ 		die_horribly(AH, modulename, "could not open input file \"%s\": %s\n",
+ 					 fname, strerror(errno));
+ 
+ 	ahlog(AH, 1, "restoring large object OID %u\n", oid);
+ 
+ 	StartRestoreBlob(AH, oid, ropt->dropSchema, false);
+ 
+ 	while ((cnt = tarRead(buf, 4095, th)) > 0)
+ 	{
+ 		buf[cnt] = '\0';
+ 		ahwrite(buf, 1, cnt, AH);
+ 	}
+ 	EndRestoreBlob(AH, oid);
+ 
+ 	tarClose(AH, th);
+ 
+ 	EndRestoreBlobs(AH);
+ }
  
  static int
  _WriteByte(ArchiveHandle *AH, const int i)
***************
*** 894,919 **** _scriptOut(ArchiveHandle *AH, const void *buf, size_t len)
   */
  
  /*
-  * 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 = tarOpen(AH, fname, 'w');
- }
- 
- /*
   * Called by the archiver when the dumper calls StartBlob.
   *
   * Mandatory.
--- 929,934 ----
***************
*** 923,929 **** _StartBlobs(ArchiveHandle *AH, TocEntry *te)
  static void
  _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
  {
- 	lclContext *ctx = (lclContext *) AH->formatData;
  	lclTocEntry *tctx = (lclTocEntry *) te->formatData;
  	char		fname[255];
  	char	   *sfx;
--- 938,943 ----
***************
*** 938,945 **** _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
  
  	sprintf(fname, "blob_%u.dat%s", oid, sfx);
  
- 	tarPrintf(AH, ctx->blobToc, "%u %s\n", oid, fname);
- 
  	tctx->TH = tarOpen(AH, fname, 'w');
  }
  
--- 952,957 ----
***************
*** 957,981 **** _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
  	tarClose(AH, tctx->TH);
  }
  
- /*
-  * 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); */
- 
- 	tarClose(AH, ctx->blobToc);
- }
- 
- 
- 
  /*------------
   * TAR Support
   *------------
--- 969,974 ----
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 190,198 **** static void selectSourceSchema(const char *schemaName);
  static char *getFormattedTypeName(Oid oid, OidOptions opts);
  static char *myFormatType(const char *typname, int32 typmod);
  static const char *fmtQualifiedId(const char *schema, const char *id);
! static bool hasBlobs(Archive *AH);
! static int	dumpBlobs(Archive *AH, void *arg);
! static int	dumpBlobComments(Archive *AH, void *arg);
  static void dumpDatabase(Archive *AH);
  static void dumpEncoding(Archive *AH);
  static void dumpStdStrings(Archive *AH);
--- 190,198 ----
  static char *getFormattedTypeName(Oid oid, OidOptions opts);
  static char *myFormatType(const char *typname, int32 typmod);
  static const char *fmtQualifiedId(const char *schema, const char *id);
! static void getLargeObjects(Archive *AH);
! static void dumpLargeObject(Archive *AH, LargeObjectInfo *loinfo);
! static int	dumpLargeObjectData(Archive *AH, void *arg);
  static void dumpDatabase(Archive *AH);
  static void dumpEncoding(Archive *AH);
  static void dumpStdStrings(Archive *AH);
***************
*** 701,725 **** main(int argc, char **argv)
  			getTableDataFKConstraints();
  	}
  
! 	if (outputBlobs && hasBlobs(g_fout))
! 	{
! 		/* Add placeholders to allow correct sorting of blobs */
! 		DumpableObject *blobobj;
! 		DumpableObject *blobcobj;
! 
! 		blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
! 		blobobj->objType = DO_BLOBS;
! 		blobobj->catId = nilCatalogId;
! 		AssignDumpId(blobobj);
! 		blobobj->name = strdup("BLOBS");
! 
! 		blobcobj = (DumpableObject *) malloc(sizeof(DumpableObject));
! 		blobcobj->objType = DO_BLOB_COMMENTS;
! 		blobcobj->catId = nilCatalogId;
! 		AssignDumpId(blobcobj);
! 		blobcobj->name = strdup("BLOB COMMENTS");
! 		addObjectDependency(blobcobj, blobobj->dumpId);
! 	}
  
  	/*
  	 * Collect dependency data to assist in ordering the objects.
--- 701,708 ----
  			getTableDataFKConstraints();
  	}
  
! 	if (outputBlobs)
! 		getLargeObjects(g_fout);
  
  	/*
  	 * Collect dependency data to assist in ordering the objects.
***************
*** 1936,2183 **** dumpStdStrings(Archive *AH)
  	destroyPQExpBuffer(qry);
  }
  
- 
  /*
!  * hasBlobs:
!  *	Test whether database contains any large objects
   */
! static bool
! hasBlobs(Archive *AH)
  {
! 	bool		result;
! 	const char *blobQry;
! 	PGresult   *res;
  
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	/* Check for BLOB OIDs */
  	if (AH->remoteVersion >= 80500)
! 		blobQry = "SELECT oid FROM pg_largeobject_metadata LIMIT 1";
  	else if (AH->remoteVersion >= 70100)
! 		blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
  	else
! 		blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
  
! 	res = PQexec(g_conn, blobQry);
! 	check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
  
! 	result = PQntuples(res) > 0;
  
  	PQclear(res);
  
! 	return result;
  }
  
  /*
!  * dumpBlobs:
!  *	dump all blobs
   */
! static int
! dumpBlobs(Archive *AH, void *arg)
  {
! 	const char *blobQry;
! 	const char *blobFetchQry;
! 	PGresult   *res;
! 	char		buf[LOBBUFSIZE];
! 	int			i;
! 	int			cnt;
! 
! 	if (g_verbose)
! 		write_msg(NULL, "saving large objects\n");
  
! 	/* Make sure we are in proper schema */
! 	selectSourceSchema("pg_catalog");
! 
! 	/* Cursor to get all BLOB OIDs */
! 	if (AH->remoteVersion >= 80500)
! 		blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
! 	else if (AH->remoteVersion >= 70100)
! 		blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
! 	else
! 		blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
  
! 	res = PQexec(g_conn, blobQry);
! 	check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
! 
! 	/* Command to fetch from cursor */
! 	blobFetchQry = "FETCH 1000 IN bloboid";
! 
! 	do
  	{
! 		PQclear(res);
! 
! 		/* Do a fetch */
! 		res = PQexec(g_conn, blobFetchQry);
! 		check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
! 
! 		/* Process the tuples, if any */
! 		for (i = 0; i < PQntuples(res); i++)
! 		{
! 			Oid			blobOid;
! 			int			loFd;
! 
! 			blobOid = atooid(PQgetvalue(res, i, 0));
! 			/* Open the BLOB */
! 			loFd = lo_open(g_conn, blobOid, INV_READ);
! 			if (loFd == -1)
! 			{
! 				write_msg(NULL, "dumpBlobs(): could not open large object: %s",
! 						  PQerrorMessage(g_conn));
! 				exit_nicely();
! 			}
! 
! 			StartBlob(AH, blobOid);
! 
! 			/* Now read it in chunks, sending data to archive */
! 			do
! 			{
! 				cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
! 				if (cnt < 0)
! 				{
! 					write_msg(NULL, "dumpBlobs(): error reading large object: %s",
! 							  PQerrorMessage(g_conn));
! 					exit_nicely();
! 				}
! 
! 				WriteData(AH, buf, cnt);
! 			} while (cnt > 0);
! 
! 			lo_close(g_conn, loFd);
! 
! 			EndBlob(AH, blobOid);
! 		}
! 	} while (PQntuples(res) > 0);
  
! 	PQclear(res);
  
! 	return 1;
  }
  
- /*
-  * dumpBlobComments
-  *	dump all blob properties.
-  *  It has "BLOB COMMENTS" tag due to the historical reason, but note
-  *  that it is the routine to dump all the properties of blobs.
-  *
-  * Since we don't provide any way to be selective about dumping blobs,
-  * there's no need to be selective about their comments either.  We put
-  * all the comments into one big TOC entry.
-  */
  static int
! dumpBlobComments(Archive *AH, void *arg)
  {
! 	const char *blobQry;
! 	const char *blobFetchQry;
! 	PQExpBuffer cmdQry = createPQExpBuffer();
! 	PGresult   *res;
! 	int			i;
! 
! 	if (g_verbose)
! 		write_msg(NULL, "saving large object properties\n");
! 
! 	/* Make sure we are in proper schema */
! 	selectSourceSchema("pg_catalog");
  
! 	/* Cursor to get all BLOB comments */
! 	if (AH->remoteVersion >= 80500)
! 		blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
! 			"obj_description(oid, 'pg_largeobject'), "
! 			"pg_get_userbyid(lomowner), lomacl "
! 			"FROM pg_largeobject_metadata";
! 	else if (AH->remoteVersion >= 70300)
! 		blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
! 			"obj_description(loid, 'pg_largeobject'), NULL, NULL "
! 			"FROM (SELECT DISTINCT loid FROM "
! 			"pg_description d JOIN pg_largeobject l ON (objoid = loid) "
! 			"WHERE classoid = 'pg_largeobject'::regclass) ss";
! 	else if (AH->remoteVersion >= 70200)
! 		blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
! 			"obj_description(loid, 'pg_largeobject'), NULL, NULL "
! 			"FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
! 	else if (AH->remoteVersion >= 70100)
! 		blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
! 			"obj_description(loid), NULL, NULL "
! 			"FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
! 	else
! 		blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
! 			"	( "
! 			"		SELECT description "
! 			"		FROM pg_description pd "
! 			"		WHERE pd.objoid=pc.oid "
! 			"	), NULL, NULL "
! 			"FROM pg_class pc WHERE relkind = 'l'";
! 
! 	res = PQexec(g_conn, blobQry);
! 	check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
  
! 	/* Command to fetch from cursor */
! 	blobFetchQry = "FETCH 100 IN blobcmt";
  
  	do
  	{
! 		PQclear(res);
! 
! 		/* Do a fetch */
! 		res = PQexec(g_conn, blobFetchQry);
! 		check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
! 
! 		/* Process the tuples, if any */
! 		for (i = 0; i < PQntuples(res); i++)
  		{
! 			Oid			blobOid = atooid(PQgetvalue(res, i, 0));
! 			char	   *lo_comment = PQgetvalue(res, i, 1);
! 			char	   *lo_owner = PQgetvalue(res, i, 2);
! 			char	   *lo_acl = PQgetvalue(res, i, 3);
! 			char		lo_name[32];
! 
! 			resetPQExpBuffer(cmdQry);
! 
! 			/* comment on the blob */
! 			if (!PQgetisnull(res, i, 1))
! 			{
! 				appendPQExpBuffer(cmdQry,
! 								  "COMMENT ON LARGE OBJECT %u IS ", blobOid);
! 				appendStringLiteralAH(cmdQry, lo_comment, AH);
! 				appendPQExpBuffer(cmdQry, ";\n");
! 			}
! 
! 			/* dump blob ownership, if necessary */
! 			if (!PQgetisnull(res, i, 2))
! 			{
! 				appendPQExpBuffer(cmdQry,
! 								  "ALTER LARGE OBJECT %u OWNER TO %s;\n",
! 								  blobOid, lo_owner);
! 			}
! 
! 			/* dump blob privileges, if necessary */
! 			if (!PQgetisnull(res, i, 3) &&
! 				!dataOnly && !aclsSkip)
! 			{
! 				snprintf(lo_name, sizeof(lo_name), "%u", blobOid);
! 				if (!buildACLCommands(lo_name, NULL, "LARGE OBJECT",
! 									  lo_acl, lo_owner, "",
! 									  AH->remoteVersion, cmdQry))
! 				{
! 					write_msg(NULL, "could not parse ACL (%s) for "
! 							  "large object %u", lo_acl, blobOid);
! 					exit_nicely();
! 				}
! 			}
! 
! 			if (cmdQry->len > 0)
! 			{
! 				appendPQExpBuffer(cmdQry, "\n");
! 				archputs(cmdQry->data, AH);
! 			}
  		}
- 	} while (PQntuples(res) > 0);
  
! 	PQclear(res);
  
! 	archputs("\n", AH);
  
! 	destroyPQExpBuffer(cmdQry);
  
  	return 1;
  }
--- 1919,2077 ----
  	destroyPQExpBuffer(qry);
  }
  
  /*
!  * getLargeObjects 
!  *	Gather the information of large obejcts.
   */
! static void
! getLargeObjects(Archive *AH)
  {
! 	PQExpBuffer			loQry = createPQExpBuffer();
! 	LargeObjectInfo	   *loinfo;
! 	PGresult		   *res;
! 	int					i;
  
  	/* Make sure we are in proper schema */
  	selectSourceSchema("pg_catalog");
  
! 	/* Collect large object metadata */
  	if (AH->remoteVersion >= 80500)
! 		appendPQExpBuffer(loQry,
! 						  "SELECT oid, (%s lomowner), lomacl,"
! 						  " obj_description(oid, 'pg_largeobject')"
! 						  " FROM pg_largeobject_metadata",
! 						  username_subquery);
! 	else if (AH->remoteVersion >= 70200)
! 		appendPQExpBuffer(loQry,
! 						  "SELECT DISTINCT loid, NULL, NULL, "
! 						  " obj_description(loid, 'pg_largeobject')"
! 						  " FROM pg_largeobject");
  	else if (AH->remoteVersion >= 70100)
! 		appendPQExpBuffer(loQry,
! 						  "SELECT DISTINCT loid, NULL, NULL, "
! 						  " obj_description(loid)"
! 						  " FROM pg_largeobject");
  	else
! 		appendPQExpBuffer(loQry,
! 						  "SELECT DISTINCT oid, NULL, NULL, "
! 						  " obj_description(oid)"
! 						  " FROM pg_class WHERE relkind = 'l'");
  
! 	res = PQexec(g_conn, loQry->data);
! 	check_sql_result(res, g_conn, loQry->data, PGRES_TUPLES_OK);
  
! 	for (i = 0; i < PQntuples(res); i++)
! 	{
! 		loinfo = (LargeObjectInfo *) malloc(sizeof(LargeObjectInfo));
! 		loinfo->dobj.objType = DO_LARGE_OBJECT;
! 		loinfo->dobj.catId = nilCatalogId;
! 		AssignDumpId(&loinfo->dobj);
  
+ 		loinfo->dobj.name = strdup(PQgetvalue(res, i, 0));
+ 		loinfo->rolname = strdup(PQgetvalue(res, i, 1));
+ 		loinfo->loacl = strdup(PQgetvalue(res, i, 2));
+ 		loinfo->locomm = strdup(PQgetvalue(res, i, 3));
+ 	}
  	PQclear(res);
  
! 	destroyPQExpBuffer(loQry);
  }
  
  /*
!  * dumpLargeObject
!  *	dump a large object metadata
   */
! static void
! dumpLargeObject(Archive *AH, LargeObjectInfo *loinfo)
  {
! 	PQExpBuffer		cquery;
! 	PQExpBuffer		dquery;
  
! 	cquery = createPQExpBuffer();
! 	dquery = createPQExpBuffer();
  
! 	/*
! 	 * create an empty large object
! 	 */
! 	appendPQExpBuffer(cquery, "SELECT lo_create(%s);\n",
! 					  loinfo->dobj.name);
! 	/*
! 	 * COMMENT ON, if necessary. Note that we cannot use dumpComment()
! 	 * because it will be deployed on SECTION_NONE.
! 	 */
! 	if (loinfo->locomm && strlen(loinfo->locomm) > 0)
  	{
! 		appendPQExpBuffer(cquery,
! 						  "\nCOMMENT ON LARGE OBJECT %s IS ",
! 						  loinfo->dobj.name);
! 		appendStringLiteralAH(cquery, loinfo->locomm, AH);
! 		appendPQExpBuffer(cquery, ";\n");
! 	}
  
! 	/*
! 	 * cleanup a large object
! 	 */
! 	appendPQExpBuffer(dquery, "SELECT lo_unlink(%s);\n",
! 					  loinfo->dobj.name);
  
! 	ArchiveEntry(AH, loinfo->dobj.catId, loinfo->dobj.dumpId,
! 				 loinfo->dobj.name,
! 				 NULL, NULL,
! 				 loinfo->rolname, false,
! 				 "LARGE OBJECT", SECTION_DATA,
! 				 cquery->data, dquery->data, NULL,
! 				 loinfo->dobj.dependencies, loinfo->dobj.nDeps,
! 				 dumpLargeObjectData, loinfo);
! 	/*
! 	 * Dump access privileges, if necessary
! 	 */
! 	dumpACL(AH, loinfo->dobj.catId, loinfo->dobj.dumpId,
! 			"LARGE OBJECT",
! 			loinfo->dobj.name, NULL,
! 			loinfo->dobj.name, NULL,
! 			loinfo->rolname, loinfo->loacl);
  }
  
  static int
! dumpLargeObjectData(Archive *AH, void *arg)
  {
! 	LargeObjectInfo	   *loinfo = (LargeObjectInfo *)arg;
! 	Oid		blobOid;
! 	int		blobFd;
! 	int		cnt;
! 	char	buf[LOBBUFSIZE];
  
! 	blobOid = atooid(loinfo->dobj.name);
  
! 	/* open the large obejct */
! 	blobFd = lo_open(g_conn, blobOid, INV_READ);
! 	if (blobFd == -1)
! 	{
! 		write_msg(NULL, "%s: could not open large object: %s",
! 				  __FUNCTION__,
! 				  PQerrorMessage(g_conn));
! 		exit_nicely();
! 	}
  
+ 	StartBlob(AH, blobOid);
+ 	/* Now read it in chunks, sending data to archive */
  	do
  	{
! 		cnt = lo_read(g_conn, blobFd, buf, LOBBUFSIZE);
! 		if (cnt < 0)
  		{
! 			write_msg(NULL, "%s(): error reading large object: %s",
! 					  __FUNCTION__,
! 					  PQerrorMessage(g_conn));
! 			exit_nicely();
  		}
  
! 		WriteData(AH, buf, cnt);
! 	} while (cnt > 0);
  
! 	lo_close(g_conn, blobFd);
  
! 	EndBlob(AH, blobOid);
  
  	return 1;
  }
***************
*** 6524,6544 **** dumpDumpableObject(Archive *fout, DumpableObject *dobj)
  		case DO_DEFAULT_ACL:
  			dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
  			break;
! 		case DO_BLOBS:
! 			ArchiveEntry(fout, dobj->catId, dobj->dumpId,
! 						 dobj->name, NULL, NULL, "",
! 						 false, "BLOBS", SECTION_DATA,
! 						 "", "", NULL,
! 						 dobj->dependencies, dobj->nDeps,
! 						 dumpBlobs, NULL);
! 			break;
! 		case DO_BLOB_COMMENTS:
! 			ArchiveEntry(fout, dobj->catId, dobj->dumpId,
! 						 dobj->name, NULL, NULL, "",
! 						 false, "BLOB COMMENTS", SECTION_DATA,
! 						 "", "", NULL,
! 						 dobj->dependencies, dobj->nDeps,
! 						 dumpBlobComments, NULL);
  			break;
  	}
  }
--- 6418,6425 ----
  		case DO_DEFAULT_ACL:
  			dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
  			break;
! 		case DO_LARGE_OBJECT:
! 			dumpLargeObject(fout, (LargeObjectInfo *) dobj);
  			break;
  	}
  }
***************
*** 10395,10401 **** dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
  	PQExpBuffer sql;
  
  	/* Do nothing if ACL dump is not enabled */
! 	if (dataOnly || aclsSkip)
  		return;
  
  	sql = createPQExpBuffer();
--- 10276,10284 ----
  	PQExpBuffer sql;
  
  	/* Do nothing if ACL dump is not enabled */
! 	/* Large object is an exception of --data-only */
! 	if (aclsSkip ||
! 		(dataOnly && strcmp(type, "LARGE OBJECT") != 0))
  		return;
  
  	sql = createPQExpBuffer();
*** a/src/bin/pg_dump/pg_dump.h
--- b/src/bin/pg_dump/pg_dump.h
***************
*** 115,122 **** typedef enum
  	DO_FDW,
  	DO_FOREIGN_SERVER,
  	DO_DEFAULT_ACL,
! 	DO_BLOBS,
! 	DO_BLOB_COMMENTS
  } DumpableObjectType;
  
  typedef struct _dumpableObject
--- 115,121 ----
  	DO_FDW,
  	DO_FOREIGN_SERVER,
  	DO_DEFAULT_ACL,
! 	DO_LARGE_OBJECT,
  } DumpableObjectType;
  
  typedef struct _dumpableObject
***************
*** 443,448 **** typedef struct _defaultACLInfo
--- 442,455 ----
  	char	   *defaclacl;
  } DefaultACLInfo;
  
+ typedef struct _largeObjectInfo
+ {
+ 	DumpableObject	dobj;
+ 	char	   *rolname;
+ 	char	   *loacl;
+ 	char	   *locomm;
+ } LargeObjectInfo;
+ 
  /* global decls */
  extern bool force_quotes;		/* double-quotes for identifiers flag */
  extern bool g_verbose;			/* verbose flag */
*** a/src/bin/pg_dump/pg_dump_sort.c
--- b/src/bin/pg_dump/pg_dump_sort.c
***************
*** 55,62 **** static const int oldObjectTypePriority[] =
  	3,							/* DO_FDW */
  	4,							/* DO_FOREIGN_SERVER */
  	17,							/* DO_DEFAULT_ACL */
! 	10,							/* DO_BLOBS */
! 	11							/* DO_BLOB_COMMENTS */
  };
  
  /*
--- 55,61 ----
  	3,							/* DO_FDW */
  	4,							/* DO_FOREIGN_SERVER */
  	17,							/* DO_DEFAULT_ACL */
! 	10,							/* DO_LARGE_OBJECT */
  };
  
  /*
***************
*** 92,99 **** static const int newObjectTypePriority[] =
  	14,							/* DO_FDW */
  	15,							/* DO_FOREIGN_SERVER */
  	27,							/* DO_DEFAULT_ACL */
! 	20,							/* DO_BLOBS */
! 	21							/* DO_BLOB_COMMENTS */
  };
  
  
--- 91,97 ----
  	14,							/* DO_FDW */
  	15,							/* DO_FOREIGN_SERVER */
  	27,							/* DO_DEFAULT_ACL */
! 	20,							/* DO_LARGE_OBJECT */
  };
  
  
***************
*** 1146,1160 **** describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
  					 "DEFAULT ACL %s  (ID %d OID %u)",
  					 obj->name, obj->dumpId, obj->catId.oid);
  			return;
! 		case DO_BLOBS:
  			snprintf(buf, bufsize,
! 					 "BLOBS  (ID %d)",
! 					 obj->dumpId);
! 			return;
! 		case DO_BLOB_COMMENTS:
! 			snprintf(buf, bufsize,
! 					 "BLOB COMMENTS  (ID %d)",
! 					 obj->dumpId);
  			return;
  	}
  	/* shouldn't get here */
--- 1144,1153 ----
  					 "DEFAULT ACL %s  (ID %d OID %u)",
  					 obj->name, obj->dumpId, obj->catId.oid);
  			return;
! 		case DO_LARGE_OBJECT:
  			snprintf(buf, bufsize,
! 					 "LARGE OBJECT (OID %s)",
! 					 obj->name);
  			return;
  	}
  	/* shouldn't get here */
