Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
841a5150
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
841a5150
编写于
1月 21, 2013
作者:
R
Robert Haas
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add ddl_command_end support for event triggers.
Dimitri Fontaine, with slight changes by me
上级
765cbfdc
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
390 addition
and
152 deletion
+390
-152
doc/src/sgml/event-trigger.sgml
doc/src/sgml/event-trigger.sgml
+91
-2
src/backend/commands/event_trigger.c
src/backend/commands/event_trigger.c
+135
-25
src/backend/tcop/utility.c
src/backend/tcop/utility.c
+150
-123
src/backend/utils/cache/evtcache.c
src/backend/utils/cache/evtcache.c
+2
-0
src/include/commands/event_trigger.h
src/include/commands/event_trigger.h
+1
-0
src/include/utils/evtcache.h
src/include/utils/evtcache.h
+2
-1
src/test/regress/expected/event_trigger.out
src/test/regress/expected/event_trigger.out
+5
-1
src/test/regress/sql/event_trigger.sql
src/test/regress/sql/event_trigger.sql
+4
-0
未找到文件。
doc/src/sgml/event-trigger.sgml
浏览文件 @
841a5150
...
...
@@ -27,8 +27,9 @@
<para>
An event trigger fires whenever the event with which it is associated
occurs in the database in which it is defined. Currently, the only
supported event is <literal>ddl_command_start</>. Support for
additional events may be added in future releases.
supported events are <literal>ddl_command_start</>
and <literal>ddl_command_end</>. Support for additional events may be
added in future releases.
</para>
<para>
...
...
@@ -43,6 +44,13 @@
<literal>CREATE TABLE AS</literal>.
</para>
<para>
The <literal>ddl_command_end</> event occurs just before returning
control from the execution of a <literal>CREATE</>, <literal>ALTER</>,
or <literal>DROP</> commmand. It shares the same exceptions as
the <literal>ddl_command_start</> event.
</para>
<para>
For a complete list of commands supported by the event trigger mechanism,
see <xref linkend="event-trigger-matrix">.
...
...
@@ -84,328 +92,409 @@
<row>
<entry>command tag</entry>
<entry><literal>ddl_command_start</literal></entry>
<entry><literal>ddl_command_end</literal></entry>
</row>
</thead>
<tbody>
<row>
<entry align="left"><literal>ALTER AGGREGATE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER COLLATION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER CONVERSION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER DOMAIN</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER EXTENSION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER FOREIGN DATA WRAPPER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER FOREIGN TABLE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER FUNCTION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER LANGUAGE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER OPERATOR</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER OPERATOR CLASS</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER OPERATOR FAMILY</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER SCHEMA</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER SEQUENCE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER SERVER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER TABLE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER TEXT SEARCH CONFIGURATION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER TEXT SEARCH DICTIONARY</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER TEXT SEARCH PARSER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER TEXT SEARCH TEMPLATE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER TRIGGER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER TYPE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER USER MAPPING</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>ALTER VIEW</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE AGGREGATE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE CAST</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE COLLATION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE CONVERSION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE DOMAIN</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE EXTENSION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE FOREIGN DATA WRAPPER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE FOREIGN TABLE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE FUNCTION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE INDEX</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE LANGUAGE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE OPERATOR</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE OPERATOR CLASS</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE OPERATOR FAMILY</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE RULE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE SCHEMA</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE SEQUENCE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE SERVER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TABLE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TABLE AS</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TEXT SEARCH CONFIGURATION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TEXT SEARCH DICTIONARY</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TEXT SEARCH PARSER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TEXT SEARCH TEMPLATE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TRIGGER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE TYPE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE USER MAPPING</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>CREATE VIEW</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP AGGREGATE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP CAST</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP COLLATION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP CONVERSION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP DOMAIN</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP EXTENSION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP FOREIGN DATA WRAPPER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP FOREIGN TABLE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP FUNCTION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP INDEX</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP LANGUAGE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP OPERATOR</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP OPERATOR CLASS</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP OPERATOR FAMILY</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP RULE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP SCHEMA</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP SEQUENCE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP SERVER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP TABLE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP TEXT SEARCH CONFIGURATION</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP TEXT SEARCH DICTIONARY</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP TEXT SEARCH PARSER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP TEXT SEARCH TEMPLATE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP TRIGGER</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP TYPE</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP USER MAPPING</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>DROP VIEW</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
<row>
<entry align="left"><literal>SELECT INTO</literal></entry>
<entry align="center"><literal>X</literal></entry>
<entry align="center"><literal>X</literal></entry>
</row>
</tbody>
</tgroup>
...
...
src/backend/commands/event_trigger.c
浏览文件 @
841a5150
...
...
@@ -125,7 +125,8 @@ CreateEventTrigger(CreateEventTrigStmt *stmt)
errhint
(
"Must be superuser to create an event trigger."
)));
/* Validate event name. */
if
(
strcmp
(
stmt
->
eventname
,
"ddl_command_start"
)
!=
0
)
if
(
strcmp
(
stmt
->
eventname
,
"ddl_command_start"
)
!=
0
&&
strcmp
(
stmt
->
eventname
,
"ddl_command_end"
)
!=
0
)
ereport
(
ERROR
,
(
errcode
(
ERRCODE_SYNTAX_ERROR
),
errmsg
(
"unrecognized event name
\"
%s
\"
"
,
...
...
@@ -526,6 +527,39 @@ get_event_trigger_oid(const char *trigname, bool missing_ok)
return
oid
;
}
/*
* Return true when we want to fire given Event Trigger and false otherwise,
* filtering on the session replication role and the event trigger registered
* tags matching.
*/
static
bool
filter_event_trigger
(
const
char
**
tag
,
EventTriggerCacheItem
*
item
)
{
/*
* Filter by session replication role, knowing that we never see disabled
* items down here.
*/
if
(
SessionReplicationRole
==
SESSION_REPLICATION_ROLE_REPLICA
)
{
if
(
item
->
enabled
==
TRIGGER_FIRES_ON_ORIGIN
)
return
false
;
}
else
{
if
(
item
->
enabled
==
TRIGGER_FIRES_ON_REPLICA
)
return
false
;
}
/* Filter by tags, if any were specified. */
if
(
item
->
ntags
!=
0
&&
bsearch
(
&
tag
,
item
->
tag
,
item
->
ntags
,
sizeof
(
char
*
),
pg_qsort_strcmp
)
==
NULL
)
return
false
;
/* if we reach that point, we're not filtering out this item */
return
true
;
}
/*
* Fire ddl_command_start triggers.
*/
...
...
@@ -601,34 +635,105 @@ EventTriggerDDLCommandStart(Node *parsetree)
{
EventTriggerCacheItem
*
item
=
lfirst
(
lc
);
/* Filter by session replication role. */
if
(
SessionReplicationRole
==
SESSION_REPLICATION_ROLE_REPLICA
)
{
if
(
item
->
enabled
==
TRIGGER_FIRES_ON_ORIGIN
)
continue
;
}
else
if
(
filter_event_trigger
(
&
tag
,
item
))
{
if
(
item
->
enabled
==
TRIGGER_FIRES_ON_REPLICA
)
continue
;
/* We must plan to fire this trigger. */
runlist
=
lappend_oid
(
runlist
,
item
->
fnoid
)
;
}
}
/* Construct event trigger data. */
trigdata
.
type
=
T_EventTriggerData
;
trigdata
.
event
=
"ddl_command_start"
;
trigdata
.
parsetree
=
parsetree
;
trigdata
.
tag
=
tag
;
/* Run the triggers. */
EventTriggerInvoke
(
runlist
,
&
trigdata
);
/* Cleanup. */
list_free
(
runlist
);
/*
* Make sure anything the event triggers did will be visible to
* the main command.
*/
CommandCounterIncrement
();
}
/*
* Fire ddl_command_end triggers.
*/
void
EventTriggerDDLCommandEnd
(
Node
*
parsetree
)
{
List
*
cachelist
;
List
*
runlist
=
NIL
;
ListCell
*
lc
;
const
char
*
tag
;
EventTriggerData
trigdata
;
/*
* See EventTriggerDDLCommandStart for a discussion about why event
* triggers are disabled in single user mode.
*/
if
(
!
IsUnderPostmaster
)
return
;
/* Filter by tags, if any were specified. */
if
(
item
->
ntags
!=
0
&&
bsearch
(
&
tag
,
item
->
tag
,
item
->
ntags
,
sizeof
(
char
*
),
pg_qsort_strcmp
)
==
NULL
)
continue
;
/*
* See EventTriggerDDLCommandStart for a discussion about why this check is
* important.
*
*/
#ifdef USE_ASSERT_CHECKING
if
(
assert_enabled
)
{
const
char
*
dbgtag
;
/* We must plan to fire this trigger. */
runlist
=
lappend_oid
(
runlist
,
item
->
fnoid
);
dbgtag
=
CreateCommandTag
(
parsetree
);
if
(
check_ddl_tag
(
dbgtag
)
!=
EVENT_TRIGGER_COMMAND_TAG_OK
)
elog
(
ERROR
,
"unexpected command tag
\"
%s
\"
"
,
dbgtag
);
}
#endif
/* Use cache to find triggers for this event; fast exit if none. */
cachelist
=
EventCacheLookup
(
EVT_DDLCommandEnd
);
if
(
cachelist
==
NULL
)
return
;
/* Get the command tag. */
tag
=
CreateCommandTag
(
parsetree
);
/*
* Filter list of event triggers by command tag, and copy them into
* our memory context. Once we start running the command trigers, or
* indeed once we do anything at all that touches the catalogs, an
* invalidation might leave cachelist pointing at garbage, so we must
* do this before we can do much else.
*/
foreach
(
lc
,
cachelist
)
{
EventTriggerCacheItem
*
item
=
lfirst
(
lc
);
if
(
filter_event_trigger
(
&
tag
,
item
))
{
/* We must plan to fire this trigger. */
runlist
=
lappend_oid
(
runlist
,
item
->
fnoid
);
}
}
/* Construct event trigger data. */
trigdata
.
type
=
T_EventTriggerData
;
trigdata
.
event
=
"ddl_command_
start
"
;
trigdata
.
event
=
"ddl_command_
end
"
;
trigdata
.
parsetree
=
parsetree
;
trigdata
.
tag
=
tag
;
/*
* Make sure anything the main command did will be visible to the
* event triggers.
*/
CommandCounterIncrement
();
/* Run the triggers. */
EventTriggerInvoke
(
runlist
,
&
trigdata
);
...
...
@@ -645,6 +750,7 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
MemoryContext
context
;
MemoryContext
oldcontext
;
ListCell
*
lc
;
bool
first
=
true
;
/*
* Let's evaluate event triggers in their own memory context, so
...
...
@@ -665,6 +771,17 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
FunctionCallInfoData
fcinfo
;
PgStat_FunctionCallUsage
fcusage
;
/*
* We want each event trigger to be able to see the results of
* the previous event trigger's action. Caller is responsible
* for any command-counter increment that is needed between the
* event trigger and anything else in the transaction.
*/
if
(
first
)
first
=
false
;
else
CommandCounterIncrement
();
/* Look up the function */
fmgr_info
(
fnoid
,
&
flinfo
);
...
...
@@ -677,13 +794,6 @@ EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
/* Reclaim memory. */
MemoryContextReset
(
context
);
/*
* We want each event trigger to be able to see the results of
* the previous event trigger's action, and we want the main
* command to be able to see the results of all event triggers.
*/
CommandCounterIncrement
();
}
/* Restore old memory context and delete the temporary one. */
...
...
src/backend/tcop/utility.c
浏览文件 @
841a5150
...
...
@@ -340,6 +340,34 @@ ProcessUtility(Node *parsetree,
dest
,
completionTag
,
context
);
}
#define InvokeDDLCommandEventTriggers(parsetree, fncall) \
do { \
if (isCompleteQuery) \
{ \
EventTriggerDDLCommandStart(parsetree); \
} \
fncall; \
if (isCompleteQuery) \
{ \
EventTriggerDDLCommandEnd(parsetree); \
} \
} while (0)
#define InvokeDDLCommandEventTriggersIfSupported(parsetree, fncall, objtype) \
do { \
bool _supported = EventTriggerSupportsObjectType(objtype); \
\
if (_supported) \
{ \
EventTriggerDDLCommandStart(parsetree); \
} \
fncall; \
if (_supported) \
{ \
EventTriggerDDLCommandEnd(parsetree); \
} \
} while (0)
void
standard_ProcessUtility
(
Node
*
parsetree
,
const
char
*
queryString
,
...
...
@@ -507,10 +535,10 @@ standard_ProcessUtility(Node *parsetree,
* relation and attribute manipulation
*/
case
T_CreateSchemaStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateSchemaCommand
((
CreateSchemaStmt
*
)
parsetree
,
queryString
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateSchemaCommand
((
CreateSchemaStmt
*
)
parsetree
,
queryString
)
);
break
;
case
T_CreateStmt
:
...
...
@@ -583,6 +611,9 @@ standard_ProcessUtility(Node *parsetree,
if
(
lnext
(
l
)
!=
NULL
)
CommandCounterIncrement
();
}
if
(
isCompleteQuery
)
EventTriggerDDLCommandEnd
(
parsetree
);
}
break
;
...
...
@@ -604,63 +635,63 @@ standard_ProcessUtility(Node *parsetree,
break
;
case
T_CreateExtensionStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateExtension
((
CreateExtensionStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateExtension
((
CreateExtensionStmt
*
)
parsetree
)
);
break
;
case
T_AlterExtensionStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
ExecAlterExtensionStmt
((
AlterExtensionStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
ExecAlterExtensionStmt
((
AlterExtensionStmt
*
)
parsetree
)
);
break
;
case
T_AlterExtensionContentsStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
ExecAlterExtensionContentsStmt
((
AlterExtensionContentsStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
ExecAlterExtensionContentsStmt
((
AlterExtensionContentsStmt
*
)
parsetree
)
);
break
;
case
T_CreateFdwStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateForeignDataWrapper
((
CreateFdwStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateForeignDataWrapper
((
CreateFdwStmt
*
)
parsetree
)
);
break
;
case
T_AlterFdwStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterForeignDataWrapper
((
AlterFdwStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterForeignDataWrapper
((
AlterFdwStmt
*
)
parsetree
)
);
break
;
case
T_CreateForeignServerStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateForeignServer
((
CreateForeignServerStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateForeignServer
((
CreateForeignServerStmt
*
)
parsetree
)
);
break
;
case
T_AlterForeignServerStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterForeignServer
((
AlterForeignServerStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterForeignServer
((
AlterForeignServerStmt
*
)
parsetree
)
);
break
;
case
T_CreateUserMappingStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateUserMapping
((
CreateUserMappingStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateUserMapping
((
CreateUserMappingStmt
*
)
parsetree
)
);
break
;
case
T_AlterUserMappingStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterUserMapping
((
AlterUserMappingStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterUserMapping
((
AlterUserMappingStmt
*
)
parsetree
)
);
break
;
case
T_DropUserMappingStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
RemoveUserMapping
((
DropUserMappingStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
RemoveUserMapping
((
DropUserMappingStmt
*
)
parsetree
)
);
break
;
case
T_DropStmt
:
...
...
@@ -689,6 +720,11 @@ standard_ProcessUtility(Node *parsetree,
RemoveObjects
((
DropStmt
*
)
parsetree
);
break
;
}
if
(
isCompleteQuery
&&
EventTriggerSupportsObjectType
(
stmt
->
removeType
))
EventTriggerDDLCommandEnd
(
parsetree
);
break
;
}
...
...
@@ -736,37 +772,29 @@ standard_ProcessUtility(Node *parsetree,
*/
case
T_RenameStmt
:
{
RenameStmt
*
stmt
;
RenameStmt
*
stmt
=
(
RenameStmt
*
)
parsetree
;
stmt
=
(
RenameStmt
*
)
parsetree
;
if
(
isCompleteQuery
&&
EventTriggerSupportsObjectType
(
stmt
->
renameType
))
EventTriggerDDLCommandStart
(
parsetree
);
ExecRenameStmt
(
stmt
);
InvokeDDLCommandEventTriggersIfSupported
(
parsetree
,
ExecRenameStmt
(
stmt
),
stmt
->
renameType
);
break
;
}
case
T_AlterObjectSchemaStmt
:
{
AlterObjectSchemaStmt
*
stmt
;
stmt
=
(
AlterObjectSchemaStmt
*
)
parsetree
;
if
(
isCompleteQuery
&&
EventTriggerSupportsObjectType
(
stmt
->
objectType
))
EventTriggerDDLCommandStart
(
parsetree
);
ExecAlterObjectSchemaStmt
(
stmt
);
AlterObjectSchemaStmt
*
stmt
=
(
AlterObjectSchemaStmt
*
)
parsetree
;
InvokeDDLCommandEventTriggersIfSupported
(
parsetree
,
ExecAlterObjectSchemaStmt
(
stmt
),
stmt
->
objectType
);
break
;
}
case
T_AlterOwnerStmt
:
{
AlterOwnerStmt
*
stmt
;
stmt
=
(
AlterOwnerStmt
*
)
parsetree
;
if
(
isCompleteQuery
&&
EventTriggerSupportsObjectType
(
stmt
->
objectType
))
EventTriggerDDLCommandStart
(
parsetree
);
ExecAlterOwnerStmt
(
stmt
);
AlterOwnerStmt
*
stmt
=
(
AlterOwnerStmt
*
)
parsetree
;
InvokeDDLCommandEventTriggersIfSupported
(
parsetree
,
ExecAlterOwnerStmt
(
stmt
),
stmt
->
objectType
);
break
;
}
...
...
@@ -889,9 +917,9 @@ standard_ProcessUtility(Node *parsetree,
break
;
case
T_AlterDefaultPrivilegesStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
ExecAlterDefaultPrivilegesStmt
((
AlterDefaultPrivilegesStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
ExecAlterDefaultPrivilegesStmt
((
AlterDefaultPrivilegesStmt
*
)
parsetree
)
);
break
;
/*
...
...
@@ -950,47 +978,46 @@ standard_ProcessUtility(Node *parsetree,
{
CompositeTypeStmt
*
stmt
=
(
CompositeTypeStmt
*
)
parsetree
;
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineCompositeType
(
stmt
->
typevar
,
stmt
->
coldeflist
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineCompositeType
(
stmt
->
typevar
,
stmt
->
coldeflist
));
}
break
;
case
T_CreateEnumStmt
:
/* CREATE TYPE AS ENUM */
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineEnum
((
CreateEnumStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineEnum
((
CreateEnumStmt
*
)
parsetree
)
);
break
;
case
T_CreateRangeStmt
:
/* CREATE TYPE AS RANGE */
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineRange
((
CreateRangeStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineRange
((
CreateRangeStmt
*
)
parsetree
)
);
break
;
case
T_AlterEnumStmt
:
/* ALTER TYPE (enum) */
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterEnum
((
AlterEnumStmt
*
)
parsetree
,
isTopLevel
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterEnum
((
AlterEnumStmt
*
)
parsetree
,
isTopLevel
)
);
break
;
case
T_ViewStmt
:
/* CREATE VIEW */
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineView
((
ViewStmt
*
)
parsetree
,
queryString
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineView
((
ViewStmt
*
)
parsetree
,
queryString
)
);
break
;
case
T_CreateFunctionStmt
:
/* CREATE FUNCTION */
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateFunction
((
CreateFunctionStmt
*
)
parsetree
,
queryString
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateFunction
((
CreateFunctionStmt
*
)
parsetree
,
queryString
)
);
break
;
case
T_AlterFunctionStmt
:
/* ALTER FUNCTION */
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterFunction
((
AlterFunctionStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterFunction
((
AlterFunctionStmt
*
)
parsetree
)
);
break
;
case
T_IndexStmt
:
/* CREATE INDEX */
...
...
@@ -1019,21 +1046,21 @@ standard_ProcessUtility(Node *parsetree,
break
;
case
T_RuleStmt
:
/* CREATE RULE */
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineRule
((
RuleStmt
*
)
parsetree
,
queryString
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineRule
((
RuleStmt
*
)
parsetree
,
queryString
)
);
break
;
case
T_CreateSeqStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineSequence
((
CreateSeqStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineSequence
((
CreateSeqStmt
*
)
parsetree
)
);
break
;
case
T_AlterSeqStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterSequence
((
AlterSeqStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterSequence
((
AlterSeqStmt
*
)
parsetree
)
);
break
;
case
T_DoStmt
:
...
...
@@ -1131,10 +1158,10 @@ standard_ProcessUtility(Node *parsetree,
break
;
case
T_CreateTableAsStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
ExecCreateTableAs
((
CreateTableAsStmt
*
)
parsetree
,
queryString
,
params
,
completionTag
);
InvokeDDLCommandEventTriggers
(
parsetree
,
ExecCreateTableAs
((
CreateTableAsStmt
*
)
parsetree
,
queryString
,
params
,
completionTag
)
);
break
;
case
T_VariableSetStmt
:
...
...
@@ -1156,10 +1183,10 @@ standard_ProcessUtility(Node *parsetree,
break
;
case
T_CreateTrigStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
(
void
)
CreateTrigger
((
CreateTrigStmt
*
)
parsetree
,
queryString
,
InvalidOid
,
InvalidOid
,
false
);
InvokeDDLCommandEventTriggers
(
parsetree
,
(
void
)
CreateTrigger
((
CreateTrigStmt
*
)
parsetree
,
queryString
,
InvalidOid
,
InvalidOid
,
false
)
);
break
;
case
T_CreateEventTrigStmt
:
...
...
@@ -1173,18 +1200,18 @@ standard_ProcessUtility(Node *parsetree,
break
;
case
T_CreatePLangStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateProceduralLanguage
((
CreatePLangStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateProceduralLanguage
((
CreatePLangStmt
*
)
parsetree
)
);
break
;
/*
* ******************************** DOMAIN statements ****
*/
case
T_CreateDomainStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineDomain
((
CreateDomainStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineDomain
((
CreateDomainStmt
*
)
parsetree
)
);
break
;
/*
...
...
@@ -1288,45 +1315,45 @@ standard_ProcessUtility(Node *parsetree,
break
;
case
T_CreateConversionStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateConversionCommand
((
CreateConversionStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateConversionCommand
((
CreateConversionStmt
*
)
parsetree
)
);
break
;
case
T_CreateCastStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
CreateCast
((
CreateCastStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
CreateCast
((
CreateCastStmt
*
)
parsetree
)
);
break
;
case
T_CreateOpClassStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineOpClass
((
CreateOpClassStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineOpClass
((
CreateOpClassStmt
*
)
parsetree
)
);
break
;
case
T_CreateOpFamilyStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
DefineOpFamily
((
CreateOpFamilyStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
DefineOpFamily
((
CreateOpFamilyStmt
*
)
parsetree
)
);
break
;
case
T_AlterOpFamilyStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterOpFamily
((
AlterOpFamilyStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterOpFamily
((
AlterOpFamilyStmt
*
)
parsetree
)
);
break
;
case
T_AlterTSDictionaryStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterTSDictionary
((
AlterTSDictionaryStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterTSDictionary
((
AlterTSDictionaryStmt
*
)
parsetree
)
);
break
;
case
T_AlterTSConfigurationStmt
:
if
(
isCompleteQuery
)
EventTriggerDDLCommandStart
(
parsetree
);
AlterTSConfiguration
((
AlterTSConfigurationStmt
*
)
parsetree
);
InvokeDDLCommandEventTriggers
(
parsetree
,
AlterTSConfiguration
((
AlterTSConfigurationStmt
*
)
parsetree
)
);
break
;
default:
...
...
src/backend/utils/cache/evtcache.c
浏览文件 @
841a5150
...
...
@@ -167,6 +167,8 @@ BuildEventTriggerCache(void)
evtevent
=
NameStr
(
form
->
evtevent
);
if
(
strcmp
(
evtevent
,
"ddl_command_start"
)
==
0
)
event
=
EVT_DDLCommandStart
;
else
if
(
strcmp
(
evtevent
,
"ddl_command_end"
)
==
0
)
event
=
EVT_DDLCommandEnd
;
else
continue
;
...
...
src/include/commands/event_trigger.h
浏览文件 @
841a5150
...
...
@@ -41,5 +41,6 @@ extern void AlterEventTriggerOwner_oid(Oid, Oid newOwnerId);
extern
bool
EventTriggerSupportsObjectType
(
ObjectType
obtype
);
extern
void
EventTriggerDDLCommandStart
(
Node
*
parsetree
);
extern
void
EventTriggerDDLCommandEnd
(
Node
*
parsetree
);
#endif
/* EVENT_TRIGGER_H */
src/include/utils/evtcache.h
浏览文件 @
841a5150
...
...
@@ -18,7 +18,8 @@
typedef
enum
{
EVT_DDLCommandStart
EVT_DDLCommandStart
,
EVT_DDLCommandEnd
}
EventTriggerEvent
;
typedef
struct
...
...
src/test/regress/expected/event_trigger.out
浏览文件 @
841a5150
...
...
@@ -16,6 +16,8 @@ ERROR: unrecognized event name "elephant_bootstrap"
-- OK
create event trigger regress_event_trigger on ddl_command_start
execute procedure test_event_trigger();
create event trigger regress_event_trigger_end on ddl_command_end
execute procedure test_event_trigger();
-- should fail, food is not a valid filter variable
create event trigger regress_event_trigger2 on ddl_command_start
when food in ('sandwhich')
...
...
@@ -65,9 +67,10 @@ alter event trigger regress_event_trigger enable;
alter event trigger regress_event_trigger disable;
-- regress_event_trigger2 should fire, but not regress_event_trigger
create table event_trigger_fire1 (a int);
NOTICE: test_event_trigger: ddl_command_
start
CREATE TABLE
NOTICE: test_event_trigger: ddl_command_
end
CREATE TABLE
-- but nothing should fire here
drop table event_trigger_fire1;
NOTICE: test_event_trigger: ddl_command_end DROP TABLE
-- alter owner to non-superuser should fail
alter event trigger regress_event_trigger owner to regression_bob;
ERROR: permission denied to change owner of event trigger "regress_event_trigger"
...
...
@@ -92,5 +95,6 @@ drop event trigger if exists regress_event_trigger2;
drop event trigger if exists regress_event_trigger2;
NOTICE: event trigger "regress_event_trigger2" does not exist, skipping
drop event trigger regress_event_trigger3;
drop event trigger regress_event_trigger_end;
drop function test_event_trigger();
drop role regression_bob;
src/test/regress/sql/event_trigger.sql
浏览文件 @
841a5150
...
...
@@ -18,6 +18,9 @@ create event trigger regress_event_trigger on elephant_bootstrap
create
event
trigger
regress_event_trigger
on
ddl_command_start
execute
procedure
test_event_trigger
();
create
event
trigger
regress_event_trigger_end
on
ddl_command_end
execute
procedure
test_event_trigger
();
-- should fail, food is not a valid filter variable
create
event
trigger
regress_event_trigger2
on
ddl_command_start
when
food
in
(
'sandwhich'
)
...
...
@@ -96,5 +99,6 @@ drop role regression_bob;
drop
event
trigger
if
exists
regress_event_trigger2
;
drop
event
trigger
if
exists
regress_event_trigger2
;
drop
event
trigger
regress_event_trigger3
;
drop
event
trigger
regress_event_trigger_end
;
drop
function
test_event_trigger
();
drop
role
regression_bob
;
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录