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 opt_existing_window_name %type opt_if_not_exists +%type 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;