Fix up pg_dump to do string escaping fully correctly for client encoding
and standard_conforming_strings; likewise for the other client programs that need it. As per previous discussion, a pg_dump dump now conforms to the standard_conforming_strings setting of the source database. We don't use E'' syntax in the dump, thereby improving portability of the SQL. I added a SET escape_strings_warning = off command to keep the dumps from getting a lot of back-chatter from that.
This commit is contained in:
parent
117d73a9e7
commit
134b463f02
@ -7,14 +7,13 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/quote.c,v 1.19 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/quote.c,v 1.20 2006/05/28 21:13:53 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "utils/builtins.h"
|
||||
#include "parser/gramparse.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -49,6 +48,12 @@ quote_ident(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* quote_literal -
|
||||
* returns a properly quoted literal
|
||||
*
|
||||
* NOTE: think not to make this function's behavior change with
|
||||
* standard_conforming_strings. We don't know where the result
|
||||
* literal will be used, and so we must generate a result that
|
||||
* will work with either setting. Take a look at what dblink
|
||||
* uses this for before thinking you know better.
|
||||
*/
|
||||
Datum
|
||||
quote_literal(PG_FUNCTION_ARGS)
|
||||
@ -66,20 +71,22 @@ quote_literal(PG_FUNCTION_ARGS)
|
||||
cp1 = VARDATA(t);
|
||||
cp2 = VARDATA(result);
|
||||
|
||||
if (!standard_conforming_strings)
|
||||
for (; len-- > 0; cp1++)
|
||||
{
|
||||
if (*cp1 == '\\')
|
||||
{
|
||||
*cp2++ = ESCAPE_STRING_SYNTAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
len = VARSIZE(t) - VARHDRSZ;
|
||||
cp1 = VARDATA(t);
|
||||
|
||||
*cp2++ = '\'';
|
||||
while (len-- > 0)
|
||||
{
|
||||
if (SQL_STR_DOUBLE(*cp1, !standard_conforming_strings))
|
||||
if (SQL_STR_DOUBLE(*cp1, true))
|
||||
*cp2++ = *cp1;
|
||||
*cp2++ = *cp1++;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
* ruleutils.c - Functions to convert stored expressions/querytrees
|
||||
* back to source text
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.222 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.223 2006/05/28 21:13:53 tgl Exp $
|
||||
**********************************************************************/
|
||||
|
||||
#include "postgres.h"
|
||||
@ -534,18 +534,23 @@ pg_get_triggerdef(PG_FUNCTION_ARGS)
|
||||
{
|
||||
if (i > 0)
|
||||
appendStringInfo(&buf, ", ");
|
||||
if (!standard_conforming_strings && strchr(p, '\\') != NULL)
|
||||
appendStringInfoChar(&buf, ESCAPE_STRING_SYNTAX);
|
||||
/*
|
||||
* We form the string literal according to the prevailing setting
|
||||
* of standard_conforming_strings; we never use E''.
|
||||
* User is responsible for making sure result is used correctly.
|
||||
*/
|
||||
appendStringInfoChar(&buf, '\'');
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (SQL_STR_DOUBLE(*p, !standard_conforming_strings))
|
||||
appendStringInfoChar(&buf, *p);
|
||||
appendStringInfoChar(&buf, *p++);
|
||||
char ch = *p++;
|
||||
|
||||
if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
|
||||
appendStringInfoChar(&buf, ch);
|
||||
appendStringInfoChar(&buf, ch);
|
||||
}
|
||||
p++;
|
||||
appendStringInfoChar(&buf, '\'');
|
||||
/* advance p to next string embedded in tgargs */
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3883,7 +3888,6 @@ get_const_expr(Const *constval, deparse_context *context)
|
||||
char *valptr;
|
||||
bool isfloat = false;
|
||||
bool needlabel;
|
||||
bool is_e_string = false;
|
||||
|
||||
if (constval->constisnull)
|
||||
{
|
||||
@ -3946,33 +3950,19 @@ get_const_expr(Const *constval, deparse_context *context)
|
||||
default:
|
||||
|
||||
/*
|
||||
* We must quote any funny characters in the constant's
|
||||
* representation. XXX Any MULTIBYTE considerations here?
|
||||
* We form the string literal according to the prevailing setting
|
||||
* of standard_conforming_strings; we never use E''.
|
||||
* User is responsible for making sure result is used correctly.
|
||||
*/
|
||||
for (valptr = extval; *valptr; valptr++)
|
||||
if ((!standard_conforming_strings && *valptr == '\\') ||
|
||||
(unsigned char) *valptr < (unsigned char) ' ')
|
||||
{
|
||||
appendStringInfoChar(buf, ESCAPE_STRING_SYNTAX);
|
||||
is_e_string = true;
|
||||
break;
|
||||
}
|
||||
|
||||
appendStringInfoChar(buf, '\'');
|
||||
for (valptr = extval; *valptr; valptr++)
|
||||
{
|
||||
char ch = *valptr;
|
||||
|
||||
if (SQL_STR_DOUBLE(ch, is_e_string))
|
||||
{
|
||||
if (SQL_STR_DOUBLE(ch, !standard_conforming_strings))
|
||||
appendStringInfoChar(buf, ch);
|
||||
appendStringInfoChar(buf, ch);
|
||||
}
|
||||
else if ((unsigned char) ch < (unsigned char) ' ')
|
||||
appendStringInfo(buf, "\\%03o", (int) ch);
|
||||
else
|
||||
appendStringInfoChar(buf, ch);
|
||||
}
|
||||
appendStringInfoChar(buf, '\'');
|
||||
break;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.28 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.29 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -100,63 +100,102 @@ fmtId(const char *rawid)
|
||||
|
||||
/*
|
||||
* Convert a string value to an SQL string literal and append it to
|
||||
* the given buffer.
|
||||
* the given buffer. We assume the specified client_encoding and
|
||||
* standard_conforming_strings settings.
|
||||
*
|
||||
* Special characters are escaped. Quote mark ' goes to '' per SQL
|
||||
* standard, other stuff goes to \ sequences. If escapeAll is false,
|
||||
* whitespace characters are not escaped (tabs, newlines, etc.). This
|
||||
* is appropriate for dump file output. Using E'' strings for
|
||||
* backslashes is always safe for standard_conforming_strings on or off.
|
||||
* This is essentially equivalent to libpq's PQescapeStringInternal,
|
||||
* except for the output buffer structure. We need it in situations
|
||||
* where we do not have a PGconn available. Where we do,
|
||||
* appendStringLiteralConn is a better choice.
|
||||
*/
|
||||
void
|
||||
appendStringLiteral(PQExpBuffer buf, const char *str, bool escapeAll,
|
||||
bool e_string_for_backslash)
|
||||
appendStringLiteral(PQExpBuffer buf, const char *str,
|
||||
int encoding, bool std_strings)
|
||||
{
|
||||
char ch;
|
||||
const char *p;
|
||||
bool is_e_string = false;
|
||||
size_t length = strlen(str);
|
||||
const char *source = str;
|
||||
char *target;
|
||||
|
||||
for (p = str; *p; p++)
|
||||
{
|
||||
ch = *p;
|
||||
if (!enlargePQExpBuffer(buf, 2 * length + 2))
|
||||
return;
|
||||
|
||||
if ((e_string_for_backslash && ch == '\\') ||
|
||||
((unsigned char) ch < (unsigned char) ' ' &&
|
||||
(escapeAll ||
|
||||
(ch != '\t' && ch != '\n' && ch != '\v' &&
|
||||
ch != '\f' && ch != '\r'))))
|
||||
target = buf->data + buf->len;
|
||||
*target++ = '\'';
|
||||
|
||||
while (*source != '\0')
|
||||
{
|
||||
appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX);
|
||||
is_e_string = true;
|
||||
char c = *source;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
/* Fast path for plain ASCII */
|
||||
if (!IS_HIGHBIT_SET(c))
|
||||
{
|
||||
/* Apply quoting if needed */
|
||||
if (SQL_STR_DOUBLE(c, !std_strings))
|
||||
*target++ = c;
|
||||
/* Copy the character */
|
||||
*target++ = c;
|
||||
source++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Slow path for possible multibyte characters */
|
||||
len = PQmblen(source, encoding);
|
||||
|
||||
/* Copy the character */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (*source == '\0')
|
||||
break;
|
||||
*target++ = *source++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we hit premature end of string (ie, incomplete multibyte
|
||||
* character), try to pad out to the correct length with spaces.
|
||||
* We may not be able to pad completely, but we will always be able
|
||||
* to insert at least one pad space (since we'd not have quoted a
|
||||
* multibyte character). This should be enough to make a string that
|
||||
* the server will error out on.
|
||||
*/
|
||||
if (i < len)
|
||||
{
|
||||
char *stop = buf->data + buf->maxlen - 2;
|
||||
|
||||
for (; i < len; i++)
|
||||
{
|
||||
if (target >= stop)
|
||||
break;
|
||||
*target++ = ' ';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
appendPQExpBufferChar(buf, '\'');
|
||||
for (p = str; *p; p++)
|
||||
{
|
||||
ch = *p;
|
||||
if (SQL_STR_DOUBLE(ch, is_e_string))
|
||||
{
|
||||
appendPQExpBufferChar(buf, ch);
|
||||
appendPQExpBufferChar(buf, ch);
|
||||
/* Write the terminating quote and NUL character. */
|
||||
*target++ = '\'';
|
||||
*target = '\0';
|
||||
|
||||
buf->len = target - buf->data;
|
||||
}
|
||||
else if ((unsigned char) ch < (unsigned char) ' ' &&
|
||||
(escapeAll ||
|
||||
(ch != '\t' && ch != '\n' && ch != '\v' &&
|
||||
ch != '\f' && ch != '\r')))
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
* generate octal escape for control chars other than whitespace
|
||||
* Convert a string value to an SQL string literal and append it to
|
||||
* the given buffer. Encoding and string syntax rules are as indicated
|
||||
* by current settings of the PGconn.
|
||||
*/
|
||||
appendPQExpBufferChar(buf, '\\');
|
||||
appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
|
||||
appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
|
||||
appendPQExpBufferChar(buf, (ch & 7) + '0');
|
||||
}
|
||||
else
|
||||
appendPQExpBufferChar(buf, ch);
|
||||
}
|
||||
void
|
||||
appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
|
||||
{
|
||||
size_t length = strlen(str);
|
||||
|
||||
if (!enlargePQExpBuffer(buf, 2 * length + 2))
|
||||
return;
|
||||
appendPQExpBufferChar(buf, '\'');
|
||||
buf->len += PQescapeStringConn(conn, buf->data + buf->len,
|
||||
str, length, NULL);
|
||||
appendPQExpBufferChar(buf, '\'');
|
||||
}
|
||||
|
||||
@ -167,7 +206,8 @@ appendStringLiteral(PQExpBuffer buf, const char *str, bool escapeAll,
|
||||
* dollar quote delimiter will begin with that (after the opening $).
|
||||
*
|
||||
* No escaping is done at all on str, in compliance with the rules
|
||||
* for parsing dollar quoted strings.
|
||||
* for parsing dollar quoted strings. Also, we need not worry about
|
||||
* encoding issues.
|
||||
*/
|
||||
void
|
||||
appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
|
||||
@ -204,21 +244,6 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Use dollar quoting if the string to be quoted contains ' or \,
|
||||
* otherwise use standard quoting.
|
||||
*/
|
||||
void
|
||||
appendStringLiteralDQOpt(PQExpBuffer buf, const char *str,
|
||||
bool escapeAll, const char *dqprefix)
|
||||
{
|
||||
if (strchr(str, '\'') == NULL && strchr(str, '\\') == NULL)
|
||||
appendStringLiteral(buf, str, escapeAll, true);
|
||||
else
|
||||
appendStringLiteralDQ(buf, str, dqprefix);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert backend's version string into a number.
|
||||
*/
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.16 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.17 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -15,15 +15,16 @@
|
||||
#ifndef DUMPUTILS_H
|
||||
#define DUMPUTILS_H
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#include "pqexpbuffer.h"
|
||||
|
||||
extern const char *fmtId(const char *identifier);
|
||||
extern void appendStringLiteral(PQExpBuffer buf, const char *str,
|
||||
bool escapeAll, bool e_string_for_backslash);
|
||||
int encoding, bool std_strings);
|
||||
extern void appendStringLiteralConn(PQExpBuffer buf, const char *str,
|
||||
PGconn *conn);
|
||||
extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str,
|
||||
const char *dqprefix);
|
||||
extern void appendStringLiteralDQOpt(PQExpBuffer buf, const char *str,
|
||||
bool escapeAll, const char *dqprefix);
|
||||
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,
|
||||
|
@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.38 2006/02/12 04:04:32 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup.h,v 1.39 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -60,6 +60,10 @@ typedef struct _Archive
|
||||
int minRemoteVersion; /* allowable range */
|
||||
int maxRemoteVersion;
|
||||
|
||||
/* info needed for string escaping */
|
||||
int encoding; /* libpq code for client_encoding */
|
||||
bool std_strings; /* standard_conforming_strings */
|
||||
|
||||
/* error handling */
|
||||
bool exit_on_error; /* whether to exit on SQL errors... */
|
||||
int n_errors; /* number of errors (if no die) */
|
||||
@ -182,4 +186,7 @@ archprintf(Archive *AH, const char *fmt,...)
|
||||
/* This extension allows gcc to check the format string */
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
#define appendStringLiteralAH(buf,str,AH) \
|
||||
appendStringLiteral(buf, str, (AH)->encoding, (AH)->std_strings)
|
||||
|
||||
#endif /* PG_BACKUP_H */
|
||||
|
@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.130 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.131 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
#include "pqexpbuffer.h"
|
||||
#include "libpq/libpq-fs.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
|
||||
const char *progname;
|
||||
@ -60,7 +61,8 @@ static void _becomeUser(ArchiveHandle *AH, const char *user);
|
||||
static void _becomeOwner(ArchiveHandle *AH, TocEntry *te);
|
||||
static void _selectOutputSchema(ArchiveHandle *AH, const char *schemaName);
|
||||
static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
|
||||
|
||||
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
|
||||
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
|
||||
static teReqs _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls);
|
||||
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
|
||||
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt);
|
||||
@ -1589,6 +1591,14 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
|
||||
AH->vmin = K_VERS_MINOR;
|
||||
AH->vrev = K_VERS_REV;
|
||||
|
||||
/* initialize for backwards compatible string processing */
|
||||
AH->public.encoding = PG_SQL_ASCII;
|
||||
AH->public.std_strings = false;
|
||||
|
||||
/* sql error handling */
|
||||
AH->public.exit_on_error = true;
|
||||
AH->public.n_errors = 0;
|
||||
|
||||
AH->createDate = time(NULL);
|
||||
|
||||
AH->intSize = sizeof(int);
|
||||
@ -1676,10 +1686,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
|
||||
die_horribly(AH, modulename, "unrecognized file format \"%d\"\n", fmt);
|
||||
}
|
||||
|
||||
/* sql error handling */
|
||||
AH->public.exit_on_error = true;
|
||||
AH->public.n_errors = 0;
|
||||
|
||||
return AH;
|
||||
}
|
||||
|
||||
@ -1888,22 +1894,72 @@ ReadToc(ArchiveHandle *AH)
|
||||
ahlog(AH, 3, "read TOC entry %d (ID %d) for %s %s\n",
|
||||
i, te->dumpId, te->desc, te->tag);
|
||||
|
||||
/* link completed entry into TOC circular list */
|
||||
te->prev = AH->toc->prev;
|
||||
AH->toc->prev->next = te;
|
||||
AH->toc->prev = te;
|
||||
te->next = AH->toc;
|
||||
|
||||
/* special processing immediately upon read for some items */
|
||||
if (strcmp(te->desc, "ENCODING") == 0)
|
||||
processEncodingEntry(AH, te);
|
||||
else if (strcmp(te->desc, "STDSTRINGS") == 0)
|
||||
processStdStringsEntry(AH, te);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
processEncodingEntry(ArchiveHandle *AH, TocEntry *te)
|
||||
{
|
||||
/* te->defn should have the form SET client_encoding = 'foo'; */
|
||||
char *defn = strdup(te->defn);
|
||||
char *ptr1;
|
||||
char *ptr2 = NULL;
|
||||
int encoding;
|
||||
|
||||
ptr1 = strchr(defn, '\'');
|
||||
if (ptr1)
|
||||
ptr2 = strchr(++ptr1, '\'');
|
||||
if (ptr2)
|
||||
{
|
||||
*ptr2 = '\0';
|
||||
encoding = pg_char_to_encoding(ptr1);
|
||||
if (encoding < 0)
|
||||
die_horribly(AH, modulename, "unrecognized encoding \"%s\"\n",
|
||||
ptr1);
|
||||
AH->public.encoding = encoding;
|
||||
}
|
||||
else
|
||||
die_horribly(AH, modulename, "invalid ENCODING item: %s\n",
|
||||
te->defn);
|
||||
|
||||
free(defn);
|
||||
}
|
||||
|
||||
static void
|
||||
processStdStringsEntry(ArchiveHandle *AH, TocEntry *te)
|
||||
{
|
||||
/* te->defn should have the form SET standard_conforming_strings = 'x'; */
|
||||
char *ptr1;
|
||||
|
||||
ptr1 = strchr(te->defn, '\'');
|
||||
if (ptr1 && strncmp(ptr1, "'on'", 4) == 0)
|
||||
AH->public.std_strings = true;
|
||||
else if (ptr1 && strncmp(ptr1, "'off'", 5) == 0)
|
||||
AH->public.std_strings = false;
|
||||
else
|
||||
die_horribly(AH, modulename, "invalid STDSTRINGS item: %s\n",
|
||||
te->defn);
|
||||
}
|
||||
|
||||
static teReqs
|
||||
_tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
|
||||
{
|
||||
teReqs res = REQ_ALL;
|
||||
|
||||
/* ENCODING and STDSTRINGS objects are dumped specially, so always reject */
|
||||
if (strcmp(te->desc, "ENCODING") == 0)
|
||||
return 0;
|
||||
if (strcmp(te->desc, "STDSTRINGS") == 0)
|
||||
/* ENCODING and STDSTRINGS items are dumped specially, so always reject */
|
||||
if (strcmp(te->desc, "ENCODING") == 0 ||
|
||||
strcmp(te->desc, "STDSTRINGS") == 0)
|
||||
return 0;
|
||||
|
||||
/* If it's an ACL, maybe ignore it */
|
||||
@ -2005,24 +2061,21 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
|
||||
static void
|
||||
_doSetFixedOutputState(ArchiveHandle *AH)
|
||||
{
|
||||
TocEntry *te;
|
||||
/* Select the correct character set encoding */
|
||||
ahprintf(AH, "SET client_encoding = '%s';\n",
|
||||
pg_encoding_to_char(AH->public.encoding));
|
||||
|
||||
/* If we have an encoding or std_strings setting, emit that */
|
||||
te = AH->toc->next;
|
||||
while (te != AH->toc)
|
||||
{
|
||||
if (strcmp(te->desc, "ENCODING") == 0)
|
||||
ahprintf(AH, "%s", te->defn);
|
||||
if (strcmp(te->desc, "STDSTRINGS") == 0)
|
||||
ahprintf(AH, "%s", te->defn);
|
||||
te = te->next;
|
||||
}
|
||||
/* Select the correct string literal syntax */
|
||||
ahprintf(AH, "SET standard_conforming_strings = %s;\n",
|
||||
AH->public.std_strings ? "on" : "off");
|
||||
|
||||
/* Make sure function checking is disabled */
|
||||
ahprintf(AH, "SET check_function_bodies = false;\n");
|
||||
|
||||
/* Avoid annoying notices etc */
|
||||
ahprintf(AH, "SET client_min_messages = warning;\n");
|
||||
if (!AH->public.std_strings)
|
||||
ahprintf(AH, "SET escape_string_warning = off;\n");
|
||||
|
||||
ahprintf(AH, "\n");
|
||||
}
|
||||
@ -2043,7 +2096,7 @@ _doSetSessionAuth(ArchiveHandle *AH, const char *user)
|
||||
* SQL requires a string literal here. Might as well be correct.
|
||||
*/
|
||||
if (user && *user)
|
||||
appendStringLiteral(cmd, user, false, true);
|
||||
appendStringLiteralAHX(cmd, user, AH);
|
||||
else
|
||||
appendPQExpBuffer(cmd, "DEFAULT");
|
||||
appendPQExpBuffer(cmd, ";");
|
||||
|
@ -17,7 +17,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.69 2006/02/05 20:58:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.h,v 1.70 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -326,6 +326,9 @@ extern void WriteDataChunks(ArchiveHandle *AH);
|
||||
extern teReqs TocIDRequired(ArchiveHandle *AH, DumpId id, RestoreOptions *ropt);
|
||||
extern bool checkSeek(FILE *fp);
|
||||
|
||||
#define appendStringLiteralAHX(buf,str,AH) \
|
||||
appendStringLiteral(buf, str, (AH)->public.encoding, (AH)->public.std_strings)
|
||||
|
||||
/*
|
||||
* Mandatory routines for each supported format
|
||||
*/
|
||||
|
@ -12,7 +12,7 @@
|
||||
* by PostgreSQL
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.435 2006/05/28 17:23:29 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.436 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -57,6 +57,7 @@ int optreset;
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#include "libpq/libpq-fs.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
#include "pg_dump.h"
|
||||
#include "pg_backup.h"
|
||||
@ -82,7 +83,6 @@ bool g_verbose; /* User wants verbose narration of our
|
||||
* activities. */
|
||||
Archive *g_fout; /* the script file */
|
||||
PGconn *g_conn; /* the database connection */
|
||||
bool std_strings = false; /* GUC variable */
|
||||
|
||||
/* various user-settable parameters */
|
||||
bool dumpInserts; /* dump data using proper insert strings */
|
||||
@ -194,6 +194,7 @@ main(int argc, char **argv)
|
||||
const char *pgport = NULL;
|
||||
const char *username = NULL;
|
||||
const char *dumpencoding = NULL;
|
||||
const char *std_strings;
|
||||
bool oids = false;
|
||||
TableInfo *tblinfo;
|
||||
int numTables;
|
||||
@ -517,6 +518,29 @@ main(int argc, char **argv)
|
||||
g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
|
||||
username, force_password, ignore_version);
|
||||
|
||||
/* Set the client encoding if requested */
|
||||
if (dumpencoding)
|
||||
{
|
||||
if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
|
||||
{
|
||||
write_msg(NULL, "invalid client encoding \"%s\" specified\n",
|
||||
dumpencoding);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the active encoding and the standard_conforming_strings setting,
|
||||
* so we know how to escape strings.
|
||||
*/
|
||||
g_fout->encoding = PQclientEncoding(g_conn);
|
||||
|
||||
std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
|
||||
g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
|
||||
|
||||
/* Set the datestyle to ISO to ensure the dump's portability */
|
||||
do_sql_command(g_conn, "SET DATESTYLE = ISO");
|
||||
|
||||
/*
|
||||
* Start serializable transaction to dump consistent data.
|
||||
*/
|
||||
@ -524,19 +548,6 @@ main(int argc, char **argv)
|
||||
|
||||
do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
|
||||
|
||||
/* Set the datestyle to ISO to ensure the dump's portability */
|
||||
do_sql_command(g_conn, "SET DATESTYLE = ISO");
|
||||
|
||||
/* Set the client encoding */
|
||||
if (dumpencoding)
|
||||
{
|
||||
char *cmd = malloc(strlen(dumpencoding) + 32);
|
||||
|
||||
sprintf(cmd, "SET client_encoding='%s'", dumpencoding);
|
||||
do_sql_command(g_conn, cmd);
|
||||
free(cmd);
|
||||
}
|
||||
|
||||
/* Select the appropriate subquery to convert user IDs to names */
|
||||
if (g_fout->remoteVersion >= 80100)
|
||||
username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
|
||||
@ -618,12 +629,11 @@ main(int argc, char **argv)
|
||||
* order.
|
||||
*/
|
||||
|
||||
/* First the special encoding entry. */
|
||||
/* First the special ENCODING and STDSTRINGS entries. */
|
||||
dumpEncoding(g_fout);
|
||||
|
||||
dumpStdStrings(g_fout);
|
||||
|
||||
/* The database item is always second, unless we don't want it at all */
|
||||
/* The database item is always next, unless we don't want it at all */
|
||||
if (!dataOnly && selectTableName == NULL && selectSchemaName == NULL)
|
||||
dumpDatabase(g_fout);
|
||||
|
||||
@ -1088,7 +1098,9 @@ dumpTableData_insert(Archive *fout, void *dcontext)
|
||||
default:
|
||||
/* All other types are printed as string literals. */
|
||||
resetPQExpBuffer(q);
|
||||
appendStringLiteral(q, PQgetvalue(res, tuple, field), false, !std_strings);
|
||||
appendStringLiteralAH(q,
|
||||
PQgetvalue(res, tuple, field),
|
||||
fout);
|
||||
archputs(q->data, fout);
|
||||
break;
|
||||
}
|
||||
@ -1240,7 +1252,7 @@ dumpDatabase(Archive *AH)
|
||||
"FROM pg_database "
|
||||
"WHERE datname = ",
|
||||
username_subquery);
|
||||
appendStringLiteral(dbQry, datname, true, !std_strings);
|
||||
appendStringLiteralAH(dbQry, datname, AH);
|
||||
}
|
||||
else if (g_fout->remoteVersion >= 80000)
|
||||
{
|
||||
@ -1251,7 +1263,7 @@ dumpDatabase(Archive *AH)
|
||||
"FROM pg_database "
|
||||
"WHERE datname = ",
|
||||
username_subquery);
|
||||
appendStringLiteral(dbQry, datname, true, !std_strings);
|
||||
appendStringLiteralAH(dbQry, datname, AH);
|
||||
}
|
||||
else if (g_fout->remoteVersion >= 70100)
|
||||
{
|
||||
@ -1262,7 +1274,7 @@ dumpDatabase(Archive *AH)
|
||||
"FROM pg_database "
|
||||
"WHERE datname = ",
|
||||
username_subquery);
|
||||
appendStringLiteral(dbQry, datname, true, !std_strings);
|
||||
appendStringLiteralAH(dbQry, datname, AH);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1275,7 +1287,7 @@ dumpDatabase(Archive *AH)
|
||||
"FROM pg_database "
|
||||
"WHERE datname = ",
|
||||
username_subquery);
|
||||
appendStringLiteral(dbQry, datname, true, !std_strings);
|
||||
appendStringLiteralAH(dbQry, datname, AH);
|
||||
}
|
||||
|
||||
res = PQexec(g_conn, dbQry->data);
|
||||
@ -1314,7 +1326,7 @@ dumpDatabase(Archive *AH)
|
||||
if (strlen(encoding) > 0)
|
||||
{
|
||||
appendPQExpBuffer(creaQry, " ENCODING = ");
|
||||
appendStringLiteral(creaQry, encoding, true, !std_strings);
|
||||
appendStringLiteralAH(creaQry, encoding, AH);
|
||||
}
|
||||
if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
|
||||
appendPQExpBuffer(creaQry, " TABLESPACE = %s",
|
||||
@ -1353,7 +1365,7 @@ dumpDatabase(Archive *AH)
|
||||
if (comment && strlen(comment)) {
|
||||
resetPQExpBuffer(dbQry);
|
||||
appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
|
||||
appendStringLiteral(dbQry, comment, false, !std_strings);
|
||||
appendStringLiteralAH(dbQry, comment, AH);
|
||||
appendPQExpBuffer(dbQry, ";\n");
|
||||
|
||||
ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
|
||||
@ -1381,28 +1393,14 @@ dumpDatabase(Archive *AH)
|
||||
static void
|
||||
dumpEncoding(Archive *AH)
|
||||
{
|
||||
PQExpBuffer qry;
|
||||
PGresult *res;
|
||||
|
||||
/* Can't read the encoding from pre-7.3 servers (SHOW isn't a query) */
|
||||
if (AH->remoteVersion < 70300)
|
||||
return;
|
||||
const char *encname = pg_encoding_to_char(AH->encoding);
|
||||
PQExpBuffer qry = createPQExpBuffer();
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "saving encoding\n");
|
||||
|
||||
qry = createPQExpBuffer();
|
||||
|
||||
appendPQExpBuffer(qry, "SHOW client_encoding");
|
||||
|
||||
res = PQexec(g_conn, qry->data);
|
||||
|
||||
check_sql_result(res, g_conn, qry->data, PGRES_TUPLES_OK);
|
||||
|
||||
resetPQExpBuffer(qry);
|
||||
write_msg(NULL, "saving encoding = %s\n", encname);
|
||||
|
||||
appendPQExpBuffer(qry, "SET client_encoding = ");
|
||||
appendStringLiteral(qry, PQgetvalue(res, 0, 0), true, !std_strings);
|
||||
appendStringLiteralAH(qry, encname, AH);
|
||||
appendPQExpBuffer(qry, ";\n");
|
||||
|
||||
ArchiveEntry(AH, nilCatalogId, createDumpId(),
|
||||
@ -1411,8 +1409,6 @@ dumpEncoding(Archive *AH)
|
||||
NULL, 0,
|
||||
NULL, NULL);
|
||||
|
||||
PQclear(res);
|
||||
|
||||
destroyPQExpBuffer(qry);
|
||||
}
|
||||
|
||||
@ -1423,38 +1419,15 @@ dumpEncoding(Archive *AH)
|
||||
static void
|
||||
dumpStdStrings(Archive *AH)
|
||||
{
|
||||
PQExpBuffer qry;
|
||||
PGresult *res;
|
||||
const char *stdstrings = AH->std_strings ? "on" : "off";
|
||||
PQExpBuffer qry = createPQExpBuffer();
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "saving standard_conforming_strings setting\n");
|
||||
write_msg(NULL, "saving standard_conforming_strings = %s\n",
|
||||
stdstrings);
|
||||
|
||||
qry = createPQExpBuffer();
|
||||
|
||||
/* standard_conforming_strings not used in pre-8.2 servers */
|
||||
if (AH->remoteVersion < 80200)
|
||||
{
|
||||
appendPQExpBuffer(qry, "SET standard_conforming_strings = 'off';\n");
|
||||
std_strings = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(qry, "SHOW standard_conforming_strings");
|
||||
|
||||
res = PQexec(g_conn, qry->data);
|
||||
|
||||
check_sql_result(res, g_conn, qry->data, PGRES_TUPLES_OK);
|
||||
|
||||
resetPQExpBuffer(qry);
|
||||
|
||||
std_strings = (strcmp(PQgetvalue(res, 0, 0), "on") == 0);
|
||||
appendPQExpBuffer(qry, "SET standard_conforming_strings = ");
|
||||
appendStringLiteral(qry, PQgetvalue(res, 0, 0), true, !std_strings);
|
||||
appendPQExpBuffer(qry, ";\n");
|
||||
puts(PQgetvalue(res, 0, 0));
|
||||
|
||||
PQclear(res);
|
||||
}
|
||||
appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
|
||||
stdstrings);
|
||||
|
||||
ArchiveEntry(AH, nilCatalogId, createDumpId(),
|
||||
"STDSTRINGS", NULL, NULL, "",
|
||||
@ -1639,7 +1612,7 @@ dumpBlobComments(Archive *AH, void *arg)
|
||||
|
||||
printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
|
||||
blobOid);
|
||||
appendStringLiteral(commentcmd, comment, false, !std_strings);
|
||||
appendStringLiteralAH(commentcmd, comment, AH);
|
||||
appendPQExpBuffer(commentcmd, ";\n");
|
||||
|
||||
archputs(commentcmd->data, AH);
|
||||
@ -4393,7 +4366,7 @@ dumpComment(Archive *fout, const char *target,
|
||||
PQExpBuffer query = createPQExpBuffer();
|
||||
|
||||
appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
|
||||
appendStringLiteral(query, comments->descr, false, !std_strings);
|
||||
appendStringLiteralAH(query, comments->descr, fout);
|
||||
appendPQExpBuffer(query, ";\n");
|
||||
|
||||
ArchiveEntry(fout, nilCatalogId, createDumpId(),
|
||||
@ -4451,7 +4424,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
|
||||
|
||||
resetPQExpBuffer(query);
|
||||
appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
|
||||
appendStringLiteral(query, descr, false, !std_strings);
|
||||
appendStringLiteralAH(query, descr, fout);
|
||||
appendPQExpBuffer(query, ";\n");
|
||||
|
||||
ArchiveEntry(fout, nilCatalogId, createDumpId(),
|
||||
@ -4473,7 +4446,7 @@ dumpTableComment(Archive *fout, TableInfo *tbinfo,
|
||||
|
||||
resetPQExpBuffer(query);
|
||||
appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
|
||||
appendStringLiteral(query, descr, false, !std_strings);
|
||||
appendStringLiteralAH(query, descr, fout);
|
||||
appendPQExpBuffer(query, ";\n");
|
||||
|
||||
ArchiveEntry(fout, nilCatalogId, createDumpId(),
|
||||
@ -5039,7 +5012,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
|
||||
{
|
||||
appendPQExpBuffer(q, ",\n DEFAULT = ");
|
||||
if (typdefault_is_literal)
|
||||
appendStringLiteral(q, typdefault, true, !std_strings);
|
||||
appendStringLiteralAH(q, typdefault, fout);
|
||||
else
|
||||
appendPQExpBufferStr(q, typdefault);
|
||||
}
|
||||
@ -5058,7 +5031,7 @@ dumpBaseType(Archive *fout, TypeInfo *tinfo)
|
||||
if (typdelim && strcmp(typdelim, ",") != 0)
|
||||
{
|
||||
appendPQExpBuffer(q, ",\n DELIMITER = ");
|
||||
appendStringLiteral(q, typdelim, true, !std_strings);
|
||||
appendStringLiteralAH(q, typdelim, fout);
|
||||
}
|
||||
|
||||
if (strcmp(typalign, "c") == 0)
|
||||
@ -5173,7 +5146,7 @@ dumpDomain(Archive *fout, TypeInfo *tinfo)
|
||||
{
|
||||
appendPQExpBuffer(q, " DEFAULT ");
|
||||
if (typdefault_is_literal)
|
||||
appendStringLiteral(q, typdefault, true, !std_strings);
|
||||
appendStringLiteralAH(q, typdefault, fout);
|
||||
else
|
||||
appendPQExpBufferStr(q, typdefault);
|
||||
}
|
||||
@ -5743,7 +5716,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
||||
if (strcmp(probin, "-") != 0)
|
||||
{
|
||||
appendPQExpBuffer(asPart, "AS ");
|
||||
appendStringLiteral(asPart, probin, true, !std_strings);
|
||||
appendStringLiteralAH(asPart, probin, fout);
|
||||
if (strcmp(prosrc, "-") != 0)
|
||||
{
|
||||
appendPQExpBuffer(asPart, ", ");
|
||||
@ -5752,10 +5725,11 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
||||
* where we have bin, use dollar quoting if allowed and src
|
||||
* contains quote or backslash; else use regular quoting.
|
||||
*/
|
||||
if (disable_dollar_quoting)
|
||||
appendStringLiteral(asPart, prosrc, false, !std_strings);
|
||||
if (disable_dollar_quoting ||
|
||||
(strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
|
||||
appendStringLiteralAH(asPart, prosrc, fout);
|
||||
else
|
||||
appendStringLiteralDQOpt(asPart, prosrc, false, NULL);
|
||||
appendStringLiteralDQ(asPart, prosrc, NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -5765,7 +5739,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
||||
appendPQExpBuffer(asPart, "AS ");
|
||||
/* with no bin, dollar quote src unconditionally if allowed */
|
||||
if (disable_dollar_quoting)
|
||||
appendStringLiteral(asPart, prosrc, false, !std_strings);
|
||||
appendStringLiteralAH(asPart, prosrc, fout);
|
||||
else
|
||||
appendStringLiteralDQ(asPart, prosrc, NULL);
|
||||
}
|
||||
@ -6681,9 +6655,9 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
|
||||
appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
|
||||
(condefault) ? "DEFAULT " : "",
|
||||
fmtId(convinfo->dobj.name));
|
||||
appendStringLiteral(q, conforencoding, true, !std_strings);
|
||||
appendStringLiteralAH(q, conforencoding, fout);
|
||||
appendPQExpBuffer(q, " TO ");
|
||||
appendStringLiteral(q, contoencoding, true, !std_strings);
|
||||
appendStringLiteralAH(q, contoencoding, fout);
|
||||
/* regproc is automatically quoted in 7.3 and above */
|
||||
appendPQExpBuffer(q, " FROM %s;\n", conproc);
|
||||
|
||||
@ -6924,7 +6898,7 @@ dumpAgg(Archive *fout, AggInfo *agginfo)
|
||||
if (!PQgetisnull(res, 0, i_agginitval))
|
||||
{
|
||||
appendPQExpBuffer(details, ",\n INITCOND = ");
|
||||
appendStringLiteral(details, agginitval, true, !std_strings);
|
||||
appendStringLiteralAH(details, agginitval, fout);
|
||||
}
|
||||
|
||||
if (strcmp(aggfinalfn, "-") != 0)
|
||||
@ -7111,7 +7085,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
||||
{
|
||||
appendPQExpBuffer(query, "SELECT definition as viewdef "
|
||||
" from pg_views where viewname = ");
|
||||
appendStringLiteral(query, tbinfo->dobj.name, true, !std_strings);
|
||||
appendStringLiteralAH(query, tbinfo->dobj.name, fout);
|
||||
appendPQExpBuffer(query, ";");
|
||||
}
|
||||
|
||||
@ -7760,7 +7734,7 @@ findLastBuiltinOid_V71(const char *dbname)
|
||||
|
||||
resetPQExpBuffer(query);
|
||||
appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
|
||||
appendStringLiteral(query, dbname, true, !std_strings);
|
||||
appendStringLiteralAH(query, dbname, g_fout);
|
||||
|
||||
res = PQexec(g_conn, query->data);
|
||||
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
|
||||
@ -7961,13 +7935,13 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
|
||||
(owning_tab = findTableByOid(tbinfo->owning_tab)) != NULL)
|
||||
{
|
||||
appendPQExpBuffer(query, "pg_catalog.pg_get_serial_sequence(");
|
||||
appendStringLiteral(query, fmtId(owning_tab->dobj.name), true, !std_strings);
|
||||
appendStringLiteralAH(query, fmtId(owning_tab->dobj.name), fout);
|
||||
appendPQExpBuffer(query, ", ");
|
||||
appendStringLiteral(query, owning_tab->attnames[tbinfo->owning_col - 1], true, !std_strings);
|
||||
appendStringLiteralAH(query, owning_tab->attnames[tbinfo->owning_col - 1], fout);
|
||||
appendPQExpBuffer(query, ")");
|
||||
}
|
||||
else
|
||||
appendStringLiteral(query, fmtId(tbinfo->dobj.name), true, !std_strings);
|
||||
appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
|
||||
appendPQExpBuffer(query, ", %s, %s);\n",
|
||||
last, (called ? "true" : "false"));
|
||||
|
||||
@ -8100,8 +8074,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
|
||||
p = tginfo->tgargs;
|
||||
for (findx = 0; findx < tginfo->tgnargs; findx++)
|
||||
{
|
||||
const char *s = p,
|
||||
*s2 = p;
|
||||
const char *s = p;
|
||||
|
||||
/* Set 'p' to end of arg string. marked by '\000' */
|
||||
for (;;)
|
||||
@ -8126,13 +8099,6 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
|
||||
}
|
||||
p--;
|
||||
|
||||
while (s2 < p)
|
||||
if (*s2++ == '\\')
|
||||
{
|
||||
appendPQExpBufferChar(query, ESCAPE_STRING_SYNTAX);
|
||||
break;
|
||||
}
|
||||
|
||||
appendPQExpBufferChar(query, '\'');
|
||||
while (s < p)
|
||||
{
|
||||
@ -8142,7 +8108,7 @@ dumpTrigger(Archive *fout, TriggerInfo *tginfo)
|
||||
* bytea unconditionally doubles backslashes, so we suppress
|
||||
* the doubling for standard_conforming_strings.
|
||||
*/
|
||||
if (std_strings && *s == '\\')
|
||||
if (fout->std_strings && *s == '\\' && s[1] == '\\')
|
||||
s++;
|
||||
appendPQExpBufferChar(query, *s++);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.76 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.77 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -36,6 +36,7 @@ int optreset;
|
||||
#include "libpq-fe.h"
|
||||
#include "pg_backup.h"
|
||||
#include "pqexpbuffer.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
|
||||
|
||||
/* version string we expect back from pg_dump */
|
||||
@ -53,7 +54,8 @@ static void dumpTablespaces(PGconn *conn);
|
||||
static void dumpCreateDB(PGconn *conn);
|
||||
static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
|
||||
static void dumpUserConfig(PGconn *conn, const char *username);
|
||||
static void makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name);
|
||||
static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
|
||||
const char *type, const char *name);
|
||||
static void dumpDatabases(PGconn *conn);
|
||||
static void dumpTimestamp(char *msg);
|
||||
|
||||
@ -88,6 +90,8 @@ main(int argc, char *argv[])
|
||||
bool globals_only = false;
|
||||
bool schema_only = false;
|
||||
PGconn *conn;
|
||||
int encoding;
|
||||
const char *std_strings;
|
||||
int c,
|
||||
ret;
|
||||
|
||||
@ -313,6 +317,15 @@ main(int argc, char *argv[])
|
||||
conn = connectDatabase("template1", pghost, pgport, pguser,
|
||||
force_password, true);
|
||||
|
||||
/*
|
||||
* Get the active encoding and the standard_conforming_strings setting,
|
||||
* so we know how to escape strings.
|
||||
*/
|
||||
encoding = PQclientEncoding(conn);
|
||||
std_strings = PQparameterStatus(conn, "standard_conforming_strings");
|
||||
if (!std_strings)
|
||||
std_strings = "off";
|
||||
|
||||
printf("--\n-- PostgreSQL database cluster dump\n--\n\n");
|
||||
if (verbose)
|
||||
dumpTimestamp("Started on");
|
||||
@ -321,6 +334,12 @@ main(int argc, char *argv[])
|
||||
|
||||
if (!data_only)
|
||||
{
|
||||
/* Replicate encoding and std_strings in output */
|
||||
printf("SET client_encoding = '%s';\n",
|
||||
pg_encoding_to_char(encoding));
|
||||
printf("SET standard_conforming_strings = %s;\n", std_strings);
|
||||
printf("\n");
|
||||
|
||||
/* Dump roles (users) */
|
||||
dumpRoles(conn);
|
||||
|
||||
@ -535,7 +554,7 @@ dumpRoles(PGconn *conn)
|
||||
if (!PQgetisnull(res, i, i_rolpassword))
|
||||
{
|
||||
appendPQExpBuffer(buf, " PASSWORD ");
|
||||
appendStringLiteral(buf, PQgetvalue(res, i, i_rolpassword), true, true);
|
||||
appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
|
||||
}
|
||||
|
||||
if (!PQgetisnull(res, i, i_rolvaliduntil))
|
||||
@ -546,7 +565,7 @@ dumpRoles(PGconn *conn)
|
||||
|
||||
if (!PQgetisnull(res, i, i_rolcomment)) {
|
||||
appendPQExpBuffer(buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
|
||||
appendStringLiteral(buf, PQgetvalue(res, i, i_rolcomment), true, true);
|
||||
appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolcomment), conn);
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
}
|
||||
|
||||
@ -730,7 +749,7 @@ dumpTablespaces(PGconn *conn)
|
||||
appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
|
||||
|
||||
appendPQExpBuffer(buf, " LOCATION ");
|
||||
appendStringLiteral(buf, spclocation, true, true);
|
||||
appendStringLiteralConn(buf, spclocation, conn);
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
|
||||
if (!skip_acls &&
|
||||
@ -745,7 +764,7 @@ dumpTablespaces(PGconn *conn)
|
||||
|
||||
if (spccomment && strlen(spccomment)) {
|
||||
appendPQExpBuffer(buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
|
||||
appendStringLiteral(buf, spccomment, true, true);
|
||||
appendStringLiteralConn(buf, spccomment, conn);
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
}
|
||||
|
||||
@ -868,7 +887,7 @@ dumpCreateDB(PGconn *conn)
|
||||
appendPQExpBuffer(buf, " OWNER = %s", fmtId(dbowner));
|
||||
|
||||
appendPQExpBuffer(buf, " ENCODING = ");
|
||||
appendStringLiteral(buf, dbencoding, true, true);
|
||||
appendStringLiteralConn(buf, dbencoding, conn);
|
||||
|
||||
/* Output tablespace if it isn't default */
|
||||
if (strcmp(dbtablespace, "pg_default") != 0)
|
||||
@ -884,7 +903,7 @@ dumpCreateDB(PGconn *conn)
|
||||
if (strcmp(dbistemplate, "t") == 0)
|
||||
{
|
||||
appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
|
||||
appendStringLiteral(buf, dbname, true, true);
|
||||
appendStringLiteralConn(buf, dbname, conn);
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
}
|
||||
}
|
||||
@ -929,13 +948,14 @@ dumpDatabaseConfig(PGconn *conn, const char *dbname)
|
||||
PGresult *res;
|
||||
|
||||
printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
|
||||
appendStringLiteral(buf, dbname, true, true);
|
||||
appendStringLiteralConn(buf, dbname, conn);
|
||||
appendPQExpBuffer(buf, ";");
|
||||
|
||||
res = executeQuery(conn, buf->data);
|
||||
if (!PQgetisnull(res, 0, 0))
|
||||
{
|
||||
makeAlterConfigCommand(PQgetvalue(res, 0, 0), "DATABASE", dbname);
|
||||
makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
|
||||
"DATABASE", dbname);
|
||||
PQclear(res);
|
||||
count++;
|
||||
}
|
||||
@ -968,13 +988,14 @@ dumpUserConfig(PGconn *conn, const char *username)
|
||||
printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM pg_authid WHERE rolname = ", count);
|
||||
else
|
||||
printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
|
||||
appendStringLiteral(buf, username, true, true);
|
||||
appendStringLiteralConn(buf, username, conn);
|
||||
|
||||
res = executeQuery(conn, buf->data);
|
||||
if (PQntuples(res) == 1 &&
|
||||
!PQgetisnull(res, 0, 0))
|
||||
{
|
||||
makeAlterConfigCommand(PQgetvalue(res, 0, 0), "ROLE", username);
|
||||
makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
|
||||
"ROLE", username);
|
||||
PQclear(res);
|
||||
count++;
|
||||
}
|
||||
@ -994,7 +1015,8 @@ dumpUserConfig(PGconn *conn, const char *username)
|
||||
* Helper function for dumpXXXConfig().
|
||||
*/
|
||||
static void
|
||||
makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name)
|
||||
makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
|
||||
const char *type, const char *name)
|
||||
{
|
||||
char *pos;
|
||||
char *mine;
|
||||
@ -1016,7 +1038,7 @@ makeAlterConfigCommand(const char *arrayitem, const char *type, const char *name
|
||||
|| pg_strcasecmp(mine, "search_path") == 0)
|
||||
appendPQExpBuffer(buf, "%s", pos + 1);
|
||||
else
|
||||
appendStringLiteral(buf, pos + 1, false, true);
|
||||
appendStringLiteralConn(buf, pos + 1, conn);
|
||||
appendPQExpBuffer(buf, ";\n");
|
||||
|
||||
printf("%s", buf->data);
|
||||
|
@ -3,13 +3,12 @@
|
||||
*
|
||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.136 2006/05/28 02:27:08 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.137 2006/05/28 21:13:54 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "describe.h"
|
||||
|
||||
#include "libpq-fe.h"
|
||||
#include "pqexpbuffer.h"
|
||||
#include "dumputils.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "settings.h"
|
||||
@ -1815,7 +1814,12 @@ processNamePattern(PQExpBuffer buf, const char *pattern,
|
||||
* Parse the pattern, converting quotes and lower-casing unquoted letters;
|
||||
* we assume this was NOT done by scan_option. Also, adjust shell-style
|
||||
* wildcard characters into regexp notation.
|
||||
*
|
||||
* Note: the result of this pass is the actual regexp pattern we want
|
||||
* to execute. Quoting/escaping it into a SQL literal will be done below.
|
||||
*/
|
||||
appendPQExpBufferChar(&namebuf, '^');
|
||||
|
||||
inquotes = false;
|
||||
cp = pattern;
|
||||
|
||||
@ -1854,6 +1858,7 @@ processNamePattern(PQExpBuffer buf, const char *pattern,
|
||||
resetPQExpBuffer(&schemabuf);
|
||||
appendPQExpBufferStr(&schemabuf, namebuf.data);
|
||||
resetPQExpBuffer(&namebuf);
|
||||
appendPQExpBufferChar(&namebuf, '^');
|
||||
cp++;
|
||||
}
|
||||
else
|
||||
@ -1869,14 +1874,9 @@ processNamePattern(PQExpBuffer buf, const char *pattern,
|
||||
*/
|
||||
if ((inquotes || force_escape) &&
|
||||
strchr("|*+?()[]{}.^$\\", *cp))
|
||||
appendPQExpBuffer(&namebuf, "\\\\");
|
||||
|
||||
/* Ensure chars special to string literals are passed properly */
|
||||
if (SQL_STR_DOUBLE(*cp, true))
|
||||
appendPQExpBufferChar(&namebuf, *cp);
|
||||
|
||||
appendPQExpBufferChar(&namebuf, '\\');
|
||||
i = PQmblen(cp, pset.encoding);
|
||||
while (i--)
|
||||
while (i-- && *cp)
|
||||
{
|
||||
appendPQExpBufferChar(&namebuf, *cp);
|
||||
cp++;
|
||||
@ -1885,49 +1885,61 @@ processNamePattern(PQExpBuffer buf, const char *pattern,
|
||||
}
|
||||
|
||||
/*
|
||||
* Now decide what we need to emit.
|
||||
* Now decide what we need to emit. Note there will be a leading '^'
|
||||
* in the patterns in any case.
|
||||
*/
|
||||
if (namebuf.len > 0)
|
||||
if (namebuf.len > 1)
|
||||
{
|
||||
/* We have a name pattern, so constrain the namevar(s) */
|
||||
|
||||
appendPQExpBufferChar(&namebuf, '$');
|
||||
/* Optimize away ".*$", and possibly the whole pattern */
|
||||
if (namebuf.len >= 3 &&
|
||||
if (namebuf.len >= 4 &&
|
||||
strcmp(namebuf.data + (namebuf.len - 3), ".*$") == 0)
|
||||
namebuf.data[namebuf.len - 3] = '\0';
|
||||
{
|
||||
namebuf.len -= 3;
|
||||
namebuf.data[namebuf.len] = '\0';
|
||||
}
|
||||
|
||||
if (namebuf.data[0])
|
||||
if (namebuf.len > 1)
|
||||
{
|
||||
WHEREAND();
|
||||
if (altnamevar)
|
||||
appendPQExpBuffer(buf,
|
||||
"(%s ~ '^%s'\n"
|
||||
" OR %s ~ '^%s')\n",
|
||||
namevar, namebuf.data,
|
||||
altnamevar, namebuf.data);
|
||||
{
|
||||
appendPQExpBuffer(buf, "(%s ~ ", namevar);
|
||||
appendStringLiteralConn(buf, namebuf.data, pset.db);
|
||||
appendPQExpBuffer(buf, "\n OR %s ~ ", altnamevar);
|
||||
appendStringLiteralConn(buf, namebuf.data, pset.db);
|
||||
appendPQExpBuffer(buf, ")\n");
|
||||
}
|
||||
else
|
||||
appendPQExpBuffer(buf,
|
||||
"%s ~ '^%s'\n",
|
||||
namevar, namebuf.data);
|
||||
{
|
||||
appendPQExpBuffer(buf, "%s ~ ", namevar);
|
||||
appendStringLiteralConn(buf, namebuf.data, pset.db);
|
||||
appendPQExpBufferChar(buf, '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (schemabuf.len > 0)
|
||||
if (schemabuf.len > 1)
|
||||
{
|
||||
/* We have a schema pattern, so constrain the schemavar */
|
||||
|
||||
appendPQExpBufferChar(&schemabuf, '$');
|
||||
/* Optimize away ".*$", and possibly the whole pattern */
|
||||
if (schemabuf.len >= 3 &&
|
||||
if (schemabuf.len >= 4 &&
|
||||
strcmp(schemabuf.data + (schemabuf.len - 3), ".*$") == 0)
|
||||
schemabuf.data[schemabuf.len - 3] = '\0';
|
||||
{
|
||||
schemabuf.len -= 3;
|
||||
schemabuf.data[schemabuf.len] = '\0';
|
||||
}
|
||||
|
||||
if (schemabuf.data[0] && schemavar)
|
||||
if (schemabuf.len > 1 && schemavar)
|
||||
{
|
||||
WHEREAND();
|
||||
appendPQExpBuffer(buf, "%s ~ '^%s'\n",
|
||||
schemavar, schemabuf.data);
|
||||
appendPQExpBuffer(buf, "%s ~ ", schemavar);
|
||||
appendStringLiteralConn(buf, schemabuf.data, pset.db);
|
||||
appendPQExpBufferChar(buf, '\n');
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.42 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/large_obj.c,v 1.43 2006/05/28 21:13:54 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "large_obj.h"
|
||||
@ -148,7 +148,6 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
|
||||
PGresult *res;
|
||||
Oid loid;
|
||||
char oidbuf[32];
|
||||
unsigned int i;
|
||||
bool own_transaction;
|
||||
|
||||
if (!start_lo_xact("\\lo_import", &own_transaction))
|
||||
@ -171,21 +170,9 @@ do_lo_import(const char *filename_arg, const char *comment_arg)
|
||||
cmdbuf = malloc(slen * 2 + 256);
|
||||
if (!cmdbuf)
|
||||
return fail_lo_xact("\\lo_import", own_transaction);
|
||||
sprintf(cmdbuf,
|
||||
"COMMENT ON LARGE OBJECT %u IS ",
|
||||
loid);
|
||||
sprintf(cmdbuf, "COMMENT ON LARGE OBJECT %u IS '", loid);
|
||||
bufptr = cmdbuf + strlen(cmdbuf);
|
||||
|
||||
if (strchr(comment_arg, '\\') != NULL)
|
||||
*bufptr++ = ESCAPE_STRING_SYNTAX;
|
||||
|
||||
*bufptr++ = '\'';
|
||||
for (i = 0; i < slen; i++)
|
||||
{
|
||||
if (SQL_STR_DOUBLE(comment_arg[i], true))
|
||||
*bufptr++ = comment_arg[i];
|
||||
*bufptr++ = comment_arg[i];
|
||||
}
|
||||
bufptr += PQescapeStringConn(pset.db, bufptr, comment_arg, slen, NULL);
|
||||
strcpy(bufptr, "'");
|
||||
|
||||
if (!(res = PSQLexec(cmdbuf, false)))
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/createdb.c,v 1.17 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/createdb.c,v 1.18 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -183,11 +183,12 @@ main(int argc, char *argv[])
|
||||
|
||||
if (comment)
|
||||
{
|
||||
conn = connectDatabase(dbname, host, port, username, password, progname);
|
||||
|
||||
printfPQExpBuffer(&sql, "COMMENT ON DATABASE %s IS ", fmtId(dbname));
|
||||
appendStringLiteral(&sql, comment, false, true);
|
||||
appendStringLiteralConn(&sql, comment, conn);
|
||||
appendPQExpBuffer(&sql, ";\n");
|
||||
|
||||
conn = connectDatabase(dbname, host, port, username, password, progname);
|
||||
if (echo)
|
||||
printf("%s", sql.data);
|
||||
result = PQexec(conn, sql.data);
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/createuser.c,v 1.28 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/scripts/createuser.c,v 1.29 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -236,6 +236,8 @@ main(int argc, char *argv[])
|
||||
if (login == 0)
|
||||
login = TRI_YES;
|
||||
|
||||
conn = connectDatabase("postgres", host, port, username, password, progname);
|
||||
|
||||
initPQExpBuffer(&sql);
|
||||
|
||||
printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser));
|
||||
@ -258,11 +260,11 @@ main(int argc, char *argv[])
|
||||
fprintf(stderr, _("Password encryption failed.\n"));
|
||||
exit(1);
|
||||
}
|
||||
appendStringLiteral(&sql, encrypted_password, false, true);
|
||||
appendStringLiteralConn(&sql, encrypted_password, conn);
|
||||
PQfreemem(encrypted_password);
|
||||
}
|
||||
else
|
||||
appendStringLiteral(&sql, newpassword, false, true);
|
||||
appendStringLiteralConn(&sql, newpassword, conn);
|
||||
}
|
||||
if (superuser == TRI_YES)
|
||||
appendPQExpBuffer(&sql, " SUPERUSER");
|
||||
@ -288,8 +290,6 @@ main(int argc, char *argv[])
|
||||
appendPQExpBuffer(&sql, " CONNECTION LIMIT %s", conn_limit);
|
||||
appendPQExpBuffer(&sql, ";\n");
|
||||
|
||||
conn = connectDatabase("postgres", host, port, username, password, progname);
|
||||
|
||||
if (echo)
|
||||
printf("%s", sql.data);
|
||||
result = PQexec(conn, sql.data);
|
||||
|
@ -12,7 +12,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/c.h,v 1.201 2006/05/26 23:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/c.h,v 1.202 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -473,12 +473,13 @@ typedef NameData *Name;
|
||||
#define NameStr(name) ((name).data)
|
||||
|
||||
/*
|
||||
* In 8.2, we are warning for \ in a non-E string if std_strings are off.
|
||||
* For this reason, we use E for \ strings, unless standard_conforming_strings
|
||||
* is on.
|
||||
* Support macros for escaping strings. escape_backslash should be TRUE
|
||||
* if generating a non-standard-conforming string. Prefixing a string
|
||||
* with ESCAPE_STRING_SYNTAX guarantees it is non-standard-conforming.
|
||||
* Beware of multiple evaluation of the "ch" argument!
|
||||
*/
|
||||
#define SQL_STR_DOUBLE(ch, escape_backslash) \
|
||||
((ch) == '\'' || ((escape_backslash) && (ch) == '\\'))
|
||||
((ch) == '\'' || ((ch) == '\\' && (escape_backslash)))
|
||||
|
||||
#define ESCAPE_STRING_SYNTAX 'E'
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.185 2006/05/28 17:23:29 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.186 2006/05/28 21:13:54 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2437,8 +2437,7 @@ PQescapeStringInternal(PGconn *conn,
|
||||
if (!IS_HIGHBIT_SET(c))
|
||||
{
|
||||
/* Apply quoting if needed */
|
||||
if (c == '\'' ||
|
||||
(c == '\\' && !std_strings))
|
||||
if (SQL_STR_DOUBLE(c, !std_strings))
|
||||
*target++ = c;
|
||||
/* Copy the character */
|
||||
*target++ = c;
|
||||
|
Loading…
Reference in New Issue
Block a user