diff options
| author | Alvaro Herrera | 2016-04-05 21:38:54 +0000 |
|---|---|---|
| committer | Alvaro Herrera | 2016-04-05 21:38:54 +0000 |
| commit | f2fcad27d59c8e5c48f8fa0a96c8355e40f24273 (patch) | |
| tree | 8630b838513cbd3e2d846a68bf9db6a5f2f9c7b1 /src/backend | |
| parent | 41ea0c23761ca108e2f08f6e3151e3cb1f9652a1 (diff) | |
Support ALTER THING .. DEPENDS ON EXTENSION
This introduces a new dependency type which marks an object as depending
on an extension, such that if the extension is dropped, the object
automatically goes away; and also, if the database is dumped, the object
is included in the dump output. Currently the grammar supports this for
indexes, triggers, materialized views and functions only, although the
utility code is generic so adding support for more object types is a
matter of touching the parser rules only.
Author: Abhijit Menon-Sen
Reviewed-by: Alexander Korotkov, Álvaro Herrera
Discussion: http://www.postgresql.org/message-id/20160115062649.GA5068@toroid.org
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/catalog/dependency.c | 2 | ||||
| -rw-r--r-- | src/backend/catalog/objectaddress.c | 25 | ||||
| -rw-r--r-- | src/backend/commands/alter.c | 37 | ||||
| -rw-r--r-- | src/backend/nodes/copyfuncs.c | 17 | ||||
| -rw-r--r-- | src/backend/nodes/equalfuncs.c | 15 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 56 | ||||
| -rw-r--r-- | src/backend/tcop/utility.c | 28 |
7 files changed, 178 insertions, 2 deletions
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 17f9de1ff94..79595a9d230 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -589,6 +589,7 @@ findDependentObjects(const ObjectAddress *object, { case DEPENDENCY_NORMAL: case DEPENDENCY_AUTO: + case DEPENDENCY_AUTO_EXTENSION: /* no problem */ break; case DEPENDENCY_INTERNAL: @@ -788,6 +789,7 @@ findDependentObjects(const ObjectAddress *object, subflags = DEPFLAG_NORMAL; break; case DEPENDENCY_AUTO: + case DEPENDENCY_AUTO_EXTENSION: subflags = DEPFLAG_AUTO; break; case DEPENDENCY_INTERNAL: diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index cb3ba853f4e..13244610db1 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -1016,6 +1016,31 @@ get_object_address(ObjectType objtype, List *objname, List *objargs, } /* + * Return an ObjectAddress based on a RangeVar and an object name. The + * name of the relation identified by the RangeVar is prepended to the + * (possibly empty) list passed in as objname. This is useful to find + * the ObjectAddress of objects that depend on a relation. All other + * considerations are exactly as for get_object_address above. + */ +ObjectAddress +get_object_address_rv(ObjectType objtype, RangeVar *rel, List *objname, + List *objargs, Relation *relp, LOCKMODE lockmode, + bool missing_ok) +{ + if (rel) + { + objname = lcons(makeString(rel->relname), objname); + if (rel->schemaname) + objname = lcons(makeString(rel->schemaname), objname); + if (rel->catalogname) + objname = lcons(makeString(rel->catalogname), objname); + } + + return get_object_address(objtype, objname, objargs, + relp, lockmode, missing_ok); +} + +/* * Find an ObjectAddress for a type of object that is identified by an * unqualified name. */ diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 5af0f2ffdf3..7e39422ecd6 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -391,6 +391,43 @@ ExecRenameStmt(RenameStmt *stmt) } /* + * Executes an ALTER OBJECT / DEPENDS ON [EXTENSION] statement. + * + * Return value is the address of the altered object. refAddress is an output + * argument which, if not null, receives the address of the object that the + * altered object now depends on. + */ +ObjectAddress +ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddress) +{ + ObjectAddress address; + ObjectAddress refAddr; + Relation rel; + + address = + get_object_address_rv(stmt->objectType, stmt->relation, stmt->objname, + stmt->objargs, &rel, AccessExclusiveLock, false); + + /* + * If a relation was involved, it would have been opened and locked. + * We don't need the relation here, but we'll retain the lock until + * commit. + */ + if (rel) + heap_close(rel, NoLock); + + refAddr = get_object_address(OBJECT_EXTENSION, list_make1(stmt->extname), + NULL, &rel, AccessExclusiveLock, false); + Assert(rel == NULL); + if (refAddress) + *refAddress = refAddr; + + recordDependencyOn(&address, refAddress, DEPENDENCY_AUTO_EXTENSION); + + return address; +} + +/* * Executes an ALTER OBJECT / SET SCHEMA statement. Based on the object * type, the function appropriate to that type is executed. * diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index f4e4a91ba53..1e123d89cbb 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -3204,6 +3204,20 @@ _copyRenameStmt(const RenameStmt *from) return newnode; } +static AlterObjectDependsStmt * +_copyAlterObjectDependsStmt(const AlterObjectDependsStmt *from) +{ + AlterObjectDependsStmt *newnode = makeNode(AlterObjectDependsStmt); + + COPY_SCALAR_FIELD(objectType); + COPY_NODE_FIELD(relation); + COPY_NODE_FIELD(objname); + COPY_NODE_FIELD(objargs); + COPY_NODE_FIELD(extname); + + return newnode; +} + static AlterObjectSchemaStmt * _copyAlterObjectSchemaStmt(const AlterObjectSchemaStmt *from) { @@ -4682,6 +4696,9 @@ copyObject(const void *from) case T_RenameStmt: retval = _copyRenameStmt(from); break; + case T_AlterObjectDependsStmt: + retval = _copyAlterObjectDependsStmt(from); + break; case T_AlterObjectSchemaStmt: retval = _copyAlterObjectSchemaStmt(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 854c062d32f..6c0509602cd 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -1326,6 +1326,18 @@ _equalRenameStmt(const RenameStmt *a, const RenameStmt *b) } static bool +_equalAlterObjectDependsStmt(const AlterObjectDependsStmt *a, const AlterObjectDependsStmt *b) +{ + COMPARE_SCALAR_FIELD(objectType); + COMPARE_NODE_FIELD(relation); + COMPARE_NODE_FIELD(objname); + COMPARE_NODE_FIELD(objargs); + COMPARE_NODE_FIELD(extname); + + return true; +} + +static bool _equalAlterObjectSchemaStmt(const AlterObjectSchemaStmt *a, const AlterObjectSchemaStmt *b) { COMPARE_SCALAR_FIELD(objectType); @@ -3004,6 +3016,9 @@ equal(const void *a, const void *b) case T_RenameStmt: retval = _equalRenameStmt(a, b); break; + case T_AlterObjectDependsStmt: + retval = _equalAlterObjectDependsStmt(a, b); + break; case T_AlterObjectSchemaStmt: retval = _equalAlterObjectSchemaStmt(a, b); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 12733528eb2..18ec5f03d81 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -233,7 +233,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); AlterEventTrigStmt AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt AlterFdwStmt AlterForeignServerStmt AlterGroupStmt - AlterObjectSchemaStmt AlterOwnerStmt AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt + AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt + AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt @@ -578,7 +579,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS - DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC + DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DEPENDS DESC DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT @@ -767,6 +768,7 @@ stmt : | AlterForeignTableStmt | AlterFunctionStmt | AlterGroupStmt + | AlterObjectDependsStmt | AlterObjectSchemaStmt | AlterOwnerStmt | AlterOperatorStmt @@ -8027,6 +8029,55 @@ opt_set_data: SET DATA_P { $$ = 1; } /***************************************************************************** * + * ALTER THING name DEPENDS ON EXTENSION name + * + *****************************************************************************/ + +AlterObjectDependsStmt: + ALTER FUNCTION function_with_argtypes DEPENDS ON EXTENSION name + { + AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); + n->objectType = OBJECT_FUNCTION; + n->relation = NULL; + n->objname = $3->funcname; + n->objargs = $3->funcargs; + n->extname = makeString($7); + $$ = (Node *)n; + } + | ALTER TRIGGER name ON qualified_name DEPENDS ON EXTENSION name + { + AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); + n->objectType = OBJECT_TRIGGER; + n->relation = $5; + n->objname = list_make1(makeString($3)); + n->objargs = NIL; + n->extname = makeString($9); + $$ = (Node *)n; + } + | ALTER MATERIALIZED VIEW qualified_name DEPENDS ON EXTENSION name + { + AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); + n->objectType = OBJECT_MATVIEW; + n->relation = $4; + n->objname = NIL; + n->objargs = NIL; + n->extname = makeString($8); + $$ = (Node *)n; + } + | ALTER INDEX qualified_name DEPENDS ON EXTENSION name + { + AlterObjectDependsStmt *n = makeNode(AlterObjectDependsStmt); + n->objectType = OBJECT_INDEX; + n->relation = $3; + n->objname = NIL; + n->objargs = NIL; + n->extname = makeString($7); + $$ = (Node *)n; + } + ; + +/***************************************************************************** + * * ALTER THING name SET SCHEMA name * *****************************************************************************/ @@ -13726,6 +13777,7 @@ unreserved_keyword: | DELETE_P | DELIMITER | DELIMITERS + | DEPENDS | DICTIONARY | DISABLE_P | DISCARD diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 4d0aac979fc..ac50c2a03d1 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -147,6 +147,7 @@ check_xact_readonly(Node *parsetree) case T_AlterFunctionStmt: case T_AlterRoleStmt: case T_AlterRoleSetStmt: + case T_AlterObjectDependsStmt: case T_AlterObjectSchemaStmt: case T_AlterOwnerStmt: case T_AlterOperatorStmt: @@ -836,6 +837,19 @@ standard_ProcessUtility(Node *parsetree, } break; + case T_AlterObjectDependsStmt: + { + AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree; + + if (EventTriggerSupportsObjectType(stmt->objectType)) + ProcessUtilitySlow(parsetree, queryString, + context, params, + dest, completionTag); + else + ExecAlterObjectDependsStmt(stmt, NULL); + } + break; + case T_AlterObjectSchemaStmt: { AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree; @@ -1472,6 +1486,12 @@ ProcessUtilitySlow(Node *parsetree, address = ExecRenameStmt((RenameStmt *) parsetree); break; + case T_AlterObjectDependsStmt: + address = + ExecAlterObjectDependsStmt((AlterObjectDependsStmt *) parsetree, + &secondaryObject); + break; + case T_AlterObjectSchemaStmt: address = ExecAlterObjectSchemaStmt((AlterObjectSchemaStmt *) parsetree, @@ -2192,6 +2212,10 @@ CreateCommandTag(Node *parsetree) tag = AlterObjectTypeCommandTag(((RenameStmt *) parsetree)->renameType); break; + case T_AlterObjectDependsStmt: + tag = AlterObjectTypeCommandTag(((AlterObjectDependsStmt *) parsetree)->objectType); + break; + case T_AlterObjectSchemaStmt: tag = AlterObjectTypeCommandTag(((AlterObjectSchemaStmt *) parsetree)->objectType); break; @@ -2822,6 +2846,10 @@ GetCommandLogLevel(Node *parsetree) lev = LOGSTMT_DDL; break; + case T_AlterObjectDependsStmt: + lev = LOGSTMT_DDL; + break; + case T_AlterObjectSchemaStmt: lev = LOGSTMT_DDL; break; |
