提交 1a1167a1 编写于 作者: T Tom Lane

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 b1732111 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.
上级 b414dde4
......@@ -274,6 +274,84 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
}
/*
* Convert a bytea value (presented as raw bytes) to an SQL string literal
* and append it to the given buffer. We assume the specified
* standard_conforming_strings setting.
*
* This is needed in situations where we do not have a PGconn available.
* Where we do, PQescapeByteaConn is a better choice.
*/
void
appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
bool std_strings)
{
const unsigned char *vp;
unsigned char *rp;
size_t i;
size_t len;
size_t bslash_len = (std_strings ? 1 : 2);
len = 2; /* for the quote marks */
vp = str;
for (i = length; i > 0; i--, vp++)
{
if (*vp < 0x20 || *vp > 0x7e)
len += bslash_len + 3;
else if (*vp == '\'')
len += 2;
else if (*vp == '\\')
len += bslash_len + bslash_len;
else
len++;
}
if (!enlargePQExpBuffer(buf, len))
return;
rp = (unsigned char *) (buf->data + buf->len);
*rp++ = '\'';
vp = str;
for (i = length; i > 0; i--, vp++)
{
if (*vp < 0x20 || *vp > 0x7e)
{
int val = *vp;
if (!std_strings)
*rp++ = '\\';
*rp++ = '\\';
*rp++ = (val >> 6) + '0';
*rp++ = ((val >> 3) & 07) + '0';
*rp++ = (val & 07) + '0';
}
else if (*vp == '\'')
{
*rp++ = '\'';
*rp++ = '\'';
}
else if (*vp == '\\')
{
if (!std_strings)
{
*rp++ = '\\';
*rp++ = '\\';
}
*rp++ = '\\';
*rp++ = '\\';
}
else
*rp++ = *vp;
}
*rp++ = '\'';
*rp = '\0';
buf->len = ((char *) rp) - buf->data;
}
/*
* Convert backend's version string into a number.
*/
......
......@@ -26,6 +26,9 @@ extern void appendStringLiteralConn(PQExpBuffer buf, const char *str,
PGconn *conn);
extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str,
const char *dqprefix);
extern void appendByteaLiteral(PQExpBuffer buf,
const unsigned char *str, size_t length,
bool std_strings);
extern int parse_version(const char *versionString);
extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
extern bool buildACLCommands(const char *name, const char *type,
......
......@@ -1090,20 +1090,19 @@ dump_lo_buf(ArchiveHandle *AH)
}
else
{
unsigned char *str;
size_t len;
PQExpBuffer buf = createPQExpBuffer();
str = PQescapeBytea((const unsigned char *) AH->lo_buf,
AH->lo_buf_used, &len);
if (!str)
die_horribly(AH, modulename, "out of memory\n");
appendByteaLiteralAHX(buf,
(const unsigned char *) AH->lo_buf,
AH->lo_buf_used,
AH);
/* Hack: turn off writingBlob so ahwrite doesn't recurse to here */
AH->writingBlob = 0;
ahprintf(AH, "SELECT lowrite(0, '%s');\n", str);
ahprintf(AH, "SELECT pg_catalog.lowrite(0, %s);\n", buf->data);
AH->writingBlob = 1;
free(str);
destroyPQExpBuffer(buf);
}
AH->lo_buf_used = 0;
}
......
......@@ -323,6 +323,9 @@ extern bool checkSeek(FILE *fp);
#define appendStringLiteralAHX(buf,str,AH) \
appendStringLiteral(buf, str, (AH)->public.encoding, (AH)->public.std_strings)
#define appendByteaLiteralAHX(buf,str,len,AH) \
appendByteaLiteral(buf, str, len, (AH)->public.std_strings)
/*
* Mandatory routines for each supported format
*/
......
......@@ -23,6 +23,7 @@
*/
#include "pg_backup_archiver.h"
#include "dumputils.h"
#include <unistd.h> /* for dup */
......@@ -98,16 +99,16 @@ _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen)
{
if (dLen > 0)
{
unsigned char *str;
size_t len;
PQExpBuffer buf = createPQExpBuffer();
str = PQescapeBytea((const unsigned char *) data, dLen, &len);
if (!str)
die_horribly(AH, NULL, "out of memory\n");
appendByteaLiteralAHX(buf,
(const unsigned char *) data,
dLen,
AH);
ahprintf(AH, "SELECT lowrite(0, '%s');\n", str);
ahprintf(AH, "SELECT pg_catalog.lowrite(0, %s);\n", buf->data);
free(str);
destroyPQExpBuffer(buf);
}
return dLen;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册