Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+50-1
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

+4-1
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

+8-9
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

+4-1
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

+9-8
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)