Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit841a515

Browse files
committed
Add ddl_command_end support for event triggers.
Dimitri Fontaine, with slight changes by me
1 parent765cbfd commit841a515

File tree

8 files changed

+390
-152
lines changed

8 files changed

+390
-152
lines changed

‎doc/src/sgml/event-trigger.sgml

Lines changed: 91 additions & 2 deletions
Large diffs are not rendered by default.

‎src/backend/commands/event_trigger.c

Lines changed: 135 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
125125
errhint("Must be superuser to create an event trigger.")));
126126

127127
/* Validate event name. */
128-
if (strcmp(stmt->eventname,"ddl_command_start")!=0)
128+
if (strcmp(stmt->eventname,"ddl_command_start")!=0&&
129+
strcmp(stmt->eventname,"ddl_command_end")!=0)
129130
ereport(ERROR,
130131
(errcode(ERRCODE_SYNTAX_ERROR),
131132
errmsg("unrecognized event name \"%s\"",
@@ -526,6 +527,39 @@ get_event_trigger_oid(const char *trigname, bool missing_ok)
526527
returnoid;
527528
}
528529

530+
/*
531+
* Return true when we want to fire given Event Trigger and false otherwise,
532+
* filtering on the session replication role and the event trigger registered
533+
* tags matching.
534+
*/
535+
staticbool
536+
filter_event_trigger(constchar**tag,EventTriggerCacheItem*item)
537+
{
538+
/*
539+
* Filter by session replication role, knowing that we never see disabled
540+
* items down here.
541+
*/
542+
if (SessionReplicationRole==SESSION_REPLICATION_ROLE_REPLICA)
543+
{
544+
if (item->enabled==TRIGGER_FIRES_ON_ORIGIN)
545+
return false;
546+
}
547+
else
548+
{
549+
if (item->enabled==TRIGGER_FIRES_ON_REPLICA)
550+
return false;
551+
}
552+
553+
/* Filter by tags, if any were specified. */
554+
if (item->ntags!=0&&bsearch(&tag,item->tag,
555+
item->ntags,sizeof(char*),
556+
pg_qsort_strcmp)==NULL)
557+
return false;
558+
559+
/* if we reach that point, we're not filtering out this item */
560+
return true;
561+
}
562+
529563
/*
530564
* Fire ddl_command_start triggers.
531565
*/
@@ -601,34 +635,105 @@ EventTriggerDDLCommandStart(Node *parsetree)
601635
{
602636
EventTriggerCacheItem*item=lfirst(lc);
603637

604-
/* Filter by session replication role. */
605-
if (SessionReplicationRole==SESSION_REPLICATION_ROLE_REPLICA)
606-
{
607-
if (item->enabled==TRIGGER_FIRES_ON_ORIGIN)
608-
continue;
609-
}
610-
else
638+
if (filter_event_trigger(&tag,item))
611639
{
612-
if (item->enabled==TRIGGER_FIRES_ON_REPLICA)
613-
continue;
640+
/* We must plan to fire this trigger. */
641+
runlist=lappend_oid(runlist,item->fnoid);
614642
}
643+
}
644+
645+
/* Construct event trigger data. */
646+
trigdata.type=T_EventTriggerData;
647+
trigdata.event="ddl_command_start";
648+
trigdata.parsetree=parsetree;
649+
trigdata.tag=tag;
650+
651+
/* Run the triggers. */
652+
EventTriggerInvoke(runlist,&trigdata);
653+
654+
/* Cleanup. */
655+
list_free(runlist);
656+
657+
/*
658+
* Make sure anything the event triggers did will be visible to
659+
* the main command.
660+
*/
661+
CommandCounterIncrement();
662+
}
663+
664+
/*
665+
* Fire ddl_command_end triggers.
666+
*/
667+
void
668+
EventTriggerDDLCommandEnd(Node*parsetree)
669+
{
670+
List*cachelist;
671+
List*runlist=NIL;
672+
ListCell*lc;
673+
constchar*tag;
674+
EventTriggerDatatrigdata;
675+
676+
/*
677+
* See EventTriggerDDLCommandStart for a discussion about why event
678+
* triggers are disabled in single user mode.
679+
*/
680+
if (!IsUnderPostmaster)
681+
return;
615682

616-
/* Filter by tags, if any were specified. */
617-
if (item->ntags!=0&&bsearch(&tag,item->tag,
618-
item->ntags,sizeof(char*),
619-
pg_qsort_strcmp)==NULL)
620-
continue;
683+
/*
684+
* See EventTriggerDDLCommandStart for a discussion about why this check is
685+
* important.
686+
*
687+
*/
688+
#ifdefUSE_ASSERT_CHECKING
689+
if (assert_enabled)
690+
{
691+
constchar*dbgtag;
621692

622-
/* We must plan to fire this trigger. */
623-
runlist=lappend_oid(runlist,item->fnoid);
693+
dbgtag=CreateCommandTag(parsetree);
694+
if (check_ddl_tag(dbgtag)!=EVENT_TRIGGER_COMMAND_TAG_OK)
695+
elog(ERROR,"unexpected command tag \"%s\"",dbgtag);
696+
}
697+
#endif
698+
699+
/* Use cache to find triggers for this event; fast exit if none. */
700+
cachelist=EventCacheLookup(EVT_DDLCommandEnd);
701+
if (cachelist==NULL)
702+
return;
703+
704+
/* Get the command tag. */
705+
tag=CreateCommandTag(parsetree);
706+
707+
/*
708+
* Filter list of event triggers by command tag, and copy them into
709+
* our memory context. Once we start running the command trigers, or
710+
* indeed once we do anything at all that touches the catalogs, an
711+
* invalidation might leave cachelist pointing at garbage, so we must
712+
* do this before we can do much else.
713+
*/
714+
foreach (lc,cachelist)
715+
{
716+
EventTriggerCacheItem*item=lfirst(lc);
717+
718+
if (filter_event_trigger(&tag,item))
719+
{
720+
/* We must plan to fire this trigger. */
721+
runlist=lappend_oid(runlist,item->fnoid);
722+
}
624723
}
625724

626725
/* Construct event trigger data. */
627726
trigdata.type=T_EventTriggerData;
628-
trigdata.event="ddl_command_start";
727+
trigdata.event="ddl_command_end";
629728
trigdata.parsetree=parsetree;
630729
trigdata.tag=tag;
631730

731+
/*
732+
* Make sure anything the main command did will be visible to the
733+
* event triggers.
734+
*/
735+
CommandCounterIncrement();
736+
632737
/* Run the triggers. */
633738
EventTriggerInvoke(runlist,&trigdata);
634739

@@ -645,6 +750,7 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
645750
MemoryContextcontext;
646751
MemoryContextoldcontext;
647752
ListCell*lc;
753+
boolfirst= true;
648754

649755
/*
650756
* Let's evaluate event triggers in their own memory context, so
@@ -665,6 +771,17 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
665771
FunctionCallInfoDatafcinfo;
666772
PgStat_FunctionCallUsagefcusage;
667773

774+
/*
775+
* We want each event trigger to be able to see the results of
776+
* the previous event trigger's action. Caller is responsible
777+
* for any command-counter increment that is needed between the
778+
* event trigger and anything else in the transaction.
779+
*/
780+
if (first)
781+
first= false;
782+
else
783+
CommandCounterIncrement();
784+
668785
/* Look up the function */
669786
fmgr_info(fnoid,&flinfo);
670787

@@ -677,13 +794,6 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
677794

678795
/* Reclaim memory. */
679796
MemoryContextReset(context);
680-
681-
/*
682-
* We want each event trigger to be able to see the results of
683-
* the previous event trigger's action, and we want the main
684-
* command to be able to see the results of all event triggers.
685-
*/
686-
CommandCounterIncrement();
687797
}
688798

689799
/* Restore old memory context and delete the temporary one. */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp