From: Alvaro Herrera Date: Fri, 25 Apr 2014 19:32:20 +0000 (-0300) Subject: deparse: initial support for ALTER TABLE X-Git-Url: http://waps.l3s.uni-hannover.de/gitweb/?a=commitdiff_plain;h=96277c87baa20c97c49e5d035c6a2c4b348c7102;p=users%2Fandresfreund%2Fpostgres.git deparse: initial support for ALTER TABLE --- diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 303ab81d19..dca8a4dce8 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -50,6 +50,7 @@ typedef struct EventTriggerQueryState slist_head SQLDropList; bool in_sql_drop; MemoryContext cxt; + StashedCommand *curcmd; List *stash; /* list of StashedCommand; see deparse_utility.h */ bool in_extension; struct EventTriggerQueryState *previous; @@ -1041,6 +1042,7 @@ EventTriggerBeginCompleteQuery(void) state->cxt = cxt; slist_init(&(state->SQLDropList)); state->in_sql_drop = false; + state->curcmd = NULL; state->stash = NIL; state->in_extension = currentEventTriggerState ? currentEventTriggerState->in_extension : false; @@ -1340,6 +1342,113 @@ EventTriggerStashExtensionStop(void) currentEventTriggerState->in_extension = false; } +/* + * EventTriggerStartRecordingSubcmds + * Prepare to receive data on a complex DDL command about to be executed + * + * Note we don't actually stash the object we create here into the "stashed" + * list; instead we keep it in curcmd, and only when we're done processing the + * subcommands we will add it to the actual stash. + * + * FIXME -- this API isn't considering the possibility of an ALTER TABLE command + * being called reentrantly by an event trigger function. Do we need stackable + * commands at this level? + */ +void +EventTriggerComplexCmdStart(Node *parsetree, ObjectType objtype) +{ + MemoryContext oldcxt; + StashedCommand *stashed; + + oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt); + + stashed = palloc(sizeof(StashedCommand)); + + stashed->type = SCT_AlterTable; + stashed->in_extension = currentEventTriggerState->in_extension; + + stashed->d.alterTable.objectId = InvalidOid; + stashed->d.alterTable.objtype = objtype; + stashed->d.alterTable.subcmds = NIL; + /* XXX is it necessary to have the whole parsetree? probably not ... */ + stashed->parsetree = copyObject(parsetree); + + currentEventTriggerState->curcmd = stashed; + + MemoryContextSwitchTo(oldcxt); +} + +void +EventTriggerComplexCmdSetOid(Oid objectId) +{ + currentEventTriggerState->curcmd->d.alterTable.objectId = objectId; +} + +/* + * EventTriggerRecordSubcmd + * Save data about a single part of a complex DDL command + * + * Right now we only support ALTER TABLE; there are no other DDL commands that + * require this. (ALTER TYPE can also generate multiple subcommands, but it's + * actually parsed as ALTER TABLE, so there is no difference at this level.) + */ +void +EventTriggerRecordSubcmd(Node *subcmd, Oid relid, AttrNumber attnum, + Oid newoid) +{ + MemoryContext oldcxt; + StashedATSubcmd *newsub; + + Assert(IsA(subcmd, AlterTableCmd)); + Assert(OidIsValid(currentEventTriggerState->curcmd->d.alterTable.objectId)); + + /* + * If we receive a subcommand intended for a relation other than the one + * we've started the complex command for, ignore it. This is chiefly + * concerned with inheritance situations: in such cases, alter table + * would dispatch multiple copies of the same command for various things, + * but we're only concerned with the one for the main table. + */ + if (relid != currentEventTriggerState->curcmd->d.alterTable.objectId) + return; + + oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt); + + newsub = palloc(sizeof(StashedATSubcmd)); + newsub->attnum = attnum; + newsub->oid = newoid; + newsub->parsetree = copyObject(subcmd); + + currentEventTriggerState->curcmd->d.alterTable.subcmds = + lappend(currentEventTriggerState->curcmd->d.alterTable.subcmds, newsub); + + MemoryContextSwitchTo(oldcxt); +} + +/* + * EventTriggerEndRecordingSubcmds + * Finish up saving a complex DDL command + * + * FIXME this API isn't considering the possibility that a xact/subxact is + * aborted partway through. Probably it's best to add an + * AtEOSubXact_EventTriggers() to fix this. + */ +void +EventTriggerComplexCmdEnd(void) +{ + /* If no subcommands, don't stash anything */ + if (list_length(currentEventTriggerState->curcmd->d.alterTable.subcmds) != 0) + { + currentEventTriggerState->stash = + lappend(currentEventTriggerState->stash, + currentEventTriggerState->curcmd); + } + else + pfree(currentEventTriggerState->curcmd); + + currentEventTriggerState->curcmd = NULL; +} + Datum pg_event_trigger_get_creation_commands(PG_FUNCTION_ARGS) { @@ -1418,7 +1527,8 @@ pg_event_trigger_get_creation_commands(PG_FUNCTION_ARGS) MemSet(nulls, 0, sizeof(nulls)); - if (cmd->type == SCT_Basic) + if (cmd->type == SCT_Basic || + cmd->type == SCT_AlterTable) { Oid classId; Oid objId; @@ -1432,6 +1542,11 @@ pg_event_trigger_get_creation_commands(PG_FUNCTION_ARGS) classId = get_objtype_catalog_oid(cmd->d.basic.objtype); objId = cmd->d.basic.objectId; } + else if (cmd->type == SCT_AlterTable) + { + classId = get_objtype_catalog_oid(cmd->d.alterTable.objtype); + objId = cmd->d.alterTable.objectId; + } tag = CreateCommandTag(cmd->parsetree); addr.classId = classId; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 46dcf0ee5d..cab0b0b649 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -2728,6 +2728,8 @@ AlterTableInternal(Oid relid, List *cmds, bool recurse) rel = relation_open(relid, lockmode); + EventTriggerComplexCmdSetOid(relid); + ATController(rel, cmds, recurse, lockmode); } @@ -3553,6 +3555,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel, break; } + EventTriggerRecordSubcmd((Node *) cmd, RelationGetRelid(rel), + colno, newoid); + /* * Bump the command counter to ensure the next subcommand in the sequence * can see the changes so far @@ -5615,6 +5620,8 @@ ATExecDropColumn(List **wqueue, Relation rel, const char *colName, * There is no such command in the grammar, but parse_utilcmd.c converts * UNIQUE and PRIMARY KEY constraints into AT_AddIndex subcommands. This lets * us schedule creation of the index at the appropriate time during ALTER. + * + * Return value is the OID of the new index. */ static Oid ATExecAddIndex(AlteredTableInfo *tab, Relation rel, diff --git a/src/backend/tcop/deparse_utility.c b/src/backend/tcop/deparse_utility.c index 2412843f16..040c721ac2 100644 --- a/src/backend/tcop/deparse_utility.c +++ b/src/backend/tcop/deparse_utility.c @@ -2845,6 +2845,396 @@ deparse_AlterEnumStmt(Oid objectId, Node *parsetree) return command; } +static char * +deparse_AlterTableStmt(StashedCommand *cmd) +{ + ObjTree *alterTableStmt; + ObjTree *tmp; + ObjTree *tmp2; + List *dpcontext; + Relation rel; + List *subcmds = NIL; + ListCell *cell; + char *command; + + rel = heap_open(cmd->d.alterTable.objectId, AccessShareLock); + dpcontext = deparse_context_for(RelationGetRelationName(rel), + cmd->d.alterTable.objectId); + + alterTableStmt = + new_objtree_VA("ALTER TABLE %{identity}D %{subcmds:, }s", 0); + tmp = new_objtree_for_qualname(rel->rd_rel->relnamespace, + RelationGetRelationName(rel)); + append_object_object(alterTableStmt, "identity", tmp); + + foreach(cell, cmd->d.alterTable.subcmds) + { + StashedATSubcmd *substashed = (StashedATSubcmd *) lfirst(cell); + AlterTableCmd *subcmd = (AlterTableCmd *) substashed->parsetree; + ObjTree *tree; + + Assert(IsA(subcmd, AlterTableCmd)); + + switch (subcmd->subtype) + { + case AT_AddColumn: + case AT_AddColumnRecurse: + /* XXX need to set the "recurse" bit somewhere? */ + Assert(IsA(subcmd->def, ColumnDef)); + tree = deparse_ColumnDef(rel, dpcontext, false, + (ColumnDef *) subcmd->def); + tmp = new_objtree_VA("ADD COLUMN %{definition}s", + 2, "type", ObjTypeString, "add column", + "definition", ObjTypeObject, tree); + subcmds = lappend(subcmds, + new_object_object(NULL, tmp)); + break; + + case AT_DropColumnRecurse: + case AT_ValidateConstraintRecurse: + case AT_DropConstraintRecurse: + case AT_AddOidsRecurse: + case AT_AddIndexConstraint: + case AT_ReAddIndex: + case AT_ReAddConstraint: + case AT_ProcessedConstraint: + case AT_ReplaceRelOptions: + /* Subtypes used for internal operations; nothing to do here */ + break; + + case AT_AddColumnToView: + /* CREATE OR REPLACE VIEW -- nothing to do here */ + break; + + case AT_ColumnDefault: + if (subcmd->def == NULL) + { + tmp = new_objtree_VA("ALTER COLUMN %{column}I DROP DEFAULT", + 1, "type", ObjTypeString, "drop default"); + } + else + { + List *dpcontext; + HeapTuple attrtup; + AttrNumber attno; + + tmp = new_objtree_VA("ALTER COLUMN %{column}I SET DEFAULT %{definition}s", + 1, "type", ObjTypeString, "set default"); + + dpcontext = deparse_context_for(RelationGetRelationName(rel), + RelationGetRelid(rel)); + attrtup = SearchSysCacheAttName(RelationGetRelid(rel), subcmd->name); + attno = ((Form_pg_attribute) GETSTRUCT(attrtup))->attnum; + append_string_object(tmp, "definition", + RelationGetColumnDefault(rel, attno, dpcontext)); + ReleaseSysCache(attrtup); + } + append_string_object(tmp, "column", subcmd->name); + + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DropNotNull: + tmp = new_objtree_VA("ALTER COLUMN %{column}I DROP NOT NULL", + 1, "type", ObjTypeString, "drop not null"); + append_string_object(tmp, "column", subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_SetNotNull: + tmp = new_objtree_VA("ALTER COLUMN %{column}I SET NOT NULL", + 1, "type", ObjTypeString, "set not null"); + append_string_object(tmp, "column", subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_SetStatistics: + /* not yet */ + break; + + case AT_SetOptions: + /* not yet */ + break; + + case AT_ResetOptions: + /* not yet */ + break; + + case AT_SetStorage: + Assert(IsA(subcmd->def, String)); + tmp = new_objtree_VA("ALTER COLUMN %{column}I SET STORAGE %{storage}s", + 3, "type", ObjTypeString, "set storage", + "column", ObjTypeString, subcmd->name, + "storage", ObjTypeString, + strVal((Value *) subcmd->def)); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DropColumn: + tmp = new_objtree_VA("DROP COLUMN %{column}I", + 2, "type", ObjTypeString, "drop column", + "column", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_AddIndex: + { + Oid idxOid = substashed->oid; + IndexStmt *istmt; + Relation idx; + const char *idxname; + Oid constrOid; + + Assert(IsA(subcmd->def, IndexStmt)); + istmt = (IndexStmt *) subcmd->def; + + if (!istmt->isconstraint) + break; + + idx = relation_open(idxOid, AccessShareLock); + idxname = RelationGetRelationName(idx); + + constrOid = get_relation_constraint_oid( + cmd->d.alterTable.objectId, idxname, false); + + tmp = new_objtree_VA("ADD CONSTRAINT %{name}I %{definition}s", + 3, "type", ObjTypeString, "add constraint", + "name", ObjTypeString, idxname, + "definition", ObjTypeString, + pg_get_constraintdef_string(constrOid, false)); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + + relation_close(idx, AccessShareLock); + } + break; + + case AT_AddConstraint: + case AT_AddConstraintRecurse: + { + /* XXX need to set the "recurse" bit somewhere? */ + Oid constrOid = substashed->oid; + + tmp = new_objtree_VA("ADD CONSTRAINT %{name}I %{definition}s", + 3, "type", ObjTypeString, "add constraint", + "name", ObjTypeString, get_constraint_name(constrOid), + "definition", ObjTypeString, + pg_get_constraintdef_string(constrOid, false)); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + } + break; + + case AT_AlterConstraint: + break; + + case AT_ValidateConstraint: + tmp = new_objtree_VA("VALIDATE CONSTRAINT %{constraint}I", 2, + "type", ObjTypeString, "validate constraint", + "constraint", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DropConstraint: + tmp = new_objtree_VA("DROP CONSTRAINT %{constraint}I", 2, + "type", ObjTypeString, "drop constraint", + "constraint", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_AlterColumnType: + tmp = new_objtree_VA("ALTER COLUMN %{column}I SET DATA TYPE %{datatype}T collate_clause using_clause", + 2, "type", ObjTypeString, "alter column type", + "column", ObjTypeString, subcmd->name); + /* FIXME figure out correct typid/typmod , collate clause, using_clause */ + append_object_object(tmp, "datatype", + new_objtree_for_type(INT4OID, -1)); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_AlterColumnGenericOptions: + break; + + case AT_ChangeOwner: + tmp = new_objtree_VA("OWNER TO %{owner}I", + 2, "type", ObjTypeString, "change owner", + "owner", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_ClusterOn: + tmp = new_objtree_VA("CLUSTER ON %{index}I", 2, + "type", ObjTypeString, "cluster on", + "index", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DropCluster: + tmp = new_objtree_VA("SET WITHOUT CLUSTER", 1, + "type", ObjTypeString, "set without cluster"); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_AddOids: + tmp = new_objtree_VA("SET WITH OIDS", 1, + "type", ObjTypeString, "set with oids"); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DropOids: + tmp = new_objtree_VA("SET WITHOUT OIDS", 1, + "type", ObjTypeString, "set without oids"); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_SetTableSpace: + tmp = new_objtree_VA("SET TABLESPACE %{tablespace}I", 2, + "type", ObjTypeString, "set tablespace", + "tablespace", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_SetRelOptions: + break; + + case AT_ResetRelOptions: + break; + + /* + * FIXME --- should we unify representation of all these + * ENABLE/DISABLE TRIGGER commands?? + */ + case AT_EnableTrig: + tmp = new_objtree_VA("ENABLE TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "enable trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_EnableAlwaysTrig: + tmp = new_objtree_VA("ENABLE ALWAYS TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "enable always trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_EnableReplicaTrig: + tmp = new_objtree_VA("ENABLE REPLICA TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "enable replica trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DisableTrig: + tmp = new_objtree_VA("DISABLE TRIGGER %{trigger}I", 2, + "type", ObjTypeString, "disable trigger", + "trigger", ObjTypeString, subcmd->name); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_EnableTrigAll: + tmp = new_objtree_VA("ENABLE TRIGGER ALL", 1, + "type", ObjTypeString, "enable trigger all"); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DisableTrigAll: + tmp = new_objtree_VA("DISABLE TRIGGER ALL", 1, + "type", ObjTypeString, "disable trigger all"); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_EnableTrigUser: + tmp = new_objtree_VA("ENABLE TRIGGER USER", 1, + "type", ObjTypeString, "enable trigger user"); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_DisableTrigUser: + tmp = new_objtree_VA("DISABLE TRIGGER USER", 1, + "type", ObjTypeString, "disable trigger user"); + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_EnableRule: + break; + + case AT_EnableAlwaysRule: + break; + + case AT_EnableReplicaRule: + break; + + case AT_DisableRule: + break; + + case AT_AddInherit: + /* + * XXX this case is interesting: we cannot rely on parse node + * because parent name might be unqualified; but there's no way + * to extract it from catalog either, since we don't know which + * of the parents is the new one. + */ + break; + + case AT_DropInherit: + /* XXX ditto ... */ + break; + + case AT_AddOf: + break; + + case AT_DropOf: + break; + + case AT_ReplicaIdentity: + tmp = new_objtree_VA("REPLICA IDENTITY %{ident}s", 1, + "type", ObjTypeString, "replica identity"); + switch (((ReplicaIdentityStmt *) subcmd->def)->identity_type) + { + case REPLICA_IDENTITY_DEFAULT: + append_string_object(tmp, "ident", "DEFAULT"); + break; + case REPLICA_IDENTITY_FULL: + append_string_object(tmp, "ident", "FULL"); + break; + case REPLICA_IDENTITY_NOTHING: + append_string_object(tmp, "ident", "NOTHING"); + break; + case REPLICA_IDENTITY_INDEX: + tmp2 = new_objtree_VA("USING INDEX %{index}I", 1, + "index", ObjTypeString, + ((ReplicaIdentityStmt *) subcmd->def)->name); + append_object_object(tmp, "ident", tmp2); + break; + } + subcmds = lappend(subcmds, new_object_object(NULL, tmp)); + break; + + case AT_GenericOptions: + break; + + default: + elog(WARNING, "unsupported alter table subtype %d", + subcmd->subtype); + break; + } + } + + if (list_length(subcmds) == 0) + { + command = NULL; + } + else + { + append_array_object(alterTableStmt, "subcmds", subcmds); + command = jsonize_objtree(alterTableStmt); + } + + free_objtree(alterTableStmt); + heap_close(rel, AccessShareLock); + + return command; +} + static char * deparse_parsenode_cmd(StashedCommand *cmd) { @@ -2859,6 +3249,10 @@ deparse_parsenode_cmd(StashedCommand *cmd) case SCT_Basic: objectId = cmd->d.basic.objectId; break; + case SCT_AlterTable: + /* XXX needed? */ + objectId = cmd->d.alterTable.objectId; + break; default: elog(ERROR, "unexpected deparse node type %d", cmd->type); } @@ -2954,7 +3348,7 @@ deparse_parsenode_cmd(StashedCommand *cmd) break; case T_AlterTableStmt: - command = NULL; + command = deparse_AlterTableStmt(cmd); break; case T_AlterEnumStmt: @@ -3013,6 +3407,7 @@ deparse_utility_command(StashedCommand *cmd) switch (cmd->type) { case SCT_Basic: + case SCT_AlterTable: command = deparse_parsenode_cmd(cmd); break; default: diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index beedb01e22..03547a6506 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -982,6 +982,10 @@ ProcessUtilitySlow(Node *parsetree, stmts = transformAlterTableStmt(relid, atstmt, queryString); + /* ... ensure we have an event trigger context ... */ + EventTriggerComplexCmdStart(parsetree, atstmt->relkind); + EventTriggerComplexCmdSetOid(relid); + /* ... and do it */ foreach(l, stmts) { @@ -995,19 +999,32 @@ ProcessUtilitySlow(Node *parsetree, } else { - /* Recurse for anything else */ + /* + * Recurse for anything else. If we need to do + * so, "close" the current complex-command set, + * and start a new one at the bottom; this is + * needed to ensure the ordering of queued + * commands is consistent with the way they are + * executed here. + */ + EventTriggerComplexCmdEnd(); ProcessUtility(stmt, queryString, PROCESS_UTILITY_SUBCOMMAND, params, None_Receiver, NULL); + EventTriggerComplexCmdStart(parsetree, atstmt->relkind); + EventTriggerComplexCmdSetOid(relid); } /* Need CCI between commands */ if (lnext(l) != NULL) CommandCounterIncrement(); } + + /* done */ + EventTriggerComplexCmdEnd(); } else ereport(NOTICE, @@ -1156,6 +1173,7 @@ ProcessUtilitySlow(Node *parsetree, stmt = transformIndexStmt(relid, stmt, queryString); /* ... and do it */ + EventTriggerComplexCmdStart(parsetree, OBJECT_INDEX); /* relkind? */ objectId = DefineIndex(relid, /* OID of heap relation */ stmt, @@ -1166,6 +1184,7 @@ ProcessUtilitySlow(Node *parsetree, false); /* quiet */ EventTriggerStashCommand(objectId, OBJECT_INDEX, parsetree); + EventTriggerComplexCmdEnd(); } break; @@ -1249,8 +1268,10 @@ ProcessUtilitySlow(Node *parsetree, break; case T_ViewStmt: /* CREATE VIEW */ + EventTriggerComplexCmdStart(parsetree, OBJECT_VIEW); /* XXX relkind? */ objectId = DefineView((ViewStmt *) parsetree, queryString); EventTriggerStashCommand(objectId, OBJECT_VIEW, parsetree); + EventTriggerComplexCmdEnd(); break; case T_CreateFunctionStmt: /* CREATE FUNCTION */ @@ -1377,7 +1398,9 @@ ProcessUtilitySlow(Node *parsetree, break; case T_AlterTableSpaceMoveStmt: + EventTriggerComplexCmdStart(parsetree, OBJECT_TABLE); /* XXX relkind? */ AlterTableSpaceMove((AlterTableSpaceMoveStmt *) parsetree); + EventTriggerComplexCmdEnd(); break; case T_AlterOwnerStmt: diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index 8ddca3d31f..3e84cf79cf 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -56,5 +56,10 @@ extern void EventTriggerStashExtensionStart(void); extern void EventTriggerStashExtensionStop(void); extern void EventTriggerStashCommand(Oid objectId, ObjectType objtype, Node *parsetree); +extern void EventTriggerComplexCmdStart(Node *parsetree, ObjectType objtype); +extern void EventTriggerComplexCmdSetOid(Oid objectId); +extern void EventTriggerRecordSubcmd(Node *subcmd, Oid relid, + AttrNumber attnum, Oid newoid); +extern void EventTriggerComplexCmdEnd(void); #endif /* EVENT_TRIGGER_H */ diff --git a/src/include/tcop/deparse_utility.h b/src/include/tcop/deparse_utility.h index 865e018e27..37b38f00a8 100644 --- a/src/include/tcop/deparse_utility.h +++ b/src/include/tcop/deparse_utility.h @@ -26,6 +26,7 @@ typedef enum StashedCommandType { SCT_Basic, + SCT_AlterTable } StashedCommandType; /* @@ -42,6 +43,7 @@ typedef struct StashedCommand { StashedCommandType type; bool in_extension; + List *subcmds; /* list of StashedATSubcmd */ Node *parsetree; union @@ -51,6 +53,13 @@ typedef struct StashedCommand Oid objectId; ObjectType objtype; } basic; + + struct AlterTableCommand + { + Oid objectId; + ObjectType objtype; + List *subcmds; + } alterTable; } d; } StashedCommand;