Skip to content

Commit b2f266f

Browse files
committed
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
1 parent bdc2e7a commit b2f266f

File tree

7 files changed

+26
-10
lines changed

7 files changed

+26
-10
lines changed

src/backend/catalog/index.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "catalog/pg_type.h"
4949
#include "catalog/storage.h"
5050
#include "commands/tablecmds.h"
51+
#include "commands/event_trigger.h"
5152
#include "commands/trigger.h"
5253
#include "executor/executor.h"
5354
#include "miscadmin.h"
@@ -191,7 +192,8 @@ relationHasPrimaryKey(Relation rel)
191192
void
192193
index_check_primary_key(Relation heapRel,
193194
IndexInfo *indexInfo,
194-
bool is_alter_table)
195+
bool is_alter_table,
196+
IndexStmt *stmt)
195197
{
196198
List *cmds;
197199
int i;
@@ -263,7 +265,11 @@ index_check_primary_key(Relation heapRel,
263265
* unduly.
264266
*/
265267
if (cmds)
268+
{
269+
EventTriggerAlterTableStart((Node *) stmt);
266270
AlterTableInternal(RelationGetRelid(heapRel), cmds, false);
271+
EventTriggerAlterTableEnd();
272+
}
267273
}
268274

269275
/*

src/backend/commands/event_trigger.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,11 +1699,6 @@ EventTriggerCollectSimpleCommand(ObjectAddress address,
16991699
* Note we don't collect the command immediately; instead we keep it in
17001700
* currentCommand, and only when we're done processing the subcommands we will
17011701
* add it to the command list.
1702-
*
1703-
* XXX -- this API isn't considering the possibility of an ALTER TABLE command
1704-
* being called reentrantly by an event trigger function. Do we need stackable
1705-
* commands at this level? Perhaps at least we should detect the condition and
1706-
* raise an error.
17071702
*/
17081703
void
17091704
EventTriggerAlterTableStart(Node *parsetree)
@@ -1728,6 +1723,7 @@ EventTriggerAlterTableStart(Node *parsetree)
17281723
command->d.alterTable.subcmds = NIL;
17291724
command->parsetree = copyObject(parsetree);
17301725

1726+
command->parent = currentEventTriggerState->currentCommand;
17311727
currentEventTriggerState->currentCommand = command;
17321728

17331729
MemoryContextSwitchTo(oldcxt);
@@ -1768,6 +1764,7 @@ EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
17681764
return;
17691765

17701766
Assert(IsA(subcmd, AlterTableCmd));
1767+
Assert(OidIsValid(currentEventTriggerState->currentCommand));
17711768
Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId));
17721769

17731770
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
@@ -1793,11 +1790,15 @@ EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
17931790
void
17941791
EventTriggerAlterTableEnd(void)
17951792
{
1793+
CollectedCommand *parent;
1794+
17961795
/* ignore if event trigger context not set, or collection disabled */
17971796
if (!currentEventTriggerState ||
17981797
currentEventTriggerState->commandCollectionInhibited)
17991798
return;
18001799

1800+
parent = currentEventTriggerState->currentCommand->parent;
1801+
18011802
/* If no subcommands, don't collect */
18021803
if (list_length(currentEventTriggerState->currentCommand->d.alterTable.subcmds) != 0)
18031804
{
@@ -1808,7 +1809,7 @@ EventTriggerAlterTableEnd(void)
18081809
else
18091810
pfree(currentEventTriggerState->currentCommand);
18101811

1811-
currentEventTriggerState->currentCommand = NULL;
1812+
currentEventTriggerState->currentCommand = parent;
18121813
}
18131814

18141815
/*

src/backend/commands/indexcmds.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "commands/comment.h"
3232
#include "commands/dbcommands.h"
3333
#include "commands/defrem.h"
34+
#include "commands/event_trigger.h"
3435
#include "commands/tablecmds.h"
3536
#include "commands/tablespace.h"
3637
#include "mb/pg_wchar.h"
@@ -575,7 +576,7 @@ DefineIndex(Oid relationId,
575576
* Extra checks when creating a PRIMARY KEY index.
576577
*/
577578
if (stmt->primary)
578-
index_check_primary_key(rel, indexInfo, is_alter_table);
579+
index_check_primary_key(rel, indexInfo, is_alter_table, stmt);
579580

580581
/*
581582
* We disallow indexes on system columns other than OID. They would not

src/backend/commands/tablecmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6007,7 +6007,7 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
60076007

60086008
/* Extra checks needed if making primary key */
60096009
if (stmt->primary)
6010-
index_check_primary_key(rel, indexInfo, true);
6010+
index_check_primary_key(rel, indexInfo, true, stmt);
60116011

60126012
/* Note we currently don't support EXCLUSION constraints here */
60136013
if (stmt->primary)

src/backend/commands/view.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ validateWithCheckOption(char *value)
6161
*
6262
* Create a view relation and use the rules system to store the query
6363
* for the view.
64+
*
65+
* EventTriggerAlterTableStart must have been called already.
6466
*---------------------------------------------------------------------
6567
*/
6668
static ObjectAddress
@@ -186,6 +188,7 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
186188
atcmds = lappend(atcmds, atcmd);
187189
}
188190

191+
/* EventTriggerAlterTableStart called by ProcessUtilitySlow */
189192
AlterTableInternal(viewOid, atcmds, true);
190193

191194
/* Make the new view columns visible */
@@ -217,6 +220,7 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace,
217220
atcmd->def = (Node *) options;
218221
atcmds = list_make1(atcmd);
219222

223+
/* EventTriggerAlterTableStart called by ProcessUtilitySlow */
220224
AlterTableInternal(viewOid, atcmds, true);
221225

222226
ObjectAddressSet(address, RelationRelationId, viewOid);

src/include/catalog/index.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ typedef enum
4040

4141
extern void index_check_primary_key(Relation heapRel,
4242
IndexInfo *indexInfo,
43-
bool is_alter_table);
43+
bool is_alter_table,
44+
IndexStmt *stmt);
4445

4546
extern Oid index_create(Relation heapRelation,
4647
const char *indexRelationName,

src/include/tcop/deparse_utility.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ typedef struct CollectedATSubcmd
4444
typedef struct CollectedCommand
4545
{
4646
CollectedCommandType type;
47+
4748
bool in_extension;
4849
Node *parsetree;
4950

@@ -100,6 +101,8 @@ typedef struct CollectedCommand
100101
GrantObjectType objtype;
101102
} defprivs;
102103
} d;
104+
105+
struct CollectedCommand *parent; /* when nested */
103106
} CollectedCommand;
104107

105108
#endif /* DEPARSE_UTILITY_H */

0 commit comments

Comments
 (0)