From: Tom Lane Date: Mon, 11 Feb 2002 00:18:20 +0000 (+0000) Subject: Be more wary about mixed-case database names and user names. Get X-Git-Tag: REL7_2_1~52 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=15c30b6f9ade42754b6721c64ba1766f16252107;p=postgresql Be more wary about mixed-case database names and user names. Get the CREATE DATABASE command right in pg_dump -C case. --- diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 1a32e22b22..907590518c 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.61 2002/01/11 23:21:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.62 2002/02/11 00:18:20 tgl Exp $ * * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2 * @@ -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 b81b029e29..32d4c1e88e 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.17 2001/10/28 06:25:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup.h,v 1.18 2002/02/11 00:18:20 tgl Exp $ * * Modifications - 28-Jun-2000 - pjw@rhyme.com.au * @@ -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 baebc56e4d..2c8ea7d828 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.41 2002/02/06 17:27:50 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.42 2002/02/11 00:18:20 tgl Exp $ * * Modifications - 28-Jun-2000 - pjw@rhyme.com.au * @@ -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 0eb30b58d1..64b4887e29 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.240 2002/02/06 17:27:50 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.241 2002/02/11 00:18:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 3af39b8d2e..0d69fda200 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_dump.h,v 1.77 2002/01/11 23:21:55 tgl Exp $ + * $Id: pg_dump.h,v 1.78 2002/02/11 00:18:20 tgl Exp $ * * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2 * @@ -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 122cf75b2d..7aab5e2d76 100644 --- a/src/bin/pg_dump/pg_dumpall.sh +++ b/src/bin/pg_dump/pg_dumpall.sh @@ -6,7 +6,7 @@ # and "pg_group" tables, which belong to the whole installation rather # than any one individual database. # -# $Header: /cvsroot/pgsql/src/bin/pg_dump/Attic/pg_dumpall.sh,v 1.14 2002/01/09 04:56:44 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/pg_dump/Attic/pg_dumpall.sh,v 1.15 2002/02/11 00:18:20 tgl Exp $ CMDNAME=`basename $0` @@ -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