pg_fatal("unrecognized encoding \"%s\"",
ptr1);
AH->public.encoding = encoding;
+ setFmtEncoding(encoding);
}
else
pg_fatal("invalid ENCODING item: %s",
* we know how to escape strings.
*/
AH->encoding = PQclientEncoding(conn);
+ setFmtEncoding(AH->encoding);
std_strings = PQparameterStatus(conn, "standard_conforming_strings");
AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
* we know how to escape strings.
*/
encoding = PQclientEncoding(conn);
+ setFmtEncoding(encoding);
std_strings = PQparameterStatus(conn, "standard_conforming_strings");
if (!std_strings)
std_strings = "off";
/* save encoding info into psql internal data */
pset.encoding = PQclientEncoding(pset.db);
pset.popt.topt.encoding = pset.encoding;
+ setFmtEncoding(pset.encoding);
SetVariable(pset.vars, "ENCODING",
pg_encoding_to_char(pset.encoding));
}
pset.popt.topt.encoding = pset.encoding;
pset.sversion = PQserverVersion(pset.db);
+ setFmtEncoding(pset.encoding);
+
SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
SetVariable(pset.vars, "SERVICE", PQservice(pset.db));
SetVariable(pset.vars, "USER", PQuser(pset.db));
exit(1);
}
appendPQExpBufferStr(buf,
- fmtQualifiedId(PQgetvalue(res, 0, 1),
- PQgetvalue(res, 0, 0)));
+ fmtQualifiedIdEnc(PQgetvalue(res, 0, 1),
+ PQgetvalue(res, 0, 0),
+ PQclientEncoding(conn)));
appendPQExpBufferStr(buf, columns);
PQclear(res);
termPQExpBuffer(&sql);
conn = connectMaintenanceDatabase(&cparams, progname, echo);
+ setFmtEncoding(PQclientEncoding(conn));
+
initPQExpBuffer(&sql);
appendPQExpBuffer(&sql, "CREATE DATABASE %s",
conn = connectMaintenanceDatabase(&cparams, progname, echo);
+ setFmtEncoding(PQclientEncoding(conn));
+
initPQExpBuffer(&sql);
printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser));
exit(0);
}
- initPQExpBuffer(&sql);
-
- appendPQExpBuffer(&sql, "DROP DATABASE %s%s%s;",
- (if_exists ? "IF EXISTS " : ""),
- fmtId(dbname),
- force ? " WITH (FORCE)" : "");
-
/* Avoid trying to drop postgres db while we are connected to it. */
if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
maintenance_db = "template1";
conn = connectMaintenanceDatabase(&cparams, progname, echo);
+ initPQExpBuffer(&sql);
+ appendPQExpBuffer(&sql, "DROP DATABASE %s%s%s;",
+ (if_exists ? "IF EXISTS " : ""),
+ fmtIdEnc(dbname, PQclientEncoding(conn)),
+ force ? " WITH (FORCE)" : "");
+
if (echo)
printf("%s\n", sql.data);
result = PQexec(conn, sql.data);
initPQExpBuffer(&sql);
appendPQExpBuffer(&sql, "DROP ROLE %s%s;",
- (if_exists ? "IF EXISTS " : ""), fmtId(dropuser));
+ (if_exists ? "IF EXISTS " : ""),
+ fmtIdEnc(dropuser, PQclientEncoding(conn)));
if (echo)
printf("%s\n", sql.data);
if (tablespace)
{
- appendPQExpBuffer(&sql, "%sTABLESPACE %s", sep, fmtId(tablespace));
+ appendPQExpBuffer(&sql, "%sTABLESPACE %s", sep,
+ fmtIdEnc(tablespace, PQclientEncoding(conn)));
sep = comma;
}
{
case REINDEX_DATABASE:
case REINDEX_SYSTEM:
- appendPQExpBufferStr(&sql, fmtId(name));
+ appendPQExpBufferStr(&sql,
+ fmtIdEnc(name, PQclientEncoding(conn)));
break;
case REINDEX_INDEX:
case REINDEX_TABLE:
for (i = 0; i < ntups; i++)
{
appendPQExpBufferStr(&buf,
- fmtQualifiedId(PQgetvalue(res, i, 1),
- PQgetvalue(res, i, 0)));
+ fmtQualifiedIdEnc(PQgetvalue(res, i, 1),
+ PQgetvalue(res, i, 0),
+ PQclientEncoding(conn)));
simple_string_list_append(tables, buf.data);
resetPQExpBuffer(&buf);
* the order of tables list.
*/
appendPQExpBufferStr(&buf,
- fmtQualifiedId(PQgetvalue(res, i, 1),
- PQgetvalue(res, i, 2)));
+ fmtQualifiedIdEnc(PQgetvalue(res, i, 1),
+ PQgetvalue(res, i, 2),
+ PQclientEncoding(conn)));
simple_string_list_append(user_list, buf.data);
resetPQExpBuffer(&buf);
for (i = 0; i < ntups; i++)
{
appendPQExpBufferStr(&buf,
- fmtQualifiedId(PQgetvalue(res, i, 1),
- PQgetvalue(res, i, 0)));
+ fmtQualifiedIdEnc(PQgetvalue(res, i, 1),
+ PQgetvalue(res, i, 0),
+ PQclientEncoding(conn)));
if (objects_listed && !PQgetisnull(res, i, 2))
appendPQExpBufferStr(&buf, PQgetvalue(res, i, 2));
#include "common/keywords.h"
#include "fe_utils/string_utils.h"
+#include "mb/pg_wchar.h"
static PQExpBuffer defaultGetLocalPQExpBuffer(void);
int quote_all_identifiers = 0;
PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer;
+static int fmtIdEncoding = -1;
+
/*
* Returns a temporary PQExpBuffer, valid until the next call to the function.
return id_return;
}
+/*
+ * Set the encoding that fmtId() and fmtQualifiedId() use.
+ *
+ * This is not safe against multiple connections having different encodings,
+ * but there is no real other way to address the need to know the encoding for
+ * fmtId()/fmtQualifiedId() input for safe escaping. Eventually we should get
+ * rid of fmtId().
+ */
+void
+setFmtEncoding(int encoding)
+{
+ fmtIdEncoding = encoding;
+}
+
+/*
+ * Return the currently configured encoding for fmtId() and fmtQualifiedId().
+ */
+static int
+getFmtEncoding(void)
+{
+ if (fmtIdEncoding != -1)
+ return fmtIdEncoding;
+
+ /*
+ * In assertion builds it seems best to fail hard if the encoding was not
+ * set, to make it easier to find places with missing calls. But in
+ * production builds that seems like a bad idea, thus we instead just
+ * default to UTF-8.
+ */
+ Assert(fmtIdEncoding != -1);
+
+ return PG_UTF8;
+}
+
/*
* Quotes input string if it's not a legitimate SQL identifier as-is.
*
- * Note that the returned string must be used before calling fmtId again,
+ * Note that the returned string must be used before calling fmtIdEnc again,
* since we re-use the same return buffer each time.
*/
const char *
-fmtId(const char *rawid)
+fmtIdEnc(const char *rawid, int encoding)
{
PQExpBuffer id_return = getLocalPQExpBuffer();
}
/*
- * fmtQualifiedId - construct a schema-qualified name, with quoting as needed.
+ * Quotes input string if it's not a legitimate SQL identifier as-is.
+ *
+ * Note that the returned string must be used before calling fmtId again,
+ * since we re-use the same return buffer each time.
+ *
+ * NB: This assumes setFmtEncoding() previously has been called to configure
+ * the encoding of rawid. It is preferable to use fmtIdEnc() with an
+ * explicit encoding.
+ */
+const char *
+fmtId(const char *rawid)
+{
+ return fmtIdEnc(rawid, getFmtEncoding());
+}
+
+/*
+ * fmtQualifiedIdEnc - construct a schema-qualified name, with quoting as
+ * needed.
*
* Like fmtId, use the result before calling again.
*
* use that buffer until we're finished with calling fmtId().
*/
const char *
-fmtQualifiedId(const char *schema, const char *id)
+fmtQualifiedIdEnc(const char *schema, const char *id, int encoding)
{
PQExpBuffer id_return;
PQExpBuffer lcl_pqexp = createPQExpBuffer();
/* Some callers might fail to provide a schema name */
if (schema && *schema)
{
- appendPQExpBuffer(lcl_pqexp, "%s.", fmtId(schema));
+ appendPQExpBuffer(lcl_pqexp, "%s.", fmtIdEnc(schema, encoding));
}
- appendPQExpBufferStr(lcl_pqexp, fmtId(id));
+ appendPQExpBufferStr(lcl_pqexp, fmtIdEnc(id, encoding));
id_return = getLocalPQExpBuffer();
return id_return->data;
}
+/*
+ * fmtQualifiedId - construct a schema-qualified name, with quoting as needed.
+ *
+ * Like fmtId, use the result before calling again.
+ *
+ * Since we call fmtId and it also uses getLocalPQExpBuffer() we cannot
+ * use that buffer until we're finished with calling fmtId().
+ *
+ * NB: This assumes setFmtEncoding() previously has been called to configure
+ * the encoding of schema/id. It is preferable to use fmtQualifiedIdEnc()
+ * with an explicit encoding.
+ */
+const char *
+fmtQualifiedId(const char *schema, const char *id)
+{
+ return fmtQualifiedIdEnc(schema, id, getFmtEncoding());
+}
+
/*
* Format a Postgres version number (in the PG_VERSION_NUM integer format
/* Functions */
extern const char *fmtId(const char *rawid);
+extern const char *fmtIdEnc(const char *rawid, int encoding);
extern const char *fmtQualifiedId(const char *schema, const char *id);
+extern const char *fmtQualifiedIdEnc(const char *schema, const char *id, int encoding);
+extern void setFmtEncoding(int encoding);
extern char *formatPGVersionNumber(int version_number, bool include_minor,
char *buf, size_t buflen);