cmdtrigger-thomsreview-20120316.patch
text/x-patch
Filename: cmdtrigger-thomsreview-20120316.patch
Type: text/x-patch
Part: 0
Message:
Re: Command Triggers, v16
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| doc/src/sgml/plpgsql.sgml | 13 | 17 |
| doc/src/sgml/ref/create_command_trigger.sgml | 8 | 15 |
| src/backend/commands/cmdtrigger.c | 1 | 1 |
| src/backend/commands/dropcmds.c | 1 | 1 |
| src/backend/commands/functioncmds.c | 13 | 12 |
| src/backend/commands/opclasscmds.c | 1 | 1 |
| src/backend/commands/trigger.c | 1 | 1 |
| src/backend/commands/tsearchcmds.c | 2 | 2 |
| src/backend/rewrite/rewriteDefine.c | 1 | 2 |
| src/test/regress/expected/cmdtriggers.out | 6 | 3 |
| src/test/regress/sql/cmdtriggers.sql | 1 | 0 |
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index f5f2079..5f84751 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -3933,20 +3933,19 @@ SELECT * FROM sales_summary_bytime;
<title>Triggers on commands</title>
<para>
- <application>PL/pgSQL</application> can be used to define trigger
- procedures. A trigger procedure is created with the
+ <application>PL/pgSQL</application> can be used to define command
+ trigger procedures. A command trigger procedure is created with the
<command>CREATE FUNCTION</> command, declaring it as a function with
no arguments and a return type of <type>command trigger</type>.
</para>
<para>
When a <application>PL/pgSQL</application> function is called as a
- trigger, several special variables are created automatically in the
- top-level block. They are:
+ command trigger, several special variables are created automatically
+ in the top-level block. They are:
<variablelist>
<varlistentry>
- <varlistentry>
<term><varname>TG_TAG</varname></term>
<listitem>
<para>
@@ -4002,7 +4001,7 @@ SELECT * FROM sales_summary_bytime;
</para>
<para>
- The command trigger function return's value is not used.
+ The command trigger function's return value is not used.
</para>
<para>
@@ -4014,23 +4013,20 @@ SELECT * FROM sales_summary_bytime;
<title>A <application>PL/pgSQL</application> Command Trigger Procedure</title>
<para>
- This example trigger just raise a <literal>NOTICE</literal> message
+ This example trigger simply raises a <literal>NOTICE</literal> message
each time a supported command is executed.
</para>
<programlisting>
-create or replace function snitch()
- returns command trigger
- language plpgsql
-as $$
-begin
- raise notice 'snitch: % % %.% [%]',
+CREATE OR REPLACE FUNCTION snitch() RETURNS command trigger AS $$
+BEGIN
+ RAISE NOTICE 'snitch: % % %.% [%]',
tg_when, tg_tag, tg_schemaname, tg_objectname, tg_objectid;
-end;
-$$;
+END;
+$$ LANGUAGE plpgsql;
-create command trigger snitch_before before any command execute procedure any_snitch();
-create command trigger snitch_after after any command execute procedure any_snitch();
+CREATE COMMAND TRIGGER snitch_before BEFORE ANY COMMAND EXECUTE PROCEDURE snitch();
+CREATE COMMAND TRIGGER snitch_after AFTER ANY COMMAND EXECUTE PROCEDURE snitch();
</programlisting>
</example>
</sect2>
diff --git a/doc/src/sgml/ref/create_command_trigger.sgml b/doc/src/sgml/ref/create_command_trigger.sgml
index fc12d2e..01c7826 100644
--- a/doc/src/sgml/ref/create_command_trigger.sgml
+++ b/doc/src/sgml/ref/create_command_trigger.sgml
@@ -30,7 +30,6 @@ CREATE COMMAND TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFOR
<phrase>where <replaceable class="parameter">command</replaceable> can be one of:</phrase>
ALTER AGGREGATE
- ALTER CAST
ALTER COLLATION
ALTER CONVERSION
ALTER DOMAIN
@@ -56,6 +55,7 @@ CREATE COMMAND TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFOR
ALTER VIEW
CLUSTER
CREATE AGGREGATE
+ CREATE CAST
CREATE COLLATION
CREATE CONVERSION
CREATE DOMAIN
@@ -186,14 +186,12 @@ CREATE COMMAND TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFOR
That leaves out the following list of non supported commands.
</para>
<para>
- Commands that refers to global objects, such as databases, tablespaces
- and roles are not supported. As command triggers are per-database, it
- would be weird to affect e.g. a tablespace depending on which database
- you are connected to.
+ Commands that refer to global objects, such as databases, tablespaces
+ and roles, are not supported.
</para>
<para>
Commands that exercise their own transaction control are only
- supported in <literal>BEFORE</literal> command triggers, that's the
+ supported in <literal>BEFORE</literal> command triggers. This is the
case for <literal>VACUUM</literal>, <literal>CLUSTER</literal>,
<literal>CREATE INDEX CONCURRENTLY</literal>, and <literal>REINDEX
DATABASE</literal>.
@@ -220,11 +218,6 @@ CREATE COMMAND TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFOR
not to be able to take over control from a superuser.
</para>
<para>
- Triggers on ANY command support more commands than just this list, and
- will provide NULL values for every argument except for the argument
- that determines whether the trigger was before or after the command
- event, and the command tag.
-
Triggers on <literal>ANY</literal> command support more commands than
just this list, and will only provide the <literal>command
tag</literal> argument as <literal>NOT NULL</literal>. Supporting more
@@ -238,12 +231,12 @@ CREATE COMMAND TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFOR
<term><replaceable class="parameter">function_name</replaceable></term>
<listitem>
<para>
- A user-supplied function that is declared as taking 5 arguments of
- type text, text, oid, text, text and returning void.
+ A user-supplied function that is declared as taking no argument and
+ returning type <literal>command trigger</literal>.
</para>
<para>
If your command trigger is implemented in <literal>C</literal> then it
- will be called with yet another argument, of
+ will be called with an argument, of
type <literal>internal</literal>, which is a pointer to
the <literal>Node *</literal> parse tree.
</para>
@@ -275,7 +268,7 @@ CREATE COMMAND TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFOR
CREATE OR REPLACE FUNCTION abort_any_command()
RETURNS command trigger LANGUAGE plpgsql AS $$
BEGIN
- RAISE EXCEPTION 'command % is disabled' % tg_tag;
+ RAISE EXCEPTION 'command % is disabled', tg_tag;
END;
$$;
diff --git a/src/backend/commands/cmdtrigger.c b/src/backend/commands/cmdtrigger.c
index 6f134d5..f06f6b9 100644
--- a/src/backend/commands/cmdtrigger.c
+++ b/src/backend/commands/cmdtrigger.c
@@ -191,7 +191,7 @@ CreateCmdTrigger(CreateCmdTrigStmt *stmt, const char *queryString)
if (funcrettype != CMDTRIGGEROID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("function \"%s\" must return type \"trigger\"",
+ errmsg("function \"%s\" must return type \"command trigger\"",
NameListToString(stmt->funcname))));
trigoid = InsertCmdTriggerTuple(tgrel, stmt->command, stmt->trigname,
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index a18b0bb..87d4ca3 100644
--- a/src/backend/commands/dropcmds.c
+++ b/src/backend/commands/dropcmds.c
@@ -297,6 +297,7 @@ get_object_name(CommandContext cmd, ObjectType objtype,
case OBJECT_CAST:
cmd->objectname = NULL;
break;
+ case OBJECT_RULE:
case OBJECT_TRIGGER:
cmd->objectname = pstrdup(strVal(llast(objname)));
break;
@@ -313,7 +314,6 @@ get_object_name(CommandContext cmd, ObjectType objtype,
case OBJECT_OPERATOR:
case OBJECT_LANGUAGE:
case OBJECT_CMDTRIGGER:
- case OBJECT_RULE:
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
case OBJECT_OPCLASS:
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index a87feca..ce97b8f 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1399,6 +1399,19 @@ AlterFunction(AlterFunctionStmt *stmt)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ROWS is not applicable when function does not return a set")));
}
+
+ /* Call BEFORE ALTER FUNCTION command triggers */
+ InitCommandContext(&cmd, (Node *)stmt);
+
+ if (CommandFiresTriggers(&cmd))
+ {
+ cmd.objectId = HeapTupleGetOid(tup);
+ cmd.objectname = pstrdup(NameStr(procForm->proname));
+ cmd.schemaname = get_namespace_name(procForm->pronamespace);
+
+ ExecBeforeCommandTriggers(&cmd);
+ }
+
if (set_items)
{
Datum datum;
@@ -1434,18 +1447,6 @@ AlterFunction(AlterFunctionStmt *stmt)
repl_val, repl_null, repl_repl);
}
- /* Call BEFORE ALTER FUNCTION command triggers */
- InitCommandContext(&cmd, (Node *)stmt);
-
- if (CommandFiresTriggers(&cmd))
- {
- cmd.objectId = InvalidOid;
- cmd.objectname = pstrdup(NameStr(procForm->proname));
- cmd.schemaname = get_namespace_name(procForm->pronamespace);
-
- ExecBeforeCommandTriggers(&cmd);
- }
-
/* Do the update */
simple_heap_update(rel, &tup->t_self, tup);
CatalogUpdateIndexes(rel, tup);
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index c8dd6ce..f8c0c66 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -869,7 +869,7 @@ AlterOpFamily(AlterOpFamilyStmt *stmt)
opfForm = (Form_pg_opfamily) GETSTRUCT(htup);
cmd.objectId = opfamilyoid;
- cmd.objectname = NameStr(opfForm->opfname);
+ cmd.objectname = pstrdup(NameStr(opfForm->opfname));
cmd.schemaname = get_namespace_name(opfForm->opfnamespace);
ReleaseSysCache(htup);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 90b3525..f7f9a0e 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -437,7 +437,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
{
cmd.objectId = InvalidOid;
cmd.objectname = stmt->trigname;
- cmd.schemaname = get_namespace_name(RelationGetNamespace(rel));
+ cmd.schemaname = NULL; /* triggers are not schema qualified */
ExecBeforeCommandTriggers(&cmd);
}
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 7f473ca..fa69430 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -857,7 +857,7 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
{
Form_pg_ts_dict form = (Form_pg_ts_dict) GETSTRUCT(tup);
cmd.objectId = dictId;
- cmd.objectname = NameStr(form->dictname);
+ cmd.objectname = pstrdup(NameStr(form->dictname));
cmd.schemaname = get_namespace_name(form->dictnamespace);
ExecBeforeCommandTriggers(&cmd);
@@ -1858,7 +1858,7 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
Form_pg_ts_config form = (Form_pg_ts_config) GETSTRUCT(tup);
cmd.objectId = HeapTupleGetOid(tup);
- cmd.objectname = NameStr(form->cfgname);
+ cmd.objectname = pstrdup(NameStr(form->cfgname));
cmd.schemaname = get_namespace_name(form->cfgnamespace);
ExecBeforeCommandTriggers(&cmd);
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 958367c..399f2e0 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -492,8 +492,7 @@ DefineQueryRewrite(char *rulename,
{
cmd->objectId = InvalidOid;
cmd->objectname = rulename;
- cmd->schemaname =
- get_namespace_name(RelationGetNamespace(event_relation));
+ cmd->schemaname = NULL; /* rules are not schema qualified */
ExecBeforeCommandTriggers(cmd);
}
diff --git a/src/test/regress/expected/cmdtriggers.out b/src/test/regress/expected/cmdtriggers.out
index ee01e41..4c3fae8 100644
--- a/src/test/regress/expected/cmdtriggers.out
+++ b/src/test/regress/expected/cmdtriggers.out
@@ -449,9 +449,9 @@ NOTICE: snitch: BEFORE any CREATE FUNCTION cmd.trigfunc
NOTICE: snitch: AFTER CREATE FUNCTION cmd.trigfunc
NOTICE: snitch: AFTER any CREATE FUNCTION cmd.trigfunc
create trigger footg before update on cmd.foo for each row execute procedure cmd.trigfunc();
-NOTICE: snitch: BEFORE any CREATE TRIGGER cmd.footg
-NOTICE: snitch: BEFORE CREATE TRIGGER cmd.footg
-NOTICE: snitch: AFTER any CREATE TRIGGER cmd.footg
+NOTICE: snitch: BEFORE any CREATE TRIGGER <NULL>.footg
+NOTICE: snitch: BEFORE CREATE TRIGGER <NULL>.footg
+NOTICE: snitch: AFTER any CREATE TRIGGER <NULL>.footg
alter trigger footg on cmd.foo rename to foo_trigger;
NOTICE: snitch: BEFORE any ALTER TRIGGER cmd.footg
NOTICE: snitch: BEFORE ALTER TRIGGER cmd.footg
@@ -494,6 +494,9 @@ create text search dictionary test_stem (
NOTICE: snitch: BEFORE any CREATE TEXT SEARCH DICTIONARY public.test_stem
NOTICE: snitch: AFTER CREATE TEXT SEARCH DICTIONARY public.test_stem
NOTICE: snitch: AFTER any CREATE TEXT SEARCH DICTIONARY public.test_stem
+alter text search dictionary test_stem (StopWords = dutch );
+NOTICE: snitch: BEFORE any ALTER TEXT SEARCH DICTIONARY public.test_stem
+NOTICE: snitch: AFTER any ALTER TEXT SEARCH DICTIONARY public.test_stem
create text search parser test_parser (
start = prsd_start,
gettoken = prsd_nexttoken,
diff --git a/src/test/regress/sql/cmdtriggers.sql b/src/test/regress/sql/cmdtriggers.sql
index 82abb23..75bc573 100644
--- a/src/test/regress/sql/cmdtriggers.sql
+++ b/src/test/regress/sql/cmdtriggers.sql
@@ -218,6 +218,7 @@ create text search dictionary test_stem (
template = snowball,
language = 'english', stopwords = 'english'
);
+alter text search dictionary test_stem (StopWords = dutch );
create text search parser test_parser (
start = prsd_start,