From cfbfdc557d166ec559668d18d9769544f3c4fbbc Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Wed, 26 May 2004 13:57:04 +0000
Subject: [PATCH] This patch implement the TODO [ALTER DATABASE foo OWNER TO
 bar]. It was necessary to touch in grammar and create a new node to make home
 to the new syntax. The command is also supported in E CPG. Doc updates are
 attached too. Only superusers can change the owner of the database. New
 owners don't need any aditional privileges.

Euler Taveira de Oliveira
---
 doc/src/sgml/ref/alter_database.sgml  |  9 ++++-
 src/backend/commands/dbcommands.c     | 48 ++++++++++++++++++++++++++-
 src/backend/nodes/copyfuncs.c         | 16 ++++++++-
 src/backend/nodes/equalfuncs.c        | 14 +++++++-
 src/backend/parser/gram.y             | 15 +++++++--
 src/backend/tcop/utility.c            | 14 +++++++-
 src/bin/psql/tab-complete.c           |  4 +--
 src/include/commands/dbcommands.h     |  3 +-
 src/include/nodes/nodes.h             |  3 +-
 src/include/nodes/parsenodes.h        |  9 ++++-
 src/interfaces/ecpg/preproc/preproc.y |  7 ++--
 11 files changed, 128 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/ref/alter_database.sgml b/doc/src/sgml/ref/alter_database.sgml
index aa34fac9f05..86093712f88 100644
--- a/doc/src/sgml/ref/alter_database.sgml
+++ b/doc/src/sgml/ref/alter_database.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_database.sgml,v 1.11 2003/11/29 19:51:38 pgsql Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_database.sgml,v 1.12 2004/05/26 13:56:42 momjian Exp $
 PostgreSQL documentation
 -->
 
@@ -23,6 +23,8 @@ PostgreSQL documentation
 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,6 +56,11 @@ ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> RENAME TO <repl
    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.
+  </para>
  </refsect1>
 
  <refsect1>
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 9114983e75d..02c1bf8e204 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.133 2004/05/26 04:41:10 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.134 2004/05/26 13:56:45 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -776,6 +776,52 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
 }
 
 
+/*
+ * 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
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 21cef887922..a7ba5d04820 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.282 2004/05/26 04:41:18 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.283 2004/05/26 13:56:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2068,6 +2068,17 @@ _copyCreatedbStmt(CreatedbStmt *from)
 	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)
 {
@@ -2860,6 +2871,9 @@ copyObject(void *from)
 		case T_CreatedbStmt:
 			retval = _copyCreatedbStmt(from);
 			break;
+		case T_AlterDbOwnerStmt:
+			retval = _copyAlterDbOwnerStmt(from);
+			break;
 		case T_AlterDatabaseSetStmt:
 			retval = _copyAlterDatabaseSetStmt(from);
 			break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 236061eee2a..97701a02a1e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.221 2004/05/26 04:41:19 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.222 2004/05/26 13:56:47 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1099,6 +1099,15 @@ _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
 	return true;
 }
 
+static bool
+_equalAlterDbOwnerStmt(AlterDbOwnerStmt *a, AlterDbOwnerStmt *b)
+{
+	COMPARE_STRING_FIELD(dbname);
+	COMPARE_STRING_FIELD(uname);
+
+	return true;
+}
+
 static bool
 _equalAlterDatabaseSetStmt(AlterDatabaseSetStmt *a, AlterDatabaseSetStmt *b)
 {
@@ -2005,6 +2014,9 @@ equal(void *a, void *b)
 		case T_CreatedbStmt:
 			retval = _equalCreatedbStmt(a, b);
 			break;
+		case T_AlterDbOwnerStmt:
+			retval = _equalAlterDbOwnerStmt(a, b);
+			break;
 		case T_AlterDatabaseSetStmt:
 			retval = _equalAlterDatabaseSetStmt(a, b);
 			break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 654341ddfe8..b20f92ba7b2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.455 2004/05/26 04:41:29 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.456 2004/05/26 13:56:51 momjian Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -152,6 +152,7 @@ static void doNegateFloat(Value *v);
 		VariableResetStmt VariableSetStmt VariableShowStmt
 		ViewStmt CheckPointStmt CreateConversionStmt
 		DeallocateStmt PrepareStmt ExecuteStmt
+		AlterDbOwnerStmt
 
 %type <node>	select_no_parens select_with_parens select_clause
 				simple_select
@@ -486,7 +487,8 @@ stmtmulti:	stmtmulti ';' stmt
 		;
 
 stmt :
-			AlterDatabaseSetStmt
+			AlterDbOwnerStmt
+			| AlterDatabaseSetStmt
 			| AlterDomainStmt
 			| AlterGroupStmt
 			| AlterSeqStmt
@@ -3918,6 +3920,15 @@ opt_equal:	'='										{}
  *
  *****************************************************************************/
 
+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
 				{
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index fd9427c203d..39b69c6248c 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.216 2004/05/26 04:41:35 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.217 2004/05/26 13:56:54 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -234,6 +234,7 @@ check_xact_readonly(Node *parsetree)
 	switch (nodeTag(parsetree))
 	{
 		case T_AlterDatabaseSetStmt:
+		case T_AlterDbOwnerStmt:
 		case T_AlterDomainStmt:
 		case T_AlterGroupStmt:
 		case T_AlterSeqStmt:
@@ -675,6 +676,13 @@ ProcessUtility(Node *parsetree,
 			createdb((CreatedbStmt *) parsetree);
 			break;
 
+		case T_AlterDbOwnerStmt:
+			{
+				AlterDbOwnerStmt *stmt = (AlterDbOwnerStmt *) parsetree;
+				AlterDatabaseOwner(stmt->dbname, stmt->uname);
+			}
+			break;
+
 		case T_AlterDatabaseSetStmt:
 			AlterDatabaseSet((AlterDatabaseSetStmt *) parsetree);
 			break;
@@ -1303,6 +1311,10 @@ CreateCommandTag(Node *parsetree)
 			tag = "CREATE DATABASE";
 			break;
 
+		case T_AlterDbOwnerStmt:
+			tag = "ALTER DATABASE";
+			break;
+
 		case T_AlterDatabaseSetStmt:
 			tag = "ALTER DATABASE";
 			break;
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 2eb2f19f09f..f26c3e75337 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2003, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.106 2004/05/12 13:38:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.107 2004/05/26 13:56:55 momjian Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -642,7 +642,7 @@ psql_completion(char *text, int start, int end)
 			 pg_strcasecmp(prev2_wd, "DATABASE") == 0)
 	{
 		static const char *const list_ALTERDATABASE[] =
-		{"RESET", "SET", "RENAME TO", NULL};
+		{"RESET", "SET", "OWNER TO", "RENAME TO", NULL};
 
 		COMPLETE_WITH_LIST(list_ALTERDATABASE);
 	}
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index 6cb47f6772f..30b73d4daf1 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/dbcommands.h,v 1.30 2003/11/29 22:40:59 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/commands/dbcommands.h,v 1.31 2004/05/26 13:56:59 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -20,6 +20,7 @@ extern void createdb(const CreatedbStmt *stmt);
 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);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 6c37048229a..6feedf6762c 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.155 2004/05/26 04:41:45 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.156 2004/05/26 13:57:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -266,6 +266,7 @@ typedef enum NodeTag
 	T_ExecuteStmt,
 	T_DeallocateStmt,
 	T_DeclareCursorStmt,
+	T_AlterDbOwnerStmt,
 
 	T_A_Expr = 800,
 	T_ColumnRef,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 8eceb6e59cb..2943d0e9e08 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.255 2004/05/05 04:48:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.256 2004/05/26 13:57:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1523,6 +1523,13 @@ typedef struct CreatedbStmt
  *	Alter Database
  * ----------------------
  */
+typedef struct AlterDbOwnerStmt
+{
+	NodeTag		type;
+	char	   *dbname;
+	char	   *uname;
+} AlterDbOwnerStmt;
+
 typedef struct AlterDatabaseSetStmt
 {
 	NodeTag		type;
diff --git a/src/interfaces/ecpg/preproc/preproc.y b/src/interfaces/ecpg/preproc/preproc.y
index d12576f8035..7656521adbd 100644
--- a/src/interfaces/ecpg/preproc/preproc.y
+++ b/src/interfaces/ecpg/preproc/preproc.y
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.283 2004/05/21 13:50:12 meskes Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/preproc.y,v 1.284 2004/05/26 13:57:04 momjian Exp $ */
 
 /* Copyright comment */
 %{
@@ -519,7 +519,6 @@ add_additional_variables(char *name, bool insert)
 %type  <str>	CharacterWithoutLength BitWithLength BitWithoutLength
 %type  <str>	ConstBit GenericType TableFuncElementList opt_analyze
 %type  <str>	opt_sort_clause transaction_access_mode subquery_Op
-
 %type  <str>	ECPGWhenever ECPGConnect connection_target ECPGOpen
 %type  <str>	indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into 
 %type  <str>	storage_declaration storage_clause opt_initializer c_anything
@@ -544,6 +543,7 @@ add_additional_variables(char *name, bool insert)
 %type  <str>	inf_val_list inf_col_list using_descriptor into_descriptor 
 %type  <str>	ecpg_into_using prepared_name struct_union_type_with_symbol
 %type  <str>	ECPGunreserved ECPGunreserved_interval cvariable
+%type  <str>	AlterDatabaseOwnerStmt
 
 %type  <struct_union> s_struct_union_symbol
 
@@ -594,6 +594,7 @@ opt_at: AT connection_target
 		};
 
 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); }
@@ -2535,6 +2536,8 @@ opt_equal: '='					{ $$ = make_str("="); }
  *
  *****************************************************************************/
 
+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
-- 
GitLab