Commit 15c30b6f authored by Tom Lane's avatar Tom Lane

Be more wary about mixed-case database names and user names. Get

the CREATE DATABASE command right in pg_dump -C case.
parent 906254a5
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
* *
...@@ -590,65 +590,3 @@ findFuncByName(FuncInfo *finfo, int numFuncs, const char *name) ...@@ -590,65 +590,3 @@ findFuncByName(FuncInfo *finfo, int numFuncs, const char *name)
} }
return -1; 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() */
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
* *
...@@ -136,10 +136,11 @@ extern void ...@@ -136,10 +136,11 @@ extern void
exit_horribly(Archive *AH, const char *modulename, const char *fmt,...) exit_horribly(Archive *AH, const char *modulename, const char *fmt,...)
__attribute__((format(printf, 3, 4))); __attribute__((format(printf, 3, 4)));
extern char * extern char *simple_prompt(const char *prompt, int maxlen, bool echo);
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, PGconn *ConnectDatabase(Archive *AH,
const char *dbname, const char *dbname,
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
* *
...@@ -74,6 +74,7 @@ ...@@ -74,6 +74,7 @@
#include "pg_backup_archiver.h" #include "pg_backup_archiver.h"
#include "pg_backup_db.h" #include "pg_backup_db.h"
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> /* for dup */ #include <unistd.h> /* for dup */
...@@ -1953,7 +1954,7 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt) ...@@ -1953,7 +1954,7 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
* user, this won't do anything. * user, this won't do anything.
* *
* If we're currently restoring right into a database, this will * 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. * the script output.
*/ */
static void static void
...@@ -1974,7 +1975,8 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user) ...@@ -1974,7 +1975,8 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user)
PQExpBuffer qry = createPQExpBuffer(); PQExpBuffer qry = createPQExpBuffer();
PGresult *res; PGresult *res;
appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION '%s';", user); appendPQExpBuffer(qry, "SET SESSION AUTHORIZATION %s;",
fmtId(user, false));
res = PQexec(AH->connection, qry->data); res = PQexec(AH->connection, qry->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
...@@ -1985,19 +1987,29 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user) ...@@ -1985,19 +1987,29 @@ _reconnectAsUser(ArchiveHandle *AH, const char *dbname, const char *user)
destroyPQExpBuffer(qry); destroyPQExpBuffer(qry);
} }
else 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) else if (AH->ropt && AH->ropt->noReconnect)
{
/* When -R was given, don't do anything. */
return; return;
}
else if (RestoringToDB(AH)) else if (RestoringToDB(AH))
ReconnectToServer(AH, dbname, user); ReconnectToServer(AH, dbname, user);
else else
/* FIXME: does not handle mixed case user names */ {
ahprintf(AH, "\\connect %s %s\n\n", PQExpBuffer qry = createPQExpBuffer();
dbname ? dbname : "-",
user ? user : "-"); 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 * NOTE: currUser keeps track of what the imaginary session user in
...@@ -2025,6 +2037,69 @@ _reconnectAsOwner(ArchiveHandle *AH, const char *dbname, TocEntry *te) ...@@ -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 static int
_printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData) _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isData)
{ {
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1141,15 +1141,24 @@ dumpDatabase(Archive *AH)
PQExpBuffer creaQry = createPQExpBuffer(); PQExpBuffer creaQry = createPQExpBuffer();
PGresult *res; PGresult *res;
int ntups; 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) if (g_verbose)
write_msg(NULL, "saving database definition\n"); write_msg(NULL, "saving database definition\n");
/* Get the dba */ /* Get the database owner and parameters from pg_database */
appendPQExpBuffer(dbQry, "select (select usename from pg_user where datdba = usesysid) as dba from pg_database" appendPQExpBuffer(dbQry, "select (select usename from pg_user where usesysid = datdba) as dba,"
" encoding, datpath from pg_database"
" where datname = "); " where datname = ");
formatStringLiteral(dbQry, PQdb(g_conn), CONV_ALL); formatStringLiteral(dbQry, datname, CONV_ALL);
res = PQexec(g_conn, dbQry->data); res = PQexec(g_conn, dbQry->data);
if (!res || if (!res ||
...@@ -1165,24 +1174,39 @@ dumpDatabase(Archive *AH) ...@@ -1165,24 +1174,39 @@ dumpDatabase(Archive *AH)
if (ntups <= 0) 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(); exit_nicely();
} }
if (ntups != 1) if (ntups != 1)
{ {
write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n", write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
ntups, PQdb(g_conn)); ntups, datname);
exit_nicely(); 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"); i_dba = PQfnumber(res, "dba");
i_encoding = PQfnumber(res, "encoding");
ArchiveEntry(AH, "0" /* OID */ , PQdb(g_conn) /* Name */ , "DATABASE", NULL, 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 */ , creaQry->data /* Create */ , delQry->data /* Del */ ,
"" /* Copy */ , PQgetvalue(res, 0, i_dba) /* Owner */ , "" /* Copy */ , dba /* Owner */ ,
NULL /* Dumper */ , NULL /* Dumper Arg */ ); NULL /* Dumper */ , NULL /* Dumper Arg */ );
PQclear(res); PQclear(res);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * 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, ...@@ -280,7 +280,6 @@ extern void dumpTables(Archive *fout, TableInfo *tbinfo, int numTables,
const bool schemaOnly, const bool dataOnly); const bool schemaOnly, const bool dataOnly);
extern void dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes, extern void dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
TableInfo *tbinfo, int numTables, const char *tablename); TableInfo *tbinfo, int numTables, const char *tablename);
extern const char *fmtId(const char *identifier, bool force_quotes);
extern void exit_nicely(void); extern void exit_nicely(void);
#endif /* PG_DUMP_H */ #endif /* PG_DUMP_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# and "pg_group" tables, which belong to the whole installation rather # and "pg_group" tables, which belong to the whole installation rather
# than any one individual database. # 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` CMDNAME=`basename $0`
...@@ -217,7 +217,7 @@ while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do ...@@ -217,7 +217,7 @@ while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do
echo "--" echo "--"
echo "-- Database $DATABASE" echo "-- Database $DATABASE"
echo "--" echo "--"
echo "${BS}connect template1 $DBOWNER" echo "${BS}connect template1 \"$DBOWNER\""
if [ "$cleanschema" = yes -a "$DATABASE" != template1 ] ; then if [ "$cleanschema" = yes -a "$DATABASE" != template1 ] ; then
echo "DROP DATABASE \"$DATABASE\";" echo "DROP DATABASE \"$DATABASE\";"
...@@ -234,7 +234,7 @@ while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do ...@@ -234,7 +234,7 @@ while read DATABASE DBOWNER ENCODING ISTEMPLATE DBPATH; do
echo "$createdbcmd;" echo "$createdbcmd;"
fi fi
echo "${BS}connect $DATABASE $DBOWNER" echo "${BS}connect \"$DATABASE\" \"$DBOWNER\""
echo "dumping database \"$DATABASE\"..." 1>&2 echo "dumping database \"$DATABASE\"..." 1>&2
$PGDUMP "$DATABASE" <&4 $PGDUMP "$DATABASE" <&4
if [ "$?" -ne 0 ] ; then if [ "$?" -ne 0 ] ; then
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment