rename-force.patch.2

text/plain

Filename: rename-force.patch.2
Type: text/plain
Part: 0
Message: Re: Rename a database that has connections
diff --git a/doc/src/sgml/ref/alter_database.sgml b/doc/src/sgml/ref/alter_database.sgml
new file mode 100644
index 360732f..98ea473
*** a/doc/src/sgml/ref/alter_database.sgml
--- b/doc/src/sgml/ref/alter_database.sgml
*************** ALTER DATABASE <replaceable class="PARAM
*** 27,33 ****
  
      CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
  
! ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
  
  ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
  
--- 27,33 ----
  
      CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
  
! ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable> [ FORCE ]
  
  ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
  
*************** ALTER DATABASE <replaceable class="PARAM
*** 57,65 ****
     The second form changes the name of the database.  Only the database
     owner or a superuser can rename a database; non-superuser owners must
     also have the
!    <literal>CREATEDB</literal> privilege.  The current database cannot
!    be renamed.  (Connect to a different database if you need to do
!    that.)
    </para>
  
    <para>
--- 57,69 ----
     The second form changes the name of the database.  Only the database
     owner or a superuser can rename a database; non-superuser owners must
     also have the
!    <literal>CREATEDB</literal> privilege. If <literal>FORCE</literal>
!    is not specified the current database cannot be renamed (Connect to 
!    a different database if you need to do that). 
!    Similarly any database that has connections cannot be renamed.
!    If <literal>FORCE</literal> is specified the previous two restrictions
!    do not apply and the rename will be performed (existing connections 
!    will not be disconnected or canceled).
    </para>
  
    <para>
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
new file mode 100644
index c321224..bdc5f12
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
*************** ExecRenameStmt(RenameStmt *stmt)
*** 62,68 ****
  			break;
  
  		case OBJECT_DATABASE:
! 			RenameDatabase(stmt->subname, stmt->newname);
  			break;
  
  		case OBJECT_FUNCTION:
--- 62,68 ----
  			break;
  
  		case OBJECT_DATABASE:
! 			RenameDatabase(stmt->subname, stmt->newname, stmt->force);
  			break;
  
  		case OBJECT_FUNCTION:
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
new file mode 100644
index 4551db7..217f7ca
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
*************** dropdb(const char *dbname, bool missing_
*** 886,892 ****
   * Rename database
   */
  void
! RenameDatabase(const char *oldname, const char *newname)
  {
  	Oid			db_id;
  	HeapTuple	newtup;
--- 886,892 ----
   * Rename database
   */
  void
! RenameDatabase(const char *oldname, const char *newname, bool force)
  {
  	Oid			db_id;
  	HeapTuple	newtup;
*************** RenameDatabase(const char *oldname, cons
*** 927,954 ****
  				 errmsg("database \"%s\" already exists", newname)));
  
  	/*
  	 * XXX Client applications probably store the current database somewhere,
  	 * so renaming it could cause confusion.  On the other hand, there may not
  	 * be an actual problem besides a little confusion, so think about this
  	 * and decide.
  	 */
! 	if (db_id == MyDatabaseId)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 				 errmsg("current database cannot be renamed")));
  
  	/*
! 	 * Make sure the database does not have active sessions.  This is the same
! 	 * concern as above, but applied to other sessions.
  	 *
  	 * As in CREATE DATABASE, check this after other error conditions.
  	 */
! 	if (CountOtherDBBackends(db_id, &notherbackends, &npreparedxacts))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_OBJECT_IN_USE),
! 				 errmsg("database \"%s\" is being accessed by other users",
! 						oldname),
! 				 errdetail_busy_db(notherbackends, npreparedxacts)));
  
  	/* rename */
  	newtup = SearchSysCacheCopy1(DATABASEOID, ObjectIdGetDatum(db_id));
--- 927,958 ----
  				 errmsg("database \"%s\" already exists", newname)));
  
  	/*
+ 	 * Don't allow current database to be renamed unless force was specified.
  	 * XXX Client applications probably store the current database somewhere,
  	 * so renaming it could cause confusion.  On the other hand, there may not
  	 * be an actual problem besides a little confusion, so think about this
  	 * and decide.
  	 */
! 	if (!force)
! 		if (db_id == MyDatabaseId)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 					 errmsg("current database cannot be renamed")));
  
  	/*
! 	 * Make sure the database does not have active sessions unless force was
! 	 * specified.  This is the same concern as above, but applied to other 
! 	 * sessions.
  	 *
  	 * As in CREATE DATABASE, check this after other error conditions.
  	 */
! 	if (!force)
! 		if (CountOtherDBBackends(db_id, &notherbackends, &npreparedxacts))
! 			ereport(ERROR,
! 					(errcode(ERRCODE_OBJECT_IN_USE),
! 					 errmsg("database \"%s\" is being accessed by other users",
! 							oldname),
! 					 errdetail_busy_db(notherbackends, npreparedxacts)));
  
  	/* rename */
  	newtup = SearchSysCacheCopy1(DATABASEOID, ObjectIdGetDatum(db_id));
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index c135465..d3ad439
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** reindex_type:
*** 6404,6412 ****
  			| TABLE									{ $$ = OBJECT_TABLE; }
  		;
  
- opt_force:	FORCE									{  $$ = TRUE; }
- 			| /* EMPTY */							{  $$ = FALSE; }
- 		;
  
  
  /*****************************************************************************
--- 6404,6409 ----
*************** RenameStmt: ALTER AGGREGATE func_name ag
*** 6440,6451 ****
  					n->newname = $6;
  					$$ = (Node *)n;
  				}
! 			| ALTER DATABASE database_name RENAME TO database_name
  				{
  					RenameStmt *n = makeNode(RenameStmt);
  					n->renameType = OBJECT_DATABASE;
  					n->subname = $3;
  					n->newname = $6;
  					$$ = (Node *)n;
  				}
  			| ALTER FUNCTION function_with_argtypes RENAME TO name
--- 6437,6449 ----
  					n->newname = $6;
  					$$ = (Node *)n;
  				}
! 			| ALTER DATABASE database_name RENAME TO database_name opt_force
  				{
  					RenameStmt *n = makeNode(RenameStmt);
  					n->renameType = OBJECT_DATABASE;
  					n->subname = $3;
  					n->newname = $6;
+ 					n->force = $7;
  					$$ = (Node *)n;
  				}
  			| ALTER FUNCTION function_with_argtypes RENAME TO name
*************** opt_column: COLUMN									{ $$ = COLUMN
*** 6675,6680 ****
--- 6673,6681 ----
  opt_set_data: SET DATA_P							{ $$ = 1; }
  			| /*EMPTY*/								{ $$ = 0; }
  		;
+ opt_force:	FORCE									{  $$ = TRUE; }
+ 			| /* EMPTY */							{  $$ = FALSE; }
+ 		;
  
  /*****************************************************************************
   *
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
new file mode 100644
index 21dacff..68141b8
*** a/src/include/commands/dbcommands.h
--- b/src/include/commands/dbcommands.h
*************** typedef struct xl_dbase_drop_rec
*** 54,60 ****
  
  extern void createdb(const CreatedbStmt *stmt);
  extern void dropdb(const char *dbname, bool missing_ok);
! extern void RenameDatabase(const char *oldname, const char *newname);
  extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel);
  extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
  extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId);
--- 54,60 ----
  
  extern void createdb(const CreatedbStmt *stmt);
  extern void dropdb(const char *dbname, bool missing_ok);
! extern void RenameDatabase(const char *oldname, const char *newname, bool force);
  extern void AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel);
  extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
  extern void AlterDatabaseOwner(const char *dbname, Oid newOwnerId);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
new file mode 100644
index af6565e..8d30af9
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef struct RenameStmt
*** 2193,2198 ****
--- 2193,2199 ----
  								 * trigger, etc) */
  	char	   *newname;		/* the new name */
  	DropBehavior behavior;		/* RESTRICT or CASCADE behavior */
+ 	bool	   force;			/* with prejudice */
  } RenameStmt;
  
  /* ----------------------