8000 Fix pg_restore to do the right thing when escaping large objects. · machack666/postgres@2a1ef10 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2a1ef10

Browse files
committed
Fix pg_restore to do the right thing when escaping large objects.
Specifically, this makes the workflow pg_dump -Fc -> pg_restore -> file produce correct output for BLOBs when the source database has standard_conforming_strings turned on. It was already okay when that was off, or if pg_restore was told to restore directly into a database. This is a back-port of commit b173211 of 2009-08-04, with additional changes to emit old-style escaped bytea data instead of hex-style. At the time, we had not heard of anyone encountering the problem in the field, so I judged it not worth the risk of changing back branches. Now we do have a report, from Bosco Rama, so back-patch into 8.2 through 8.4. 9.0 and up are okay already.
1 parent 9de3f28 commit 2a1ef10

File tree

5 files changed

+99
-15
lines changed

5 files changed

+99
-15
lines changed

src/bin/pg_dump/dumputils.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,84 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
323323
}
324324

325325

326+
/*
327+
* Convert a bytea value (presented as raw bytes) to an SQL string literal
328+
* and append it to the given buffer. We assume the specified
329+
* standard_conforming_strings setting.
330+
*
331+
* This is needed in situations where we do not have a PGconn available.
332+
* Where we do, PQescapeByteaConn is a better choice.
333+
*/
334+
void
335+
appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
336+
bool std_strings)
337+
{
338+
const unsigned char *vp;
339+
unsigned char *rp;
340+
size_t i;
341+
size_t len;
342+
size_t bslash_len = (std_strings ? 1 : 2);
343+
344+
len = 2; /* for the quote marks */
345+
vp = str;
346+
for (i = length; i > 0; i--, vp++)
347+
{
348+
if (*vp < 0x20 || *vp > 0x7e)
349+
len += bslash_len + 3;
350+
else if (*vp == '\'')
351+
len += 2;
352+
else if (*vp == '\\')
353+
len += bslash_len + bslash_len;
354+
else
355+
len++;
356+
}
357+
358+
if (!enlargePQExpBuffer(buf, len))
359+
return;
360+
361+
rp = (unsigned char *) (buf->data + buf->len);
362+
*rp++ = '\'';
363+
364+
vp = str;
365+
for (i = length; i > 0; i--, vp++)
366+
{
367+
if (*vp < 0x20 || *vp > 0x7e)
368+
{
369+
int val = *vp;
370+
371+
if (!std_strings)
372+
*rp++ = '\\';
373+
*rp++ = '\\';
374+
*rp++ = (val >> 6) + '0';
375+
*rp++ = ((val >> 3) & 07) + '0';
376+
*rp++ = (val & 07) + '0';
377+
}
378+
else if (*vp == '\'')
379+
{
380+
*rp++ = '\'';
381+
*rp++ = '\'';
382+
}
383+
else if (*vp == '\\')
384+
{
385+
if (!std_strings)
386+
{
387+
*rp++ = '\\';
388+
*rp++ = '\\';
389+
}
390+
*rp++ = '\\';
391+
*rp++ = '\\';
392+
}
393+
else
394+
*rp++ = *vp;
395+
}
396+
397+
*rp++ = '\'';
398+
*rp = '\0';
399+
400+
buf->len = ((char *) rp) - buf->data;
401+
}
402+
403+
326404
/*
327405
* Convert backend's version string into a number.
328406
*/

src/bin/pg_dump/dumputils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,20 +1252,19 @@ dump_lo_buf(ArchiveHandle *AH)
12521252
}
12531253
else
12541254
{
1255-
unsigned char *str;
1256-
size_t len;
1255+
PQExpBuffer buf = createPQExpBuffer();
12571256

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

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

1268-
free(str);
1267+
destroyPQExpBuffer(buf);
12691268
}
12701269
AH->lo_buf_used = 0;
12711270
}

src/bin/pg_dump/pg_backup_archiver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
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 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)
0