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

Commita5036ca

Browse files
committed
PL/Tcl: Add event trigger support
From: Dimitri Fontaine <dimitri@2ndQuadrant.fr>
1 parent45e02e3 commita5036ca

File tree

4 files changed

+188
-23
lines changed

4 files changed

+188
-23
lines changed

‎doc/src/sgml/pltcl.sgml

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,65 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
711711
</para>
712712
</sect1>
713713

714+
<sect1 id="pltcl-event-trigger">
715+
<title>Event Trigger Procedures in PL/Tcl</title>
716+
717+
<indexterm>
718+
<primary>event trigger</primary>
719+
<secondary>in PL/Tcl</secondary>
720+
</indexterm>
721+
722+
<para>
723+
Event trigger procedures can be written in PL/Tcl.
724+
<productname>PostgreSQL</productname> requires that a procedure that is
725+
to be called as an event trigger must be declared as a function with no
726+
arguments and a return type of <literal>event_trigger</>.
727+
</para>
728+
<para>
729+
The information from the trigger manager is passed to the procedure body
730+
in the following variables:
731+
732+
<variablelist>
733+
734+
<varlistentry>
735+
<term><varname>$TG_event</varname></term>
736+
<listitem>
737+
<para>
738+
The name of the event the trigger is fired for.
739+
</para>
740+
</listitem>
741+
</varlistentry>
742+
743+
<varlistentry>
744+
<term><varname>$TG_tag</varname></term>
745+
<listitem>
746+
<para>
747+
The command tag for which the trigger is fired.
748+
</para>
749+
</listitem>
750+
</varlistentry>
751+
</variablelist>
752+
</para>
753+
754+
<para>
755+
The return value of the trigger procedure is ignored.
756+
</para>
757+
758+
<para>
759+
Here's a little example event trigger procedure that simply raises
760+
a <literal>NOTICE</literal> message each time a supported command is
761+
executed:
762+
763+
<programlisting>
764+
CREATE OR REPLACE FUNCTION tclsnitch() RETURNS event_trigger AS $$
765+
elog NOTICE "tclsnitch: $TG_event $TG_tag"
766+
$$ LANGUAGE pltcl;
767+
768+
CREATE EVENT TRIGGER tcl_a_snitch ON ddl_command_start EXECUTE PROCEDURE tclsnitch();
769+
</programlisting>
770+
</para>
771+
</sect1>
772+
714773
<sect1 id="pltcl-unknown">
715774
<title>Modules and the <function>unknown</> Command</title>
716775
<para>

‎src/pl/tcl/expected/pltcl_setup.out

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,26 @@ select tcl_date_week(2001,10,24);
519519
42
520520
(1 row)
521521

522+
-- test pltcl event triggers
523+
create or replace function tclsnitch() returns event_trigger language pltcl as $$
524+
elog NOTICE "tclsnitch: $TG_event $TG_tag"
525+
$$;
526+
create event trigger tcl_a_snitch on ddl_command_start execute procedure tclsnitch();
527+
create event trigger tcl_b_snitch on ddl_command_end execute procedure tclsnitch();
528+
create or replace function foobar() returns int language sql as $$select 1;$$;
529+
NOTICE: tclsnitch: ddl_command_start CREATE FUNCTION
530+
NOTICE: tclsnitch: ddl_command_end CREATE FUNCTION
531+
alter function foobar() cost 77;
532+
NOTICE: tclsnitch: ddl_command_start ALTER FUNCTION
533+
NOTICE: tclsnitch: ddl_command_end ALTER FUNCTION
534+
drop function foobar();
535+
NOTICE: tclsnitch: ddl_command_start DROP FUNCTION
536+
NOTICE: tclsnitch: ddl_command_end DROP FUNCTION
537+
create table foo();
538+
NOTICE: tclsnitch: ddl_command_start CREATE TABLE
539+
NOTICE: tclsnitch: ddl_command_end CREATE TABLE
540+
drop table foo;
541+
NOTICE: tclsnitch: ddl_command_start DROP TABLE
542+
NOTICE: tclsnitch: ddl_command_end DROP TABLE
543+
drop event trigger tcl_a_snitch;
544+
drop event trigger tcl_b_snitch;

‎src/pl/tcl/pltcl.c

Lines changed: 88 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include"access/xact.h"
2828
#include"catalog/pg_proc.h"
2929
#include"catalog/pg_type.h"
30+
#include"commands/event_trigger.h"
3031
#include"commands/trigger.h"
3132
#include"executor/spi.h"
3233
#include"fmgr.h"
@@ -200,11 +201,13 @@ static Datum pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted);
200201
staticDatumpltcl_func_handler(PG_FUNCTION_ARGS,boolpltrusted);
201202

202203
staticHeapTuplepltcl_trigger_handler(PG_FUNCTION_ARGS,boolpltrusted);
204+
staticvoidpltcl_event_trigger_handler(PG_FUNCTION_ARGS,boolpltrusted);
203205

204206
staticvoidthrow_tcl_error(Tcl_Interp*interp,constchar*proname);
205207

206208
staticpltcl_proc_desc*compile_pltcl_function(Oidfn_oid,Oidtgreloid,
207-
boolpltrusted);
209+
boolis_event_trigger,
210+
boolpltrusted);
208211

209212
staticintpltcl_elog(ClientDatacdata,Tcl_Interp*interp,
210213
intargc,CONST84char*argv[]);
@@ -644,6 +647,12 @@ pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted)
644647
pltcl_current_fcinfo=NULL;
645648
retval=PointerGetDatum(pltcl_trigger_handler(fcinfo,pltrusted));
646649
}
650+
elseif (CALLED_AS_EVENT_TRIGGER(fcinfo))
651+
{
652+
pltcl_current_fcinfo=NULL;
653+
pltcl_event_trigger_handler(fcinfo,pltrusted);
654+
retval= (Datum)0;
655+
}
647656
else
648657
{
649658
pltcl_current_fcinfo=fcinfo;
@@ -685,7 +694,7 @@ pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted)
685694

686695
/* Find or compile the function */
687696
prodesc=compile_pltcl_function(fcinfo->flinfo->fn_oid,InvalidOid,
688-
pltrusted);
697+
false,pltrusted);
689698

690699
pltcl_current_prodesc=prodesc;
691700

@@ -844,6 +853,7 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
844853
/* Find or compile the function */
845854
prodesc=compile_pltcl_function(fcinfo->flinfo->fn_oid,
846855
RelationGetRelid(trigdata->tg_relation),
856+
false,/* not an event trigger */
847857
pltrusted);
848858

849859
pltcl_current_prodesc=prodesc;
@@ -1130,6 +1140,47 @@ pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted)
11301140
returnrettup;
11311141
}
11321142

1143+
/**********************************************************************
1144+
* pltcl_event_trigger_handler()- Handler for event trigger calls
1145+
**********************************************************************/
1146+
staticvoid
1147+
pltcl_event_trigger_handler(PG_FUNCTION_ARGS,boolpltrusted)
1148+
{
1149+
pltcl_proc_desc*prodesc;
1150+
Tcl_Interp*volatileinterp;
1151+
EventTriggerData*tdata= (EventTriggerData*)fcinfo->context;
1152+
Tcl_DStringtcl_cmd;
1153+
inttcl_rc;
1154+
1155+
/* Connect to SPI manager */
1156+
if (SPI_connect()!=SPI_OK_CONNECT)
1157+
elog(ERROR,"could not connect to SPI manager");
1158+
1159+
/* Find or compile the function */
1160+
prodesc=compile_pltcl_function(fcinfo->flinfo->fn_oid,
1161+
InvalidOid, true,pltrusted);
1162+
1163+
pltcl_current_prodesc=prodesc;
1164+
1165+
interp=prodesc->interp_desc->interp;
1166+
1167+
/* Create the tcl command and call the internal proc */
1168+
Tcl_DStringInit(&tcl_cmd);
1169+
Tcl_DStringAppendElement(&tcl_cmd,prodesc->internal_proname);
1170+
Tcl_DStringAppendElement(&tcl_cmd,tdata->event);
1171+
Tcl_DStringAppendElement(&tcl_cmd,tdata->tag);
1172+
1173+
tcl_rc=Tcl_GlobalEval(interp,Tcl_DStringValue(&tcl_cmd));
1174+
Tcl_DStringFree(&tcl_cmd);
1175+
1176+
/* Check for errors reported by Tcl. */
1177+
if (tcl_rc!=TCL_OK)
1178+
throw_tcl_error(interp,prodesc->user_proname);
1179+
1180+
if (SPI_finish()!=SPI_OK_FINISH)
1181+
elog(ERROR,"SPI_finish() failed");
1182+
}
1183+
11331184

11341185
/**********************************************************************
11351186
* throw_tcl_error- ereport an error returned from the Tcl interpreter
@@ -1168,7 +1219,8 @@ throw_tcl_error(Tcl_Interp *interp, const char *proname)
11681219
* (InvalidOid) when compiling a plain function.
11691220
**********************************************************************/
11701221
staticpltcl_proc_desc*
1171-
compile_pltcl_function(Oidfn_oid,Oidtgreloid,boolpltrusted)
1222+
compile_pltcl_function(Oidfn_oid,Oidtgreloid,
1223+
boolis_event_trigger,boolpltrusted)
11721224
{
11731225
HeapTupleprocTup;
11741226
Form_pg_procprocStruct;
@@ -1245,10 +1297,13 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
12451297
* "_trigger" when appropriate to ensure the normal and trigger
12461298
* cases are kept separate.
12471299
************************************************************/
1248-
if (!is_trigger)
1300+
if (!is_trigger&& !is_event_trigger)
12491301
snprintf(internal_proname,sizeof(internal_proname),
12501302
"__PLTcl_proc_%u",fn_oid);
1251-
else
1303+
elseif (is_event_trigger)
1304+
snprintf(internal_proname,sizeof(internal_proname),
1305+
"__PLTcl_proc_%u_evttrigger",fn_oid);
1306+
elseif (is_trigger)
12521307
snprintf(internal_proname,sizeof(internal_proname),
12531308
"__PLTcl_proc_%u_trigger",fn_oid);
12541309

@@ -1286,7 +1341,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
12861341
* Get the required information for input conversion of the
12871342
* return value.
12881343
************************************************************/
1289-
if (!is_trigger)
1344+
if (!is_trigger&& !is_event_trigger)
12901345
{
12911346
typeTup=
12921347
SearchSysCache1(TYPEOID,
@@ -1306,7 +1361,8 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
13061361
{
13071362
if (procStruct->prorettype==VOIDOID)
13081363
/* okay */ ;
1309-
elseif (procStruct->prorettype==TRIGGEROID)
1364+
elseif (procStruct->prorettype==TRIGGEROID||
1365+
procStruct->prorettype==EVTTRIGGEROID)
13101366
{
13111367
free(prodesc->user_proname);
13121368
free(prodesc->internal_proname);
@@ -1347,7 +1403,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
13471403
* Get the required information for output conversion
13481404
* of all procedure arguments
13491405
************************************************************/
1350-
if (!is_trigger)
1406+
if (!is_trigger&& !is_event_trigger)
13511407
{
13521408
prodesc->nargs=procStruct->pronargs;
13531409
proc_internal_args[0]='\0';
@@ -1397,12 +1453,17 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
13971453
ReleaseSysCache(typeTup);
13981454
}
13991455
}
1400-
else
1456+
elseif (is_trigger)
14011457
{
14021458
/* trigger procedure has fixed args */
14031459
strcpy(proc_internal_args,
14041460
"TG_name TG_relid TG_table_name TG_table_schema TG_relatts TG_when TG_level TG_op __PLTcl_Tup_NEW __PLTcl_Tup_OLD args");
14051461
}
1462+
elseif (is_event_trigger)
1463+
{
1464+
/* event trigger procedure has fixed args */
1465+
strcpy(proc_internal_args,"TG_event TG_tag");
1466+
}
14061467

14071468
/************************************************************
14081469
* Create the tcl command to define the internal
@@ -1422,20 +1483,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
14221483
Tcl_DStringAppend(&proc_internal_body,"upvar #0 ",-1);
14231484
Tcl_DStringAppend(&proc_internal_body,internal_proname,-1);
14241485
Tcl_DStringAppend(&proc_internal_body," GD\n",-1);
1425-
if (!is_trigger)
1426-
{
1427-
for (i=0;i<prodesc->nargs;i++)
1428-
{
1429-
if (prodesc->arg_is_rowtype[i])
1430-
{
1431-
snprintf(buf,sizeof(buf),
1432-
"array set %d $__PLTcl_Tup_%d\n",
1433-
i+1,i+1);
1434-
Tcl_DStringAppend(&proc_internal_body,buf,-1);
1435-
}
1436-
}
1437-
}
1438-
else
1486+
if (is_trigger)
14391487
{
14401488
Tcl_DStringAppend(&proc_internal_body,
14411489
"array set NEW $__PLTcl_Tup_NEW\n",-1);
@@ -1451,6 +1499,23 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool pltrusted)
14511499
"}\n"
14521500
"unset i v\n\n",-1);
14531501
}
1502+
elseif (is_event_trigger)
1503+
{
1504+
/* no argument support for event triggers */
1505+
}
1506+
else
1507+
{
1508+
for (i=0;i<prodesc->nargs;i++)
1509+
{
1510+
if (prodesc->arg_is_rowtype[i])
1511+
{
1512+
snprintf(buf,sizeof(buf),
1513+
"array set %d $__PLTcl_Tup_%d\n",
1514+
i+1,i+1);
1515+
Tcl_DStringAppend(&proc_internal_body,buf,-1);
1516+
}
1517+
}
1518+
}
14541519

14551520
/************************************************************
14561521
* Add user's function definition to proc body

‎src/pl/tcl/sql/pltcl_setup.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,21 @@ $$ language pltcl immutable;
559559

560560
select tcl_date_week(2010,1,24);
561561
select tcl_date_week(2001,10,24);
562+
563+
-- test pltcl event triggers
564+
create or replacefunctiontclsnitch() returns event_trigger language pltclas $$
565+
elog NOTICE"tclsnitch: $TG_event $TG_tag"
566+
$$;
567+
568+
create event trigger tcl_a_snitchon ddl_command_start execute procedure tclsnitch();
569+
create event trigger tcl_b_snitchon ddl_command_end execute procedure tclsnitch();
570+
571+
create or replacefunctionfoobar() returnsint language sqlas $$select1;$$;
572+
alterfunction foobar() cost77;
573+
dropfunction foobar();
574+
575+
createtablefoo();
576+
droptable foo;
577+
578+
drop event trigger tcl_a_snitch;
579+
drop event trigger tcl_b_snitch;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp