1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

Fix event triggers for partitioned tables

Index DDL cascading on partitioned tables introduced a way for ALTER
TABLE to be called reentrantly.  This caused an an important deficiency
in event trigger support to be exposed: on exiting the reentrant call,
the alter table state object was clobbered, causing a crash when the
outer alter table tries to finalize its processing.  Fix the crash by
creating a stack of event trigger state objects.  There are still ways
to cause things to misbehave (and probably other crashers) with more
elaborate tricks, but at least it now doesn't crash in the obvious
scenario.

Backpatch to 9.5, where DDL deparsing of event triggers was introduced.

Reported-by: Marco Slot
Authors: Michaël Paquier, Álvaro Herrera
Discussion: https://postgr.es/m/CANNhMLCpi+HQ7M36uPfGbJZEQLyTy7XvX=5EFkpR-b1bo0uJew@mail.gmail.com
This commit is contained in:
Alvaro Herrera
2018-10-06 19:17:46 -03:00
parent 29ef2b310d
commit ad08006ba0
11 changed files with 78 additions and 11 deletions

View File

@ -1696,11 +1696,6 @@ EventTriggerCollectSimpleCommand(ObjectAddress address,
* Note we don't collect the command immediately; instead we keep it in
* currentCommand, and only when we're done processing the subcommands we will
* add it to the command list.
*
* XXX -- 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? Perhaps at least we should detect the condition and
* raise an error.
*/
void
EventTriggerAlterTableStart(Node *parsetree)
@ -1725,6 +1720,7 @@ EventTriggerAlterTableStart(Node *parsetree)
command->d.alterTable.subcmds = NIL;
command->parsetree = copyObject(parsetree);
command->parent = currentEventTriggerState->currentCommand;
currentEventTriggerState->currentCommand = command;
MemoryContextSwitchTo(oldcxt);
@ -1765,6 +1761,7 @@ EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
return;
Assert(IsA(subcmd, AlterTableCmd));
Assert(OidIsValid(currentEventTriggerState->currentCommand));
Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId));
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
@ -1790,11 +1787,15 @@ EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
void
EventTriggerAlterTableEnd(void)
{
CollectedCommand *parent;
/* ignore if event trigger context not set, or collection disabled */
if (!currentEventTriggerState ||
currentEventTriggerState->commandCollectionInhibited)
return;
parent = currentEventTriggerState->currentCommand->parent;
/* If no subcommands, don't collect */
if (list_length(currentEventTriggerState->currentCommand->d.alterTable.subcmds) != 0)
{
@ -1805,7 +1806,7 @@ EventTriggerAlterTableEnd(void)
else
pfree(currentEventTriggerState->currentCommand);
currentEventTriggerState->currentCommand = NULL;
currentEventTriggerState->currentCommand = parent;
}
/*