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 1156627..6cc586b 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(ObjectType objtype, List *objnames)
case 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 570e65a..f415c1d 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:
@@ -2248,7 +2252,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, objtype,
- 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 0d63866..dd2aab0 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 d2020d0..f50423d 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, OBJECT_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, OBJECT_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 71c5caa..6e06a63 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, OBJECT_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 e5d2de5..5ed8282 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2926,6 +2926,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)
{
@@ -3751,7 +3763,7 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from)
{
AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(options);
return newnode;
@@ -3762,7 +3774,7 @@ _copyAlterDatabaseSetStmt(const AlterDatabaseSetStmt *from)
{
AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(setstmt);
return newnode;
@@ -4241,7 +4253,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;
@@ -5568,7 +5580,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 785dc54..ac8c375 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1647,7 +1647,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;
@@ -1656,7 +1656,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;
@@ -2063,7 +2063,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;
@@ -2889,6 +2889,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
*/
@@ -3705,6 +3715,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 459a227..78a443e 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;
}
@@ -6425,6 +6427,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);
@@ -6589,7 +6599,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; }
@@ -6638,6 +6647,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
{
@@ -6726,8 +6745,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; }
@@ -7087,7 +7105,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;
@@ -9314,11 +9332,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;
}
@@ -10140,24 +10158,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;
@@ -10165,10 +10183,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;
}
@@ -13692,6 +13710,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);
@@ -14662,7 +14684,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; };
@@ -14688,6 +14739,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -15343,6 +15396,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -16254,6 +16308,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 0cfc297..d90331a 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 c5f5a1c..bdc5cd3 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8360,6 +8360,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/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 74b094a..62b2938 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 bbacbe1..ef2cfa4 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
@@ -2440,7 +2457,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;
@@ -3050,14 +3067,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 f4d4be8..7422c8e 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -215,6 +215,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 0c86c64..2dfb69a 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 ad9434f..0b31579 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 27cd498..d2c6830 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -187,3 +187,4 @@ test: hash_part
test: indexing
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