Extend "ALTER EXTENSION ADD object" to permit "DROP object" as well.

Per discussion, this is something we should have sooner rather than later,
and it doesn't take much additional code to support it.
This commit is contained in:
Tom Lane 2011-02-10 17:36:44 -05:00
parent 289d730655
commit 01467d3e4f
12 changed files with 207 additions and 112 deletions

View File

@ -25,6 +25,7 @@ PostgreSQL documentation
<synopsis>
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> SET SCHEMA <replaceable class="PARAMETER">new_schema</replaceable>
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD <replaceable class="PARAMETER">member_object</replaceable>
ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> DROP <replaceable class="PARAMETER">member_object</replaceable>
<phrase>where <replaceable class="PARAMETER">member_object</replaceable> is:</phrase>
@ -82,6 +83,17 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>DROP <replaceable class="PARAMETER">member_object</replaceable></literal></term>
<listitem>
<para>
This form removes a member object from the extension. This is mainly
useful in extension upgrade scripts. The object is not dropped, only
disassociated from the extension.
</para>
</listitem>
</varlistentry>
</variablelist>
See <xref linkend="extend-extensions"> for more information about these
@ -123,7 +135,8 @@ ALTER EXTENSION <replaceable class="PARAMETER">extension_name</replaceable> ADD
<term><replaceable class="parameter">operator_name</replaceable></term>
<listitem>
<para>
The name of an object to be added to the extension. Names of tables,
The name of an object to be added to or removed from the extension.
Names of tables,
aggregates, domains, foreign tables, functions, operators,
operator classes, operator families, sequences, text search objects,
types, and views can be schema-qualified.

View File

@ -199,6 +199,57 @@ deleteDependencyRecordsFor(Oid classId, Oid objectId,
return count;
}
/*
* deleteDependencyRecordsForClass -- delete all records with given depender
* classId/objectId, dependee classId, and deptype.
* Returns the number of records deleted.
*
* This is a variant of deleteDependencyRecordsFor, useful when revoking
* an object property that is expressed by a dependency record (such as
* extension membership).
*/
long
deleteDependencyRecordsForClass(Oid classId, Oid objectId,
Oid refclassId, char deptype)
{
long count = 0;
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
Anum_pg_depend_classid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(classId));
ScanKeyInit(&key[1],
Anum_pg_depend_objid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(objectId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
if (depform->refclassid == refclassId && depform->deptype == deptype)
{
simple_heap_delete(depRel, &tup->t_self);
count++;
}
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
return count;
}
/*
* Adjust dependency record(s) to point to a different object of the same type
*
@ -470,39 +521,8 @@ sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId)
void
markSequenceUnowned(Oid seqId)
{
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
depRel = heap_open(DependRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
Anum_pg_depend_classid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1],
Anum_pg_depend_objid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(seqId));
scan = systable_beginscan(depRel, DependDependerIndexId, true,
SnapshotNow, 2, key);
while (HeapTupleIsValid((tup = systable_getnext(scan))))
{
Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup);
if (depform->refclassid == RelationRelationId &&
depform->deptype == DEPENDENCY_AUTO)
{
simple_heap_delete(depRel, &tup->t_self);
}
}
systable_endscan(scan);
heap_close(depRel, RowExclusiveLock);
deleteDependencyRecordsForClass(RelationRelationId, seqId,
RelationRelationId, DEPENDENCY_AUTO);
}
/*

View File

@ -1436,14 +1436,15 @@ AlterExtensionNamespace(List *names, const char *newschema)
}
/*
* Execute ALTER EXTENSION ADD
* Execute ALTER EXTENSION ADD/DROP
*/
void
ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
{
ObjectAddress extension;
ObjectAddress object;
Relation relation;
Oid oldExtension;
/*
* For now, insist on superuser privilege. Later we might want to
@ -1462,25 +1463,54 @@ ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt)
/*
* Translate the parser representation that identifies the object into
* an ObjectAddress. get_object_address() will throw an error if the
* object does not exist, and will also acquire a lock on the object
* to guard against concurrent DROP and ALTER EXTENSION ADD operations.
* object does not exist, and will also acquire a lock on the object to
* guard against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
*/
object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
&relation, ShareUpdateExclusiveLock);
/*
* Complain if object is already attached to some extension.
* Check existing extension membership.
*/
if (getExtensionOfObject(object.classId, object.objectId) != InvalidOid)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of an extension",
getObjectDescription(&object))));
oldExtension = getExtensionOfObject(object.classId, object.objectId);
/*
* OK, add the dependency.
*/
recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
if (stmt->action > 0)
{
/*
* ADD, so complain if object is already attached to some extension.
*/
if (OidIsValid(oldExtension))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is already a member of extension \"%s\"",
getObjectDescription(&object),
get_extension_name(oldExtension))));
/*
* OK, add the dependency.
*/
recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
}
else
{
/*
* DROP, so complain if it's not a member.
*/
if (oldExtension != extension.objectId)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("%s is not a member of extension \"%s\"",
getObjectDescription(&object),
stmt->extname)));
/*
* OK, drop the dependency.
*/
if (deleteDependencyRecordsForClass(object.classId, object.objectId,
ExtensionRelationId,
DEPENDENCY_EXTENSION) != 1)
elog(ERROR, "unexpected number of extension dependency records");
}
/*
* If get_object_address() opened the relation for us, we close it to keep

View File

@ -3251,12 +3251,13 @@ _copyCreateExtensionStmt(CreateExtensionStmt *from)
return newnode;
}
static AlterExtensionAddStmt *
_copyAlterExtensionAddStmt(AlterExtensionAddStmt *from)
static AlterExtensionContentsStmt *
_copyAlterExtensionContentsStmt(AlterExtensionContentsStmt *from)
{
AlterExtensionAddStmt *newnode = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *newnode = makeNode(AlterExtensionContentsStmt);
COPY_STRING_FIELD(extname);
COPY_SCALAR_FIELD(action);
COPY_SCALAR_FIELD(objtype);
COPY_NODE_FIELD(objname);
COPY_NODE_FIELD(objargs);
@ -4266,8 +4267,8 @@ copyObject(void *from)
case T_CreateExtensionStmt:
retval = _copyCreateExtensionStmt(from);
break;
case T_AlterExtensionAddStmt:
retval = _copyAlterExtensionAddStmt(from);
case T_AlterExtensionContentsStmt:
retval = _copyAlterExtensionContentsStmt(from);
break;
case T_CreateFdwStmt:
retval = _copyCreateFdwStmt(from);

View File

@ -1655,9 +1655,10 @@ _equalCreateExtensionStmt(CreateExtensionStmt *a, CreateExtensionStmt *b)
}
static bool
_equalAlterExtensionAddStmt(AlterExtensionAddStmt *a, AlterExtensionAddStmt *b)
_equalAlterExtensionContentsStmt(AlterExtensionContentsStmt *a, AlterExtensionContentsStmt *b)
{
COMPARE_STRING_FIELD(extname);
COMPARE_SCALAR_FIELD(action);
COMPARE_SCALAR_FIELD(objtype);
COMPARE_NODE_FIELD(objname);
COMPARE_NODE_FIELD(objargs);
@ -2868,8 +2869,8 @@ equal(void *a, void *b)
case T_CreateExtensionStmt:
retval = _equalCreateExtensionStmt(a, b);
break;
case T_AlterExtensionAddStmt:
retval = _equalAlterExtensionAddStmt(a, b);
case T_AlterExtensionContentsStmt:
retval = _equalAlterExtensionContentsStmt(a, b);
break;
case T_CreateFdwStmt:
retval = _equalCreateFdwStmt(a, b);

View File

@ -185,7 +185,7 @@ static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterEnumStmt
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
AlterExtensionAddStmt AlterForeignTableStmt
AlterExtensionContentsStmt AlterForeignTableStmt
AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
AlterRoleStmt AlterRoleSetStmt
AlterDefaultPrivilegesStmt DefACLAction
@ -664,7 +664,7 @@ stmt :
| AlterDefaultPrivilegesStmt
| AlterDomainStmt
| AlterEnumStmt
| AlterExtensionAddStmt
| AlterExtensionContentsStmt
| AlterFdwStmt
| AlterForeignServerStmt
| AlterForeignTableStmt
@ -3251,181 +3251,202 @@ create_extension_opt_item:
/*****************************************************************************
*
* ALTER EXTENSION name ADD object-identifier
* ALTER EXTENSION name ADD/DROP object-identifier
*
*****************************************************************************/
AlterExtensionAddStmt:
ALTER EXTENSION name ADD_P AGGREGATE func_name aggr_args
AlterExtensionContentsStmt:
ALTER EXTENSION name add_drop AGGREGATE func_name aggr_args
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_AGGREGATE;
n->objname = $6;
n->objargs = $7;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P CAST '(' Typename AS Typename ')'
| ALTER EXTENSION name add_drop CAST '(' Typename AS Typename ')'
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_CAST;
n->objname = list_make1($7);
n->objargs = list_make1($9);
$$ = (Node *) n;
}
| ALTER EXTENSION name ADD_P CONVERSION_P any_name
| ALTER EXTENSION name add_drop CONVERSION_P any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_CONVERSION;
n->objname = $6;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P DOMAIN_P any_name
| ALTER EXTENSION name add_drop DOMAIN_P any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_DOMAIN;
n->objname = $6;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P FUNCTION function_with_argtypes
| ALTER EXTENSION name add_drop FUNCTION function_with_argtypes
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_FUNCTION;
n->objname = $6->funcname;
n->objargs = $6->funcargs;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P opt_procedural LANGUAGE name
| ALTER EXTENSION name add_drop opt_procedural LANGUAGE name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_LANGUAGE;
n->objname = list_make1(makeString($7));
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P OPERATOR any_operator oper_argtypes
| ALTER EXTENSION name add_drop OPERATOR any_operator oper_argtypes
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_OPERATOR;
n->objname = $6;
n->objargs = $7;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P OPERATOR CLASS any_name USING access_method
| ALTER EXTENSION name add_drop OPERATOR CLASS any_name USING access_method
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_OPCLASS;
n->objname = $7;
n->objargs = list_make1(makeString($9));
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P OPERATOR FAMILY any_name USING access_method
| ALTER EXTENSION name add_drop OPERATOR FAMILY any_name USING access_method
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_OPFAMILY;
n->objname = $7;
n->objargs = list_make1(makeString($9));
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P SCHEMA name
| ALTER EXTENSION name add_drop SCHEMA name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_SCHEMA;
n->objname = list_make1(makeString($6));
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P TABLE any_name
| ALTER EXTENSION name add_drop TABLE any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_TABLE;
n->objname = $6;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P TEXT_P SEARCH PARSER any_name
| ALTER EXTENSION name add_drop TEXT_P SEARCH PARSER any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_TSPARSER;
n->objname = $8;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P TEXT_P SEARCH DICTIONARY any_name
| ALTER EXTENSION name add_drop TEXT_P SEARCH DICTIONARY any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_TSDICTIONARY;
n->objname = $8;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P TEXT_P SEARCH TEMPLATE any_name
| ALTER EXTENSION name add_drop TEXT_P SEARCH TEMPLATE any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_TSTEMPLATE;
n->objname = $8;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P TEXT_P SEARCH CONFIGURATION any_name
| ALTER EXTENSION name add_drop TEXT_P SEARCH CONFIGURATION any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_TSCONFIGURATION;
n->objname = $8;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P SEQUENCE any_name
| ALTER EXTENSION name add_drop SEQUENCE any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_SEQUENCE;
n->objname = $6;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P VIEW any_name
| ALTER EXTENSION name add_drop VIEW any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_VIEW;
n->objname = $6;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P FOREIGN TABLE any_name
| ALTER EXTENSION name add_drop FOREIGN TABLE any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_FOREIGN_TABLE;
n->objname = $7;
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P FOREIGN DATA_P WRAPPER name
| ALTER EXTENSION name add_drop FOREIGN DATA_P WRAPPER name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_FDW;
n->objname = list_make1(makeString($8));
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P SERVER name
| ALTER EXTENSION name add_drop SERVER name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_FOREIGN_SERVER;
n->objname = list_make1(makeString($6));
$$ = (Node *)n;
}
| ALTER EXTENSION name ADD_P TYPE_P any_name
| ALTER EXTENSION name add_drop TYPE_P any_name
{
AlterExtensionAddStmt *n = makeNode(AlterExtensionAddStmt);
AlterExtensionContentsStmt *n = makeNode(AlterExtensionContentsStmt);
n->extname = $3;
n->action = $4;
n->objtype = OBJECT_TYPE;
n->objname = $6;
$$ = (Node *)n;

View File

@ -212,7 +212,7 @@ check_xact_readonly(Node *parsetree)
case T_AlterTSDictionaryStmt:
case T_AlterTSConfigurationStmt:
case T_CreateExtensionStmt:
case T_AlterExtensionAddStmt:
case T_AlterExtensionContentsStmt:
case T_CreateFdwStmt:
case T_AlterFdwStmt:
case T_DropFdwStmt:
@ -601,8 +601,8 @@ standard_ProcessUtility(Node *parsetree,
CreateExtension((CreateExtensionStmt *) parsetree);
break;
case T_AlterExtensionAddStmt:
ExecAlterExtensionAddStmt((AlterExtensionAddStmt *) parsetree);
case T_AlterExtensionContentsStmt:
ExecAlterExtensionContentsStmt((AlterExtensionContentsStmt *) parsetree);
break;
case T_CreateFdwStmt:
@ -1680,7 +1680,7 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE EXTENSION";
break;
case T_AlterExtensionAddStmt:
case T_AlterExtensionContentsStmt:
tag = "ALTER EXTENSION";
break;
@ -2307,7 +2307,7 @@ GetCommandLogLevel(Node *parsetree)
break;
case T_CreateExtensionStmt:
case T_AlterExtensionAddStmt:
case T_AlterExtensionContentsStmt:
lev = LOGSTMT_DDL;
break;

View File

@ -855,7 +855,12 @@ psql_completion(char *text, int start, int end)
/* ALTER EXTENSION <name> */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
COMPLETE_WITH_CONST("SET SCHEMA");
{
static const char *const list_ALTEREXTENSION[] =
{"ADD", "DROP", "SET SCHEMA", NULL};
COMPLETE_WITH_LIST(list_ALTEREXTENSION);
}
/* ALTER FOREIGN */
else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&

View File

@ -205,6 +205,9 @@ extern void recordDependencyOnCurrentExtension(const ObjectAddress *object);
extern long deleteDependencyRecordsFor(Oid classId, Oid objectId,
bool skipExtensionDeps);
extern long deleteDependencyRecordsForClass(Oid classId, Oid objectId,
Oid refclassId, char deptype);
extern long changeDependencyFor(Oid classId, Oid objectId,
Oid refClassId, Oid oldRefObjectId,
Oid newRefObjectId);

View File

@ -37,7 +37,7 @@ extern Oid InsertExtensionTuple(const char *extName, Oid extOwner,
Datum extConfig, Datum extCondition,
List *requiredExtensions);
extern void ExecAlterExtensionAddStmt(AlterExtensionAddStmt *stmt);
extern void ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt);
extern Oid get_extension_oid(const char *extname, bool missing_ok);
extern char *get_extension_name(Oid ext_oid);

View File

@ -356,7 +356,7 @@ typedef enum NodeTag
T_SecLabelStmt,
T_CreateForeignTableStmt,
T_CreateExtensionStmt,
T_AlterExtensionAddStmt,
T_AlterExtensionContentsStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)

View File

@ -1546,14 +1546,15 @@ typedef struct CreateExtensionStmt
List *options; /* List of DefElem nodes */
} CreateExtensionStmt;
typedef struct AlterExtensionAddStmt
typedef struct AlterExtensionContentsStmt
{
NodeTag type;
char *extname; /* Extension's name */
int action; /* +1 = add object, -1 = drop object */
ObjectType objtype; /* Object's type */
List *objname; /* Qualified name of the object */
List *objargs; /* Arguments if needed (eg, for functions) */
} AlterExtensionAddStmt;
} AlterExtensionContentsStmt;
/* ----------------------
* Create/Drop FOREIGN DATA WRAPPER Statements