From 2468af150386b46d1dd219795257d238ed1073fb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 11 Feb 2002 00:18:20 +0000 Subject: [PATCH] Be more wary about mixed-case database names and user names. Get the CREATE DATABASE command right in pg_dump -C case. --- src/bin/pg_dump/common.c | 62 ------------------- src/bin/pg_dump/pg_backup.h | 7 ++- src/bin/pg_dump/pg_backup_archiver.c | 93 +++++++++++++++++++++++++--- src/bin/pg_dump/pg_dump.c | 46 ++++++++++---- src/bin/pg_dump/pg_dump.h | 1 - src/bin/pg_dump/pg_dumpall.sh | 4 +- 6 files changed, 125 insertions(+), 88 deletions(-) diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 164db3c402..2d0ab5980e 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -590,65 +590,3 @@ findFuncByName(FuncInfo *finfo, int numFuncs, const char *name) } return -1; } - -/* - * fmtId - * - * checks input string for non-lowercase characters - * returns pointer to input string or string surrounded by double quotes - * - * Note that the returned string should be used immediately since it - * uses a static buffer to hold the string. Non-reentrant but faster? - */ -const char * -fmtId(const char *rawid, bool force_quotes) -{ - static PQExpBuffer id_return = NULL; - const char *cp; - - if (!force_quotes) - { - /* do a quick check on the first character... */ - if (!islower((unsigned char) *rawid)) - force_quotes = true; - /* otherwise check the entire string */ - else - for (cp = rawid; *cp; cp++) - { - if (!(islower((unsigned char) *cp) || - isdigit((unsigned char) *cp) || - (*cp == '_'))) - { - force_quotes = true; - break; - } - } - } - - if (!force_quotes) - return rawid; /* no quoting needed */ - - if (id_return) - resetPQExpBuffer(id_return); - else - id_return = createPQExpBuffer(); - - appendPQExpBufferChar(id_return, '\"'); - for (cp = rawid; *cp; cp++) - { - /* - * Did we find a double-quote in the string? Then make this a - * double double-quote per SQL99. Before, we put in a - * backslash/double-quote pair. - thomas 2000-08-05 - */ - if (*cp == '\"') - { - appendPQExpBufferChar(id_return, '\"'); - appendPQExpBufferChar(id_return, '\"'); - } - appendPQExpBufferChar(id_return, *cp); - } - appendPQExpBufferChar(id_return, '\"'); - - return id_return->data; -} /* fmtId() */ diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index 0665413481..2d73320796 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -136,10 +136,11 @@ extern void exit_horribly(Archive *AH, const char *modulename, const char *fmt,...) __attribute__((format(printf, 3, 4))); -extern char * - simple_prompt(const char *prompt, int maxlen, bool echo); +extern char *simple_prompt(const char *prompt, int maxlen, bool echo); -/* Lets the archibe know we have a DB connection to shutdown if it dies */ +extern const char *fmtId(const char *identifier, bool force_quotes); + +/* Lets the archive know we have a DB connection to shutdown if it dies */ PGconn *ConnectDatabase(Archive *AH, const char *dbname, diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 1204eb4b64..5b45fefc99 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -74,6 +74,7 @@ #include "pg_backup_archiver.h" #include "pg_backup_db.h" +#include #include #include /* for dup */ @@ -1953,7 +1954,7 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt) * user, this won't do anything. * * If we're currently restoring right into a database, this will - * actuall establish a connection. Otherwise it puts a \connect into + * actually establish a connection. Otherwise it puts a \connect into * the script output. */ static void @@ -1974,7 +1975,8 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user) PQExpBuffer qry = createPQExpBuffer(); PGresult *res; - appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION '%s';", user); + appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION %s;", + fmtId(user, false)); res = PQexec(AH->connection, qry->data); if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) @@ -1985,19 +1987,29 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user) destroyPQExpBuffer(qry); } else - ahprintf(AH, "SET SESSION AUTHORIZATION '%s';\n\n", user); + ahprintf(AH, "SET SESSION AUTHORIZATION %s;\n\n", + fmtId(user, false)); } - /* When -R was given, don't do anything. */ else if (AH->ropt && AH->ropt->noReconnect) + { + /* When -R was given, don't do anything. */ return; - + } else if (RestoringToDB(AH)) ReconnectToServer(AH, dbname, user); else - /* FIXME: does not handle mixed case user names */ - ahprintf(AH, "\\connect %s %s\n\n", - dbname ? dbname : "-", - user ? user : "-"); + { + PQExpBuffer qry = createPQExpBuffer(); + + appendPQExpBuffer(qry, "\\connect %s", + dbname ? fmtId(dbname, false) : "-"); + appendPQExpBuffer(qry, " %s\n\n", + fmtId(user, false)); + + ahprintf(AH, qry->data); + + destroyPQExpBuffer(qry); + } /* * NOTE: currUser keeps track of what the imaginary session user in @@ -2025,6 +2037,69 @@ _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te) } +/* + * fmtId + * + * checks input string for non-lowercase characters + * returns pointer to input string or string surrounded by double quotes + * + * Note that the returned string should be used immediately since it + * uses a static buffer to hold the string. Non-reentrant but faster? + */ +const char * +fmtId(const char *rawid, bool force_quotes) +{ + static PQExpBuffer id_return = NULL; + const char *cp; + + if (!force_quotes) + { + /* do a quick check on the first character... */ + if (!islower((unsigned char) *rawid)) + force_quotes = true; + /* otherwise check the entire string */ + else + for (cp = rawid; *cp; cp++) + { + if (!(islower((unsigned char) *cp) || + isdigit((unsigned char) *cp) || + (*cp == '_'))) + { + force_quotes = true; + break; + } + } + } + + if (!force_quotes) + return rawid; /* no quoting needed */ + + if (id_return) + resetPQExpBuffer(id_return); + else + id_return = createPQExpBuffer(); + + appendPQExpBufferChar(id_return, '\"'); + for (cp = rawid; *cp; cp++) + { + /* + * Did we find a double-quote in the string? Then make this a + * double double-quote per SQL99. Before, we put in a + * backslash/double-quote pair. - thomas 2000-08-05 + */ + if (*cp == '\"') + { + appendPQExpBufferChar(id_return, '\"'); + appendPQExpBufferChar(id_return, '\"'); + } + appendPQExpBufferChar(id_return, *cp); + } + appendPQExpBufferChar(id_return, '\"'); + + return id_return->data; +} + + static int _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData) { diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 6263f05892..432c6ae6fb 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -1141,15 +1141,24 @@ dumpDatabase(Archive *AH) PQExpBuffer creaQry = createPQExpBuffer(); PGresult *res; int ntups; - int i_dba; + int i_dba, + i_encoding, + i_datpath; + const char *datname, + *dba, + *encoding, + *datpath; + + datname = PQdb(g_conn); if (g_verbose) write_msg(NULL, "saving database definition\n"); - /* Get the dba */ - appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database" + /* Get the database owner and parameters from pg_database */ + appendPQExpBuffer(dbQry, "select (select usename from pg_user where usesysid = datdba) as dba," + " encoding, datpath from pg_database" " where datname = "); - formatStringLiteral(dbQry, PQdb(g_conn), CONV_ALL); + formatStringLiteral(dbQry, datname, CONV_ALL); res = PQexec(g_conn, dbQry->data); if (!res || @@ -1165,24 +1174,39 @@ dumpDatabase(Archive *AH) if (ntups <= 0) { - write_msg(NULL, "missing pg_database entry for database \"%s\"\n", PQdb(g_conn)); + write_msg(NULL, "missing pg_database entry for database \"%s\"\n", + datname); exit_nicely(); } if (ntups != 1) { write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n", - ntups, PQdb(g_conn)); + ntups, datname); exit_nicely(); } - appendPQExpBuffer(creaQry, "Create Database \"%s\";\n", PQdb(g_conn)); - appendPQExpBuffer(delQry, "Drop Database \"%s\";\n", PQdb(g_conn)); i_dba = PQfnumber(res, "dba"); - - ArchiveEntry(AH, "0" /* OID */ , PQdb(g_conn) /* Name */ , "DATABASE", NULL, + i_encoding = PQfnumber(res, "encoding"); + i_datpath = PQfnumber(res, "datpath"); + dba = PQgetvalue(res, 0, i_dba); + encoding = PQgetvalue(res, 0, i_encoding); + datpath = PQgetvalue(res, 0, i_datpath); + + appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0", + fmtId(datname, force_quotes)); + if (strlen(encoding) > 0) + appendPQExpBuffer(creaQry, " ENCODING = %s", encoding); + if (strlen(datpath) > 0) + appendPQExpBuffer(creaQry, " LOCATION = '%s'", datpath); + appendPQExpBuffer(creaQry, ";\n"); + + appendPQExpBuffer(delQry, "DROP DATABASE %s;\n", + fmtId(datname, force_quotes)); + + ArchiveEntry(AH, "0" /* OID */ , datname /* Name */ , "DATABASE", NULL, creaQry->data /* Create */ , delQry->data /* Del */ , - "" /* Copy */ , PQgetvalue(res, 0, i_dba) /* Owner */ , + "" /* Copy */ , dba /* Owner */ , NULL /* Dumper */ , NULL /* Dumper Arg */ ); PQclear(res); diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index a6ebcdc1e8..b9b0b63dce 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -280,7 +280,6 @@ extern void dumpTables(Archive *fout, TableInfo *tbinfo, int numTables, const bool schemaOnly, const bool dataOnly); extern void dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes, TableInfo *tbinfo, int numTables, const char *tablename); -extern const char *fmtId(const char *identifier, bool force_quotes); extern void exit_nicely(void); #endif /* PG_DUMP_H */ diff --git a/src/bin/pg_dump/pg_dumpall.sh b/src/bin/pg_dump/pg_dumpall.sh index f836e072c5..6176e7cc5e 100644 --- a/src/bin/pg_dump/pg_dumpall.sh +++ b/src/bin/pg_dump/pg_dumpall.sh @@ -217,7 +217,7 @@ while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do echo "--" echo "-- Database $DATABASE" echo "--" - echo "${BS}connect template1 $DBOWNER" + echo "${BS}connect template1 \"$DBOWNER\"" if [ "$cleanschema" = yes -a "$DATABASE" != template1 ] ; then echo "DROP DATABASE \"$DATABASE\";" @@ -234,7 +234,7 @@ while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do echo "$createdbcmd;" fi - echo "${BS}connect $DATABASE $DBOWNER" + echo "${BS}connect \"$DATABASE\" \"$DBOWNER\"" echo "dumping database \"$DATABASE\"..." 1>&2 $PGDUMP "$DATABASE" <&4 if [ "$?" -ne 0 ] ; then -- 2.39.5