Skip to content

Commit b173211

Browse files
committed
Fix pg_dump to do the right thing when escaping the contents of large objects.
The previous implementation got it right in most cases but failed in one: if you pg_dump into an archive with standard_conforming_strings enabled, then pg_restore to a script file (not directly to a database), the script will set standard_conforming_strings = on but then emit large object data as nonstandardly-escaped strings. At the moment the code is made to emit hex-format bytea strings when dumping to a script file. We might want to change to old-style escaping for backwards compatibility, but that would be slower and bulkier. If we do, it's just a matter of reimplementing appendByteaLiteral(). This has been broken for a long time, but given the lack of field complaints I'm not going to worry about back-patching.
1 parent 50d0834 commit b173211

File tree

5 files changed

+75
-20
lines changed

5 files changed

+75
-20
lines changed

src/bin/pg_dump/dumputils.c

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.47 2009/07/14 20:24:10 tgl Exp $
11+
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.48 2009/08/04 21:56:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -325,6 +325,55 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
325325
}
326326

327327

328+
/*
329+
* Convert a bytea value (presented as raw bytes) to an SQL string literal
330+
* and append it to the given buffer. We assume the specified
331+
* standard_conforming_strings setting.
332+
*
333+
* This is needed in situations where we do not have a PGconn available.
334+
* Where we do, PQescapeByteaConn is a better choice.
335+
*/
336+
void
337+
appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
338+
bool std_strings)
339+
{
340+
const unsigned char *source = str;
341+
char *target;
342+
343+
static const char hextbl[] = "0123456789abcdef";
344+
345+
/*
346+
* This implementation is hard-wired to produce hex-format output.
347+
* We do not know the server version the output will be loaded into,
348+
* so making an intelligent format choice is impossible. It might be
349+
* better to always use the old escaped format.
350+
*/
351+
if (!enlargePQExpBuffer(buf, 2 * length + 5))
352+
return;
353+
354+
target = buf->data + buf->len;
355+
*target++ = '\'';
356+
if (!std_strings)
357+
*target++ = '\\';
358+
*target++ = '\\';
359+
*target++ = 'x';
360+
361+
while (length-- > 0)
362+
{
363+
unsigned char c = *source++;
364+
365+
*target++ = hextbl[(c >> 4) & 0xF];
366+
*target++ = hextbl[c & 0xF];
367+
}
368+
369+
/* Write the terminating quote and NUL character. */
370+
*target++ = '\'';
371+
*target = '\0';
372+
373+
buf->len = target - buf->data;
374+
}
375+
376+
328377
/*
329378
* Convert backend's version string into a number.
330379
*/

src/bin/pg_dump/dumputils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
99
* Portions Copyright (c) 1994, Regents of the University of California
1010
*
11-
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.24 2009/03/11 03:33:29 adunstan Exp $
11+
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.25 2009/08/04 21:56:08 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -27,6 +27,9 @@ extern void appendStringLiteralConn(PQExpBuffer buf, const char *str,
2727
PGconn *conn);
2828
extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str,
2929
const char *dqprefix);
30+
extern void appendByteaLiteral(PQExpBuffer buf,
31+
const unsigned char *str, size_t length,
32+
bool std_strings);
3033
extern int parse_version(const char *versionString);
3134
extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
3235
extern bool buildACLCommands(const char *name, const char *subname,

src/bin/pg_dump/pg_backup_archiver.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
*
1717
* IDENTIFICATION
18-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.173 2009/07/21 21:46:10 tgl Exp $
18+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.174 2009/08/04 21:56:08 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -1249,20 +1249,19 @@ dump_lo_buf(ArchiveHandle *AH)
12491249
}
12501250
else
12511251
{
1252-
unsigned char *str;
1253-
size_t len;
1252+
PQExpBuffer buf = createPQExpBuffer();
12541253

1255-
str = PQescapeBytea((const unsigned char *) AH->lo_buf,
1256-
AH->lo_buf_used, &len);
1257-
if (!str)
1258-
die_horribly(AH, modulename, "out of memory\n");
1254+
appendByteaLiteralAHX(buf,
1255+
(const unsigned char *) AH->lo_buf,
1256+
AH->lo_buf_used,
1257+
AH);
12591258

12601259
/* Hack: turn off writingBlob so ahwrite doesn't recurse to here */
12611260
AH->writingBlob = 0;
1262-
ahprintf(AH, "SELECT pg_catalog.lowrite(0, '%s');\n", str);
1261+
ahprintf(AH, "SELECT pg_catalog.lowrite(0, %s);\n", buf->data);
12631262
AH->writingBlob = 1;
12641263

1265-
free(str);
1264+
destroyPQExpBuffer(buf);
12661265
}
12671266
AH->lo_buf_used = 0;
12681267
}

src/bin/pg_dump/pg_backup_archiver.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
*
1818
*
1919
* IDENTIFICATION
20-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.80 2009/07/21 21:46:10 tgl Exp $
20+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.81 2009/08/04 21:56:09 tgl Exp $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
@@ -342,6 +342,9 @@ extern bool checkSeek(FILE *fp);
342342
#define appendStringLiteralAHX(buf,str,AH) \
343343
appendStringLiteral(buf, str, (AH)->public.encoding, (AH)->public.std_strings)
344344

345+
#define appendByteaLiteralAHX(buf,str,len,AH) \
346+
appendByteaLiteral(buf, str, len, (AH)->public.std_strings)
347+
345348
/*
346349
* Mandatory routines for each supported format
347350
*/

src/bin/pg_dump/pg_backup_null.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
*
1818
*
1919
* IDENTIFICATION
20-
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.21 2009/07/21 21:46:10 tgl Exp $
20+
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_null.c,v 1.22 2009/08/04 21:56:09 tgl Exp $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
2424

2525
#include "pg_backup_archiver.h"
26+
#include "dumputils.h"
2627

2728
#include <unistd.h> /* for dup */
2829

@@ -101,16 +102,16 @@ _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen)
101102
{
102103
if (dLen > 0)
103104
{
104-
unsigned char *str;
105-
size_t len;
105+
PQExpBuffer buf = createPQExpBuffer();
106106

107-
str = PQescapeBytea((const unsigned char *) data, dLen, &len);
108-
if (!str)
109-
die_horribly(AH, NULL, "out of memory\n");
107+
appendByteaLiteralAHX(buf,
108+
(const unsigned char *) data,
109+
dLen,
110+
AH);
110111

111-
ahprintf(AH, "SELECT pg_catalog.lowrite(0, '%s');\n", str);
112+
ahprintf(AH, "SELECT pg_catalog.lowrite(0, %s);\n", buf->data);
112113

113-
free(str);
114+
destroyPQExpBuffer(buf);
114115
}
115116
return dLen;
116117
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy