On Tue, 2011-02-01 at 07:35 +0100, Magnus Hagander wrote: > On Tue, Feb 1, 2011 at 03:29, Robert Haas <robertmh...@gmail.com> wrote: > > On Mon, Jan 31, 2011 at 8:52 PM, Tom Lane <t...@sss.pgh.pa.us> wrote: > >>> Then again - in theory, there's no reason why we couldn't drop a > >>> database on the master when it's in use, kicking out everyone using it > >>> with this very same error code. We don't happen to handle it that way > >>> right now, but... > >> > >> Yeah, that was in the back of my mind too. "DROP DATABASE foo FORCE", > >> maybe? > > > > I have to think some people would find that useful. > > Yes. > > If nothing else, it would save some typing :-)
I like it also. It allows me to get rid of the concept of "non-retryable recovery conflicts", so we just have one code path that works in both normal mode and standby. Sweet. Here's the basic patch, will work on the refactoring if no objections. -- Simon Riggs http://www.2ndQuadrant.com/books/ PostgreSQL Development, 24x7 Support, Training and Services
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 9a9b4cb..8b1878c 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -732,7 +732,7 @@ createdb_failure_callback(int code, Datum arg) * DROP DATABASE */ void -dropdb(const char *dbname, bool missing_ok) +dropdb(const char *dbname, bool missing_ok, bool force) { Oid db_id; bool db_istemplate; @@ -800,11 +800,16 @@ dropdb(const char *dbname, bool missing_ok) * As in CREATE DATABASE, check this after other error conditions. */ if (CountOtherDBBackends(db_id, ¬herbackends, &npreparedxacts)) - ereport(ERROR, + { + if (force) + ResolveRecoveryConflictWithDatabase(db_id); + else + ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", dbname), errdetail_busy_db(notherbackends, npreparedxacts))); + } /* * Remove the database's tuple from pg_database. diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index fb9da83..ee595af 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3074,6 +3074,7 @@ _copyDropdbStmt(DropdbStmt *from) COPY_STRING_FIELD(dbname); COPY_SCALAR_FIELD(missing_ok); + COPY_SCALAR_FIELD(force); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 2ef1a33..60d4e8c 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1523,6 +1523,7 @@ _equalDropdbStmt(DropdbStmt *a, DropdbStmt *b) { COMPARE_STRING_FIELD(dbname); COMPARE_SCALAR_FIELD(missing_ok); + COMPARE_SCALAR_FIELD(force); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 660947c..ec67cf5 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -6973,18 +6973,20 @@ alterdb_opt_item: * This is implicitly CASCADE, no need for drop behavior *****************************************************************************/ -DropdbStmt: DROP DATABASE database_name +DropdbStmt: DROP DATABASE database_name opt_force { DropdbStmt *n = makeNode(DropdbStmt); n->dbname = $3; n->missing_ok = FALSE; + n->force = $4; $$ = (Node *)n; } - | DROP DATABASE IF_P EXISTS database_name + | DROP DATABASE IF_P EXISTS database_name opt_force { DropdbStmt *n = makeNode(DropdbStmt); n->dbname = $5; n->missing_ok = TRUE; + n->force = $6; $$ = (Node *)n; } ; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 9500037..28dfbe2 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -995,7 +995,7 @@ standard_ProcessUtility(Node *parsetree, DropdbStmt *stmt = (DropdbStmt *) parsetree; PreventTransactionChain(isTopLevel, "DROP DATABASE"); - dropdb(stmt->dbname, stmt->missing_ok); + dropdb(stmt->dbname, stmt->missing_ok, stmt->force); } break; diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h index 8097547..eea939b 100644 --- a/src/include/commands/dbcommands.h +++ b/src/include/commands/dbcommands.h @@ -53,7 +53,7 @@ typedef struct xl_dbase_drop_rec } xl_dbase_drop_rec; extern void createdb(const CreatedbStmt *stmt); -extern void dropdb(const char *dbname, bool missing_ok); +extern void dropdb(const char *dbname, bool missing_ok, bool force); extern void RenameDatabase(const char *oldname, const char *newname); extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel); extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 3d2ae99..f104a1b 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2293,6 +2293,7 @@ typedef struct DropdbStmt NodeTag type; char *dbname; /* database to drop */ bool missing_ok; /* skip error if db is missing? */ + bool force; /* force off any users before drop? */ } DropdbStmt; /* ----------------------
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers