diff --git a/doc/src/sgml/ref/alter_database.sgml b/doc/src/sgml/ref/alter_database.sgml index 7db878c..48cd840 100644 --- a/doc/src/sgml/ref/alter_database.sgml +++ b/doc/src/sgml/ref/alter_database.sgml @@ -31,14 +31,14 @@ ALTER DATABASE name [ [ WITH ] name RENAME TO new_name -ALTER DATABASE name OWNER TO { new_owner | CURRENT_USER | SESSION_USER } +ALTER DATABASE { name | CURRENT_DATABASE } OWNER TO { new_owner | CURRENT_USER | SESSION_USER } ALTER DATABASE name SET TABLESPACE new_tablespace -ALTER DATABASE name SET configuration_parameter { TO | = } { value | DEFAULT } -ALTER DATABASE name SET configuration_parameter FROM CURRENT -ALTER DATABASE name RESET configuration_parameter -ALTER DATABASE name RESET ALL +ALTER DATABASE { name | CURRENT_DATABASE } SET configuration_parameter { TO | = } { value | DEFAULT } +ALTER DATABASE { name | CURRENT_DATABASE } SET configuration_parameter FROM CURRENT +ALTER DATABASE { name | CURRENT_DATABASE } RESET configuration_parameter +ALTER DATABASE { name | CURRENT_DATABASE } RESET ALL diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml index 573a3e8..cf7b575 100644 --- a/doc/src/sgml/ref/alter_role.sgml +++ b/doc/src/sgml/ref/alter_role.sgml @@ -38,16 +38,21 @@ ALTER ROLE role_specification [ WIT ALTER ROLE name RENAME TO new_name -ALTER ROLE { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT } -ALTER ROLE { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT -ALTER ROLE { role_specification | ALL } [ IN DATABASE database_name ] RESET configuration_parameter -ALTER ROLE { role_specification | ALL } [ IN DATABASE database_name ] RESET ALL +ALTER ROLE { role_specification | ALL } [ IN DATABASE database_specification ] SET configuration_parameter { TO | = } { value | DEFAULT } +ALTER ROLE { role_specification | ALL } [ IN DATABASE database_specification ] SET configuration_parameter FROM CURRENT +ALTER ROLE { role_specification | ALL } [ IN DATABASE database_specification ] RESET configuration_parameter +ALTER ROLE { role_specification | ALL } [ IN DATABASE database_specification ] RESET ALL where role_specification can be: role_name | CURRENT_USER | SESSION_USER + +where database_specification can be: + + database_name + | CURRENT_DATABASE diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml index 8f50f43..cbf8163 100644 --- a/doc/src/sgml/ref/alter_user.sgml +++ b/doc/src/sgml/ref/alter_user.sgml @@ -38,16 +38,21 @@ ALTER USER role_specification [ WIT ALTER USER name RENAME TO new_name -ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT } -ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT -ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] RESET configuration_parameter -ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] RESET ALL +ALTER USER { role_specification | ALL } [ IN DATABASE database_specification ] SET configuration_parameter { TO | = } { value | DEFAULT } +ALTER USER { role_specification | ALL } [ IN DATABASE database_specification ] SET configuration_parameter FROM CURRENT +ALTER USER { role_specification | ALL } [ IN DATABASE database_specification ] RESET configuration_parameter +ALTER USER { role_specification | ALL } [ IN DATABASE database_specification ] RESET ALL where role_specification can be: role_name | CURRENT_USER | SESSION_USER + +where database_specification can be: + + database_name + | CURRENT_DATABASE diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml index 965c5a4..025b672 100644 --- a/doc/src/sgml/ref/comment.sgml +++ b/doc/src/sgml/ref/comment.sgml @@ -31,7 +31,7 @@ COMMENT ON CONSTRAINT constraint_name ON table_name | CONSTRAINT constraint_name ON DOMAIN domain_name | CONVERSION object_name | - DATABASE object_name | + DATABASE database_specification | DOMAIN object_name | EXTENSION object_name | EVENT TRIGGER object_name | @@ -73,6 +73,11 @@ COMMENT ON * | [ argmode ] [ argname ] argtype [ , ... ] | [ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ] argtype [ , ... ] + +where database_specification is: + + database_name + | CURRENT_DATABASE @@ -315,6 +320,7 @@ COMMENT ON CONVERSION my_conv IS 'Conversion to UTF8'; COMMENT ON CONSTRAINT bar_col_cons ON bar IS 'Constrains column col'; COMMENT ON CONSTRAINT dom_col_constr ON DOMAIN dom IS 'Constrains col of domain'; COMMENT ON DATABASE my_database IS 'Development Database'; +COMMENT ON DATABASE current_database IS 'Comment on current Database'; COMMENT ON DOMAIN my_domain IS 'Email Address Domain'; COMMENT ON EXTENSION hstore IS 'implements the hstore data type'; COMMENT ON FOREIGN DATA WRAPPER mywrapper IS 'my foreign data wrapper'; diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index ff64c7a..880a30d 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -39,9 +39,14 @@ GRANT { { USAGE | SELECT | UPDATE } TO role_specification [, ...] [ WITH GRANT OPTION ] GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] } - ON DATABASE database_name [, ...] + ON DATABASE database_specification [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] +where database_specification can be: + + database_name + | CURRENT_DATABASE + GRANT { USAGE | ALL [ PRIVILEGES ] } ON DOMAIN domain_name [, ...] TO role_specification [, ...] [ WITH GRANT OPTION ] diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index 7018202..f7a3055 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -46,10 +46,15 @@ REVOKE [ GRANT OPTION FOR ] REVOKE [ GRANT OPTION FOR ] { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] } - ON DATABASE database_name [, ...] + ON DATABASE database_specification [, ...] FROM { [ GROUP ] role_name | PUBLIC } [, ...] [ CASCADE | RESTRICT ] +where database_specification can be: + + database_name + | CURRENT_DATABASE + REVOKE [ GRANT OPTION FOR ] { USAGE | ALL [ PRIVILEGES ] } ON DOMAIN domain_name [, ...] diff --git a/doc/src/sgml/ref/security_label.sgml b/doc/src/sgml/ref/security_label.sgml index e9cfdec..c582c96 100644 --- a/doc/src/sgml/ref/security_label.sgml +++ b/doc/src/sgml/ref/security_label.sgml @@ -26,7 +26,7 @@ SECURITY LABEL [ FOR provider ] ON TABLE object_name | COLUMN table_name.column_name | AGGREGATE aggregate_name ( aggregate_signature ) | - DATABASE object_name | + DATABASE database_specification | DOMAIN object_name | EVENT TRIGGER object_name | FOREIGN TABLE object_name @@ -51,6 +51,11 @@ SECURITY LABEL [ FOR provider ] ON * | [ argmode ] [ argname ] argtype [ , ... ] | [ [ argmode ] [ argname ] argtype [ , ... ] ] ORDER BY [ argmode ] [ argname ] argtype [ , ... ] + +where database_specification is: + + database_name + | CURRENT_DATABASE diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index fac8061..68d7c63 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -65,6 +65,7 @@ #include "foreign/foreign.h" #include "miscadmin.h" #include "nodes/makefuncs.h" +#include "nodes/parsenodes.h" #include "parser/parse_func.h" #include "parser/parse_type.h" #include "utils/acl.h" @@ -657,10 +658,10 @@ objectNamesToOids(GrantObjectType objtype, List *objnames) case ACL_OBJECT_DATABASE: foreach(cell, objnames) { - char *dbname = strVal(lfirst(cell)); + DbSpec *dbspec = lfirst(cell); Oid dbid; - dbid = get_database_oid(dbname, false); + dbid = get_dbspec_oid(dbspec,false); objects = lappend_oid(objects, dbid); } break; diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index bc999ca..a070930 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -868,6 +868,10 @@ get_object_address(ObjectType objtype, Node *object, } break; case OBJECT_DATABASE: + address.classId = DatabaseRelationId; + address.objectId = get_dbspec_oid((DbSpec *)object, missing_ok); + address.objectSubId = 0; + break; case OBJECT_EXTENSION: case OBJECT_TABLESPACE: case OBJECT_ROLE: @@ -2247,7 +2251,7 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, case OBJECT_DATABASE: if (!pg_database_ownercheck(address.objectId, roleid)) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - strVal((Value *) object)); + get_dbspec_name((DbSpec *)object)); break; case OBJECT_TYPE: case OBJECT_DOMAIN: diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 3995c5e..5f9dd9f 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -806,7 +806,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt) switch (stmt->objectType) { case OBJECT_DATABASE: - return AlterDatabaseOwner(strVal((Value *) stmt->object), newowner); + return AlterDatabaseOwner((DbSpec *) stmt->object, newowner); case OBJECT_SCHEMA: return AlterSchemaOwner(strVal((Value *) stmt->object), newowner); diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 2f2e69b..64bd07d 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -52,13 +52,15 @@ CommentObject(CommentStmt *stmt) */ if (stmt->objtype == OBJECT_DATABASE) { - char *database = strVal((Value *) stmt->object); - - if (!OidIsValid(get_database_oid(database, true))) + if (!OidIsValid(get_dbspec_oid((DbSpec *)stmt->object, true))) { + char *dbname = NULL; + + dbname = get_dbspec_name((DbSpec *)stmt->object); + ereport(WARNING, (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist", database))); + errmsg("database \"%s\" does not exist", dbname))); return address; } } diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 0b111fc..490f420 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -1413,6 +1413,9 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) Datum new_record[Natts_pg_database]; bool new_record_nulls[Natts_pg_database]; bool new_record_repl[Natts_pg_database]; + char *dbname = NULL; + + dbname = get_dbspec_name(stmt->dbspec); /* Extract options from the statement node tree */ foreach(option, stmt->options) @@ -1477,7 +1480,7 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) parser_errposition(pstate, dtablespace->location))); /* this case isn't allowed within a transaction block */ PreventTransactionChain(isTopLevel, "ALTER DATABASE SET TABLESPACE"); - movedb(stmt->dbname, defGetString(dtablespace)); + movedb(dbname, defGetString(dtablespace)); return InvalidOid; } @@ -1503,20 +1506,20 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) ScanKeyInit(&scankey, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, - CStringGetDatum(stmt->dbname)); + CStringGetDatum(dbname)); scan = systable_beginscan(rel, DatabaseNameIndexId, true, NULL, 1, &scankey); tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), - errmsg("database \"%s\" does not exist", stmt->dbname))); + errmsg("database \"%s\" does not exist", dbname))); dboid = HeapTupleGetOid(tuple); if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->dbname); + dbname); /* * In order to avoid getting locked out and having to go through @@ -1574,7 +1577,9 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel) Oid AlterDatabaseSet(AlterDatabaseSetStmt *stmt) { - Oid datid = get_database_oid(stmt->dbname, false); + Oid datid; + + datid = get_dbspec_oid(stmt->dbspec, false); /* * Obtain a lock on the database and make sure it didn't go away in the @@ -1584,7 +1589,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) if (!pg_database_ownercheck(datid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->dbname); + get_dbspec_name(stmt->dbspec)); AlterSetting(datid, InvalidOid, stmt->setstmt); @@ -1598,7 +1603,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt) * ALTER DATABASE name OWNER TO newowner */ ObjectAddress -AlterDatabaseOwner(const char *dbname, Oid newOwnerId) +AlterDatabaseOwner(const DbSpec *dbspec, Oid newOwnerId) { Oid db_id; HeapTuple tuple; @@ -1607,6 +1612,9 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId) SysScanDesc scan; Form_pg_database datForm; ObjectAddress address; + char *dbname; + + dbname = get_dbspec_name(dbspec); /* * Get the old tuple. We don't need a lock on the database per se, diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index d559c29..9e82d19 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -927,9 +927,9 @@ AlterRoleSet(AlterRoleSetStmt *stmt) } /* look up and lock the database, if specified */ - if (stmt->database != NULL) + if (stmt->dbspec != NULL) { - databaseid = get_database_oid(stmt->database, false); + databaseid = get_dbspec_oid(stmt->dbspec,false); shdepLockAndCheckObject(DatabaseRelationId, databaseid); if (!stmt->role) @@ -940,11 +940,11 @@ AlterRoleSet(AlterRoleSetStmt *stmt) */ if (!pg_database_ownercheck(databaseid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, - stmt->database); + get_dbspec_name(stmt->dbspec)); } } - if (!stmt->role && !stmt->database) + if (!stmt->role && !stmt->dbspec) { /* Must be superuser to alter settings globally. */ if (!superuser()) diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index f646fd9..2558177 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -2320,6 +2320,7 @@ ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op) *op->resnull = fcinfo.isnull; break; case SVFOP_CURRENT_CATALOG: + case SVFOP_CURRENT_DATABASE: InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL); *op->resvalue = current_database(&fcinfo); *op->resnull = fcinfo.isnull; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index ddbbc79..3c3c8be 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2924,6 +2924,18 @@ _copyTriggerTransition(const TriggerTransition *from) return newnode; } +static DbSpec * +_copyDatabaseSpec(const DbSpec *from) +{ + DbSpec *newnode = makeNode(DbSpec); + + COPY_SCALAR_FIELD(dbtype); + COPY_STRING_FIELD(dbname); + COPY_LOCATION_FIELD(location); + + return newnode; +} + static Query * _copyQuery(const Query *from) { @@ -3748,7 +3760,7 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from) { AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt); - COPY_STRING_FIELD(dbname); + COPY_NODE_FIELD(dbspec); COPY_NODE_FIELD(options); return newnode; @@ -3759,7 +3771,7 @@ _copyAlterDatabaseSetStmt(const AlterDatabaseSetStmt *from) { AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt); - COPY_STRING_FIELD(dbname); + COPY_NODE_FIELD(dbspec); COPY_NODE_FIELD(setstmt); return newnode; @@ -4238,7 +4250,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from) AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt); COPY_NODE_FIELD(role); - COPY_STRING_FIELD(database); + COPY_NODE_FIELD(dbspec); COPY_NODE_FIELD(setstmt); return newnode; @@ -5565,7 +5577,9 @@ copyObjectImpl(const void *from) case T_PartitionCmd: retval = _copyPartitionCmd(from); break; - + case T_DbSpec: + retval = _copyDatabaseSpec(from); + break; /* * MISCELLANEOUS NODES */ diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 30ccc9c..d939139 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1645,7 +1645,7 @@ _equalCreatedbStmt(const CreatedbStmt *a, const CreatedbStmt *b) static bool _equalAlterDatabaseStmt(const AlterDatabaseStmt *a, const AlterDatabaseStmt *b) { - COMPARE_STRING_FIELD(dbname); + COMPARE_NODE_FIELD(dbspec); COMPARE_NODE_FIELD(options); return true; @@ -1654,7 +1654,7 @@ _equalAlterDatabaseStmt(const AlterDatabaseStmt *a, const AlterDatabaseStmt *b) static bool _equalAlterDatabaseSetStmt(const AlterDatabaseSetStmt *a, const AlterDatabaseSetStmt *b) { - COMPARE_STRING_FIELD(dbname); + COMPARE_NODE_FIELD(dbspec); COMPARE_NODE_FIELD(setstmt); return true; @@ -2061,7 +2061,7 @@ static bool _equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b) { COMPARE_NODE_FIELD(role); - COMPARE_STRING_FIELD(database); + COMPARE_NODE_FIELD(dbspec); COMPARE_NODE_FIELD(setstmt); return true; @@ -2887,6 +2887,16 @@ _equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b) return true; } +static bool +_equalDatabaseSpec(const DbSpec *a, const DbSpec *b) +{ + COMPARE_SCALAR_FIELD(dbtype); + COMPARE_STRING_FIELD(dbname); + COMPARE_LOCATION_FIELD(location); + + return true; +} + /* * Stuff from pg_list.h */ @@ -3703,6 +3713,9 @@ equal(const void *a, const void *b) case T_PartitionCmd: retval = _equalPartitionCmd(a, b); break; + case T_DbSpec: + retval = _equalDatabaseSpec(a, b); + break; default: elog(ERROR, "unrecognized node type: %d", diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e42b7ca..0bc0c94 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -187,7 +187,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); - +static DbSpec *makeDbSpec(DbSpecType type, int location); %} %pure-parser @@ -241,6 +241,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); PartitionSpec *partspec; PartitionBoundSpec *partboundspec; RoleSpec *rolespec; + DbSpec *dbspec; } %type stmt schema_stmt @@ -316,7 +317,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type opt_type %type foreign_server_version opt_foreign_server_version -%type opt_in_database +%type opt_in_database %type OptSchemaName %type OptSchemaEltList @@ -397,7 +398,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); transform_element_list transform_type_list TriggerTransitions TriggerReferencing publication_name_list - vacuum_relation_list opt_vacuum_relation_list + vacuum_relation_list opt_vacuum_relation_list db_spec_name_list %type group_by_list %type group_by_item empty_grouping_set rollup_clause cube_clause @@ -572,6 +573,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); opt_frame_clause frame_extent frame_bound %type opt_existing_window_name %type opt_if_not_exists +%type db_spec_name %type generated_when override_kind %type PartitionSpec OptPartitionSpec %type part_strategy @@ -617,7 +619,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); COMMITTED CONCURRENTLY CONFIGURATION CONFLICT CONNECTION CONSTRAINT CONSTRAINTS CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CROSS CSV CUBE CURRENT_P - CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA + CURRENT_CATALOG CURRENT_DATABASE CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS @@ -1156,7 +1158,7 @@ AlterRoleStmt: opt_in_database: /* EMPTY */ { $$ = NULL; } - | IN_P DATABASE database_name { $$ = $3; } + | IN_P DATABASE db_spec_name { $$ = $3; } ; AlterRoleSetStmt: @@ -1164,7 +1166,7 @@ AlterRoleSetStmt: { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = $3; - n->database = $4; + n->dbspec = $4; n->setstmt = $5; $$ = (Node *)n; } @@ -1172,7 +1174,7 @@ AlterRoleSetStmt: { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = NULL; - n->database = $4; + n->dbspec = $4; n->setstmt = $5; $$ = (Node *)n; } @@ -1180,7 +1182,7 @@ AlterRoleSetStmt: { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = $3; - n->database = $4; + n->dbspec = $4; n->setstmt = $5; $$ = (Node *)n; } @@ -1188,7 +1190,7 @@ AlterRoleSetStmt: { AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt); n->role = NULL; - n->database = $4; + n->dbspec = $4; n->setstmt = $5; $$ = (Node *)n; } @@ -6400,6 +6402,14 @@ CommentStmt: n->comment = $6; $$ = (Node *) n; } + | COMMENT ON DATABASE db_spec_name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_DATABASE; + n->object = (Node *) $4; + n->comment = $6; + $$ = (Node *) n; + } | COMMENT ON TYPE_P Typename IS comment_text { CommentStmt *n = makeNode(CommentStmt); @@ -6564,7 +6574,6 @@ comment_type_any_name: /* object types taking name */ comment_type_name: ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; } - | DATABASE { $$ = OBJECT_DATABASE; } | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } | EXTENSION { $$ = OBJECT_EXTENSION; } | FOREIGN DATA_P WRAPPER { $$ = OBJECT_FDW; } @@ -6613,6 +6622,16 @@ SecLabelStmt: n->label = $8; $$ = (Node *) n; } + | SECURITY LABEL opt_provider ON DATABASE db_spec_name + IS security_label + { + SecLabelStmt *n = makeNode(SecLabelStmt); + n->provider = $3; + n->objtype = OBJECT_DATABASE; + n->object = (Node *) $6; + n->label = $8; + $$ = (Node *) n; + } | SECURITY LABEL opt_provider ON TYPE_P Typename IS security_label { @@ -6701,8 +6720,7 @@ security_label_type_any_name: /* object types taking name */ security_label_type_name: - DATABASE { $$ = OBJECT_DATABASE; } - | EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } + EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; } | opt_procedural LANGUAGE { $$ = OBJECT_LANGUAGE; } | PUBLICATION { $$ = OBJECT_PUBLICATION; } | ROLE { $$ = OBJECT_ROLE; } @@ -7062,7 +7080,7 @@ privilege_target: n->objs = $2; $$ = n; } - | DATABASE name_list + | DATABASE db_spec_name_list { PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget)); n->targtype = ACL_TARGET_OBJECT; @@ -9287,11 +9305,11 @@ AlterOwnerStmt: ALTER AGGREGATE aggregate_with_argtypes OWNER TO RoleSpec n->newowner = $6; $$ = (Node *)n; } - | ALTER DATABASE database_name OWNER TO RoleSpec + | ALTER DATABASE db_spec_name OWNER TO RoleSpec { AlterOwnerStmt *n = makeNode(AlterOwnerStmt); n->objectType = OBJECT_DATABASE; - n->object = (Node *) makeString($3); + n->object = (Node *) $3; n->newowner = $6; $$ = (Node *)n; } @@ -10113,24 +10131,24 @@ opt_equal: '=' {} *****************************************************************************/ AlterDatabaseStmt: - ALTER DATABASE database_name WITH createdb_opt_list + ALTER DATABASE db_spec_name WITH createdb_opt_list { AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); - n->dbname = $3; + n->dbspec = $3; n->options = $5; $$ = (Node *)n; } - | ALTER DATABASE database_name createdb_opt_list + | ALTER DATABASE db_spec_name createdb_opt_list { AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); - n->dbname = $3; + n->dbspec = $3; n->options = $4; $$ = (Node *)n; } - | ALTER DATABASE database_name SET TABLESPACE name + | ALTER DATABASE db_spec_name SET TABLESPACE name { AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt); - n->dbname = $3; + n->dbspec = $3; n->options = list_make1(makeDefElem("tablespace", (Node *)makeString($6), @6)); $$ = (Node *)n; @@ -10138,10 +10156,10 @@ AlterDatabaseStmt: ; AlterDatabaseSetStmt: - ALTER DATABASE database_name SetResetClause + ALTER DATABASE db_spec_name SetResetClause { AlterDatabaseSetStmt *n = makeNode(AlterDatabaseSetStmt); - n->dbname = $3; + n->dbspec = $3; n->setstmt = $4; $$ = (Node *)n; } @@ -13665,6 +13683,10 @@ func_expr_common_subexpr: { $$ = makeSQLValueFunction(SVFOP_SESSION_USER, -1, @1); } + | CURRENT_DATABASE + { + $$ = makeSQLValueFunction(SVFOP_CURRENT_DATABASE, -1, @1); + } | USER { $$ = makeSQLValueFunction(SVFOP_USER, -1, @1); @@ -14635,7 +14657,36 @@ name_list: name name: ColId { $$ = $1; }; database_name: - ColId { $$ = $1; }; + ColId { $$ = $1; } + | CURRENT_DATABASE + { + ereport(ERROR, + (errcode(ERRCODE_RESERVED_NAME), + errmsg("%s cannot be used as a database name here", + "CURRENT_DATABASE"), + parser_errposition(@1))); + } + ; + +db_spec_name_list: db_spec_name + { $$ = list_make1($1); } + | db_spec_name_list ',' db_spec_name + { $$ = lappend($1, $3); } + ; + + +db_spec_name: + ColId + { + DbSpec *n = makeDbSpec(DBSPEC_CSTRING, @1); + n->dbname = pstrdup($1); + $$ = n; + } + | CURRENT_DATABASE + { + $$ = makeDbSpec(DBSPEC_CURRENT_DATABASE, @1); + } + ; access_method: ColId { $$ = $1; }; @@ -14661,6 +14712,8 @@ func_name: type_function_name $$ = check_func_name(lcons(makeString($1), $2), yyscanner); } + | CURRENT_DATABASE + { $$ = list_make1(makeString("current_database")); } ; @@ -15316,6 +15369,7 @@ reserved_keyword: | CONSTRAINT | CREATE | CURRENT_CATALOG + | CURRENT_DATABASE | CURRENT_DATE | CURRENT_ROLE | CURRENT_TIME @@ -16227,6 +16281,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) return (Node *) s; } +/* makeDbSpec + * Create a DbSpec with the given type + */ +static DbSpec * +makeDbSpec(DbSpecType type, int location) +{ + DbSpec *spec = makeNode(DbSpec); + + spec->dbtype = type; + spec->location = location; + + return spec; +} + /* parser_init() * Initialize to parse one query string */ diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index b2f5e46..74a0ada 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -2334,6 +2334,7 @@ transformSQLValueFunction(ParseState *pstate, SQLValueFunction *svf) case SVFOP_SESSION_USER: case SVFOP_CURRENT_CATALOG: case SVFOP_CURRENT_SCHEMA: + case SVFOP_CURRENT_DATABASE: svf->type = NAMEOID; break; } diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index ea209cd..14cee21 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -1882,6 +1882,9 @@ FigureColnameInternal(Node *node, char **name) case SVFOP_CURRENT_SCHEMA: *name = "current_schema"; return 2; + case SVFOP_CURRENT_DATABASE: + *name = "current_database"; + return 2; } break; case T_XmlExpr: diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index c11f3dd..75829ec 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -24,6 +24,7 @@ #include "catalog/pg_auth_members.h" #include "catalog/pg_type.h" #include "catalog/pg_class.h" +#include "catalog/pg_database.h" #include "commands/dbcommands.h" #include "commands/proclang.h" #include "commands/tablespace.h" @@ -5273,3 +5274,64 @@ check_rolespec_name(const RoleSpec *role, const char *detail_msg) role->rolename))); } } + +/* + * Given a DbSpec, returns a palloc'ed copy of the corresponding database name. + */ +char * +get_dbspec_name(const DbSpec *db) +{ + char *dbname; + HeapTuple tuple; + Form_pg_database dbForm; + + switch (db->dbtype) + { + case DBSPEC_CSTRING: + Assert(db->dbname); + dbname = db->dbname; + break; + + case DBSPEC_CURRENT_DATABASE: + tuple = SearchSysCache1(DATABASEOID, ObjectIdGetDatum(MyDatabaseId)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for database %u", MyDatabaseId); + + dbForm = (Form_pg_database) GETSTRUCT(tuple); + dbname = pstrdup(NameStr(dbForm->datname)); + ReleaseSysCache(tuple); + break; + + default: + elog(ERROR, "unexpected database type %d", db->dbtype); + } + + return dbname; +} + +/* + * Given a DbSpec node, return the OID it corresponds to. If missing_ok is + * true, return InvalidOid if the database does not exist. + */ +Oid +get_dbspec_oid(const DbSpec *db, bool missing_ok) +{ + Oid oid; + + switch (db->dbtype) + { + case DBSPEC_CSTRING: + Assert(db->dbname); + oid = get_database_oid(db->dbname, missing_ok); + break; + + case DBSPEC_CURRENT_DATABASE: + oid = MyDatabaseId; + break; + + default: + elog(ERROR, "unexpected database type %d", db->dbtype); + } + + return oid; +} diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9cdbb06..6952588 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -8357,6 +8357,10 @@ get_rule_expr(Node *node, deparse_context *context, case SVFOP_CURRENT_SCHEMA: appendStringInfoString(buf, "CURRENT_SCHEMA"); break; + case SVFOP_CURRENT_DATABASE: + appendStringInfoString(buf, "CURRENT_DATABASE"); + break; + } } break; diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 32ad600..db581c0 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -682,6 +682,40 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, } /* + * emitDatabaseSecLabels + * + * Format security label data on database. + */ +void +emitDatabaseSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer, + const char *objname, bool current_datbase) +{ + int i; + + for (i = 0; i < PQntuples(res); i++) + { + char *provider = PQgetvalue(res, i, 0); + char *label = PQgetvalue(res, i, 1); + + /* must use fmtId result before calling it again */ + appendPQExpBuffer(buffer, + "SECURITY LABEL FOR %s ON DATABASE", + fmtId(provider)); + + if(current_datbase) + appendPQExpBuffer(buffer," CURRENT_DATABASE IS "); + else + { + appendPQExpBuffer(buffer, + " %s IS ", + fmtId(objname)); + } + appendStringLiteralConn(buffer, label, conn); + appendPQExpBufferStr(buffer, ";\n"); + } +} + +/* * buildACLQueries * * Build the subqueries to extract out the correct set of ACLs to be diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index d5f150d..766b46f 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -49,8 +49,10 @@ extern bool buildDefaultACLCommands(const char *type, const char *nspname, extern void buildShSecLabelQuery(PGconn *conn, const char *catalog_name, uint32 objectId, PQExpBuffer sql); extern void emitShSecLabels(PGconn *conn, PGresult *res, - PQExpBuffer buffer, const char *target, const char *objname); - + PQExpBuffer buffer, const char *target, + const char *objname); +extern void emitDatabaseSecLabels(PGconn *conn, PGresult *res, + PQExpBuffer buffer, const char *objname, bool current_datbase); extern void buildACLQueries(PQExpBuffer acl_subquery, PQExpBuffer racl_subquery, PQExpBuffer init_acl_subquery, PQExpBuffer init_racl_subquery, const char *acl_column, const char *acl_owner, diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 27628a3..3bfbda2 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2803,7 +2803,10 @@ dumpDatabase(Archive *fout) * Generates warning when loaded into a differently-named * database. */ - appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname)); + if (fout->remoteVersion >= 110000) + appendPQExpBuffer(dbQry, "COMMENT ON DATABASE CURRENT_DATABASE IS "); + else + appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname)); appendStringLiteralAH(dbQry, comment, fout); appendPQExpBufferStr(dbQry, ";\n"); @@ -2832,7 +2835,10 @@ dumpDatabase(Archive *fout) buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry); shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK); resetPQExpBuffer(seclabelQry); - emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname); + if (fout->remoteVersion >= 110000) + emitDatabaseSecLabels(conn, shres, seclabelQry, datname, true); + else + emitDatabaseSecLabels(conn, shres, seclabelQry, datname, false); if (strlen(seclabelQry->data)) ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL, dba, false, "SECURITY LABEL", SECTION_NONE, @@ -14788,9 +14794,17 @@ dumpSecLabel(Archive *fout, const char *target, if (labels[i].objsubid != subid) continue; - appendPQExpBuffer(query, - "SECURITY LABEL FOR %s ON %s IS ", - fmtId(labels[i].provider), target); + if (fout->remoteVersion >= 110000 && (strncmp(target, "DATABASE", 8) != 0)) + { + appendPQExpBuffer(query, + "SECURITY LABEL FOR %s ON DATABASE CURRENT_DATABASE IS ", + fmtId(labels[i].provider)); + } + else + appendPQExpBuffer(query, + "SECURITY LABEL FOR %s ON %s IS ", + fmtId(labels[i].provider), target); + appendStringLiteralAH(query, labels[i].label, fout); appendPQExpBufferStr(query, ";\n"); } diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 7cf9bda..8ba5db2 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -1512,10 +1512,10 @@ qr/^ALTER (?!EVENT TRIGGER|LARGE OBJECT|PUBLICATION|SUBSCRIPTION)(.*) OWNER TO . section_pre_data => 1, section_post_data => 1, }, }, - 'COMMENT ON DATABASE postgres' => { + 'COMMENT ON DATABASE CURRENT_DATABASE' => { all_runs => 1, catch_all => 'COMMENT commands', - regexp => qr/^COMMENT ON DATABASE postgres IS .*;/m, + regexp => qr/^COMMENT ON DATABASE CURRENT_DATABASE IS .*;/m, like => { binary_upgrade => 1, clean => 1, diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h index 677c7fc..a08e99d 100644 --- a/src/include/commands/dbcommands.h +++ b/src/include/commands/dbcommands.h @@ -24,7 +24,7 @@ extern void dropdb(const char *dbname, bool missing_ok); extern ObjectAddress RenameDatabase(const char *oldname, const char *newname); extern Oid AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel); extern Oid AlterDatabaseSet(AlterDatabaseSetStmt *stmt); -extern ObjectAddress AlterDatabaseOwner(const char *dbname, Oid newOwnerId); +extern ObjectAddress AlterDatabaseOwner(const DbSpec *dbspec, Oid newOwnerId); extern Oid get_database_oid(const char *dbname, bool missingok); extern char *get_database_name(Oid dbid); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 2eb3d6d..fd8115e 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -464,6 +464,7 @@ typedef enum NodeTag T_OnConflictClause, T_CommonTableExpr, T_RoleSpec, + T_DbSpec, T_TriggerTransition, T_PartitionElem, T_PartitionSpec, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index b72178e..fd8f880 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -330,6 +330,23 @@ typedef struct RoleSpec } RoleSpec; /* + * DbSpecType - The type of a database name. + */ +typedef enum DbSpecType +{ + DBSPEC_CSTRING, /* database name is stored as a C string */ + DBSPEC_CURRENT_DATABASE /* database name is CURRENT_DATABASE */ +} DbSpecType; + +typedef struct DbSpec +{ + NodeTag type; + DbSpecType dbtype; /* Type of the database */ + char *dbname; /* filled only for DBSPEC_CSTRING */ + int location; /* token location, or -1 if unknown */ +} DbSpec; + +/* * FuncCall - a function or aggregate invocation * * agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if @@ -2459,7 +2476,7 @@ typedef struct AlterRoleSetStmt { NodeTag type; RoleSpec *role; /* role */ - char *database; /* database name, or NULL */ + DbSpec *dbspec; /* name of database to set */ VariableSetStmt *setstmt; /* SET or RESET subcommand */ } AlterRoleSetStmt; @@ -3057,14 +3074,14 @@ typedef struct CreatedbStmt typedef struct AlterDatabaseStmt { NodeTag type; - char *dbname; /* name of database to alter */ - List *options; /* List of DefElem nodes */ + DbSpec *dbspec; /* name of database to alter */ + List *options; /* List of DefElem nodes */ } AlterDatabaseStmt; typedef struct AlterDatabaseSetStmt { NodeTag type; - char *dbname; /* database name */ + DbSpec *dbspec; /* DbSpec */ VariableSetStmt *setstmt; /* SET or RESET subcommand */ } AlterDatabaseSetStmt; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index 1b4b0d7..efc1a9c 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1102,7 +1102,8 @@ typedef enum SQLValueFunctionOp SVFOP_USER, SVFOP_SESSION_USER, SVFOP_CURRENT_CATALOG, - SVFOP_CURRENT_SCHEMA + SVFOP_CURRENT_SCHEMA, + SVFOP_CURRENT_DATABASE } SQLValueFunctionOp; typedef struct SQLValueFunction diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 26af944..fb706d0 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -105,6 +105,7 @@ PG_KEYWORD("csv", CSV, UNRESERVED_KEYWORD) PG_KEYWORD("cube", CUBE, UNRESERVED_KEYWORD) PG_KEYWORD("current", CURRENT_P, UNRESERVED_KEYWORD) PG_KEYWORD("current_catalog", CURRENT_CATALOG, RESERVED_KEYWORD) +PG_KEYWORD("current_database", CURRENT_DATABASE, RESERVED_KEYWORD) PG_KEYWORD("current_date", CURRENT_DATE, RESERVED_KEYWORD) PG_KEYWORD("current_role", CURRENT_ROLE, RESERVED_KEYWORD) PG_KEYWORD("current_schema", CURRENT_SCHEMA, TYPE_FUNC_NAME_KEYWORD) diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 67c7b2d..44b9ab2 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -246,6 +246,8 @@ extern Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok); extern void check_rolespec_name(const RoleSpec *role, const char *detail_msg); extern HeapTuple get_rolespec_tuple(const RoleSpec *role); extern char *get_rolespec_name(const RoleSpec *role); +extern char *get_dbspec_name(const DbSpec *db); +extern Oid get_dbspec_oid(const DbSpec *db, bool missing_ok); extern void select_best_grantor(Oid roleId, AclMode privileges, const Acl *acl, Oid ownerId, diff --git a/src/test/regress/expected/dbname.out b/src/test/regress/expected/dbname.out new file mode 100644 index 0000000..cac34de --- /dev/null +++ b/src/test/regress/expected/dbname.out @@ -0,0 +1,113 @@ +CREATE ROLE dbuser1 with LOGIN; +CREATE ROLE dbuser2 with SUPERUSER LOGIN; +CREATE ROLE dbuser3 with SUPERUSER LOGIN; +DROP DATABASE IF EXISTS db1; +NOTICE: database "db1" does not exist, skipping +CREATE DATABASE db1 with owner=dbuser1; +CREATE DATABASE "current_database" with owner=dbuser1; +CREATE DATABASE current_database with owner=dbuser1; +ERROR: CURRENT_DATABASE cannot be used as a database name here +LINE 1: CREATE DATABASE current_database with owner=dbuser1; + ^ +SELECT d.datname as "Name", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' +ORDER BY 1; + Name | Description +------------------+------------- + current_database | + db1 | +(2 rows) + +\c db1; +SELECT CURRENT_DATABASE; + current_database +------------------ + db1 +(1 row) + +COMMENT ON DATABASE current_database IS 'db1'; +COMMENT ON DATABASE "current_database" IS 'db2'; +SELECT d.datname as "Name", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' +ORDER BY 1; + Name | Description +------------------+------------- + current_database | db2 + db1 | db1 +(2 rows) + +-- test alter owner +ALTER DATABASE current_database OWNER to dbuser2; +ALTER DATABASE "current_database" OWNER to dbuser2; +SELECT d.datname as "Name", + pg_catalog.pg_get_userbyid(d.datdba) as "Owner", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' +ORDER BY 1; + Name | Owner | Description +------------------+---------+------------- + current_database | dbuser2 | db2 + db1 | dbuser2 | db1 +(2 rows) + +-- test alter database tablespace +ALTER DATABASE current_database SET TABLESPACE pg_default; +ERROR: cannot change the tablespace of the currently open database +ALTER DATABASE "current_database" SET TABLESPACE pg_default; +-- test alter database rename +ALTER DATABASE current_database rename to db2; +ERROR: CURRENT_DATABASE cannot be used as a database name here +LINE 1: ALTER DATABASE current_database rename to db2; + ^ +COMMENT ON DATABASE "current_database" IS 'changed from current_database'; +ALTER DATABASE "current_database" rename to db2; +ALTER DATABASE db2 rename to current_database; +ERROR: CURRENT_DATABASE cannot be used as a database name here +LINE 1: ALTER DATABASE db2 rename to current_database; + ^ +SELECT d.datname as "Name", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' or d.datname='db2' +ORDER BY 1; + Name | Description +------+------------------------------- + db1 | db1 + db2 | changed from current_database +(2 rows) + +-- test alter database set parameter +ALTER DATABASE current_database SET parallel_tuple_cost=0.3; +\c db1 +show parallel_tuple_cost; + parallel_tuple_cost +--------------------- + 0.3 +(1 row) + +ALTER DATABASE current_database RESET parallel_tuple_cost; +\c db1 +show parallel_tuple_cost; + parallel_tuple_cost +--------------------- + 0.1 +(1 row) + +-- clean up +\c postgres +DROP DATABASE IF EXISTS "current_database"; +NOTICE: database "current_database" does not exist, skipping +DROP DATABASE IF EXISTS db1; +DROP DATABASE IF EXISTS db2; +DROP ROLE dbuser1; +DROP ROLE dbuser2; +DROP ROLE dbuser3; diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out index b101331..81d8629 100644 --- a/src/test/regress/expected/publication.out +++ b/src/test/regress/expected/publication.out @@ -206,6 +206,17 @@ ALTER PUBLICATION testpub2 ADD TABLE testpub_tbl1; -- ok DROP PUBLICATION testpub2; SET ROLE regress_publication_user; REVOKE CREATE ON DATABASE regression FROM regress_publication_user2; +--- test grant on database current_database +GRANT CREATE ON DATABASE CURRENT_DATABASE TO regress_publication_user2; +SET ROLE regress_publication_user2; +CREATE PUBLICATION testpub2; -- ok +DROP PUBLICATION testpub2; +SET ROLE regress_publication_user; +REVOKE CREATE ON DATABASE CURRENT_DATABASE FROM regress_publication_user2; +SET ROLE regress_publication_user2; +CREATE PUBLICATION testpub2; -- fail +ERROR: permission denied for database regression +SET ROLE regress_publication_user; DROP TABLE testpub_parted; DROP VIEW testpub_view; DROP TABLE testpub_tbl1; diff --git a/src/test/regress/expected/rolenames.out b/src/test/regress/expected/rolenames.out index dce82f5..ab02155 100644 --- a/src/test/regress/expected/rolenames.out +++ b/src/test/regress/expected/rolenames.out @@ -369,6 +369,26 @@ SELECT * FROM chksetconfig(); ----+------+------------+----------- (0 rows) +-- ALTER ROLE IN DATABASE CURRENT_DATABASE SET/RESET +ALTER ROLE CURRENT_USER IN DATABASE CURRENT_DATABASE SET application_name to 'FOO'; +ALTER ROLE "current_user" IN DATABASE CURRENT_DATABASE SET application_name to 'FOOFOO'; +ALTER ROLE "Public" IN DATABASE CURRENT_DATABASE SET application_name to 'BARBAR'; +SELECT * FROM chksetconfig(); + db | role | rolkeyword | setconfig +------------+------------------+--------------+--------------------------- + regression | Public | - | {application_name=BARBAR} + regression | current_user | - | {application_name=FOOFOO} + regression | regress_testrol2 | current_user | {application_name=FOO} +(3 rows) + +ALTER ROLE CURRENT_USER IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER ROLE "current_user" IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER ROLE "Public" IN DATABASE CURRENT_DATABASE RESET application_name; +SELECT * FROM chksetconfig(); + db | role | rolkeyword | setconfig +----+------+------------+----------- +(0 rows) + ALTER ROLE CURRENT_ROLE SET application_name to 'BAZ'; -- error ERROR: syntax error at or near "CURRENT_ROLE" LINE 1: ALTER ROLE CURRENT_ROLE SET application_name to 'BAZ'; @@ -421,6 +441,26 @@ SELECT * FROM chksetconfig(); ----+------+------------+----------- (0 rows) +-- ALTER USER IN DATABASE CURRENT_DATABASE SET/RESET +ALTER USER SESSION_USER IN DATABASE CURRENT_DATABASE SET application_name to 'BAR'; +ALTER USER "current_user" IN DATABASE CURRENT_DATABASE SET application_name to 'FOOFOO'; +ALTER USER "Public" IN DATABASE CURRENT_DATABASE SET application_name to 'BARBAR'; +SELECT * FROM chksetconfig(); + db | role | rolkeyword | setconfig +------------+------------------+--------------+--------------------------- + regression | Public | - | {application_name=BARBAR} + regression | current_user | - | {application_name=FOOFOO} + regression | regress_testrol1 | session_user | {application_name=BAR} +(3 rows) + +ALTER USER SESSION_USER IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER USER "current_user" IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER USER "Public" IN DATABASE CURRENT_DATABASE RESET application_name; +SELECT * FROM chksetconfig(); + db | role | rolkeyword | setconfig +----+------+------------+----------- +(0 rows) + ALTER USER CURRENT_USER SET application_name to 'BAZ'; -- error ALTER USER USER SET application_name to 'BOOM'; -- error ERROR: syntax error at or near "USER" diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index e224977..ef69620 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -123,3 +123,4 @@ test: event_trigger # run stats by itself because its delay may be insufficient under heavy load test: stats +test: dbname \ No newline at end of file diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index 9fc5f1a..5bcb13d 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -186,3 +186,4 @@ test: reloptions test: hash_part test: event_trigger test: stats +test: dbname diff --git a/src/test/regress/sql/dbname.sql b/src/test/regress/sql/dbname.sql new file mode 100644 index 0000000..5c8b36e --- /dev/null +++ b/src/test/regress/sql/dbname.sql @@ -0,0 +1,77 @@ +CREATE ROLE dbuser1 with LOGIN; +CREATE ROLE dbuser2 with SUPERUSER LOGIN; +CREATE ROLE dbuser3 with SUPERUSER LOGIN; + +DROP DATABASE IF EXISTS db1; +CREATE DATABASE db1 with owner=dbuser1; +CREATE DATABASE "current_database" with owner=dbuser1; +CREATE DATABASE current_database with owner=dbuser1; + +SELECT d.datname as "Name", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' +ORDER BY 1; + + +\c db1; +SELECT CURRENT_DATABASE; + + +COMMENT ON DATABASE current_database IS 'db1'; +COMMENT ON DATABASE "current_database" IS 'db2'; + +SELECT d.datname as "Name", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' +ORDER BY 1; + +-- test alter owner +ALTER DATABASE current_database OWNER to dbuser2; +ALTER DATABASE "current_database" OWNER to dbuser2; + +SELECT d.datname as "Name", + pg_catalog.pg_get_userbyid(d.datdba) as "Owner", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' +ORDER BY 1; + +-- test alter database tablespace +ALTER DATABASE current_database SET TABLESPACE pg_default; +ALTER DATABASE "current_database" SET TABLESPACE pg_default; + +-- test alter database rename +ALTER DATABASE current_database rename to db2; +COMMENT ON DATABASE "current_database" IS 'changed from current_database'; +ALTER DATABASE "current_database" rename to db2; +ALTER DATABASE db2 rename to current_database; + +SELECT d.datname as "Name", + pg_catalog.shobj_description(d.oid, 'pg_database') as "Description" +FROM pg_catalog.pg_database d + JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid +WHERE d.datname='current_database' or d.datname='db1' or d.datname='db2' +ORDER BY 1; + +-- test alter database set parameter +ALTER DATABASE current_database SET parallel_tuple_cost=0.3; +\c db1 +show parallel_tuple_cost; +ALTER DATABASE current_database RESET parallel_tuple_cost; +\c db1 +show parallel_tuple_cost; + +-- clean up +\c postgres + +DROP DATABASE IF EXISTS "current_database"; +DROP DATABASE IF EXISTS db1; +DROP DATABASE IF EXISTS db2; +DROP ROLE dbuser1; +DROP ROLE dbuser2; +DROP ROLE dbuser3; diff --git a/src/test/regress/sql/publication.sql b/src/test/regress/sql/publication.sql index 815410b..0ee3fd3 100644 --- a/src/test/regress/sql/publication.sql +++ b/src/test/regress/sql/publication.sql @@ -112,6 +112,18 @@ DROP PUBLICATION testpub2; SET ROLE regress_publication_user; REVOKE CREATE ON DATABASE regression FROM regress_publication_user2; +--- test grant on database current_database +GRANT CREATE ON DATABASE CURRENT_DATABASE TO regress_publication_user2; +SET ROLE regress_publication_user2; +CREATE PUBLICATION testpub2; -- ok +DROP PUBLICATION testpub2; + +SET ROLE regress_publication_user; +REVOKE CREATE ON DATABASE CURRENT_DATABASE FROM regress_publication_user2; +SET ROLE regress_publication_user2; +CREATE PUBLICATION testpub2; -- fail +SET ROLE regress_publication_user; + DROP TABLE testpub_parted; DROP VIEW testpub_view; DROP TABLE testpub_tbl1; diff --git a/src/test/regress/sql/rolenames.sql b/src/test/regress/sql/rolenames.sql index 4c5706b..ff11931 100644 --- a/src/test/regress/sql/rolenames.sql +++ b/src/test/regress/sql/rolenames.sql @@ -146,6 +146,15 @@ ALTER ROLE "Public" RESET application_name; ALTER ROLE ALL RESET application_name; SELECT * FROM chksetconfig(); +-- ALTER ROLE IN DATABASE CURRENT_DATABASE SET/RESET +ALTER ROLE CURRENT_USER IN DATABASE CURRENT_DATABASE SET application_name to 'FOO'; +ALTER ROLE "current_user" IN DATABASE CURRENT_DATABASE SET application_name to 'FOOFOO'; +ALTER ROLE "Public" IN DATABASE CURRENT_DATABASE SET application_name to 'BARBAR'; +SELECT * FROM chksetconfig(); +ALTER ROLE CURRENT_USER IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER ROLE "current_user" IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER ROLE "Public" IN DATABASE CURRENT_DATABASE RESET application_name; +SELECT * FROM chksetconfig(); ALTER ROLE CURRENT_ROLE SET application_name to 'BAZ'; -- error ALTER ROLE USER SET application_name to 'BOOM'; -- error @@ -170,6 +179,16 @@ ALTER USER ALL RESET application_name; SELECT * FROM chksetconfig(); +-- ALTER USER IN DATABASE CURRENT_DATABASE SET/RESET +ALTER USER SESSION_USER IN DATABASE CURRENT_DATABASE SET application_name to 'BAR'; +ALTER USER "current_user" IN DATABASE CURRENT_DATABASE SET application_name to 'FOOFOO'; +ALTER USER "Public" IN DATABASE CURRENT_DATABASE SET application_name to 'BARBAR'; +SELECT * FROM chksetconfig(); +ALTER USER SESSION_USER IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER USER "current_user" IN DATABASE CURRENT_DATABASE RESET application_name; +ALTER USER "Public" IN DATABASE CURRENT_DATABASE RESET application_name; +SELECT * FROM chksetconfig(); + ALTER USER CURRENT_USER SET application_name to 'BAZ'; -- error ALTER USER USER SET application_name to 'BOOM'; -- error ALTER USER PUBLIC SET application_name to 'BOMB'; -- error