*** ./doc/src/sgml/ref/alter_database.sgml.orig	2004-03-28 16:10:19.000000000 -0300
--- ./doc/src/sgml/ref/alter_database.sgml	2004-03-28 16:56:27.000000000 -0300
***************
*** 23,28 ****
--- 23,30 ----
  ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> SET <replaceable>parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
  ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RESET <replaceable>parameter</replaceable>
  
+ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+ 
  ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>newname</replaceable>
  </synopsis>
   </refsynopsisdiv>
***************
*** 54,59 ****
--- 56,67 ----
     be renamed.  (Connect to a different database if you need to do
     that.)
    </para>
+ 
+   <para>
+    The fourth form changes the owner of the database.  Only a superuser
+    can change the database's owner. The new owner does not need any
+    privilege.
+   </para>
   </refsect1>
  
   <refsect1>
*** ./src/backend/commands/dbcommands.c.orig	2004-03-28 16:10:36.000000000 -0300
--- ./src/backend/commands/dbcommands.c	2004-03-28 16:56:27.000000000 -0300
***************
*** 774,779 ****
--- 774,825 ----
  }
  
  
+ /*
+  * ALTER DATABASE name OWNER TO newowner
+  */
+ void
+ AlterDatabaseOwner(const char *dbname, const char *newowner)
+ {
+ 	AclId		newdatdba;
+ 	HeapTuple	tuple,
+ 				newtuple;
+ 	Relation	rel;
+ 	ScanKeyData scankey;
+ 	SysScanDesc scan;
+ 
+ 	rel = heap_openr(DatabaseRelationName, RowExclusiveLock);
+ 	ScanKeyInit(&scankey,
+ 				Anum_pg_database_datname,
+ 				BTEqualStrategyNumber, F_NAMEEQ,
+ 				NameGetDatum(dbname));
+ 	scan = systable_beginscan(rel, DatabaseNameIndex, true,
+ 							  SnapshotNow, 1, &scankey);
+ 	tuple = systable_getnext(scan);
+ 	if (!HeapTupleIsValid(tuple))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_DATABASE),
+ 				 errmsg("database \"%s\" does not exist", dbname)));
+ 
+ 	/* obtain sysid of proposed owner */
+ 	newdatdba = get_usesysid(newowner); /* will ereport if no such user */
+ 
+ 	/* changing owner's database for someone else: must be superuser */
+ 	/* note that the someone else need not have any permissions */
+ 	if (!superuser())
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 				 errmsg("must be superuser to change owner's database for another user")));
+ 
+ 	/* change owner */
+ 	newtuple = heap_copytuple(tuple);
+ 	((Form_pg_database) GETSTRUCT(newtuple))->datdba = newdatdba;
+ 	simple_heap_update(rel, &tuple->t_self, newtuple);
+ 	CatalogUpdateIndexes(rel, newtuple);
+ 
+ 	systable_endscan(scan);
+ 	heap_close(rel, NoLock);
+ }
+ 
  
  /*
   * Helper functions
*** ./src/backend/nodes/copyfuncs.c.orig	2004-03-28 16:10:57.000000000 -0300
--- ./src/backend/nodes/copyfuncs.c	2004-03-29 23:04:18.000000000 -0300
***************
*** 2118,2123 ****
--- 2118,2134 ----
  	return newnode;
  }
  
+ static AlterDbOwnerStmt *
+ _copyAlterDbOwnerStmt(AlterDbOwnerStmt *from)
+ {
+ 	AlterDbOwnerStmt *newnode = makeNode(AlterDbOwnerStmt);
+ 
+ 	COPY_STRING_FIELD(dbname);
+ 	COPY_STRING_FIELD(uname);
+ 
+ 	return newnode;
+ }
+ 
  static AlterDatabaseSetStmt *
  _copyAlterDatabaseSetStmt(AlterDatabaseSetStmt *from)
  {
***************
*** 2872,2877 ****
--- 2883,2891 ----
  		case T_CreatedbStmt:
  			retval = _copyCreatedbStmt(from);
  			break;
+ 		case T_AlterDbOwnerStmt:
+ 			retval = _copyAlterDbOwnerStmt(from);
+ 			break;
  		case T_AlterDatabaseSetStmt:
  			retval = _copyAlterDatabaseSetStmt(from);
  			break;
*** ./src/backend/nodes/equalfuncs.c.orig	2004-03-28 16:11:25.000000000 -0300
--- ./src/backend/nodes/equalfuncs.c	2004-03-29 23:05:06.000000000 -0300
***************
*** 1085,1090 ****
--- 1085,1099 ----
  }
  
  static bool
+ _equalAlterDbOwnerStmt(AlterDbOwnerStmt *a, AlterDbOwnerStmt *b)
+ {
+ 	COMPARE_STRING_FIELD(dbname);
+ 	COMPARE_STRING_FIELD(uname);
+ 
+ 	return true;
+ }
+ 
+ static bool
  _equalAlterDatabaseSetStmt(AlterDatabaseSetStmt *a, AlterDatabaseSetStmt *b)
  {
  	COMPARE_STRING_FIELD(dbname);
***************
*** 1945,1950 ****
--- 1954,1962 ----
  		case T_CreatedbStmt:
  			retval = _equalCreatedbStmt(a, b);
  			break;
+ 		case T_AlterDbOwnerStmt:
+ 			retval = _equalAlterDbOwnerStmt(a, b);
+ 			break;
  		case T_AlterDatabaseSetStmt:
  			retval = _equalAlterDatabaseSetStmt(a, b);
  			break;
*** ./src/backend/parser/gram.y.orig	2004-03-28 16:11:41.000000000 -0300
--- ./src/backend/parser/gram.y	2004-03-29 22:55:35.000000000 -0300
***************
*** 154,159 ****
--- 154,160 ----
  		VariableResetStmt VariableSetStmt VariableShowStmt
  		ViewStmt CheckPointStmt CreateConversionStmt
  		DeallocateStmt PrepareStmt ExecuteStmt
+ 		AlterDbOwnerStmt
  
  %type <node>	select_no_parens select_with_parens select_clause
  				simple_select
***************
*** 483,489 ****
  		;
  
  stmt :
! 			AlterDatabaseSetStmt
  			| AlterDomainStmt
  			| AlterGroupStmt
  			| AlterSeqStmt
--- 484,491 ----
  		;
  
  stmt :
! 			AlterDbOwnerStmt
! 			| AlterDatabaseSetStmt
  			| AlterDomainStmt
  			| AlterGroupStmt
  			| AlterSeqStmt
***************
*** 3877,3882 ****
--- 3879,3893 ----
   *
   *****************************************************************************/
  
+ AlterDbOwnerStmt: ALTER DATABASE database_name OWNER TO UserId
+ 				{
+ 					AlterDbOwnerStmt *n = makeNode(AlterDbOwnerStmt);
+ 					n->dbname = $3;
+ 					n->uname = $6;
+ 					$$ = (Node *)n;
+ 				}
+ 		;
+ 
  AlterDatabaseSetStmt:
  			ALTER DATABASE database_name SET set_rest
  				{
*** ./src/backend/tcop/utility.c.orig	2004-03-28 16:11:59.000000000 -0300
--- ./src/backend/tcop/utility.c	2004-03-29 22:58:43.000000000 -0300
***************
*** 217,222 ****
--- 217,223 ----
  	switch (nodeTag(parsetree))
  	{
  		case T_AlterDatabaseSetStmt:
+ 		case T_AlterDbOwnerStmt:
  		case T_AlterDomainStmt:
  		case T_AlterGroupStmt:
  		case T_AlterSeqStmt:
***************
*** 775,780 ****
--- 776,788 ----
  			createdb((CreatedbStmt *) parsetree);
  			break;
  
+ 		case T_AlterDbOwnerStmt:
+ 			{
+ 				AlterDbOwnerStmt *stmt = (AlterDbOwnerStmt *) parsetree;
+ 				AlterDatabaseOwner(stmt->dbname, stmt->uname);
+ 			}
+ 			break;
+ 
  		case T_AlterDatabaseSetStmt:
  			AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
  			break;
***************
*** 1403,1408 ****
--- 1411,1420 ----
  			tag = "CREATE DATABASE";
  			break;
  
+ 		case T_AlterDbOwnerStmt:
+ 			tag = "ALTER DATABASE";
+ 			break;
+ 
  		case T_AlterDatabaseSetStmt:
  			tag = "ALTER DATABASE";
  			break;
*** ./src/bin/psql/tab-complete.c.orig	2004-03-28 16:12:48.000000000 -0300
--- ./src/bin/psql/tab-complete.c	2004-03-28 16:56:27.000000000 -0300
***************
*** 642,648 ****
  			 strcasecmp(prev2_wd, "DATABASE") == 0)
  	{
  		static const char *const list_ALTERDATABASE[] =
! 		{"RESET", "SET", "RENAME TO", NULL};
  
  		COMPLETE_WITH_LIST(list_ALTERDATABASE);
  	}
--- 642,648 ----
  			 strcasecmp(prev2_wd, "DATABASE") == 0)
  	{
  		static const char *const list_ALTERDATABASE[] =
! 		{"RESET", "SET", "OWNER TO", "RENAME TO", NULL};
  
  		COMPLETE_WITH_LIST(list_ALTERDATABASE);
  	}
*** ./src/include/commands/dbcommands.h.orig	2004-03-28 16:13:07.000000000 -0300
--- ./src/include/commands/dbcommands.h	2004-03-28 16:56:27.000000000 -0300
***************
*** 20,25 ****
--- 20,26 ----
  extern void dropdb(const char *dbname);
  extern void RenameDatabase(const char *oldname, const char *newname);
  extern void AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
+ extern void AlterDatabaseOwner(const char *dbname, const char *uname);
  
  extern Oid	get_database_oid(const char *dbname);
  extern char *get_database_name(Oid dbid);
*** ./src/include/nodes/nodes.h.orig	2004-03-28 16:13:30.000000000 -0300
--- ./src/include/nodes/nodes.h	2004-03-29 23:00:46.000000000 -0300
***************
*** 260,265 ****
--- 260,266 ----
  	T_ExecuteStmt,
  	T_DeallocateStmt,
  	T_DeclareCursorStmt,
+ 	T_AlterDbOwnerStmt,
  
  	T_A_Expr = 800,
  	T_ColumnRef,
*** ./src/include/nodes/parsenodes.h.orig	2004-03-28 16:13:47.000000000 -0300
--- ./src/include/nodes/parsenodes.h	2004-03-29 23:02:26.000000000 -0300
***************
*** 1506,1511 ****
--- 1506,1518 ----
   *	Alter Database
   * ----------------------
   */
+ typedef struct AlterDbOwnerStmt
+ {
+ 	NodeTag		type;
+ 	char	   *dbname;
+ 	char	   *uname;
+ } AlterDbOwnerStmt;
+ 
  typedef struct AlterDatabaseSetStmt
  {
  	NodeTag		type;
*** ./src/interfaces/ecpg/preproc/preproc.y.orig	2004-03-28 16:56:15.000000000 -0300
--- ./src/interfaces/ecpg/preproc/preproc.y	2004-03-29 22:17:00.000000000 -0300
***************
*** 516,522 ****
  %type  <str>	iso_level type_list CharacterWithLength ConstCharacter
  %type  <str>	CharacterWithoutLength BitWithLength BitWithoutLength
  %type  <str>	ConstBit GenericType TableFuncElementList opt_analyze
! %type  <str>	opt_sort_clause transaction_access_mode
  
  %type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen
  %type  <str>	indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into 
--- 516,522 ----
  %type  <str>	iso_level type_list CharacterWithLength ConstCharacter
  %type  <str>	CharacterWithoutLength BitWithLength BitWithoutLength
  %type  <str>	ConstBit GenericType TableFuncElementList opt_analyze
! %type  <str>	opt_sort_clause transaction_access_mode AlterDatabaseOwnerStmt
  
  %type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen
  %type  <str>	indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into 
***************
*** 592,597 ****
--- 592,598 ----
  		};
  
  stmt:  AlterDatabaseSetStmt		{ output_statement($1, 0, connection); }
+ 		| AlterDatabaseOwnerStmt	{ output_statement($1, 0, connection); }
  		| AlterDomainStmt	{ output_statement($1, 0, connection); }
  		| AlterGroupStmt	{ output_statement($1, 0, connection); }
  		| AlterSeqStmt		{ output_statement($1, 0, connection); }
***************
*** 2495,2500 ****
--- 2496,2503 ----
   *
   *****************************************************************************/
  
+ AlterDatabaseOwnerStmt: ALTER DATABASE database_name OWNER TO UserId
+ 		      	{ $$ = cat_str(4, make_str("alter database"), $3, make_str("owner to"), $6); }
  AlterDatabaseSetStmt: ALTER DATABASE database_name SET set_rest
  			{ $$ = cat_str(4, make_str("alter database"), $3, make_str("set"), $5); }
  		| ALTER DATABASE database_name VariableResetStmt
