Re: Support to COMMENT ON DATABASE CURRENT_DATABASE
Hi all,
The patch has been updated according to Nathan's comments.
Thanks Nathan's review.
Please find the updated patch in the attached files:
comment_on_current_database_no_pgdump_v4.3.patch --- support
current_database keyword exclude the pg_dump part.
comment_on_current_database_for_pgdump_v4.3.patch --- only for the pg_dump
part changed based on the previous patch
Regards,
Jing Wang
Fujitsu Australia
Attachments:
comment_on_current_database_no_pgdump_v4.3.patchapplication/octet-stream; name=comment_on_current_database_no_pgdump_v4.3.patchDownload
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index df32811..58623f0 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -31,7 +31,7 @@ COMMENT ON
CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ON <replaceable class="PARAMETER">table_name</replaceable> |
CONSTRAINT <replaceable class="PARAMETER">constraint_name</replaceable> ON DOMAIN <replaceable class="PARAMETER">domain_name</replaceable> |
CONVERSION <replaceable class="PARAMETER">object_name</replaceable> |
- DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
+ DATABASE <replaceable class="PARAMETER">database_name</replaceable> |
DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
EXTENSION <replaceable class="PARAMETER">object_name</replaceable> |
EVENT TRIGGER <replaceable class="PARAMETER">object_name</replaceable> |
@@ -149,6 +149,16 @@ COMMENT ON
</varlistentry>
<varlistentry>
+ <term><replaceable class="parameter">database_name</replaceable></term>
+ <listitem>
+ <para>
+ The name of a database or keyword current_database. When using
+ current_database,it means using the name of the connecting database.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable>source_type</replaceable></term>
<listitem>
<para>
@@ -311,6 +321,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/security_label.sgml b/doc/src/sgml/ref/security_label.sgml
index aa8be47..e10d58e 100644
--- a/doc/src/sgml/ref/security_label.sgml
+++ b/doc/src/sgml/ref/security_label.sgml
@@ -26,7 +26,7 @@ SECURITY LABEL [ FOR <replaceable class="PARAMETER">provider</replaceable> ] ON
TABLE <replaceable class="PARAMETER">object_name</replaceable> |
COLUMN <replaceable class="PARAMETER">table_name</replaceable>.<replaceable class="PARAMETER">column_name</replaceable> |
AGGREGATE <replaceable class="PARAMETER">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
- DATABASE <replaceable class="PARAMETER">object_name</replaceable> |
+ DATABASE <replaceable class="PARAMETER">database_name</replaceable> |
DOMAIN <replaceable class="PARAMETER">object_name</replaceable> |
EVENT TRIGGER <replaceable class="PARAMETER">object_name</replaceable> |
FOREIGN TABLE <replaceable class="PARAMETER">object_name</replaceable>
@@ -103,6 +103,16 @@ SECURITY LABEL [ FOR <replaceable class="PARAMETER">provider</replaceable> ] ON
</varlistentry>
<varlistentry>
+ <term><replaceable class="parameter">database_name</replaceable></term>
+ <listitem>
+ <para>
+ The name of a database or keyword current_database. When using
+ current_database,it means using the name of the connecting database.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable class="parameter">provider</replaceable></term>
<listitem>
<para>
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index c2ad7c6..f1424b8 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -721,7 +721,8 @@ const ObjectAddress InvalidObjectAddress =
InvalidOid,
0
};
-
+static ObjectAddress get_object_address_database(ObjectType objtype,
+ DbSpec * object, bool missing_ok);
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
Value *strval, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
@@ -865,6 +866,8 @@ get_object_address(ObjectType objtype, Node *object,
}
break;
case OBJECT_DATABASE:
+ address = get_object_address_database(objtype, (DbSpec*)object, missing_ok);
+ break;
case OBJECT_EXTENSION:
case OBJECT_TABLESPACE:
case OBJECT_ROLE:
@@ -1108,6 +1111,25 @@ get_object_address_rv(ObjectType objtype, RangeVar *rel, List *object,
/*
* Find an ObjectAddress for a type of object that is identified by an
+ * database name
+ */
+static ObjectAddress
+get_object_address_database(ObjectType objtype, DbSpec *object, bool missing_ok)
+{
+ char *dbname;
+ ObjectAddress address;
+
+ dbname = get_dbspec_name(object);
+
+ address.classId = DatabaseRelationId;
+ address.objectId = get_database_oid(dbname, missing_ok);
+ address.objectSubId = 0;
+
+ return address;
+}
+
+/*
+ * Find an ObjectAddress for a type of object that is identified by an
* unqualified name.
*/
static ObjectAddress
@@ -2242,7 +2264,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 4f81479..e1de191 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -802,7 +802,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 1c17927..ac7de1f 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 e138539..e0dfa0c 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((DbSpec*)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((DbSpec*)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((DbSpec*)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/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index c5e97ef..33665bc 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2016,6 +2016,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 c1a83ca..46a503e 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2920,6 +2920,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)
{
@@ -3732,7 +3744,7 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from)
{
AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(options);
return newnode;
@@ -3743,7 +3755,7 @@ _copyAlterDatabaseSetStmt(const AlterDatabaseSetStmt *from)
{
AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(setstmt);
return newnode;
@@ -5544,7 +5556,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 7a70001..c0e2dc3 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1635,7 +1635,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;
@@ -1644,7 +1644,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;
@@ -2875,6 +2875,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
*/
@@ -3688,6 +3698,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 4c83a63..7176fec 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 Node *makeDbSpec(DbSpecType type, int location);
%}
%pure-parser
@@ -572,6 +572,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
opt_frame_clause frame_extent frame_bound
%type <str> opt_existing_window_name
%type <boolean> opt_if_not_exists
+%type <node> db_spec_name
%type <ival> generated_when override_kind
%type <partspec> PartitionSpec OptPartitionSpec
%type <str> part_strategy
@@ -616,7 +617,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
@@ -6295,6 +6296,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);
@@ -6443,7 +6452,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; }
@@ -6492,6 +6500,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
{
@@ -6560,8 +6578,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; }
@@ -8990,11 +9007,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;
}
@@ -9800,24 +9817,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;
@@ -9825,10 +9842,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;
}
@@ -13357,6 +13374,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);
@@ -14327,7 +14348,29 @@ 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:
+ ColId
+ {
+ DbSpec *n = (DbSpec *) makeDbSpec(DBSPEC_CSTRING, @1);
+ n->dbname = pstrdup($1);
+ $$ = (Node *)n;
+ }
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeDbSpec(DBSPEC_CURRENT_DATABASE, @1);
+ }
+ ;
access_method:
ColId { $$ = $1; };
@@ -14353,6 +14396,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -15004,6 +15049,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -15915,6 +15961,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
return (Node *) s;
}
+/* makeDbSpec
+ * Create a DbSpec with the given type
+ */
+static Node *
+makeDbSpec(DbSpecType type, int location)
+{
+ DbSpec *spec = makeNode(DbSpec);
+
+ spec->dbtype = type;
+ spec->location = location;
+
+ return (Node *) 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 1aaa524..57b908f 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2328,6 +2328,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 2547524..7a55e3f 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1873,6 +1873,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 0c26e44..fced2c9 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"
@@ -5268,3 +5269,68 @@ check_rolespec_name(const RoleSpec *role, const char *detail_msg)
role->rolename)));
}
}
+
+
+/*
+ * Given a DbSpec, returns a palloc'ed copy of the corresponding role's name.
+ */
+char *
+get_dbspec_name(const DbSpec *db)
+{
+ char *dbname;
+
+ switch (db->dbtype)
+ {
+ case DBSPEC_CSTRING:
+ dbname = db->dbname;
+ break;
+
+ case DBSPEC_CURRENT_DATABASE:
+ {
+ HeapTuple tuple;
+ Form_pg_database dbForm;
+
+ 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 84759b6..d3c67db 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8344,6 +8344,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 f42c8cd..9221b54 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -24,7 +24,8 @@ 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 ffeeb49..7847af5 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -462,6 +462,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 50eec73..5672b92 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3016,6 +3016,24 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
+
+/*
+ * 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;
+
/* ----------------------
* Createdb Statement
* ----------------------
@@ -3034,14 +3052,14 @@ typedef struct CreatedbStmt
typedef struct AlterDatabaseStmt
{
NodeTag type;
- char *dbname; /* name of database to alter */
- List *options; /* List of DefElem nodes */
+ Node *dbspec; /* name of database to alter, DbSpec */
+ List *options; /* List of DefElem nodes */
} AlterDatabaseStmt;
typedef struct AlterDatabaseSetStmt
{
NodeTag type;
- char *dbname; /* database name */
+ Node *dbspec; /* DbSpec */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterDatabaseSetStmt;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index ccb5123..064e3ed 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1095,7 +1095,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 f50e45e..a022826 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -104,6 +104,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 254a811..c9cfa85 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/parallel_schedule b/src/test/regress/parallel_schedule
index 860e8ab..b062cc0 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -122,3 +122,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 ef275d0..404de67 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -180,3 +180,4 @@ test: with
test: xml
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;
comment_on_current_database_for_pgdump_v4.3.patchapplication/octet-stream; name=comment_on_current_database_for_pgdump_v4.3.patchDownload
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index e4c95fe..7746039 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -670,6 +670,7 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
appendPQExpBuffer(buffer,
"SECURITY LABEL FOR %s ON %s",
fmtId(provider), target);
+
appendPQExpBuffer(buffer,
" %s IS ",
fmtId(objname));
@@ -679,6 +680,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 fe364dd..cee625b 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 e34c83a..3e7d53f 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2802,7 +2802,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 >= 100000)
+ 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");
@@ -2831,7 +2834,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 >= 100000)
+ 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,
@@ -14683,9 +14689,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 >= 100000 && (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");
}
@@ -14769,6 +14783,7 @@ dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
resetPQExpBuffer(target);
appendPQExpBuffer(target, "%s %s", reltypename,
fmtId(tbinfo->dobj.name));
+
ArchiveEntry(fout, nilCatalogId, createDumpId(),
target->data,
tbinfo->dobj.namespace->dobj.name,
Hi
I don't know why the previous email can't be linked with the original email
webpage. It is weird. So supplementing following information for
understanding:
The original email link:
/messages/by-id/CAF3+xM+xSswcWQZMP1cjj12gPz8DXHcM9_fT1y-0fVzxi9pmOw@mail.gmail.com
The recent email with updated patch is as following:
/messages/by-id/CAF3+xMKkKpd8oVRpN9i1BFMau2dFhVrt-Y0BE=DsoKtOm=C2AQ@mail.gmail.com
--
Regards,
Jing Wang
Fujitsu Australia
On 10/5/17, 11:53 PM, "Jing Wang" <jingwangian@gmail.com> wrote:
The patch has been updated according to Nathan's comments.
Thanks Nathan's review.
Thanks for the new versions of the patches. I apologize for
the long delay for this new review.
It looks like the no-pgdump patch needs a rebase at this point.
I was able to apply the code portions with a 3-way merge, but
the documentation changes still did not apply. I didn't have
any problems applying the pgdump patch.
+ <listitem>
+ <para>
+ The name of a database or keyword current_database. When using
+ current_database,it means using the name of the connecting database.
+ </para>
+ </listitem>
For commands that accept the CURRENT_USER and SESSION_USER
keywords, the keywords are typically listed in the 'Synopsis'
section. I think CURRENT_DATABASE should be no different. For
example, the parameter type above could be
"database_specification," and the following definition could be
included at the bottom of the synopsis:
where database_specification can be:
object_name
| CURRENT_DATABASE
Then, in the parameters section, the CURRENT_DATABASE keyword
would be defined:
CURRENT_DATABASE
Comment on the current database instead of an
explicitly identified role.
Also, it looks like only the COMMENT and SECURITY LABEL
documentation is being updated in this patch set. However, this
keyword seems applicable to many other commands, too (e.g.
GRANT, ALTER DATABASE, ALTER ROLE, etc.).
+static ObjectAddress
+get_object_address_database(ObjectType objtype, DbSpec *object, bool missing_ok)
+{
+ char *dbname;
+ ObjectAddress address;
+
+ dbname = get_dbspec_name(object);
+
+ address.classId = DatabaseRelationId;
+ address.objectId = get_database_oid(dbname, missing_ok);
+ address.objectSubId = 0;
+
+ return address;
+}
This helper function is only used once, and it seems simple
enough to build the ObjectAddress in the switch statement.
Also, instead of get_database_oid(), could we use
get_dbspec_oid()?
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;
}
}
This section seems to assume that the DbSpec will be of type
DBSPEC_CSTRING in the error handling. That should be safe for
now, as you cannot drop the current database, but I would
suggest adding assertions here to be sure.
+ dbname = get_dbspec_name((DbSpec*)stmt->dbspec);
As a general note, casts are typically styled as "(DbSpec *)
stmt" (with the spaces) in PostgreSQL.
+ case DBSPEC_CURRENT_DATABASE:
+ {
+ HeapTuple tuple;
+ Form_pg_database dbForm;
Can we just declare "tuple" and "dbForm" at the beginning of
get_dbspec_name() so we don't need the extra set of braces?
+ if (fout->remoteVersion >= 100000)
+ appendPQExpBuffer(dbQry, "COMMENT ON DATABASE CURRENT_DATABASE IS ");
+ else
+ appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
This feature would probably only be added to v11, so the version
checks in the pgdump patch will need to be updated.
Nathan
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi Nathan,
Thanks for review comments.
Enclosed please find the patch which has been updated according to your
suggestion.
The CURRENT_DATABASE can be used as following SQL statements and people can
find information from sgml files:
1. COMMENT ON DATABASE CURRENT_DATABASE is ...
2. ALTER DATABASE CURRENT_DATABASE OWNER to ...
3. ALTER DATABASE CURRENT_DATABASE SET parameter ...
4. ALTER DATABASE CURRENT_DATABASE RESET parameter ...
5. ALTER DATABASE CURRENT_DATABASE RESET ALL
6. SELECT CURRENT_DATABASE
7. SECURITY LABEL ON DATABASE CURRENT_DATABASE
As your mentioned the database_name are also present in the
GRANT/REVOKE/ALTER ROLE, so a patch will be present later for supporting
CURRENT_DATABASE on these SQL statements.
Regards,
Jing Wang
Fujitsu Australia
Attachments:
comment_on_current_database_no_pgdump_v4.4.patchapplication/octet-stream; name=comment_on_current_database_no_pgdump_v4.4.patchDownload
diff --git a/doc/src/sgml/ref/alter_database.sgml b/doc/src/sgml/ref/alter_database.sgml
index 1e09b5d..c9070f9 100644
--- a/doc/src/sgml/ref/alter_database.sgml
+++ b/doc/src/sgml/ref/alter_database.sgml
@@ -31,14 +31,14 @@ ALTER DATABASE <replaceable class="parameter">name</replaceable> [ [ WITH ] <rep
ALTER DATABASE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
ALTER DATABASE <replaceable class="parameter">name</replaceable> SET TABLESPACE <replaceable class="parameter">new_tablespace</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET ALL
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> RESET <replaceable>configuration_parameter</replaceable>
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> RESET ALL
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index d705792..d02179f 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -31,7 +31,7 @@ COMMENT ON
CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ON <replaceable class="parameter">table_name</replaceable> |
CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ON DOMAIN <replaceable class="parameter">domain_name</replaceable> |
CONVERSION <replaceable class="parameter">object_name</replaceable> |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EXTENSION <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
@@ -71,6 +71,11 @@ COMMENT ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ object_name
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
@@ -311,6 +316,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/security_label.sgml b/doc/src/sgml/ref/security_label.sgml
index ce5a1c1..3e2391b 100644
--- a/doc/src/sgml/ref/security_label.sgml
+++ b/doc/src/sgml/ref/security_label.sgml
@@ -26,7 +26,7 @@ SECURITY LABEL [ FOR <replaceable class="parameter">provider</replaceable> ] ON
TABLE <replaceable class="parameter">object_name</replaceable> |
COLUMN <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> |
AGGREGATE <replaceable class="parameter">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
FOREIGN TABLE <replaceable class="parameter">object_name</replaceable>
@@ -49,6 +49,11 @@ SECURITY LABEL [ FOR <replaceable class="parameter">provider</replaceable> ] ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ object_name
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 8d55c76..519ab55 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -721,7 +721,6 @@ const ObjectAddress InvalidObjectAddress =
InvalidOid,
0
};
-
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
Value *strval, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
@@ -865,6 +864,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:
@@ -2242,7 +2245,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 4f81479..573eefc 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -802,7 +802,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 2dc9371..047d283 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 eb1a469..600b592 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((DbSpec *)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((DbSpec *)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((DbSpec *)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/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 6c4612d..7172125 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2043,6 +2043,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 d9ff8a7..933378a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2922,6 +2922,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)
{
@@ -3734,7 +3746,7 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from)
{
AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(options);
return newnode;
@@ -3745,7 +3757,7 @@ _copyAlterDatabaseSetStmt(const AlterDatabaseSetStmt *from)
{
AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(setstmt);
return newnode;
@@ -5548,7 +5560,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 2866fd7..3570514 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1635,7 +1635,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;
@@ -1644,7 +1644,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;
@@ -2877,6 +2877,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
*/
@@ -3690,6 +3700,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 c301ca4..431a287 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 Node *makeDbSpec(DbSpecType type, int location);
%}
%pure-parser
@@ -572,6 +572,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
opt_frame_clause frame_extent frame_bound
%type <str> opt_existing_window_name
%type <boolean> opt_if_not_exists
+%type <node> db_spec_name
%type <ival> generated_when override_kind
%type <partspec> PartitionSpec OptPartitionSpec
%type <str> part_strategy
@@ -617,7 +618,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
@@ -6367,6 +6368,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);
@@ -6515,7 +6524,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; }
@@ -6564,6 +6572,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
{
@@ -6632,8 +6650,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; }
@@ -9062,11 +9079,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;
}
@@ -9872,24 +9889,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;
@@ -9897,10 +9914,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;
}
@@ -13429,6 +13446,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);
@@ -14399,7 +14420,29 @@ 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:
+ ColId
+ {
+ DbSpec *n = (DbSpec *) makeDbSpec(DBSPEC_CSTRING, @1);
+ n->dbname = pstrdup($1);
+ $$ = (Node *)n;
+ }
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeDbSpec(DBSPEC_CURRENT_DATABASE, @1);
+ }
+ ;
access_method:
ColId { $$ = $1; };
@@ -14425,6 +14468,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -15076,6 +15121,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -15987,6 +16033,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
return (Node *) s;
}
+/* makeDbSpec
+ * Create a DbSpec with the given type
+ */
+static Node *
+makeDbSpec(DbSpecType type, int location)
+{
+ DbSpec *spec = makeNode(DbSpec);
+
+ spec->dbtype = type;
+ spec->location = location;
+
+ return (Node *) 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 86d1da0..82a6c5f 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2328,6 +2328,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 21593b2..508fd41 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 fa6b792..a9f468a 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"
@@ -5270,3 +5271,66 @@ check_rolespec_name(const RoleSpec *role, const char *detail_msg)
role->rolename)));
}
}
+
+
+/*
+ * Given a DbSpec, returns a palloc'ed copy of the corresponding role's 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 06cf32f..8478c60 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8351,6 +8351,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 f42c8cd..9221b54 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -24,7 +24,8 @@ 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 ffeeb49..7847af5 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -462,6 +462,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 34d6afc..4852c7d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3023,6 +3023,24 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
+
+/*
+ * 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;
+
/* ----------------------
* Createdb Statement
* ----------------------
@@ -3041,14 +3059,14 @@ typedef struct CreatedbStmt
typedef struct AlterDatabaseStmt
{
NodeTag type;
- char *dbname; /* name of database to alter */
- List *options; /* List of DefElem nodes */
+ Node *dbspec; /* name of database to alter, DbSpec */
+ List *options; /* List of DefElem nodes */
} AlterDatabaseStmt;
typedef struct AlterDatabaseSetStmt
{
NodeTag type;
- char *dbname; /* database name */
+ Node *dbspec; /* DbSpec */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterDatabaseSetStmt;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 074ae0a..c65a05c 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 f50e45e..a022826 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -104,6 +104,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 254a811..c9cfa85 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/parallel_schedule b/src/test/regress/parallel_schedule
index aa5e6af..6a6382c 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 3866314..96e6202 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -183,3 +183,4 @@ test: partition_join
test: reloptions
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;
comment_on_current_database_for_pgdump_v4.4.patchapplication/octet-stream; name=comment_on_current_database_for_pgdump_v4.4.patchDownload
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index 70d8f24..12ea7dc 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -670,6 +670,7 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
appendPQExpBuffer(buffer,
"SECURITY LABEL FOR %s ON %s",
fmtId(provider), target);
+
appendPQExpBuffer(buffer,
" %s IS ",
fmtId(objname));
@@ -679,6 +680,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 fe364dd..cee625b 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 d8fb356..d0d9545 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,
@@ -14774,9 +14780,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");
}
Hi All,
This is a patch for current_database working on ALTER ROLE/GRANT/REVOKE
statements which should be applied after the previous patch
"comment_on_current_database_no_pgdump_v4.4.patch".
By using the patch the CURRENT_DATABASE can working in the following SQL
statements:
ALTER ROLE ... IN DATABASE CURRENT_DATABASE SET/RESET
configuration_parameter
GRANT ... ON DATABASE CURRENT_DATABASE TO role_specification ...
REVOKE ... ON DATABASE CURRENT_DATABASE FROM ...
Regards,
Jing Wang
Fujitsu Australia
Attachments:
current_database_on_grant_revoke_role_v4.4.patchapplication/octet-stream; name=current_database_on_grant_revoke_role_v4.4.patchDownload
diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml
index c135364..28bcc07 100644
--- a/doc/src/sgml/ref/alter_role.sgml
+++ b/doc/src/sgml/ref/alter_role.sgml
@@ -38,16 +38,21 @@ ALTER ROLE <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER ROLE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index 8e03510..b33d87d 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -38,16 +38,21 @@ ALTER USER <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER USER <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index d02179f..d978789 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -74,7 +74,7 @@ COMMENT ON
<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
- object_name
+ <replaceable class="parameter">database_name</replaceable>
| CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index 475c85b..fac722f 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -39,9 +39,14 @@ GRANT { { USAGE | SELECT | UPDATE }
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
- ON DATABASE <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index e3e3f2f..c7caaf1 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 <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
diff --git a/doc/src/sgml/ref/security_label.sgml b/doc/src/sgml/ref/security_label.sgml
index 3e2391b..050243f 100644
--- a/doc/src/sgml/ref/security_label.sgml
+++ b/doc/src/sgml/ref/security_label.sgml
@@ -52,7 +52,7 @@ SECURITY LABEL [ FOR <replaceable class="parameter">provider</replaceable> ] ON
<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
- object_name
+ <replaceable class="parameter">database_name</replaceable>
| CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index ccde66a..c1a3e06 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"
@@ -647,10 +648,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/commands/user.c b/src/backend/commands/user.c
index f294135..71cfa13 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((DbSpec *)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((DbSpec *)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/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 933378a..3c67c45 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -4236,7 +4236,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;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 3570514..fcdd8fa 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2051,7 +2051,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;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 431a287..b8a2c73 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -397,7 +397,7 @@ static Node *makeDbSpec(DbSpecType type, int location);
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 <list> group_by_list
%type <node> group_by_item empty_grouping_set rollup_clause cube_clause
@@ -1142,7 +1142,7 @@ AlterRoleStmt:
opt_in_database:
/* EMPTY */ { $$ = NULL; }
- | IN_P DATABASE database_name { $$ = $3; }
+ | IN_P DATABASE db_spec_name { $$ = $3; }
;
AlterRoleSetStmt:
@@ -1150,7 +1150,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -1158,7 +1158,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = NULL;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -1166,7 +1166,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -1174,7 +1174,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = NULL;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -6994,7 +6994,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;
@@ -14431,6 +14431,13 @@ database_name:
}
;
+db_spec_name_list: db_spec_name
+ { $$ = list_make1($1); }
+ | db_spec_name_list ',' db_spec_name
+ { $$ = lappend($1, $3); }
+ ;
+
+
db_spec_name:
ColId
{
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 4852c7d..692ad74 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2455,7 +2455,7 @@ typedef struct AlterRoleSetStmt
{
NodeTag type;
RoleSpec *role; /* role */
- char *database; /* database name, or NULL */
+ Node *dbspec; /* name of database to set, DbSpec */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
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/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
Import Notes
Resolved by subject fallback
On Mon, Nov 27, 2017 at 11:41 AM, Jing Wang <jingwangian@gmail.com> wrote:
Hi All,
This is a patch for current_database working on ALTER ROLE/GRANT/REVOKE
statements which should be applied after the previous patch
"comment_on_current_database_no_pgdump_v4.4.patch".By using the patch the CURRENT_DATABASE can working in the following SQL
statements:ALTER ROLE ... IN DATABASE CURRENT_DATABASE SET/RESET
configuration_parameter
GRANT ... ON DATABASE CURRENT_DATABASE TO role_specification ...
REVOKE ... ON DATABASE CURRENT_DATABASE FROM ...
Moved to next CF with same status, "needs review".
--
Michael
On Wed, Nov 29, 2017 at 11:35 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:
On Mon, Nov 27, 2017 at 11:41 AM, Jing Wang <jingwangian@gmail.com> wrote:
This is a patch for current_database working on ALTER ROLE/GRANT/REVOKE
statements which should be applied after the previous patch
"comment_on_current_database_no_pgdump_v4.4.patch".By using the patch the CURRENT_DATABASE can working in the following SQL
statements:ALTER ROLE ... IN DATABASE CURRENT_DATABASE SET/RESET
configuration_parameter
GRANT ... ON DATABASE CURRENT_DATABASE TO role_specification ...
REVOKE ... ON DATABASE CURRENT_DATABASE FROM ...Moved to next CF with same status, "needs review".
Patch no longer applies.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Hi,
I have rebased the patch on the latest version.
Because the CURRENT_DATABASE can not only being used on COMMENT ON
statement but also on other statements as following list so the patch name
is renamed to "support_CURRENT_DATABASE_keyword_vxx.patch".
1. COMMENT ON DATABASE CURRENT_DATABASE is ...
2. ALTER DATABASE CURRENT_DATABASE OWNER to ...
3. ALTER DATABASE CURRENT_DATABASE SET parameter ...
4. ALTER DATABASE CURRENT_DATABASE RESET parameter ...
5. ALTER DATABASE CURRENT_DATABASE RESET ALL
6. SELECT CURRENT_DATABASE
7. SECURITY LABEL ON DATABASE CURRENT_DATABASE
8. ALTER ROLE ... IN DATABASE CURRENT_DATABASE SET/RESET
configuration_parameter
9. GRANT ... ON DATABASE CURRENT_DATABASE TO role_specification ...
10. REVOKE ... ON DATABASE CURRENT_DATABASE FROM ...
Regards,
Jing Wang
Fujitsu Australia
Attachments:
support_CURRENT_DATABASE_keyword_v4.5.patchapplication/octet-stream; name=support_CURRENT_DATABASE_keyword_v4.5.patchDownload
diff --git a/doc/src/sgml/ref/alter_database.sgml b/doc/src/sgml/ref/alter_database.sgml
index 7db878c..3c56d90 100644
--- a/doc/src/sgml/ref/alter_database.sgml
+++ b/doc/src/sgml/ref/alter_database.sgml
@@ -31,14 +31,14 @@ ALTER DATABASE <replaceable class="parameter">name</replaceable> [ [ WITH ] <rep
ALTER DATABASE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
ALTER DATABASE <replaceable class="parameter">name</replaceable> SET TABLESPACE <replaceable class="parameter">new_tablespace</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET ALL
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> RESET <replaceable>configuration_parameter</replaceable>
+ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> RESET ALL
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER ROLE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER USER <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">constraint_name</replaceable> ON <replaceable class="parameter">table_name</replaceable> |
CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ON DOMAIN <replaceable class="parameter">domain_name</replaceable> |
CONVERSION <replaceable class="parameter">object_name</replaceable> |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EXTENSION <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
@@ -73,6 +73,11 @@ COMMENT ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
@@ -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 <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
- ON DATABASE <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ 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 <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
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 <replaceable class="parameter">provider</replaceable> ] ON
TABLE <replaceable class="parameter">object_name</replaceable> |
COLUMN <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> |
AGGREGATE <replaceable class="parameter">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
FOREIGN TABLE <replaceable class="parameter">object_name</replaceable>
@@ -51,6 +51,11 @@ SECURITY LABEL [ FOR <replaceable class="parameter">provider</replaceable> ] ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index e481cf3..5d71fdf 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 9553675..8bdc315 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -724,7 +724,6 @@ const ObjectAddress InvalidObjectAddress =
InvalidOid,
0
};
-
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
Value *strval, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
@@ -868,6 +867,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 +2250,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 21e3f1e..2999ae9 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 2dc9371..047d283 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 eb1a469..600b592 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((DbSpec *)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((DbSpec *)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((DbSpec *)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 f294135..71cfa13 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((DbSpec *)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((DbSpec *)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 6c4612d..7172125 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -2043,6 +2043,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 aff9a62..0a9d588 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2922,6 +2922,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)
{
@@ -3746,7 +3758,7 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from)
{
AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(options);
return newnode;
@@ -3757,7 +3769,7 @@ _copyAlterDatabaseSetStmt(const AlterDatabaseSetStmt *from)
{
AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(setstmt);
return newnode;
@@ -4236,7 +4248,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;
@@ -5563,7 +5575,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 2e869a9..c73f682 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 ebfc94f..224ee1b 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 Node *makeDbSpec(DbSpecType type, int location);
%}
%pure-parser
@@ -397,7 +397,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 <list> group_by_list
%type <node> group_by_item empty_grouping_set rollup_clause cube_clause
@@ -572,6 +572,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
opt_frame_clause frame_extent frame_bound
%type <str> opt_existing_window_name
%type <boolean> opt_if_not_exists
+%type <node> db_spec_name
%type <ival> generated_when override_kind
%type <partspec> PartitionSpec OptPartitionSpec
%type <str> part_strategy
@@ -617,7 +618,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 +1157,7 @@ AlterRoleStmt:
opt_in_database:
/* EMPTY */ { $$ = NULL; }
- | IN_P DATABASE database_name { $$ = $3; }
+ | IN_P DATABASE db_spec_name { $$ = $3; }
;
AlterRoleSetStmt:
@@ -1164,7 +1165,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -1172,7 +1173,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = NULL;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -1180,7 +1181,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -1188,7 +1189,7 @@ AlterRoleSetStmt:
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = NULL;
- n->database = $4;
+ n->dbspec = (Node *)$4;
n->setstmt = $5;
$$ = (Node *)n;
}
@@ -6400,6 +6401,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 +6573,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 +6621,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 +6719,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 +7079,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 +9304,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 +10130,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 +10155,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;
}
@@ -13670,6 +13687,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);
@@ -14640,7 +14661,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 = (DbSpec *) makeDbSpec(DBSPEC_CSTRING, @1);
+ n->dbname = pstrdup($1);
+ $$ = (Node *)n;
+ }
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeDbSpec(DBSPEC_CURRENT_DATABASE, @1);
+ }
+ ;
access_method:
ColId { $$ = $1; };
@@ -14666,6 +14716,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -15321,6 +15373,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -16232,6 +16285,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
return (Node *) s;
}
+/* makeDbSpec
+ * Create a DbSpec with the given type
+ */
+static Node *
+makeDbSpec(DbSpecType type, int location)
+{
+ DbSpec *spec = makeNode(DbSpec);
+
+ spec->dbtype = type;
+ spec->location = location;
+
+ return (Node *) 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 29f9da7..226a15b 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 21593b2..508fd41 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 2f2758f..498cc4d 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,66 @@ check_rolespec_name(const RoleSpec *role, const char *detail_msg)
role->rolename)));
}
}
+
+
+/*
+ * Given a DbSpec, returns a palloc'ed copy of the corresponding role's 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 8514c21..560f3ff 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 12290a1..a48f04b 100644
--- a/src/bin/pg_dump/dumputils.c
+++ b/src/bin/pg_dump/dumputils.c
@@ -673,6 +673,7 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
appendPQExpBuffer(buffer,
"SECURITY LABEL FOR %s ON %s",
fmtId(provider), target);
+
appendPQExpBuffer(buffer,
" %s IS ",
fmtId(objname));
@@ -682,6 +683,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 fe364dd..cee625b 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 e6701aa..e00c89d 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/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index f42c8cd..9221b54 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -24,7 +24,8 @@ 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 c5b5115..d48ed0c 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 2eaa6b2..217301b 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2459,7 +2459,7 @@ typedef struct AlterRoleSetStmt
{
NodeTag type;
RoleSpec *role; /* role */
- char *database; /* database name, or NULL */
+ Node *dbspec; /* name of database to set, DbSpec */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -3039,6 +3039,24 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
+
+/*
+ * 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;
+
/* ----------------------
* Createdb Statement
* ----------------------
@@ -3057,14 +3075,14 @@ typedef struct CreatedbStmt
typedef struct AlterDatabaseStmt
{
NodeTag type;
- char *dbname; /* name of database to alter */
- List *options; /* List of DefElem nodes */
+ Node *dbspec; /* name of database to alter, DbSpec */
+ List *options; /* List of DefElem nodes */
} AlterDatabaseStmt;
typedef struct AlterDatabaseSetStmt
{
NodeTag type;
- char *dbname; /* database name */
+ Node *dbspec; /* DbSpec */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterDatabaseSetStmt;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 074ae0a..c65a05c 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 a932400..f7d4b9a 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 254a811..c9cfa85 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
On Mon, Dec 4, 2017 at 1:34 PM, Jing Wang <jingwangian@gmail.com> wrote:
I have rebased the patch on the latest version.
Hi Jing,
According to my testing robot this fails make check-world (or
presumably cd src/bin/pg_dump ; make check), here:
t/001_basic.pl ......... ok
# Failed test 'binary_upgrade: dumps COMMENT ON DATABASE postgres'
# at t/002_pg_dump.pl line 6753.
... masses of dump output omitted ...
# Looks like you failed 19 tests of 4727.
t/002_pg_dump.pl .......
Dubious, test returned 19 (wstat 4864, 0x1300)
Failed 19/4727 subtests
t/010_dump_connstr.pl .. ok
Test Summary Report
-------------------
t/002_pg_dump.pl (Wstat: 4864 Tests: 4727 Failed: 19)
Failed tests: 63, 224, 412, 702, 992, 1161, 1330, 1503
1672, 1840, 2008, 2176, 2343, 2495, 2663
3150, 3901, 4282, 4610
Non-zero exit status: 19
There is also a warning from my compiler here:
gram.y:1160:19: error: incompatible pointer types assigning to 'char
*' from 'Node *' (aka 'struct Node *')
[-Werror,-Wincompatible-pointer-types]
{ (yyval.str) = (yyvsp[0].node); }
^ ~~~~~~~~~~~~~~~
--
Thomas Munro
http://www.enterprisedb.com
Greetings Jing,
* Jing Wang (jingwangian@gmail.com) wrote:
I have rebased the patch on the latest version.
Thanks! Looks like there's still more work to be done here, and
unfortunately this ended up on a new thread somehow from the prior one.
I've added this newer thread to the CF app too.
Because the CURRENT_DATABASE can not only being used on COMMENT ON
statement but also on other statements as following list so the patch name
is renamed to "support_CURRENT_DATABASE_keyword_vxx.patch".
Makes sense.
Unfortunately, this still is throwing a warning when building:
/src/backend/parser/gram.y: In function ‘base_yyparse’:
/src/backend/parser/gram.y:1160:19: warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
| IN_P DATABASE db_spec_name { $$ = $3; }
^
Also, the documentation changes aren't quite right, you're doing:
ALTER DATABASE <replaceable class="parameter">{name | CURRENT_DATABASE}</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
When it should be:
ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
Note that the "replaceable class" tag goes directly around 'name', and
doesn't include CURRENT_DATABASE. Also, keep a space before 'name' and
after 'CURRENT_DATABASE', just like how the "OWNER TO ..." piece works.
Please don't include whitespace-only hunks, like this one:
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
*************** const ObjectAddress InvalidObjectAddress
*** 724,730 ****
InvalidOid,
0
};
-
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
Value *strval, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
The TAP regression tests for pg_dump are failing. It looks like you've
changed pg_dump to use CURRENT_DATABASE, which is fine, but please
adjust the regexp's used in the pg_dump TAP tests to handle that. The
regexp you're looking to change is in src/bin/pg_dump/t/002_pg_dump.pl,
around line 1515 in current head (look for the stanza:
'COMMENT ON DATABASE postgres' => {
and the regexp:
regexp => qr/^COMMENT ON DATABASE postgres IS .*;/m,
That looks to be the only thing that needs to be changed to make this
test pass.
In gram.y, I would have thought to make a db_spec_name a 'dbspec' type,
similar to what was done with 'rolespec' (though, I note, the efforts
around RoleSpec seem to have stalled since COMMENT ON ROLE CURRENT_ROLE
doesn't work and get_object_address seems to still think that the parser
works with roles as strings, when only half of it actually does..) and
then make makeDbSpec() return a DbSpec and then try to minimize the
forced-casting happening. On a similar vein, I would think that the
various 'dbspec' pointers in AlterRoleSetStmt and others should be of
the DbSpec type instead of just being Node*'s.
Ideally, try to make sure that the changes you're making are pgindent'd
properly.
There's probably more to do on this, but hopefully this gets the patch
into a bit of a cleaner state for further review. Setting to Waiting on
Author.
Thanks!
Stephen
Hi Stephen and Thomas,
Thanks your review comments.
Enclosed please find the latest patch.
/src/backend/parser/gram.y: In function ‘base_yyparse’:
/src/backend/parser/gram.y:1160:19: warning: assignment from incompatible
pointer type [-Wincompatible-pointer-types]
| IN_P DATABASE db_spec_name { $$ = $3; }
The warning has been dismissed.
When it should be:
ALTER DATABASE { <replaceable class="parameter">name</replaceable> |
CURRENT_DATABASE } OWNER TO { <replaceable>new_owner</replaceable> |
CURRENT_USER | SESSION_USER }
Yes. It should be.
Please don't include whitespace-only hunks, like this one:
Ok.
The TAP regression tests for pg_dump are failing.
The test case has been updated.
make makeDbSpec() return a DbSpec and then try to minimize the
forced-casting happening.
Makes sense. It has been changed.
Regards,
Jing Wang
Fujitsu Australia
Attachments:
support_CURRENT_DATABASE_keyword_v4.6.patchapplication/octet-stream; name=support_CURRENT_DATABASE_keyword_v4.6.patchDownload
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 <replaceable class="parameter">name</replaceable> [ [ WITH ] <rep
ALTER DATABASE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
ALTER DATABASE <replaceable class="parameter">name</replaceable> SET TABLESPACE <replaceable class="parameter">new_tablespace</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET ALL
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } RESET <replaceable>configuration_parameter</replaceable>
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } RESET ALL
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER ROLE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER USER <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">constraint_name</replaceable> ON <replaceable class="parameter">table_name</replaceable> |
CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ON DOMAIN <replaceable class="parameter">domain_name</replaceable> |
CONVERSION <replaceable class="parameter">object_name</replaceable> |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EXTENSION <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
@@ -73,6 +73,11 @@ COMMENT ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
@@ -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 <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
- ON DATABASE <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ 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 <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
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 <replaceable class="parameter">provider</replaceable> ] ON
TABLE <replaceable class="parameter">object_name</replaceable> |
COLUMN <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> |
AGGREGATE <replaceable class="parameter">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
FOREIGN TABLE <replaceable class="parameter">object_name</replaceable>
@@ -51,6 +51,11 @@ SECURITY LABEL [ FOR <replaceable class="parameter">provider</replaceable> ] ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <node> stmt schema_stmt
@@ -316,7 +317,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> opt_in_database
+%type <dbspec> opt_in_database
%type <str> OptSchemaName
%type <list> 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 <list> group_by_list
%type <node> 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 <str> opt_existing_window_name
%type <boolean> opt_if_not_exists
+%type <dbspec> db_spec_name
%type <ival> generated_when override_kind
%type <partspec> PartitionSpec OptPartitionSpec
%type <str> 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
Jing Wang <jingwangian@gmail.com> writes:
[ support_CURRENT_DATABASE_keyword_v4.6.patch ]
Not surprisingly, this patch no longer applies in the wake of commit
b3f840120. Rather than rebasing the pg_dump portions, I would suggest
you just drop them. It is no longer necessary for pg_dump to worry about
this, because it won't emit COMMENT ON DATABASE or SECURITY LABEL FOR
DATABASE except in cases where it just created the target database
and so knows the DB name for sure. So, using COMMENT ON DATABASE
CURRENT_DATABASE would just create an unnecessary version dependency
in the output script. (BTW, using the source database's version to decide
what to emit is not per pg_dump policy. Also, if you did still want to
modify pg_dump to use CURRENT_DATABASE, you'd have to extend the patch
to handle ACLs and some other ALTER DATABASE commands.)
I'm not really sure how much of the use-case for this feature rested
on the pg_dump issue. It may still be worthwhile for other use cases,
or maybe we should just drop it.
I notice some other patch application failures in dbcommands.c,
objectaddress.c, and user.c, so there's more work to do besides
this ...
regards, tom lane
Not surprisingly, this patch no longer applies in the wake of commit
b3f840120. Rather than rebasing the pg_dump portions, I would suggest
you just drop them.
It has been removed from the pg_dump codes.
I notice some other patch application failures in dbcommands.c,
objectaddress.c, and user.c, so there's more work to do besides
this
Yes. fixed it.
Enclosed please find the latest patch fixed above.
Regards,
Jing Wang
Fujitsu Australia
Attachments:
support_CURRENT_DATABASE_keyword_v4.7.patchapplication/octet-stream; name=support_CURRENT_DATABASE_keyword_v4.7.patchDownload
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 <replaceable class="parameter">name</replaceable> [ [ WITH ] <rep
ALTER DATABASE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } OWNER TO { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER }
ALTER DATABASE <replaceable class="parameter">name</replaceable> SET TABLESPACE <replaceable class="parameter">new_tablespace</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER DATABASE <replaceable class="parameter">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
-ALTER DATABASE <replaceable class="parameter">name</replaceable> RESET ALL
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } RESET <replaceable>configuration_parameter</replaceable>
+ALTER DATABASE { <replaceable class="parameter">name</replaceable> | CURRENT_DATABASE } RESET ALL
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER ROLE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER ROLE { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">role_specification</replaceable> [ WIT
ALTER USER <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_name</replaceable> ] RESET ALL
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER USER { <replaceable class="parameter">role_specification</replaceable> | ALL } [ IN DATABASE <replaceable class="parameter">database_specification</replaceable> ] RESET ALL
<phrase>where <replaceable class="parameter">role_specification</replaceable> can be:</phrase>
<replaceable class="parameter">role_name</replaceable>
| CURRENT_USER
| SESSION_USER
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <replaceable class="parameter">constraint_name</replaceable> ON <replaceable class="parameter">table_name</replaceable> |
CONSTRAINT <replaceable class="parameter">constraint_name</replaceable> ON DOMAIN <replaceable class="parameter">domain_name</replaceable> |
CONVERSION <replaceable class="parameter">object_name</replaceable> |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EXTENSION <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
@@ -73,6 +73,11 @@ COMMENT ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
@@ -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 <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
- ON DATABASE <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ 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 <replaceable>database_name</replaceable> [, ...]
+ ON DATABASE <replaceable>database_specification</replaceable> [, ...]
FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+<phrase>where <replaceable class="parameter">database_specification</replaceable> can be:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
+
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
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 <replaceable class="parameter">provider</replaceable> ] ON
TABLE <replaceable class="parameter">object_name</replaceable> |
COLUMN <replaceable class="parameter">table_name</replaceable>.<replaceable class="parameter">column_name</replaceable> |
AGGREGATE <replaceable class="parameter">aggregate_name</replaceable> ( <replaceable>aggregate_signature</replaceable> ) |
- DATABASE <replaceable class="parameter">object_name</replaceable> |
+ DATABASE <replaceable class="parameter">database_specification</replaceable> |
DOMAIN <replaceable class="parameter">object_name</replaceable> |
EVENT TRIGGER <replaceable class="parameter">object_name</replaceable> |
FOREIGN TABLE <replaceable class="parameter">object_name</replaceable>
@@ -51,6 +51,11 @@ SECURITY LABEL [ FOR <replaceable class="parameter">provider</replaceable> ] ON
* |
[ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] |
[ [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ] ] ORDER BY [ <replaceable>argmode</replaceable> ] [ <replaceable>argname</replaceable> ] <replaceable>argtype</replaceable> [ , ... ]
+
+<phrase>where <replaceable class="parameter">database_specification</replaceable> is:</phrase>
+
+ <replaceable class="parameter">database_name</replaceable>
+ | CURRENT_DATABASE
</synopsis>
</refsynopsisdiv>
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 <node> stmt schema_stmt
@@ -316,7 +317,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> opt_in_database
+%type <dbspec> opt_in_database
%type <str> OptSchemaName
%type <list> 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 <list> group_by_list
%type <node> 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 <str> opt_existing_window_name
%type <boolean> opt_if_not_exists
+%type <dbspec> db_spec_name
%type <ival> generated_when override_kind
%type <partspec> PartitionSpec OptPartitionSpec
%type <str> 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
Jing Wang <jingwangian@gmail.com> writes:
[ support_CURRENT_DATABASE_keyword_v4.7.patch ]
TBH, I think we should reject this patch. While it's not huge,
it's not trivial either, and I find the grammar changes rather ugly.
The argument for using the feature to fix pg_dump issues has evaporated,
but I don't see anything in the discussion suggesting that people see
a need for it beyond that.
I particularly object to inventing a CURRENT_DATABASE parameterless
function. That's encroaching on user namespace to no purpose whatever,
as we already have a perfectly good regular function for that.
Also, from a user standpoint, turning CURRENT_DATABASE into a fully
reserved word seems like a bad idea. If nothing else, that breaks
queries that are relying on the existing current_database() function.
The parallel to CURRENT_ROLE is not very good, because there at least
we can point to the SQL spec and say it's reserved according to the
standard. CURRENT_DATABASE has no such excuse.
regards, tom lane
Hi Jing,
On 3/1/18 2:09 PM, Tom Lane wrote:
Jing Wang <jingwangian@gmail.com> writes:
[ support_CURRENT_DATABASE_keyword_v4.7.patch ]
TBH, I think we should reject this patch. While it's not huge,
it's not trivial either, and I find the grammar changes rather ugly.
The argument for using the feature to fix pg_dump issues has evaporated,
but I don't see anything in the discussion suggesting that people see
a need for it beyond that.I particularly object to inventing a CURRENT_DATABASE parameterless
function. That's encroaching on user namespace to no purpose whatever,
as we already have a perfectly good regular function for that.Also, from a user standpoint, turning CURRENT_DATABASE into a fully
reserved word seems like a bad idea. If nothing else, that breaks
queries that are relying on the existing current_database() function.
The parallel to CURRENT_ROLE is not very good, because there at least
we can point to the SQL spec and say it's reserved according to the
standard. CURRENT_DATABASE has no such excuse.
Based on Tom's feedback, and hearing no opinions to the contrary, I have
marked this patch Rejected.
Regards,
--
-David
david@pgmasters.net
David Steele wrote:
On 3/1/18 2:09 PM, Tom Lane wrote:
TBH, I think we should reject this patch. While it's not huge,
it's not trivial either, and I find the grammar changes rather ugly.
The argument for using the feature to fix pg_dump issues has evaporated,
but I don't see anything in the discussion suggesting that people see
a need for it beyond that.
Based on Tom's feedback, and hearing no opinions to the contrary, I have
marked this patch Rejected.
I think I opine contrarywise, but I haven't made time to review the
status of this in detail. I'm fine with keeping it rejected for now,
but I reserve the option to revive it in the future.
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Hi Álvaro,
On 3/6/18 10:25 AM, Alvaro Herrera wrote:
David Steele wrote:
On 3/1/18 2:09 PM, Tom Lane wrote:
TBH, I think we should reject this patch. While it's not huge,
it's not trivial either, and I find the grammar changes rather ugly.
The argument for using the feature to fix pg_dump issues has evaporated,
but I don't see anything in the discussion suggesting that people see
a need for it beyond that.Based on Tom's feedback, and hearing no opinions to the contrary, I have
marked this patch Rejected.I think I opine contrarywise, but I haven't made time to review the
status of this in detail. I'm fine with keeping it rejected for now,
but I reserve the option to revive it in the future.
Absolutely.
From my perspective reviving a patch is pretty much always an option.
I'm attempting to update patches based on what I see as the current
status, but my decision is certainly not final and I do make mistakes.
Regards,
--
-David
david@pgmasters.net
Alvaro Herrera <alvherre@alvh.no-ip.org> writes:
David Steele wrote:
Based on Tom's feedback, and hearing no opinions to the contrary, I have
marked this patch Rejected.
I think I opine contrarywise, but I haven't made time to review the
status of this in detail. I'm fine with keeping it rejected for now,
but I reserve the option to revive it in the future.
I'm fine with reviving it if someone can find a way around the new-
reserved-word problem. But that's gonna be a bit hard given that
the patch wants to do
database_name:
ColId
| CURRENT_DATABASE
You might be able to preserve the accessibility of the current_database()
function by making CURRENT_DATABASE into a type_func_name_keyword instead
of a fully-reserved word. But that's ugly (I think you'd need a single-
purpose production for it to be used as a function), and you've still
broken any SQL code using "current_database" as a table or column name.
I'm dubious that the remaining use-case for the feature is worth it.
regards, tom lane