On 24 February 2012 22:04, Dimitri Fontaine <dimi...@2ndquadrant.fr> wrote:
> Hi,
>
> Please find attached the latest version of the command triggers patch,
> in context diff format, with support for 79 commands and documentation
> about why only those, and with some limitations explained.
>
> I also cleaned up the node function support business that was still in
> there from the command rewriting stuff that we dropped, and did a merge
> from tonight's master branch (one of a few clean merges).
>
> This is now the whole of it, and I continue being available to make any
> necessary change, although I expect only minor changes now.  Thanks to
> all reviewers and participants into the previous threads, you all have
> allowed me to reach the current point by your precious advice, comments
> and interest.
>
> The patch implements :
>
>  - BEFORE/AFTER ANY command triggers
>  - BEFORE/AFTER command triggers for 79 documented commands
>  - regression tests exercised by the serial schedule only
>  - documentation updates with examples
>
> That means you need to `make installcheck` here. Installing the tests in
> the parallel schedule does not lead to consistent output as installing a
> command trigger will impact any other test using that command, and the
> output becomes subject to the exact ordering of the concurrent tests.
>
> The only way for a BEFORE command triggers to change the command's
> behaviour is by raising an exception that aborts the whole transaction.
>
> Command triggers are called with the following arguments:
>
>  - the “event” (similar to TG_WHEN, either 'BEFORE' or 'AFTER')
>  - the command tag (the real one even when an ANY trigger is called)
>  - the object Id if available (e.g. NULL for a CREATE statement)
>  - the schema name (can be NULL)
>  - the object name (can be NULL)
>
> When the trigger's procedure we're calling is written in C, then another
> argument is passed next, which is the parse tree Node * pointer.
>
> I've been talking with Marko Kreen about supporting ALTER TABLE and such
> commands automatically in Londiste: given that patch, it requires
> writing code in C that will rewrite the command string.  It so happens
> that I already have worked on that code, so we intend on bringing
> support for ALTER TABLE and other commands in Skytools 3 for 9.2.
>
> I think the support code should be made into an extension that both
> Skytools and Slony would be able to share. The extension code will be
> able to adapt to major versions changes as they are released.  Bucardo
> would certainly be interested too, we could NOTIFY it from such an
> extension.  The design is yet to be done here, but it's clearly possible
> to implement such a feature given the current patch.
>
> The ANY trigger support is mainly there to allow people to stop any DDL
> traffic on their databases, then allowing it explicitly with an ALTER
> COMMAND TRIGGER ... SET DISABLE when appropriate only.  To that
> end, the ANY command trigger is supporting more commands than you can
> attach specific triggers too.
>
> It's also possible to ENABLE a command trigger on the REPLICA only
> thanks to the session_replication_role GUC.  Support for command
> triggers on an Hot Standby node is not provided in this patch.

Hi Dimitri,

I just tried building the docs with your patch and it appears
doc/src/sgml/ref/allfiles.sgml hasn't been updated with the necessary
references for alterCommandTrigger, createCommandTrigger and
dropCommandTrigger.

Also in ref/alter_command_trigger.sgml, you define SQL-CREATETRIGGER.
Shouldn't this be SQL-CREATECOMMANDTRIGGER?  And there also appears to
be orphaned text in the file too, such as "Forbids the execution of
any DDL command".  And there's a stray </para> on line 299.

I attach updated versions of both of those files, which seems to fix
all these problems.

-- 
Thom
<!--
doc/src/sgml/ref/allfiles.sgml
PostgreSQL documentation
Complete list of usable sgml source files in this directory.
-->

<!-- SQL commands -->
<!ENTITY abort              SYSTEM "abort.sgml">
<!ENTITY alterAggregate     SYSTEM "alter_aggregate.sgml">
<!ENTITY alterCollation     SYSTEM "alter_collation.sgml">
<!ENTITY alterCommandTrigger SYSTEM "alter_command_trigger.sgml">
<!ENTITY alterConversion    SYSTEM "alter_conversion.sgml">
<!ENTITY alterDatabase      SYSTEM "alter_database.sgml">
<!ENTITY alterDefaultPrivileges SYSTEM "alter_default_privileges.sgml">
<!ENTITY alterDomain        SYSTEM "alter_domain.sgml">
<!ENTITY alterExtension     SYSTEM "alter_extension.sgml">
<!ENTITY alterForeignDataWrapper SYSTEM "alter_foreign_data_wrapper.sgml">
<!ENTITY alterForeignTable  SYSTEM "alter_foreign_table.sgml">
<!ENTITY alterFunction      SYSTEM "alter_function.sgml">
<!ENTITY alterGroup         SYSTEM "alter_group.sgml">
<!ENTITY alterIndex         SYSTEM "alter_index.sgml">
<!ENTITY alterLanguage      SYSTEM "alter_language.sgml">
<!ENTITY alterLargeObject   SYSTEM "alter_large_object.sgml">
<!ENTITY alterOperator      SYSTEM "alter_operator.sgml">
<!ENTITY alterOperatorClass SYSTEM "alter_opclass.sgml">
<!ENTITY alterOperatorFamily SYSTEM "alter_opfamily.sgml">
<!ENTITY alterRole          SYSTEM "alter_role.sgml">
<!ENTITY alterSchema        SYSTEM "alter_schema.sgml">
<!ENTITY alterServer        SYSTEM "alter_server.sgml">
<!ENTITY alterSequence      SYSTEM "alter_sequence.sgml">
<!ENTITY alterTable         SYSTEM "alter_table.sgml">
<!ENTITY alterTableSpace    SYSTEM "alter_tablespace.sgml">
<!ENTITY alterTSConfig      SYSTEM "alter_tsconfig.sgml">
<!ENTITY alterTSDictionary  SYSTEM "alter_tsdictionary.sgml">
<!ENTITY alterTSParser      SYSTEM "alter_tsparser.sgml">
<!ENTITY alterTSTemplate    SYSTEM "alter_tstemplate.sgml">
<!ENTITY alterTrigger       SYSTEM "alter_trigger.sgml">
<!ENTITY alterType          SYSTEM "alter_type.sgml">
<!ENTITY alterUser          SYSTEM "alter_user.sgml">
<!ENTITY alterUserMapping   SYSTEM "alter_user_mapping.sgml">
<!ENTITY alterView          SYSTEM "alter_view.sgml">
<!ENTITY analyze            SYSTEM "analyze.sgml">
<!ENTITY begin              SYSTEM "begin.sgml">
<!ENTITY checkpoint         SYSTEM "checkpoint.sgml">
<!ENTITY close              SYSTEM "close.sgml">
<!ENTITY cluster            SYSTEM "cluster.sgml">
<!ENTITY commentOn          SYSTEM "comment.sgml">
<!ENTITY commit             SYSTEM "commit.sgml">
<!ENTITY commitPrepared     SYSTEM "commit_prepared.sgml">
<!ENTITY copyTable          SYSTEM "copy.sgml">
<!ENTITY createAggregate    SYSTEM "create_aggregate.sgml">
<!ENTITY createCast         SYSTEM "create_cast.sgml">
<!ENTITY createCollation    SYSTEM "create_collation.sgml">
<!ENTITY createCommandTrigger SYSTEM "create_command_trigger.sgml">
<!ENTITY createConversion   SYSTEM "create_conversion.sgml">
<!ENTITY createDatabase     SYSTEM "create_database.sgml">
<!ENTITY createDomain       SYSTEM "create_domain.sgml">
<!ENTITY createExtension    SYSTEM "create_extension.sgml">
<!ENTITY createForeignDataWrapper SYSTEM "create_foreign_data_wrapper.sgml">
<!ENTITY createForeignTable SYSTEM "create_foreign_table.sgml">
<!ENTITY createFunction     SYSTEM "create_function.sgml">
<!ENTITY createGroup        SYSTEM "create_group.sgml">
<!ENTITY createIndex        SYSTEM "create_index.sgml">
<!ENTITY createLanguage     SYSTEM "create_language.sgml">
<!ENTITY createOperator     SYSTEM "create_operator.sgml">
<!ENTITY createOperatorClass SYSTEM "create_opclass.sgml">
<!ENTITY createOperatorFamily SYSTEM "create_opfamily.sgml">
<!ENTITY createRole         SYSTEM "create_role.sgml">
<!ENTITY createRule         SYSTEM "create_rule.sgml">
<!ENTITY createSchema       SYSTEM "create_schema.sgml">
<!ENTITY createSequence     SYSTEM "create_sequence.sgml">
<!ENTITY createServer       SYSTEM "create_server.sgml">
<!ENTITY createTable        SYSTEM "create_table.sgml">
<!ENTITY createTableAs      SYSTEM "create_table_as.sgml">
<!ENTITY createTableSpace   SYSTEM "create_tablespace.sgml">
<!ENTITY createTrigger      SYSTEM "create_trigger.sgml">
<!ENTITY createTSConfig     SYSTEM "create_tsconfig.sgml">
<!ENTITY createTSDictionary SYSTEM "create_tsdictionary.sgml">
<!ENTITY createTSParser     SYSTEM "create_tsparser.sgml">
<!ENTITY createTSTemplate   SYSTEM "create_tstemplate.sgml">
<!ENTITY createType         SYSTEM "create_type.sgml">
<!ENTITY createUser         SYSTEM "create_user.sgml">
<!ENTITY createUserMapping  SYSTEM "create_user_mapping.sgml">
<!ENTITY createView         SYSTEM "create_view.sgml">
<!ENTITY deallocate         SYSTEM "deallocate.sgml">
<!ENTITY declare            SYSTEM "declare.sgml">
<!ENTITY delete             SYSTEM "delete.sgml">
<!ENTITY discard            SYSTEM "discard.sgml">
<!ENTITY do                 SYSTEM "do.sgml">
<!ENTITY dropAggregate      SYSTEM "drop_aggregate.sgml">
<!ENTITY dropCast           SYSTEM "drop_cast.sgml">
<!ENTITY dropCollation      SYSTEM "drop_collation.sgml">
<!ENTITY dropCommandTrigger SYSTEM "drop_command_trigger.sgml">
<!ENTITY dropConversion     SYSTEM "drop_conversion.sgml">
<!ENTITY dropDatabase       SYSTEM "drop_database.sgml">
<!ENTITY dropDomain         SYSTEM "drop_domain.sgml">
<!ENTITY dropExtension      SYSTEM "drop_extension.sgml">
<!ENTITY dropForeignDataWrapper SYSTEM "drop_foreign_data_wrapper.sgml">
<!ENTITY dropForeignTable   SYSTEM "drop_foreign_table.sgml">
<!ENTITY dropFunction       SYSTEM "drop_function.sgml">
<!ENTITY dropGroup          SYSTEM "drop_group.sgml">
<!ENTITY dropIndex          SYSTEM "drop_index.sgml">
<!ENTITY dropLanguage       SYSTEM "drop_language.sgml">
<!ENTITY dropOperator       SYSTEM "drop_operator.sgml">
<!ENTITY dropOperatorClass  SYSTEM "drop_opclass.sgml">
<!ENTITY dropOperatorFamily  SYSTEM "drop_opfamily.sgml">
<!ENTITY dropOwned          SYSTEM "drop_owned.sgml">
<!ENTITY dropRole           SYSTEM "drop_role.sgml">
<!ENTITY dropRule           SYSTEM "drop_rule.sgml">
<!ENTITY dropSchema         SYSTEM "drop_schema.sgml">
<!ENTITY dropSequence       SYSTEM "drop_sequence.sgml">
<!ENTITY dropServer         SYSTEM "drop_server.sgml">
<!ENTITY dropTable          SYSTEM "drop_table.sgml">
<!ENTITY dropTableSpace     SYSTEM "drop_tablespace.sgml">
<!ENTITY dropTrigger        SYSTEM "drop_trigger.sgml">
<!ENTITY dropTSConfig       SYSTEM "drop_tsconfig.sgml">
<!ENTITY dropTSDictionary   SYSTEM "drop_tsdictionary.sgml">
<!ENTITY dropTSParser       SYSTEM "drop_tsparser.sgml">
<!ENTITY dropTSTemplate     SYSTEM "drop_tstemplate.sgml">
<!ENTITY dropType           SYSTEM "drop_type.sgml">
<!ENTITY dropUser           SYSTEM "drop_user.sgml">
<!ENTITY dropUserMapping    SYSTEM "drop_user_mapping.sgml">
<!ENTITY dropView           SYSTEM "drop_view.sgml">
<!ENTITY end                SYSTEM "end.sgml">
<!ENTITY execute            SYSTEM "execute.sgml">
<!ENTITY explain            SYSTEM "explain.sgml">
<!ENTITY fetch              SYSTEM "fetch.sgml">
<!ENTITY grant              SYSTEM "grant.sgml">
<!ENTITY insert             SYSTEM "insert.sgml">
<!ENTITY listen             SYSTEM "listen.sgml">
<!ENTITY load               SYSTEM "load.sgml">
<!ENTITY lock               SYSTEM "lock.sgml">
<!ENTITY move               SYSTEM "move.sgml">
<!ENTITY notify             SYSTEM "notify.sgml">
<!ENTITY prepare            SYSTEM "prepare.sgml">
<!ENTITY prepareTransaction SYSTEM "prepare_transaction.sgml">
<!ENTITY reassignOwned      SYSTEM "reassign_owned.sgml">
<!ENTITY reindex            SYSTEM "reindex.sgml">
<!ENTITY releaseSavepoint   SYSTEM "release_savepoint.sgml">
<!ENTITY reset              SYSTEM "reset.sgml">
<!ENTITY revoke             SYSTEM "revoke.sgml">
<!ENTITY rollback           SYSTEM "rollback.sgml">
<!ENTITY rollbackPrepared   SYSTEM "rollback_prepared.sgml">
<!ENTITY rollbackTo         SYSTEM "rollback_to.sgml">
<!ENTITY savepoint          SYSTEM "savepoint.sgml">
<!ENTITY securityLabel      SYSTEM "security_label.sgml">
<!ENTITY select             SYSTEM "select.sgml">
<!ENTITY selectInto         SYSTEM "select_into.sgml">
<!ENTITY set                SYSTEM "set.sgml">
<!ENTITY setConstraints     SYSTEM "set_constraints.sgml">
<!ENTITY setRole            SYSTEM "set_role.sgml">
<!ENTITY setSessionAuth     SYSTEM "set_session_auth.sgml">
<!ENTITY setTransaction     SYSTEM "set_transaction.sgml">
<!ENTITY show               SYSTEM "show.sgml">
<!ENTITY startTransaction   SYSTEM "start_transaction.sgml">
<!ENTITY truncate           SYSTEM "truncate.sgml">
<!ENTITY unlisten           SYSTEM "unlisten.sgml">
<!ENTITY update             SYSTEM "update.sgml">
<!ENTITY vacuum             SYSTEM "vacuum.sgml">
<!ENTITY values             SYSTEM "values.sgml">

<!-- applications and utilities -->
<!ENTITY clusterdb          SYSTEM "clusterdb.sgml">
<!ENTITY createdb           SYSTEM "createdb.sgml">
<!ENTITY createlang         SYSTEM "createlang.sgml">
<!ENTITY createuser         SYSTEM "createuser.sgml">
<!ENTITY dropdb             SYSTEM "dropdb.sgml">
<!ENTITY droplang           SYSTEM "droplang.sgml">
<!ENTITY dropuser           SYSTEM "dropuser.sgml">
<!ENTITY ecpgRef            SYSTEM "ecpg-ref.sgml">
<!ENTITY initdb             SYSTEM "initdb.sgml">
<!ENTITY pgBasebackup       SYSTEM "pg_basebackup.sgml">
<!ENTITY pgConfig           SYSTEM "pg_config-ref.sgml">
<!ENTITY pgControldata      SYSTEM "pg_controldata.sgml">
<!ENTITY pgCtl              SYSTEM "pg_ctl-ref.sgml">
<!ENTITY pgDump             SYSTEM "pg_dump.sgml">
<!ENTITY pgDumpall          SYSTEM "pg_dumpall.sgml">
<!ENTITY pgReceivexlog      SYSTEM "pg_receivexlog.sgml">
<!ENTITY pgResetxlog        SYSTEM "pg_resetxlog.sgml">
<!ENTITY pgRestore          SYSTEM "pg_restore.sgml">
<!ENTITY postgres           SYSTEM "postgres-ref.sgml">
<!ENTITY postmaster         SYSTEM "postmaster.sgml">
<!ENTITY psqlRef            SYSTEM "psql-ref.sgml">
<!ENTITY reindexdb          SYSTEM "reindexdb.sgml">
<!ENTITY vacuumdb           SYSTEM "vacuumdb.sgml">
<!--
doc/src/sgml/ref/create_trigger.sgml
PostgreSQL documentation
-->

<refentry id="SQL-CREATECOMMANDTRIGGER">
 <refmeta>
  <refentrytitle>CREATE COMMAND TRIGGER</refentrytitle>
  <manvolnum>7</manvolnum>
  <refmiscinfo>SQL - Language Statements</refmiscinfo>
 </refmeta>

 <refnamediv>
  <refname>CREATE COMMAND TRIGGER</refname>
  <refpurpose>define a new trigger</refpurpose>
 </refnamediv>

 <indexterm zone="sql-createcommandtrigger">
  <primary>CREATE COMMAND TRIGGER</primary>
 </indexterm>

 <refsynopsisdiv>
<synopsis>
CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTER  } ANY COMMAND
    EXECUTE PROCEDURE <replaceable class="PARAMETER">function_name</replaceable> ()

CREATE TRIGGER <replaceable class="PARAMETER">name</replaceable> { BEFORE | AFTER  } COMMAND <replaceable class="PARAMETER">command</replaceable> [, ... ]
    EXECUTE PROCEDURE <replaceable class="PARAMETER">function_name</replaceable> ()

<phrase>where <replaceable class="parameter">command</replaceable> can be one of:</phrase>

    CREATE SCHEMA
    CREATE EXTENSION
    CREATE LANGUAGE
    CREATE FUNCTION
    CREATE TABLE
    CREATE SERVER
    CREATE FOREIGN TABLE
    CREATE FOREIGN DATA WRAPPER
    CREATE USER MAPPING
    CREATE INDEX
    CREATE SEQUENCE
    CREATE VIEW
    CREATE RULE
    CREATE AGGREGATE
    CREATE OPERATOR
    CREATE COLLATION
    CREATE TEXT SEARCH PARSER
    CREATE TEXT SEARCH DICTIONARY
    CREATE TEXT SEARCH TEMPLATE
    CREATE TEXT SEARCH CONFIGURATION
    CREATE TYPE_P
    CREATE DOMAIN_P
    CREATE TRIGGER
    CREATE CONVERSION_P
    CREATE CAST
    CREATE OPERATOR CLASS
    CREATE OPERATOR FAMILY
    ALTER SCHEMA
    ALTER EXTENSION
    ALTER FUNCTION
    ALTER TABLE
    ALTER SERVER
    ALTER FOREIGN TABLE
    ALTER FOREIGN DATA WRAPPER
    ALTER USER MAPPING
    ALTER AGGREGATE
    ALTER OPERATOR
    ALTER OPERATOR CLASS
    ALTER OPERATOR FAMILY
    ALTER COLLATION
    ALTER TEXT SEARCH PARSER
    ALTER TEXT SEARCH DICTIONARY
    ALTER TEXT SEARCH TEMPLATE
    ALTER TEXT SEARCH CONFIGURATION
    ALTER TYPE_P
    ALTER DOMAIN_P
    ALTER TRIGGER
    DROP TABLE
    DROP SEQUENCE
    DROP VIEW
    DROP INDEX
    DROP TYPE_P
    DROP DOMAIN_P
    DROP COLLATION
    DROP CONVERSION_P
    DROP SCHEMA
    DROP EXTENSION
    DROP TEXT SEARCH PARSER
    DROP TEXT SEARCH DICTIONARY
    DROP TEXT SEARCH TEMPLATE
    DROP TEXT SEARCH CONFIGURATION
    DROP LANGUAGE
    DROP SERVER
    DROP FOREIGN TABLE
    DROP FOREIGN DATA WRAPPER
    DROP USER MAPPING
    DROP TRIGGER
    DROP ASSERTION
    DROP OPERATOR CLASS
    DROP OPERATOR FAMILY
    DROP FUNCTION
    DROP AGGREGATE
    DROP OPERATOR
    DROP CAST
    DROP RULE
    REINDEX
    VACUUM
    CLUSTER
    LOAD
	
</synopsis>
 </refsynopsisdiv>

 <refsect1>
  <title>Description</title>

  <para>
   <command>CREATE COMMAND TRIGGER</command> creates a new command trigger.
   The trigger will be associated with the specified command and will
   execute the specified
   function <replaceable class="parameter">function_name</replaceable> when
   that command is run.
  </para>

  <para>
   The command trigger can be specified to fire before or after the command
   is executed. A command trigger's function must
   return <literal>void</literal>, the only it can aborts the execution of
   the command is by raising an exception.
  </para>

  <para>
   Refer to <xref linkend="triggers"> for more information about triggers.
  </para>
 </refsect1>

 <refsect1>
  <title>Parameters</title>

  <variablelist>
   <varlistentry>
    <term><replaceable class="parameter">name</replaceable></term>
    <listitem>
     <para>
      The name to give the new trigger.  This must be distinct from
      the name of any other trigger for the same table.
      The name cannot be schema-qualified &mdash; the trigger inherits the
      schema of its table.  For a constraint trigger, this is also the name to
      use when modifying the trigger's behavior using
      <command>SET CONSTRAINTS</>.
     </para>
    </listitem>
   </varlistentry>

   <varlistentry>
    <term><literal>BEFORE</literal></term>
    <term><literal>AFTER</literal></term>
    <listitem>
     <para>
      Determines whether the function is called before or after the command
      is executed.
     </para>
    </listitem>
   </varlistentry>

   <varlistentry>
    <term><replaceable class="parameter">command</replaceable></term>
    <listitem>
     <para>
      The tag of the command the trigger is for. Supported commands are
      mainly those acting on database objects, plus some more facilities.
      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.
     </para>
     <para>
      Commands that exercize their own transaction control are only
      supported in <literal>BEFORE</literal> command triggers, that's the
      case for <literal>VACUUM</literal>, <literal>CLUSTER</literal>
      <literal>CREATE INDEX CONCURRENTLY</literal>, and <literal>REINDEX
      DATABASE</literal>.
     </para>
     <para>
      Commands that are related to transaction control (such
      as <literal>BEGIN</literal> or <literal>COMMIT</literal>), related to
      prepared plans
      (e.g. <literal>PREPARE</literal>, <literal>DEALLOCATE</literal>),
      cursors management
      (e.g. <literal>DECLARE</literal>, <literal>FETCH</literal>), setting
      variables (<literal>SET</literal>), the <literal>LISTEN</literal>
      feature, and security are not supported either.
     </para>
     <para>
      Command triggers on <literal>CREATE COMMAND
      TRIGGER</literal>, <literal>ALTER COMMAND TRIGGER</literal>
      and <literal>DROP COMMAND TRIGGER</literal> are not supported so as
      not to be able to take over control from a superuser.
     </para>
     <para>
      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
      commands is made so that you can actually block <xref linkend="ddl">
      commands in one go.
     </para>
    </listitem>
   </varlistentry>

   <varlistentry>
    <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.
     </para>
     <para>
      If your command trigger is implemented in <literal>C</literal> then it
      will be called with yet another argument, of
      type <literal>internal</literal>, which is a pointer to
      the <literal>Node *</literal> parse tree.
     </para>
     <para>
      The command trigger function is called with the
      parameters <literal>tg_when</literal> (which is set to either 'BEFORE'
      or 'AFTER'), <literal>command
      tag</literal>, <literal>objectid</literal> (can be null in case of a
      BEFORE CREATE or an AFTER DROP command trigger
      timing), <literal>schemaname</literal> (can be null for objects not
      living in a schema, and for sequences due to an implementation limit)
      and <literal>object name</literal> (can be null for any command
      triggers).
     </para>
     <para>
      The command <literal>CREATE SEQUENCE</literal> lacks support for
      the <literal>schemaname</literal> command trigger argument, it
      provides <literal>NULL</literal> in all cases.
     </para>
    </listitem>
   </varlistentry>

  </variablelist>
 </refsect1>

 <refsect1 id="SQL-CREATECOMMANDTRIGGER-notes">
  <title>Notes</title>

  <para>
   To create a trigger on a command, the user must be superuser.
  </para>

  <para>
   Use <xref linkend="sql-dropcommandtrigger"> to remove a command trigger.
  </para>
 </refsect1>

 <refsect1 id="SQL-CREATECOMMANDTRIGGER-examples">
  <title>Examples</title>

  <para>
   Forbids the execution of any DDL command:
  </para>

<programlisting>
CREATE OR REPLACE FUNCTION abort_any_command
 (tg_when text, cmd_tag text, objectid oid, schemaname text, objectname text)
 RETURNS void LANGUAGE plpgsql AS $$
BEGIN
  RAISE EXCEPTION 'command % is disabled' % cmd_tag;
END;
$$;

CREATE TRIGGER abort_ddl
        BEFORE COMMAND CREATE TABLE
       EXECUTE PROCEDURE abort_any_command();
</programlisting>

  <para>
   Execute the function <function>enforce_local_style</> each time
   a <literal>CREATE TABLE</literal> command is run:
  </para>

<programlisting>
CREATE OR REPLACE FUNCTION enforce_local_style
 (tg_when text, cmd_tag text, objectid oid, schemaname text, objectname text)
 RETURNS bool LANGUAGE plpgsql AS $$
BEGIN
  IF substring(objectname, 0, 4) NOT IN ('ab_', 'cz_', 'fr_')
  THEN
    RAISE EXCEPTION 'invalid relation name: %', objectname;
  END IF;
END;
$$;

CREATE TRIGGER check_style
        BEFORE COMMAND CREATE TABLE
       EXECUTE PROCEDURE enforce_local_style();
</programlisting>
 </refsect1>

 <refsect1 id="SQL-CREATECOMMANDTRIGGER-compatibility">
  <title>Compatibility</title>

  <para>
   <command>CREATE COMMAND TRIGGER</command> is a
   <productname>PostgreSQL</productname> extension of the <acronym>SQL</>
   standard.
  </para>

 </refsect1>

 <refsect1>
  <title>See Also</title>

  <simplelist type="inline">
   <member><xref linkend="sql-createfunction"></member>
   <member><xref linkend="sql-altercommandtrigger"></member>
   <member><xref linkend="sql-dropcommandtrigger"></member>
  </simplelist>
 </refsect1>
</refentry>
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to