Support to COMMENT ON DATABASE CURRENT_DATABASE
Hi all,
The attached patch is to support the feature "COMMENT ON DATABASE
CURRENT_DATABASE". The solution is based on the previous discussion in [2]/messages/by-id/CAB7nPqSTXUWAx-C5Pgw+du5jxu4QZ=axQq165McmyT3UggWmuQ@mail.gmail.com .
Can't find the previous link in my email history list so create a new topic
here.
By using the patch the CURRENT_DATABASE as a keyword can be used in the
following SQL commands:
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. SELECT CURRENT_DATABASE
[1]: /messages/by-id/20150317171836.GC10492@momjian.us
[2]: /messages/by-id/CAB7nPqSTXUWAx-C5Pgw+du5jxu4QZ=axQq165McmyT3UggWmuQ@mail.gmail.com
/messages/by-id/CAB7nPqSTXUWAx-C5Pgw+du5jxu4QZ=axQq165McmyT3UggWmuQ@mail.gmail.com
--
Regards,
Jing Wang
Fujitsu Australia
Attachments:
comment_on_current_database_v2.patchtext/x-patch; charset=US-ASCII; name=comment_on_current_database_v2.patchDownload
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index e60e8e8..8895980 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -665,7 +665,8 @@ const ObjectAddress InvalidObjectAddress =
InvalidOid,
0
};
-
+static ObjectAddress get_object_address_database(ObjectType objtype,
+ List * objname, bool missing_ok);
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
List *qualname, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
@@ -803,6 +804,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
}
break;
case OBJECT_DATABASE:
+ address = get_object_address_database(objtype, objname, missing_ok);
+ break;
case OBJECT_EXTENSION:
case OBJECT_TABLESPACE:
case OBJECT_ROLE:
@@ -1042,6 +1045,44 @@ get_object_address_rv(ObjectType objtype, RangeVar *rel, List *objname,
/*
* Find an ObjectAddress for a type of object that is identified by an
+ * database name
+ */
+static ObjectAddress
+get_object_address_database(ObjectType objtype, List * objname, bool missing_ok)
+{
+ const char *name;
+ char *dbname;
+ DBSpecName *dbspecname;
+ ObjectAddress address;
+
+ if (list_length(objname) != 1)
+ {
+ const char *msg;
+
+ msg = gettext_noop("database name cannot be qualified");
+
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s", _(msg))));
+ }
+
+ /* Format is valid, extract the actual name. */
+ dbspecname = (DBSpecName*)linitial(objname);
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ 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
@@ -2086,8 +2127,20 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
break;
case OBJECT_DATABASE:
if (!pg_database_ownercheck(address.objectId, roleid))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- NameListToString(objname));
+ {
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ /* Format is valid, extract the actual name. */
+ dbspecname = (DBSpecName*)linitial(objname);
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,dbname);
+ }
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 1301bcb..78f6dfb 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -749,7 +749,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
switch (stmt->objectType)
{
case OBJECT_DATABASE:
- return AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
+ return AlterDatabaseOwner(linitial(stmt->object), newowner);
case OBJECT_SCHEMA:
return AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index a0d3f8d..f2f27d7 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -53,13 +53,21 @@ CommentObject(CommentStmt *stmt)
*/
if (stmt->objtype == OBJECT_DATABASE && list_length(stmt->objname) == 1)
{
- char *database = strVal(linitial(stmt->objname));
+ char *dbname = NULL;
+ DBSpecName *dbspecname = NULL;
- if (!OidIsValid(get_database_oid(database, true)))
+ dbspecname = (DBSpecName*)linitial(stmt->objname);
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ if (!OidIsValid(get_database_oid(dbname, true)))
{
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 f47a13d..a5c71b2 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1383,6 +1383,15 @@ AlterDatabase(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;
+ DBSpecName *dbspecname = NULL;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
/* Extract options from the statement node tree */
foreach(option, stmt->options)
@@ -1441,7 +1450,7 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
dtablespace->defname)));
/* 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;
}
@@ -1467,20 +1476,20 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
ScanKeyInit(&scankey,
Anum_pg_database_datname,
BTEqualStrategyNumber, F_NAMEEQ,
- NameGetDatum(stmt->dbname));
+ NameGetDatum(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
@@ -1541,7 +1550,18 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
Oid
AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
{
- Oid datid = get_database_oid(stmt->dbname, false);
+ Oid datid;
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ datid = get_database_oid(dbname, false);
/*
* Obtain a lock on the database and make sure it didn't go away in the
@@ -1551,7 +1571,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
if (!pg_database_ownercheck(datid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- stmt->dbname);
+ dbname);
AlterSetting(datid, InvalidOid, stmt->setstmt);
@@ -1565,7 +1585,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
* ALTER DATABASE name OWNER TO newowner
*/
ObjectAddress
-AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
+AlterDatabaseOwner(const DBSpecName *dbspec, Oid newOwnerId)
{
Oid db_id;
HeapTuple tuple;
@@ -1574,6 +1594,12 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
SysScanDesc scan;
Form_pg_database datForm;
ObjectAddress address;
+ char *dbname;
+
+ if (dbspec->dbnametype == DBSPEC_CURRENT_DATABASE)
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspec->dbname;
/*
* Get the old tuple. We don't need a lock on the database per se,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 080d444..784eb7e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -177,7 +177,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 *makeDBSpecName(DBSpecNameType type, int location);
%}
%pure-parser
@@ -539,6 +539,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
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
@@ -575,7 +576,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
@@ -5737,6 +5738,15 @@ CommentStmt:
n->comment = $6;
$$ = (Node *) n;
}
+ | COMMENT ON DATABASE db_spec_name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_DATABASE;
+ n->objname = list_make1($4);
+ n->objargs = NIL;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
| COMMENT ON TYPE_P Typename IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
@@ -5900,7 +5910,6 @@ CommentStmt:
comment_type:
ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; }
| COLUMN { $$ = OBJECT_COLUMN; }
- | DATABASE { $$ = OBJECT_DATABASE; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
| INDEX { $$ = OBJECT_INDEX; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
@@ -8372,11 +8381,11 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args 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 = list_make1(makeString($3));
+ n->object = list_make1($3);
n->newowner = $6;
$$ = (Node *)n;
}
@@ -8975,24 +8984,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)));
$$ = (Node *)n;
@@ -9000,10 +9009,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;
}
@@ -12465,6 +12474,10 @@ func_expr_common_subexpr:
{
$$ = (Node *) makeFuncCall(SystemFuncName("session_user"), NIL, @1);
}
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_database"), NIL, @1);
+ }
| USER
{
$$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1);
@@ -13465,8 +13478,31 @@ 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
+ {
+ DBSpecName *n = (Node *) makeDBSpecName(DBSPEC_CSTRING, @1);
+ n->dbname = pstrdup($1);
+ $$ = n;
+ }
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeDBSpecName(DBSPEC_CURRENT_DATABASE, @1);
+ }
+ ;
+
access_method:
ColId { $$ = $1; };
@@ -13491,6 +13527,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -14129,6 +14167,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -15001,6 +15040,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
return (Node *) s;
}
+/* makeDBSpecName
+ * Create a DBSpecName with the given type
+ */
+static Node *
+makeDBSpecName(DBSpecNameType type, int location)
+{
+ DBSpecName *spec = makeNode(DBSpecName);
+
+ spec->dbnametype = type;
+ spec->location = location;
+
+ return (Node *) spec;
+}
+
/* parser_init()
* Initialize to parse one query string
*/
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ea64c77..b79d3e1 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2717,10 +2717,20 @@ dumpDatabase(Archive *fout)
resetPQExpBuffer(dbQry);
/*
- * Generates warning when loaded into a differently-named
- * database.
- */
- appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
+ * Use the new form (COMMENT ON CURRENT DATABASE) for new version
+ */
+ if (fout->remoteVersion >= 100000)
+ {
+ appendPQExpBuffer(dbQry, "COMMENT ON DATABASE CURRENT_DATABASE IS ");
+ }
+ else
+ {
+ /*
+ * Generates warning when loaded into a differently-named
+ * database.
+ */
+ appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
+ }
appendStringLiteralAH(dbQry, comment, fout);
appendPQExpBufferStr(dbQry, ";\n");
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index b6436f1..84b6743 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(AlterDatabaseStmt *stmt, bool isTopLevel);
extern Oid AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
-extern ObjectAddress AlterDatabaseOwner(const char *dbname, Oid newOwnerId);
+extern ObjectAddress AlterDatabaseOwner(const DBSpecName *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 d3fdf55..53a638e 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -452,6 +452,7 @@ typedef enum NodeTag
T_OnConflictClause,
T_CommonTableExpr,
T_RoleSpec,
+ T_DBSpecName,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 1481fff..06c9804 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2745,6 +2745,24 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
+
+/*
+ * DBSpecType - The type of a database name.
+ */
+typedef enum DBSpecNameType
+{
+ DBSPEC_CSTRING, /* database name is stored as a C string */
+ DBSPEC_CURRENT_DATABASE /* database name is CURRENT_DATABASE */
+} DBSpecNameType;
+
+typedef struct DBSpecName
+{
+ NodeTag type;
+ DBSpecNameType dbnametype; /* Type of the database */
+ char *dbname; /* filled only for DBSPEC_CSTRING */
+ int location; /* token location, or -1 if unknown */
+} DBSpecName;
+
/* ----------------------
* Createdb Statement
* ----------------------
@@ -2763,14 +2781,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, DBSpecName */
+ List *options; /* List of DefElem nodes */
} AlterDatabaseStmt;
typedef struct AlterDatabaseSetStmt
{
NodeTag type;
- char *dbname; /* database name */
+ Node *dbspec; /* database name, DBSpecName */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterDatabaseSetStmt;
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 17ffef5..484539e 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -102,6 +102,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/test/regress/expected/dbname.out b/src/test/regress/expected/dbname.out
new file mode 100644
index 0000000..954b3f9
--- /dev/null
+++ b/src/test/regress/expected/dbname.out
@@ -0,0 +1,128 @@
+CREATE ROLE dbuser1 with LOGIN;
+CREATE ROLE dbuser2 with SUPERUSER LOGIN;
+CREATE ROLE dbuser3 with SUPERUSER LOGIN;
+CREATE DATABASE mydb1;
+CREATE DATABASE "current_database";
+CREATE DATABASE current_database;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: CREATE DATABASE current_database;
+ ^
+\l+
+ List of databases
+ Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
+------------------+-------+----------+-------------+-------------+-------------------+---------+------------+--------------------------------------------
+ current_database | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7233 kB | pg_default |
+ mydb1 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7233 kB | pg_default |
+ postgres | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7343 kB | pg_default | default administrative connection database
+ regression | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/wangj +| 63 MB | pg_default |
+ | | | | | wangj=CTc/wangj | | |
+ template0 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | unmodifiable empty database
+ | | | | | wangj=CTc/wangj | | |
+ template1 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | default template for new databases
+ | | | | | wangj=CTc/wangj | | |
+(6 rows)
+
+\c mydb1;
+SELECT CURRENT_DATABASE;
+ current_database
+------------------
+ mydb1
+(1 row)
+
+COMMENT ON DATABASE current_database IS 'db1';
+COMMENT ON DATABASE "current_database" IS 'db2';
+\l+
+ List of databases
+ Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
+------------------+-------+----------+-------------+-------------+-------------------+---------+------------+--------------------------------------------
+ current_database | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7233 kB | pg_default | db2
+ mydb1 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7343 kB | pg_default | db1
+ postgres | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7343 kB | pg_default | default administrative connection database
+ regression | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/wangj +| 63 MB | pg_default |
+ | | | | | wangj=CTc/wangj | | |
+ template0 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | unmodifiable empty database
+ | | | | | wangj=CTc/wangj | | |
+ template1 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | default template for new databases
+ | | | | | wangj=CTc/wangj | | |
+(6 rows)
+
+-- test alter owner
+ALTER DATABASE current_database OWNER to dbuser2;
+ALTER DATABASE "current_database" OWNER to dbuser2;
+-- 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 newdb1;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: ALTER DATABASE current_database RENAME TO newdb1;
+ ^
+ALTER DATABASE "current_database" RENAME TO mydb2;
+\l+
+ List of databases
+ Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
+------------+---------+----------+-------------+-------------+-------------------+---------+------------+--------------------------------------------
+ mydb1 | dbuser2 | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7343 kB | pg_default | db1
+ mydb2 | dbuser2 | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7233 kB | pg_default | db2
+ postgres | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7343 kB | pg_default | default administrative connection database
+ regression | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/wangj +| 63 MB | pg_default |
+ | | | | | wangj=CTc/wangj | | |
+ template0 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | unmodifiable empty database
+ | | | | | wangj=CTc/wangj | | |
+ template1 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | default template for new databases
+ | | | | | wangj=CTc/wangj | | |
+(6 rows)
+
+ALTER DATABASE mydb2 rename to current_database;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: ALTER DATABASE mydb2 rename to current_database;
+ ^
+ALTER DATABASE mydb2 rename to "current_database";
+\l+
+ List of databases
+ Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
+------------------+---------+----------+-------------+-------------+-------------------+---------+------------+--------------------------------------------
+ current_database | dbuser2 | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7233 kB | pg_default | db2
+ mydb1 | dbuser2 | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7343 kB | pg_default | db1
+ postgres | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | 7343 kB | pg_default | default administrative connection database
+ regression | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =Tc/wangj +| 63 MB | pg_default |
+ | | | | | wangj=CTc/wangj | | |
+ template0 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | unmodifiable empty database
+ | | | | | wangj=CTc/wangj | | |
+ template1 | wangj | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/wangj +| 7233 kB | pg_default | default template for new databases
+ | | | | | wangj=CTc/wangj | | |
+(6 rows)
+
+-- test alter database set parameter
+ALTER DATABASE current_database SET parallel_tuple_cost=0.3;
+\c mydb1
+show parallel_tuple_cost;
+ parallel_tuple_cost
+---------------------
+ 0.3
+(1 row)
+
+ALTER DATABASE current_database RESET parallel_tuple_cost;
+\c mydb1
+show parallel_tuple_cost;
+ parallel_tuple_cost
+---------------------
+ 0.1
+(1 row)
+
+-- clean up
+\c postgres
+DROP DATABASE "current_database";
+DROP DATABASE current_database;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: DROP DATABASE current_database;
+ ^
+DROP ROLE dbuser1;
+DROP ROLE dbuser2;
+ERROR: role "dbuser2" cannot be dropped because some objects depend on it
+DETAIL: owner of database mydb1
+DROP ROLE dbuser3;
+DROP DATABASE mydb1;
+DROP DATABASE mydb2;
+ERROR: database "mydb2" does not exist
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 3815182..a99d2ff 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -110,3 +110,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 8958d8c..0363c44 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -168,3 +168,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..ef9d93d
--- /dev/null
+++ b/src/test/regress/sql/dbname.sql
@@ -0,0 +1,57 @@
+CREATE ROLE dbuser1 with LOGIN;
+CREATE ROLE dbuser2 with SUPERUSER LOGIN;
+CREATE ROLE dbuser3 with SUPERUSER LOGIN;
+
+CREATE DATABASE mydb1;
+CREATE DATABASE "current_database";
+CREATE DATABASE current_database;
+
+\l+
+
+\c mydb1;
+SELECT CURRENT_DATABASE;
+
+
+COMMENT ON DATABASE current_database IS 'db1';
+COMMENT ON DATABASE "current_database" IS 'db2';
+
+\l+
+
+-- test alter owner
+ALTER DATABASE current_database OWNER to dbuser2;
+ALTER DATABASE "current_database" OWNER to dbuser2;
+
+
+
+-- 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 newdb1;
+ALTER DATABASE "current_database" RENAME TO mydb2;
+\l+
+
+ALTER DATABASE mydb2 rename to current_database;
+ALTER DATABASE mydb2 rename to "current_database";
+\l+
+
+-- test alter database set parameter
+ALTER DATABASE current_database SET parallel_tuple_cost=0.3;
+\c mydb1
+show parallel_tuple_cost;
+ALTER DATABASE current_database RESET parallel_tuple_cost;
+\c mydb1
+show parallel_tuple_cost;
+
+-- clean up
+\c postgres
+
+DROP DATABASE "current_database";
+DROP DATABASE current_database;
+
+DROP ROLE dbuser1;
+DROP ROLE dbuser2;
+DROP ROLE dbuser3;
+DROP DATABASE mydb1;
+DROP DATABASE mydb2;
On Mon, Jun 5, 2017 at 10:09 AM, Jing Wang <jingwangian@gmail.com> wrote:
By using the patch the CURRENT_DATABASE as a keyword can be used in the
following SQL commands: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. SELECT CURRENT_DATABASE
You should add that to the next commit fest:
https://commitfest.postgresql.org/14/
Note that it may take a couple of months until you get some review, as
the focus now is to stabilize Postgres 10.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi Michael,
You should add that to the next commit fest:
https://commitfest.postgresql.org/14/
<https://commitfest.postgresql.org/14/>
Thanks your mention. I will do that.
Regards,
Jing Wang
Fujitsu Australia
On Mon, Jun 5, 2017 at 4:09 AM, Jing Wang <jingwangian@gmail.com> wrote:
Hi all,
The attached patch is to support the feature "COMMENT ON DATABASE
CURRENT_DATABASE". The solution is based on the previous discussion in [2] .
Your patch doesn't cover security labels on databases which have similar
issue
and consider dividing the patch into two one for adding CURRENT_DATABASE as
a
database specifier and the other for adding database-level information to
pg_dump output
in a way that allows to load a dump into a differently named database
Regards,
Surafel
Hi Surafel,
Your patch doesn't cover security labels on databases which have similar
issue
and consider dividing the patch into two one for adding CURRENT_DATABASE
as a
database specifier and the other for adding database-level information to
pg_dump output
in a way that allows to load a dump into a differently named database.
Thanks your review and suggestion. I will add them.
Regards,
Jing Wang
Fujitsu Australia
Hi all,
Enclosed please find the updated patch with covering security labels on
database.
The patch cover the following commands:
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. SELECT CURRENT_DATABASE
6. SECURITY LABEL ON DATABASE CURRENT_DATABASE is ...
The patch doesn't cover the pg_dump part which will be included in another
patch later.
Regards,
Jing Wang
Fujitsu Australia
Attachments:
comment_on_current_database_no_pgdump_v3.patchapplication/octet-stream; name=comment_on_current_database_no_pgdump_v3.patchDownload
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index e60e8e8..db8f72a 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -665,7 +665,8 @@ const ObjectAddress InvalidObjectAddress =
InvalidOid,
0
};
-
+static ObjectAddress get_object_address_database(ObjectType objtype,
+ List * objname, bool missing_ok);
static ObjectAddress get_object_address_unqualified(ObjectType objtype,
List *qualname, bool missing_ok);
static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
@@ -803,6 +804,8 @@ get_object_address(ObjectType objtype, List *objname, List *objargs,
}
break;
case OBJECT_DATABASE:
+ address = get_object_address_database(objtype, objname, missing_ok);
+ break;
case OBJECT_EXTENSION:
case OBJECT_TABLESPACE:
case OBJECT_ROLE:
@@ -1042,6 +1045,43 @@ get_object_address_rv(ObjectType objtype, RangeVar *rel, List *objname,
/*
* Find an ObjectAddress for a type of object that is identified by an
+ * database name
+ */
+static ObjectAddress
+get_object_address_database(ObjectType objtype, List * objname, bool missing_ok)
+{
+ char *dbname;
+ DBSpecName *dbspecname;
+ ObjectAddress address;
+
+ if (list_length(objname) != 1)
+ {
+ const char *msg;
+
+ msg = gettext_noop("database name cannot be qualified");
+
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s", _(msg))));
+ }
+
+ /* Format is valid, extract the actual name. */
+ dbspecname = (DBSpecName*)linitial(objname);
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ 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
@@ -2086,8 +2126,20 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
break;
case OBJECT_DATABASE:
if (!pg_database_ownercheck(address.objectId, roleid))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- NameListToString(objname));
+ {
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ /* Format is valid, extract the actual name. */
+ dbspecname = (DBSpecName*)linitial(objname);
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,dbname);
+ }
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 1301bcb..78f6dfb 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -749,7 +749,7 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
switch (stmt->objectType)
{
case OBJECT_DATABASE:
- return AlterDatabaseOwner(strVal(linitial(stmt->object)), newowner);
+ return AlterDatabaseOwner(linitial(stmt->object), newowner);
case OBJECT_SCHEMA:
return AlterSchemaOwner(strVal(linitial(stmt->object)), newowner);
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index a0d3f8d..f2f27d7 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -53,13 +53,21 @@ CommentObject(CommentStmt *stmt)
*/
if (stmt->objtype == OBJECT_DATABASE && list_length(stmt->objname) == 1)
{
- char *database = strVal(linitial(stmt->objname));
+ char *dbname = NULL;
+ DBSpecName *dbspecname = NULL;
- if (!OidIsValid(get_database_oid(database, true)))
+ dbspecname = (DBSpecName*)linitial(stmt->objname);
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ if (!OidIsValid(get_database_oid(dbname, true)))
{
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 f47a13d..a5c71b2 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1383,6 +1383,15 @@ AlterDatabase(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;
+ DBSpecName *dbspecname = NULL;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
/* Extract options from the statement node tree */
foreach(option, stmt->options)
@@ -1441,7 +1450,7 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
dtablespace->defname)));
/* 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;
}
@@ -1467,20 +1476,20 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
ScanKeyInit(&scankey,
Anum_pg_database_datname,
BTEqualStrategyNumber, F_NAMEEQ,
- NameGetDatum(stmt->dbname));
+ NameGetDatum(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
@@ -1541,7 +1550,18 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
Oid
AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
{
- Oid datid = get_database_oid(stmt->dbname, false);
+ Oid datid;
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ datid = get_database_oid(dbname, false);
/*
* Obtain a lock on the database and make sure it didn't go away in the
@@ -1551,7 +1571,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
if (!pg_database_ownercheck(datid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- stmt->dbname);
+ dbname);
AlterSetting(datid, InvalidOid, stmt->setstmt);
@@ -1565,7 +1585,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
* ALTER DATABASE name OWNER TO newowner
*/
ObjectAddress
-AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
+AlterDatabaseOwner(const DBSpecName *dbspec, Oid newOwnerId)
{
Oid db_id;
HeapTuple tuple;
@@ -1574,6 +1594,12 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
SysScanDesc scan;
Form_pg_database datForm;
ObjectAddress address;
+ char *dbname;
+
+ if (dbspec->dbnametype == DBSPEC_CURRENT_DATABASE)
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspec->dbname;
/*
* Get the old tuple. We don't need a lock on the database per se,
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index c2b1ccf..18dce3c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2701,6 +2701,18 @@ _copyRoleSpec(const RoleSpec *from)
return newnode;
}
+static DBSpecName *
+_copyDatabaseSpec(const DBSpecName *from)
+{
+ DBSpecName *newnode = makeNode(DBSpecName);
+
+ COPY_SCALAR_FIELD(dbnametype);
+ COPY_STRING_FIELD(dbname);
+ COPY_LOCATION_FIELD(location);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -3475,7 +3487,7 @@ _copyAlterDatabaseStmt(const AlterDatabaseStmt *from)
{
AlterDatabaseStmt *newnode = makeNode(AlterDatabaseStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(options);
return newnode;
@@ -3486,7 +3498,7 @@ _copyAlterDatabaseSetStmt(const AlterDatabaseSetStmt *from)
{
AlterDatabaseSetStmt *newnode = makeNode(AlterDatabaseSetStmt);
- COPY_STRING_FIELD(dbname);
+ COPY_NODE_FIELD(dbspec);
COPY_NODE_FIELD(setstmt);
return newnode;
@@ -5066,7 +5078,9 @@ copyObject(const void *from)
case T_RoleSpec:
retval = _copyRoleSpec(from);
break;
-
+ case T_DBSpecName:
+ retval = _copyDatabaseSpec(from);
+ break;
/*
* MISCELLANEOUS NODES
*/
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 1eb6799..24cbf18 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1553,7 +1553,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;
@@ -1562,7 +1562,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;
@@ -2619,6 +2619,16 @@ _equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
return true;
}
+static bool
+_equalDatabaseSpec(const DBSpecName *a, const DBSpecName *b)
+{
+ COMPARE_SCALAR_FIELD(dbnametype);
+ COMPARE_STRING_FIELD(dbname);
+ COMPARE_LOCATION_FIELD(location);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3369,6 +3379,9 @@ equal(const void *a, const void *b)
case T_RoleSpec:
retval = _equalRoleSpec(a, b);
break;
+ case T_DBSpecName:
+ 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 080d444..db0cd94 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -177,7 +177,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 *makeDBSpecName(DBSpecNameType type, int location);
%}
%pure-parser
@@ -539,6 +539,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
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
@@ -575,7 +576,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
@@ -5737,6 +5738,15 @@ CommentStmt:
n->comment = $6;
$$ = (Node *) n;
}
+ | COMMENT ON DATABASE db_spec_name IS comment_text
+ {
+ CommentStmt *n = makeNode(CommentStmt);
+ n->objtype = OBJECT_DATABASE;
+ n->objname = list_make1($4);
+ n->objargs = NIL;
+ n->comment = $6;
+ $$ = (Node *) n;
+ }
| COMMENT ON TYPE_P Typename IS comment_text
{
CommentStmt *n = makeNode(CommentStmt);
@@ -5900,7 +5910,6 @@ CommentStmt:
comment_type:
ACCESS METHOD { $$ = OBJECT_ACCESS_METHOD; }
| COLUMN { $$ = OBJECT_COLUMN; }
- | DATABASE { $$ = OBJECT_DATABASE; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
| INDEX { $$ = OBJECT_INDEX; }
| SEQUENCE { $$ = OBJECT_SEQUENCE; }
@@ -5949,6 +5958,17 @@ 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->objname = list_make1($6);
+ n->objargs = NIL;
+ n->label = $8;
+ $$ = (Node *) n;
+ }
| SECURITY LABEL opt_provider ON TYPE_P Typename
IS security_label
{
@@ -6023,7 +6043,6 @@ opt_provider: FOR NonReservedWord_or_Sconst { $$ = $2; }
security_label_type:
COLUMN { $$ = OBJECT_COLUMN; }
- | DATABASE { $$ = OBJECT_DATABASE; }
| EVENT TRIGGER { $$ = OBJECT_EVENT_TRIGGER; }
| FOREIGN TABLE { $$ = OBJECT_FOREIGN_TABLE; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
@@ -8372,11 +8391,11 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args 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 = list_make1(makeString($3));
+ n->object = list_make1($3);
n->newowner = $6;
$$ = (Node *)n;
}
@@ -8975,24 +8994,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)));
$$ = (Node *)n;
@@ -9000,10 +9019,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;
}
@@ -12465,6 +12484,10 @@ func_expr_common_subexpr:
{
$$ = (Node *) makeFuncCall(SystemFuncName("session_user"), NIL, @1);
}
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeFuncCall(SystemFuncName("current_database"), NIL, @1);
+ }
| USER
{
$$ = (Node *) makeFuncCall(SystemFuncName("current_user"), NIL, @1);
@@ -13465,8 +13488,31 @@ 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
+ {
+ DBSpecName *n = (DBSpecName *) makeDBSpecName(DBSPEC_CSTRING, @1);
+ n->dbname = pstrdup($1);
+ $$ = (Node *)n;
+ }
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeDBSpecName(DBSPEC_CURRENT_DATABASE, @1);
+ }
+ ;
+
access_method:
ColId { $$ = $1; };
@@ -13491,6 +13537,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -14129,6 +14177,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -15001,6 +15050,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
return (Node *) s;
}
+/* makeDBSpecName
+ * Create a DBSpecName with the given type
+ */
+static Node *
+makeDBSpecName(DBSpecNameType type, int location)
+{
+ DBSpecName *spec = makeNode(DBSpecName);
+
+ spec->dbnametype = type;
+ spec->location = location;
+
+ return (Node *) spec;
+}
+
/* parser_init()
* Initialize to parse one query string
*/
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index b6436f1..84b6743 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(AlterDatabaseStmt *stmt, bool isTopLevel);
extern Oid AlterDatabaseSet(AlterDatabaseSetStmt *stmt);
-extern ObjectAddress AlterDatabaseOwner(const char *dbname, Oid newOwnerId);
+extern ObjectAddress AlterDatabaseOwner(const DBSpecName *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 d3fdf55..53a638e 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -452,6 +452,7 @@ typedef enum NodeTag
T_OnConflictClause,
T_CommonTableExpr,
T_RoleSpec,
+ T_DBSpecName,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 1481fff..06c9804 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -2745,6 +2745,24 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
+
+/*
+ * DBSpecType - The type of a database name.
+ */
+typedef enum DBSpecNameType
+{
+ DBSPEC_CSTRING, /* database name is stored as a C string */
+ DBSPEC_CURRENT_DATABASE /* database name is CURRENT_DATABASE */
+} DBSpecNameType;
+
+typedef struct DBSpecName
+{
+ NodeTag type;
+ DBSpecNameType dbnametype; /* Type of the database */
+ char *dbname; /* filled only for DBSPEC_CSTRING */
+ int location; /* token location, or -1 if unknown */
+} DBSpecName;
+
/* ----------------------
* Createdb Statement
* ----------------------
@@ -2763,14 +2781,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, DBSpecName */
+ List *options; /* List of DefElem nodes */
} AlterDatabaseStmt;
typedef struct AlterDatabaseSetStmt
{
NodeTag type;
- char *dbname; /* database name */
+ Node *dbspec; /* database name, DBSpecName */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterDatabaseSetStmt;
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
index 17ffef5..484539e 100644
--- a/src/include/parser/kwlist.h
+++ b/src/include/parser/kwlist.h
@@ -102,6 +102,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/test/regress/expected/dbname.out b/src/test/regress/expected/dbname.out
new file mode 100644
index 0000000..0e7a1e9
--- /dev/null
+++ b/src/test/regress/expected/dbname.out
@@ -0,0 +1,119 @@
+CREATE ROLE dbuser1 with LOGIN;
+CREATE ROLE dbuser2 with SUPERUSER LOGIN;
+CREATE ROLE dbuser3 with SUPERUSER LOGIN;
+CREATE DATABASE mydb1 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
+ORDER BY 1;
+ Name | Description
+------------------+--------------------------------------------
+ current_database |
+ mydb1 |
+ postgres | default administrative connection database
+ regression |
+ template0 | unmodifiable empty database
+ template1 | default template for new databases
+(6 rows)
+
+\c mydb1;
+SELECT CURRENT_DATABASE;
+ current_database
+------------------
+ mydb1
+(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
+ORDER BY 1;
+ Name | Description
+------------------+--------------------------------------------
+ current_database | db2
+ mydb1 | db1
+ postgres | default administrative connection database
+ regression |
+ template0 | unmodifiable empty database
+ template1 | default template for new databases
+(6 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='mydb1'
+ORDER BY 1;
+ Name | Owner | Description
+------------------+---------+-------------
+ current_database | dbuser2 | db2
+ mydb1 | 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 mydb2;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: ALTER DATABASE current_database rename to mydb2;
+ ^
+ALTER DATABASE "current_database" rename to mydb2;
+ALTER DATABASE mydb2 rename to current_database;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: ALTER DATABASE mydb2 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
+ORDER BY 1;
+ Name | Description
+------------+--------------------------------------------
+ mydb1 | db1
+ mydb2 | db2
+ postgres | default administrative connection database
+ regression |
+ template0 | unmodifiable empty database
+ template1 | default template for new databases
+(6 rows)
+
+-- test alter database set parameter
+ALTER DATABASE current_database SET parallel_tuple_cost=0.3;
+\c mydb1
+show parallel_tuple_cost;
+ parallel_tuple_cost
+---------------------
+ 0.3
+(1 row)
+
+ALTER DATABASE current_database RESET parallel_tuple_cost;
+\c mydb1
+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 mydb1;
+DROP DATABASE IF EXISTS mydb2;
+DROP ROLE dbuser1;
+DROP ROLE dbuser2;
+DROP ROLE dbuser3;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 3815182..a99d2ff 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -110,3 +110,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 8958d8c..0363c44 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -168,3 +168,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..2ce50e6
--- /dev/null
+++ b/src/test/regress/sql/dbname.sql
@@ -0,0 +1,72 @@
+CREATE ROLE dbuser1 with LOGIN;
+CREATE ROLE dbuser2 with SUPERUSER LOGIN;
+CREATE ROLE dbuser3 with SUPERUSER LOGIN;
+
+CREATE DATABASE mydb1 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
+ORDER BY 1;
+
+
+\c mydb1;
+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
+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='mydb1'
+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 mydb2;
+ALTER DATABASE "current_database" rename to mydb2;
+ALTER DATABASE mydb2 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
+ORDER BY 1;
+
+-- test alter database set parameter
+ALTER DATABASE current_database SET parallel_tuple_cost=0.3;
+\c mydb1
+show parallel_tuple_cost;
+ALTER DATABASE current_database RESET parallel_tuple_cost;
+\c mydb1
+show parallel_tuple_cost;
+
+-- clean up
+\c postgres
+
+DROP DATABASE IF EXISTS "current_database";
+DROP DATABASE IF EXISTS mydb1;
+DROP DATABASE IF EXISTS mydb2;
+DROP ROLE dbuser1;
+DROP ROLE dbuser2;
+DROP ROLE dbuser3;
On Fri, Aug 25, 2017 at 11:16 AM, Jing Wang <jingwangian@gmail.com> wrote:
Hi all,
Enclosed please find the updated patch with covering security labels on
database.The patch cover the following commands:
i can't apply your patch cleanly i think it needs rebase
Regards
Surafel
Hi Surafel,
Please find the rebased patch based on latest version in the attached file.
Regards,
Jing Wang
Fujitsu Australia
Attachments:
comment_on_current_database_for_pgdump_v4.patchapplication/octet-stream; name=comment_on_current_database_for_pgdump_v4.patchDownload
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
index dfc6118..a53178f 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 75f08cd..4dc4595 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2800,7 +2800,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");
@@ -2829,7 +2832,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,
@@ -14640,9 +14646,19 @@ 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);
+
+ printf("target = %s\n",target);
+
appendStringLiteralAH(query, labels[i].label, fout);
appendPQExpBufferStr(query, ";\n");
}
@@ -14726,6 +14742,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,
comment_on_current_database_no_pgdump_v4.patchapplication/octet-stream; name=comment_on_current_database_no_pgdump_v4.patchDownload
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6cac2df..46b72b4 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,
+ DBSpecName * 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, (DBSpecName*)object, missing_ok);
+ break;
case OBJECT_EXTENSION:
case OBJECT_TABLESPACE:
case OBJECT_ROLE:
@@ -1108,6 +1111,28 @@ 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, DBSpecName * object, bool missing_ok)
+{
+ char *dbname;
+ ObjectAddress address;
+
+ if (object && object->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = object->dbname;
+
+ 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
@@ -2241,8 +2266,20 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
break;
case OBJECT_DATABASE:
if (!pg_database_ownercheck(address.objectId, roleid))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- strVal((Value *) object));
+ {
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ /* Format is valid, extract the actual name. */
+ dbspecname = (DBSpecName*)object;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,dbname);
+ }
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 4f81479..ec5ca7e 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((DBSpecName*) 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..7e01943a 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -52,13 +52,20 @@ CommentObject(CommentStmt *stmt)
*/
if (stmt->objtype == OBJECT_DATABASE)
{
- char *database = strVal((Value *) stmt->object);
+ char *dbname = NULL;
+ DBSpecName *dbspecname = NULL;
- if (!OidIsValid(get_database_oid(database, true)))
+ dbspecname = (DBSpecName*)stmt->object;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+ if (!OidIsValid(get_database_oid(dbname, true)))
{
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..c1ac129 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1413,6 +1413,15 @@ 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;
+ DBSpecName *dbspecname = NULL;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
/* Extract options from the statement node tree */
foreach(option, stmt->options)
@@ -1477,7 +1486,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 +1512,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 +1583,18 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel)
Oid
AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
{
- Oid datid = get_database_oid(stmt->dbname, false);
+ Oid datid;
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ datid = get_database_oid(dbname, false);
/*
* Obtain a lock on the database and make sure it didn't go away in the
@@ -1584,7 +1604,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
if (!pg_database_ownercheck(datid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- stmt->dbname);
+ dbname);
AlterSetting(datid, InvalidOid, stmt->setstmt);
@@ -1598,7 +1618,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
* ALTER DATABASE name OWNER TO newowner
*/
ObjectAddress
-AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
+AlterDatabaseOwner(const DBSpecName *dbspec, Oid newOwnerId)
{
Oid db_id;
HeapTuple tuple;
@@ -1607,6 +1627,12 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
SysScanDesc scan;
Form_pg_database datForm;
ObjectAddress address;
+ char *dbname;
+
+ if (dbspec->dbnametype == DBSPEC_CURRENT_DATABASE)
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspec->dbname;
/*
* 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 83e0447..f56c302 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -1950,6 +1950,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 f9ddf4e..2139c9c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2921,6 +2921,18 @@ _copyTriggerTransition(const TriggerTransition *from)
return newnode;
}
+static DBSpecName *
+_copyDatabaseSpec(const DBSpecName *from)
+{
+ DBSpecName *newnode = makeNode(DBSpecName);
+
+ COPY_SCALAR_FIELD(dbnametype);
+ 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;
@@ -5529,7 +5541,9 @@ copyObjectImpl(const void *from)
case T_PartitionCmd:
retval = _copyPartitionCmd(from);
break;
-
+ case T_DBSpecName:
+ retval = _copyDatabaseSpec(from);
+ break;
/*
* MISCELLANEOUS NODES
*/
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 8d92c03..e679ec5 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;
@@ -2865,6 +2865,16 @@ _equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b)
return true;
}
+static bool
+_equalDatabaseSpec(const DBSpecName *a, const DBSpecName *b)
+{
+ COMPARE_SCALAR_FIELD(dbnametype);
+ COMPARE_STRING_FIELD(dbname);
+ COMPARE_LOCATION_FIELD(location);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3675,6 +3685,9 @@ equal(const void *a, const void *b)
case T_PartitionCmd:
retval = _equalPartitionCmd(a, b);
break;
+ case T_DBSpecName:
+ 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 7d0de99..57516d5 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 *makeDBSpecName(DBSpecNameType type, int location);
%}
%pure-parser
@@ -570,6 +570,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
@@ -614,7 +615,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
@@ -6264,6 +6265,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);
@@ -6412,7 +6421,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; }
@@ -6461,6 +6469,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
{
@@ -6529,8 +6547,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; }
@@ -8959,11 +8976,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;
}
@@ -9769,24 +9786,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;
@@ -9794,10 +9811,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;
}
@@ -13345,6 +13362,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);
@@ -14315,8 +14336,31 @@ 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
+ {
+ DBSpecName *n = (DBSpecName *) makeDBSpecName(DBSPEC_CSTRING, @1);
+ n->dbname = pstrdup($1);
+ $$ = (Node *)n;
+ }
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeDBSpecName(DBSPEC_CURRENT_DATABASE, @1);
+ }
+ ;
+
access_method:
ColId { $$ = $1; };
@@ -14341,6 +14385,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -14992,6 +15038,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -15903,6 +15950,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
return (Node *) s;
}
+/* makeDBSpecName
+ * Create a DBSpecName with the given type
+ */
+static Node *
+makeDBSpecName(DBSpecNameType type, int location)
+{
+ DBSpecName *spec = makeNode(DBSpecName);
+
+ spec->dbnametype = 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 6d8cb07..504f049 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 c3cb035..d0c9d99 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1873,6 +1873,10 @@ 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/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 43646d2..1adfbcc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8343,6 +8343,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..d6d9f9e 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 DBSpecName *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 27bd4f3..3ca8f74 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_DBSpecName,
T_TriggerTransition,
T_PartitionElem,
T_PartitionSpec,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5f2a4a7..e6379ee 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3008,6 +3008,24 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
+
+/*
+ * DBSpecType - The type of a database name.
+ */
+typedef enum DBSpecNameType
+{
+ DBSPEC_CSTRING, /* database name is stored as a C string */
+ DBSPEC_CURRENT_DATABASE /* database name is CURRENT_DATABASE */
+} DBSpecNameType;
+
+typedef struct DBSpecName
+{
+ NodeTag type;
+ DBSpecNameType dbnametype; /* Type of the database */
+ char *dbname; /* filled only for DBSPEC_CSTRING */
+ int location; /* token location, or -1 if unknown */
+} DBSpecName;
+
/* ----------------------
* Createdb Statement
* ----------------------
@@ -3026,14 +3044,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, DBSpecName */
+ List *options; /* List of DefElem nodes */
} AlterDatabaseStmt;
typedef struct AlterDatabaseSetStmt
{
NodeTag type;
- char *dbname; /* database name */
+ Node *dbspec; /* database name, DBSpecName */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterDatabaseSetStmt;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 8c536a8..7d56d4a 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/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 2fd3f2b..3a0e1f9 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -121,3 +121,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 76b0de3..0047794 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -179,3 +179,4 @@ test: with
test: xml
test: event_trigger
test: stats
+test: dbname
On Tue, Sep 12, 2017 at 1:11 PM, Jing Wang <jingwangian@gmail.com> wrote:
Please find the rebased patch based on latest version in the attached file.
Hi Jing
It looks like you created dbname.sql and dbname.out files for a
regression test but forgot to "git add" them to your branch before you
created the patch, so "make check" fails with the patch applied:
test identity ... ok
test event_trigger ... ok
test stats ... ok
test dbname ... /bin/sh: 1: cannot open
/home/travis/build/postgresql-cfbot/postgresql/src/test/regress/sql/dbname.sql:
No such file
+ printf("target = %s\n",target);
Looks like a stray debugging message?
--
Thomas Munro
http://www.enterprisedb.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi Surafel,
Sorry for that.
Yes. The test case file is forgotten to be added into the previous patch.
Kindly please use the updated patch in the attached file.
Regards,
Jing Wang
Fujitsu Australia
Attachments:
comment_on_current_database_no_pgdump_v4.1.patchapplication/octet-stream; name=comment_on_current_database_no_pgdump_v4.1.patchDownload
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 6cac2df..46b72b4 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,
+ DBSpecName * 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, (DBSpecName*)object, missing_ok);
+ break;
case OBJECT_EXTENSION:
case OBJECT_TABLESPACE:
case OBJECT_ROLE:
@@ -1108,6 +1111,28 @@ 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, DBSpecName * object, bool missing_ok)
+{
+ char *dbname;
+ ObjectAddress address;
+
+ if (object && object->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = object->dbname;
+
+ 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
@@ -2241,8 +2266,20 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
break;
case OBJECT_DATABASE:
if (!pg_database_ownercheck(address.objectId, roleid))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- strVal((Value *) object));
+ {
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ /* Format is valid, extract the actual name. */
+ dbspecname = (DBSpecName*)object;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,dbname);
+ }
break;
case OBJECT_TYPE:
case OBJECT_DOMAIN:
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 4f81479..ec5ca7e 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((DBSpecName*) 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..7e01943a 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -52,13 +52,20 @@ CommentObject(CommentStmt *stmt)
*/
if (stmt->objtype == OBJECT_DATABASE)
{
- char *database = strVal((Value *) stmt->object);
+ char *dbname = NULL;
+ DBSpecName *dbspecname = NULL;
- if (!OidIsValid(get_database_oid(database, true)))
+ dbspecname = (DBSpecName*)stmt->object;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+ if (!OidIsValid(get_database_oid(dbname, true)))
{
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..c1ac129 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -1413,6 +1413,15 @@ 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;
+ DBSpecName *dbspecname = NULL;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
/* Extract options from the statement node tree */
foreach(option, stmt->options)
@@ -1477,7 +1486,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 +1512,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 +1583,18 @@ AlterDatabase(ParseState *pstate, AlterDatabaseStmt *stmt, bool isTopLevel)
Oid
AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
{
- Oid datid = get_database_oid(stmt->dbname, false);
+ Oid datid;
+ char *dbname;
+ DBSpecName *dbspecname;
+
+ dbspecname = (DBSpecName*)stmt->dbspec;
+
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
+
+ datid = get_database_oid(dbname, false);
/*
* Obtain a lock on the database and make sure it didn't go away in the
@@ -1584,7 +1604,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
if (!pg_database_ownercheck(datid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- stmt->dbname);
+ dbname);
AlterSetting(datid, InvalidOid, stmt->setstmt);
@@ -1598,7 +1618,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
* ALTER DATABASE name OWNER TO newowner
*/
ObjectAddress
-AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
+AlterDatabaseOwner(const DBSpecName *dbspec, Oid newOwnerId)
{
Oid db_id;
HeapTuple tuple;
@@ -1607,6 +1627,12 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
SysScanDesc scan;
Form_pg_database datForm;
ObjectAddress address;
+ char *dbname;
+
+ if (dbspec->dbnametype == DBSPEC_CURRENT_DATABASE)
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspec->dbname;
/*
* 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 83e0447..f56c302 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -1950,6 +1950,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 f9ddf4e..2139c9c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2921,6 +2921,18 @@ _copyTriggerTransition(const TriggerTransition *from)
return newnode;
}
+static DBSpecName *
+_copyDatabaseSpec(const DBSpecName *from)
+{
+ DBSpecName *newnode = makeNode(DBSpecName);
+
+ COPY_SCALAR_FIELD(dbnametype);
+ 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;
@@ -5529,7 +5541,9 @@ copyObjectImpl(const void *from)
case T_PartitionCmd:
retval = _copyPartitionCmd(from);
break;
-
+ case T_DBSpecName:
+ retval = _copyDatabaseSpec(from);
+ break;
/*
* MISCELLANEOUS NODES
*/
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 8d92c03..e679ec5 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;
@@ -2865,6 +2865,16 @@ _equalPartitionCmd(const PartitionCmd *a, const PartitionCmd *b)
return true;
}
+static bool
+_equalDatabaseSpec(const DBSpecName *a, const DBSpecName *b)
+{
+ COMPARE_SCALAR_FIELD(dbnametype);
+ COMPARE_STRING_FIELD(dbname);
+ COMPARE_LOCATION_FIELD(location);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3675,6 +3685,9 @@ equal(const void *a, const void *b)
case T_PartitionCmd:
retval = _equalPartitionCmd(a, b);
break;
+ case T_DBSpecName:
+ 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 7d0de99..57516d5 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 *makeDBSpecName(DBSpecNameType type, int location);
%}
%pure-parser
@@ -570,6 +570,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
@@ -614,7 +615,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
@@ -6264,6 +6265,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);
@@ -6412,7 +6421,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; }
@@ -6461,6 +6469,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
{
@@ -6529,8 +6547,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; }
@@ -8959,11 +8976,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;
}
@@ -9769,24 +9786,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;
@@ -9794,10 +9811,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;
}
@@ -13345,6 +13362,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);
@@ -14315,8 +14336,31 @@ 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
+ {
+ DBSpecName *n = (DBSpecName *) makeDBSpecName(DBSPEC_CSTRING, @1);
+ n->dbname = pstrdup($1);
+ $$ = (Node *)n;
+ }
+ | CURRENT_DATABASE
+ {
+ $$ = (Node *) makeDBSpecName(DBSPEC_CURRENT_DATABASE, @1);
+ }
+ ;
+
access_method:
ColId { $$ = $1; };
@@ -14341,6 +14385,8 @@ func_name: type_function_name
$$ = check_func_name(lcons(makeString($1), $2),
yyscanner);
}
+ | CURRENT_DATABASE
+ { $$ = list_make1(makeString("current_database")); }
;
@@ -14992,6 +15038,7 @@ reserved_keyword:
| CONSTRAINT
| CREATE
| CURRENT_CATALOG
+ | CURRENT_DATABASE
| CURRENT_DATE
| CURRENT_ROLE
| CURRENT_TIME
@@ -15903,6 +15950,20 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query)
return (Node *) s;
}
+/* makeDBSpecName
+ * Create a DBSpecName with the given type
+ */
+static Node *
+makeDBSpecName(DBSpecNameType type, int location)
+{
+ DBSpecName *spec = makeNode(DBSpecName);
+
+ spec->dbnametype = 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 6d8cb07..504f049 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 c3cb035..d0c9d99 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1873,6 +1873,10 @@ 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/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 43646d2..1adfbcc 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8343,6 +8343,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..d6d9f9e 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 DBSpecName *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 27bd4f3..3ca8f74 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_DBSpecName,
T_TriggerTransition,
T_PartitionElem,
T_PartitionSpec,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 5f2a4a7..e6379ee 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -3008,6 +3008,24 @@ typedef struct LoadStmt
char *filename; /* file to load */
} LoadStmt;
+
+/*
+ * DBSpecType - The type of a database name.
+ */
+typedef enum DBSpecNameType
+{
+ DBSPEC_CSTRING, /* database name is stored as a C string */
+ DBSPEC_CURRENT_DATABASE /* database name is CURRENT_DATABASE */
+} DBSpecNameType;
+
+typedef struct DBSpecName
+{
+ NodeTag type;
+ DBSpecNameType dbnametype; /* Type of the database */
+ char *dbname; /* filled only for DBSPEC_CSTRING */
+ int location; /* token location, or -1 if unknown */
+} DBSpecName;
+
/* ----------------------
* Createdb Statement
* ----------------------
@@ -3026,14 +3044,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, DBSpecName */
+ List *options; /* List of DefElem nodes */
} AlterDatabaseStmt;
typedef struct AlterDatabaseSetStmt
{
NodeTag type;
- char *dbname; /* database name */
+ Node *dbspec; /* database name, DBSpecName */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterDatabaseSetStmt;
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 8c536a8..7d56d4a 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/test/regress/expected/dbname.out b/src/test/regress/expected/dbname.out
new file mode 100644
index 0000000..0e7a1e9
--- /dev/null
+++ b/src/test/regress/expected/dbname.out
@@ -0,0 +1,119 @@
+CREATE ROLE dbuser1 with LOGIN;
+CREATE ROLE dbuser2 with SUPERUSER LOGIN;
+CREATE ROLE dbuser3 with SUPERUSER LOGIN;
+CREATE DATABASE mydb1 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
+ORDER BY 1;
+ Name | Description
+------------------+--------------------------------------------
+ current_database |
+ mydb1 |
+ postgres | default administrative connection database
+ regression |
+ template0 | unmodifiable empty database
+ template1 | default template for new databases
+(6 rows)
+
+\c mydb1;
+SELECT CURRENT_DATABASE;
+ current_database
+------------------
+ mydb1
+(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
+ORDER BY 1;
+ Name | Description
+------------------+--------------------------------------------
+ current_database | db2
+ mydb1 | db1
+ postgres | default administrative connection database
+ regression |
+ template0 | unmodifiable empty database
+ template1 | default template for new databases
+(6 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='mydb1'
+ORDER BY 1;
+ Name | Owner | Description
+------------------+---------+-------------
+ current_database | dbuser2 | db2
+ mydb1 | 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 mydb2;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: ALTER DATABASE current_database rename to mydb2;
+ ^
+ALTER DATABASE "current_database" rename to mydb2;
+ALTER DATABASE mydb2 rename to current_database;
+ERROR: CURRENT_DATABASE cannot be used as a database name here
+LINE 1: ALTER DATABASE mydb2 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
+ORDER BY 1;
+ Name | Description
+------------+--------------------------------------------
+ mydb1 | db1
+ mydb2 | db2
+ postgres | default administrative connection database
+ regression |
+ template0 | unmodifiable empty database
+ template1 | default template for new databases
+(6 rows)
+
+-- test alter database set parameter
+ALTER DATABASE current_database SET parallel_tuple_cost=0.3;
+\c mydb1
+show parallel_tuple_cost;
+ parallel_tuple_cost
+---------------------
+ 0.3
+(1 row)
+
+ALTER DATABASE current_database RESET parallel_tuple_cost;
+\c mydb1
+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 mydb1;
+DROP DATABASE IF EXISTS mydb2;
+DROP ROLE dbuser1;
+DROP ROLE dbuser2;
+DROP ROLE dbuser3;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 2fd3f2b..3a0e1f9 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -121,3 +121,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 76b0de3..0047794 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -179,3 +179,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..2ce50e6
--- /dev/null
+++ b/src/test/regress/sql/dbname.sql
@@ -0,0 +1,72 @@
+CREATE ROLE dbuser1 with LOGIN;
+CREATE ROLE dbuser2 with SUPERUSER LOGIN;
+CREATE ROLE dbuser3 with SUPERUSER LOGIN;
+
+CREATE DATABASE mydb1 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
+ORDER BY 1;
+
+
+\c mydb1;
+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
+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='mydb1'
+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 mydb2;
+ALTER DATABASE "current_database" rename to mydb2;
+ALTER DATABASE mydb2 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
+ORDER BY 1;
+
+-- test alter database set parameter
+ALTER DATABASE current_database SET parallel_tuple_cost=0.3;
+\c mydb1
+show parallel_tuple_cost;
+ALTER DATABASE current_database RESET parallel_tuple_cost;
+\c mydb1
+show parallel_tuple_cost;
+
+-- clean up
+\c postgres
+
+DROP DATABASE IF EXISTS "current_database";
+DROP DATABASE IF EXISTS mydb1;
+DROP DATABASE IF EXISTS mydb2;
+DROP ROLE dbuser1;
+DROP ROLE dbuser2;
+DROP ROLE dbuser3;
A few general comments.
While this patch applies, I am still seeing some whitespace errors:
comment_on_current_database_no_pgdump_v4.1.patch:488: trailing whitespace.
ColId
comment_on_current_database_no_pgdump_v4.1.patch:490: trailing whitespace.
| CURRENT_DATABASE
comment_on_current_database_no_pgdump_v4.1.patch:491: trailing whitespace.
{
comment_on_current_database_no_pgdump_v4.1.patch:501: trailing whitespace.
ColId
comment_on_current_database_no_pgdump_v4.1.patch:502: trailing whitespace.
{
warning: squelched 9 whitespace errors
warning: 14 lines add whitespace errors.
It looks like the 'dbname' test is currently failing when you run
'make check-world'. The Travis CI build log [1]https://travis-ci.org/postgresql-cfbot/postgresql/builds/275747367 shows the details
of the failure. From a brief glance, I would guess that some of
the queries are returning unexpected databases that are created in
other tests.
Also, I think this change will require updates to the
documentation.
+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE )
+ dbname = get_database_name(MyDatabaseId);
+ else
+ dbname = dbspecname->dbname;
This pattern is repeated in the patch several times. It looks like
the end goal of these code blocks is either to get the database
name or the database OID, so perhaps we should have
get_dbspec_name() and get_dbspec_oid() helper functions (like
get_rolespec_oid() for RoleSpec nodes).
+static bool
+_equalDatabaseSpec(const DBSpecName *a, const DBSpecName *b)
+{
+ COMPARE_SCALAR_FIELD(dbnametype);
+ COMPARE_STRING_FIELD(dbname);
+ COMPARE_LOCATION_FIELD(location);
+
+ return true;
+}
There are some inconsistencies in the naming strategy. For
example, this function is called _equalDatabaseSpec(), but the
struct is DBSpecName. I would suggest calling it DatabaseSpec or
DbSpec throughout the patch.
Nathan
[1]: https://travis-ci.org/postgresql-cfbot/postgresql/builds/275747367
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 15 Sep 2017, at 16:36, Bossart, Nathan <bossartn@amazon.com> wrote:
A few general comments.
While this patch applies, I am still seeing some whitespace errors:
comment_on_current_database_no_pgdump_v4.1.patch:488: trailing whitespace.
ColId
comment_on_current_database_no_pgdump_v4.1.patch:490: trailing whitespace.
| CURRENT_DATABASE
comment_on_current_database_no_pgdump_v4.1.patch:491: trailing whitespace.
{
comment_on_current_database_no_pgdump_v4.1.patch:501: trailing whitespace.
ColId
comment_on_current_database_no_pgdump_v4.1.patch:502: trailing whitespace.
{
warning: squelched 9 whitespace errors
warning: 14 lines add whitespace errors.It looks like the 'dbname' test is currently failing when you run
'make check-world'. The Travis CI build log [1] shows the details
of the failure. From a brief glance, I would guess that some of
the queries are returning unexpected databases that are created in
other tests.Also, I think this change will require updates to the
documentation.+ if (dbspecname->dbnametype == DBSPEC_CURRENT_DATABASE ) + dbname = get_database_name(MyDatabaseId); + else + dbname = dbspecname->dbname;This pattern is repeated in the patch several times. It looks like
the end goal of these code blocks is either to get the database
name or the database OID, so perhaps we should have
get_dbspec_name() and get_dbspec_oid() helper functions (like
get_rolespec_oid() for RoleSpec nodes).+static bool +_equalDatabaseSpec(const DBSpecName *a, const DBSpecName *b) +{ + COMPARE_SCALAR_FIELD(dbnametype); + COMPARE_STRING_FIELD(dbname); + COMPARE_LOCATION_FIELD(location); + + return true; +}There are some inconsistencies in the naming strategy. For
example, this function is called _equalDatabaseSpec(), but the
struct is DBSpecName. I would suggest calling it DatabaseSpec or
DbSpec throughout the patch.
Based on this review, and that there hasn’t been a new version submitted, I’m
marking this patch Returned with Feedback. Please re-submit a new version of
the patch to an upcoming commitfest when ready.
cheers ./daniel
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers