*** ./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 name SET parameter { TO | = } { value | DEFAULT } ALTER DATABASE name RESET parameter + ALTER DATABASE name OWNER TO new_owner + ALTER DATABASE name RENAME TO newname *************** *** 54,59 **** --- 56,67 ---- be renamed. (Connect to a different database if you need to do that.) + + + 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. + *** ./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 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 iso_level type_list CharacterWithLength ConstCharacter %type CharacterWithoutLength BitWithLength BitWithoutLength %type ConstBit GenericType TableFuncElementList opt_analyze ! %type opt_sort_clause transaction_access_mode %type ECPGWhenever ECPGConnect connection_target ECPGOpen %type indicator ECPGExecute ECPGPrepare ecpg_using ecpg_into --- 516,522 ---- %type iso_level type_list CharacterWithLength ConstCharacter %type CharacterWithoutLength BitWithLength BitWithoutLength %type ConstBit GenericType TableFuncElementList opt_analyze ! %type opt_sort_clause transaction_access_mode AlterDatabaseOwnerStmt %type ECPGWhenever ECPGConnect connection_target ECPGOpen %type 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