Command Triggers - Mailing list pgsql-hackers

From Dimitri Fontaine
Subject Command Triggers
Date
Msg-id m2pqh2mrq6.fsf@2ndQuadrant.fr
Whole thread Raw
Responses Re: Command Triggers  (Dimitri Fontaine <dimitri@2ndQuadrant.fr>)
Re: Command Triggers  (Andres Freund <andres@anarazel.de>)
Re: Command Triggers  (Andres Freund <andres@anarazel.de>)
Re: Command Triggers  (Andres Freund <andres@anarazel.de>)
Re: Command Triggers  (Andres Freund <andres@anarazel.de>)
List pgsql-hackers
Hi,

As proposed by Jan Wieck on hackers and discussed in Ottawa at the
Clusters Hackers Meeting, the most (only?) workable way to ever have DDL
triggers is to have "command triggers" instead.

Rather than talking about catalogs and the like, it's all about firing a
registered user-defined function before or after processing the utility
command, or instead of processing it.  This naturally involves a new
catalog (pg_cmdtrigger) and some new subcommands of CREATE and DROP
TRIGGER, and some support code for calling the function at the right
time.

The right place to hook this code in seems to be ProcessUtility(), which
is a central place for about all the commands that we handle.  An
exception to that rule would be SELECT INTO and CREATE TABLE AS SELECT,
and my proposal would be to add specific call sites to the functions
I've provided in the attached patch rather than try to contort them into
being a good citizen as a utility command.

The ProcessUtility() integration currently looks like that:

    const char *commandTag = CreateCommandTag(parsetree);
    if (ExecBeforeOrInsteadOfCommandTriggers(parsetree, commandTag) > 0)
        return;

        ... current code ...

    ExecAfterCommandTriggers(parsetree, commandTag);

So I guess adding some call sites is manageable.


Now, the patch contains a Proof Of Concept implementation with a small
level of documentation and regression tests in order to get an agreement
on the principles that we already discussed.


The other part of the command trigger facility is what information we
should give to the user-defined functions, and in which form.  I've
settled on passing always 4 text arguments:  the command string, the
parse tree as a nodeToString() representation (Jan believes that this is
the easiest form we can provide for code consumption, and I tend to
agree), the schema name or NULL if the targeted object of the command is
not qualified, and the object name (or NULL if that does not apply).

    CREATE FUNCTION cmdtrigger_notice
     (
       IN cmd_string     text,
       IN cmd_nodestring text,
       IN schemaname     text,
       IN relname        text
     )
     RETURNS void
     LANGUAGE plpgsql
    AS $$
    BEGIN
      RAISE NOTICE 'cmd_string: %', cmd_string;
    END;
    $$;

    CREATE TRIGGER cmdtrigger_notice
             AFTER COMMAND CREATE TABLE
           EXECUTE PROCEDURE cmdtrigger_notice();

The v1 patch attached contains implementation for some commands only.
We need to add rewriting facilities for those commands we want to
support in the proposed model, because of multi-queries support in the
protocol and dynamic queries in EXECUTE e.g. (though I admit not having
had a look at EXECUTE implementation).

So each supported command has a cost, and the ones I claim to support in
the grammar in the patch are not seeing a complete support: first, I'm
missing some outfuncs and readfuncs (but I believe we can complete that
using a script on the source code) so that the cmd_nodestring argument
is currently always NULL. Second, I didn't complete the rewriting of
some more complex commands such as CREATE TABLE and ALTER TABLE.

Note that we can't reuse that much of ruleutils.c because it's written
to work from what we store in the catalogs rather than from a parsetree
object.


So, any comment on the approach before I complete the rewriting of the
commands, the out/read funcs, and add more commands to the trigger
support code?


  https://github.com/dimitri/postgres/compare/master...command_triggers


$ git diff --stat master..
 doc/src/sgml/ref/create_trigger.sgml       |   97 +++++-
 doc/src/sgml/ref/drop_trigger.sgml         |   19 +-
 src/backend/catalog/Makefile               |    2 +-
 src/backend/catalog/dependency.c           |   47 ++-
 src/backend/catalog/objectaddress.c        |    8 +
 src/backend/commands/Makefile              |    4 +-
 src/backend/commands/cmdtrigger.c          |  580 ++++++++++++++++++++++++++
 src/backend/nodes/copyfuncs.c              |   32 ++
 src/backend/nodes/equalfuncs.c             |   28 ++
 src/backend/nodes/outfuncs.c               |  405 ++++++++++++++++++
 src/backend/parser/gram.y                  |   70 +++-
 src/backend/tcop/utility.c                 |   44 ++
 src/backend/utils/adt/ruleutils.c          |  613 +++++++++++++++++++++++++++-
 src/include/catalog/dependency.h           |    1 +
 src/include/catalog/indexing.h             |    5 +
 src/include/catalog/pg_cmdtrigger.h        |   59 +++
 src/include/commands/cmdtrigger.h          |   43 ++
 src/include/commands/defrem.h              |   14 +
 src/include/nodes/nodes.h                  |    2 +
 src/include/nodes/parsenodes.h             |   28 ++
 src/include/parser/kwlist.h                |    1 +
 src/test/regress/expected/sanity_check.out |    3 +-
 src/test/regress/expected/triggers.out     |   35 ++
 src/test/regress/sql/triggers.sql          |   35 ++
 24 files changed, 2157 insertions(+), 18 deletions(-)



Regards,
--
Dimitri Fontaine
http://2ndQuadrant.fr     PostgreSQL : Expertise, Formation et Support


Attachment

pgsql-hackers by date:

Previous
From: Tom Lane
Date:
Subject: Re: Disable OpenSSL compression
Next
From: Heikki Linnakangas
Date:
Subject: Re: DatumGetInetP buggy