[EMAIL PROTECTED] wrote:
Ticket #2282 against SQLite

   http://www.sqlite.org/cvstrac/tktview?tn=2282

complains that in an INSTEAD OF trigger on a view where
the trigger has a WHEN clause, if the WHEN clause is false
and the trigger does not fire, then the UPDATE statement
that provoked the trigger should fail.  I am skeptical
of this claim, but want the opinion of others before
I reject the ticket.

Is this really a bug?  What do INSTEAD OF triggers with
false WHEN clauses do on other SQL database engines?


Richard,

Instead of triggers are an extension to standard SQL. They do not appear in the SQL:1999 standard and are only mentioned in passing in the editors notes for SQL:2003.

They do seem to be a common extension, supported by Oracle, IBM, and Microsoft in addition to SQLite, but they are all done differently. PostgreSQL does not support the non standard INSTEAD OF triggers.

From Microsoft's SQL server documentation they don't support a when clause:

CREATE TRIGGER /trigger_name /
ON { /table/ | /view /}
[ WITH ENCRYPTION ]
{
{ {* *FOR | AFTER | INSTEAD OF } { [ INSERT ] [ *, *] [ UPDATE ] [ *, *] [ DELETE ] }
[ WITH APPEND ]
[ NOT FOR REPLICATION ]
AS
[ { IF UPDATE *( */column /*) *
[ { AND | OR } UPDATE *( */column /*) *]
[ .../n /]
| IF *(* COLUMNS_UPDATED *( ) *{ /bitwise_operator /} /updated_bitmask /*)*
{ /comparison_operator /} /column_bitmask/ [ .../n /]
} ]
/sql_statement/ [* *.../n /]
}
}

INSTEAD OF

Specifies that the trigger is executed /instead of/ the triggering SQL statement, thus overriding the actions of the triggering statements.

At most, one INSTEAD OF trigger per INSERT, UPDATE, or DELETE statement can be defined on a table or view. However, it is possible to define views on views where each view has its own INSTEAD OF trigger.

INSTEAD OF triggers are not allowed on updateable views WITH CHECK OPTION. SQL Server will raise an error if an INSTEAD OF trigger is added to an updateable view WITH CHECK OPTION specified. The user must remove that option using ALTER VIEW before defining the INSTEAD OF trigger.

{ [DELETE] [*,*] [INSERT] [*,*] [UPDATE] }

Are keywords that specify which data modification statements, when attempted against this table*/ /*or view, activate the trigger. At least one option must be specified. Any combination of these in any order is allowed in the trigger definition. If more than one option is specified, separate the options with commas.

For INSTEAD OF triggers, the DELETE option is not allowed on tables that have a referential relationship specifying a cascade action ON DELETE. Similarly, the UPDATE option is not allowed on tables that have a referential relationship specifying a cascade action ON UPDATE.



From mySQL documentation, they don't support a WHEN clause either:

CREATE
   [DEFINER = { /|user|/ | CURRENT_USER }]
   TRIGGER /|trigger_name|/ /|trigger_time|/ /|trigger_event|/
   ON /|tbl_name|/ FOR EACH ROW /|trigger_stmt|/

/|trigger_time|/ is the trigger action time. It can be |BEFORE| or |AFTER| to indicate that the trigger activates before or after the statement that activated it.

/|trigger_event|/ indicates the kind of statement that activates the trigger. The /|trigger_event|/ can be one of the following:

   *

     |INSERT|: The trigger is activated whenever a new row is inserted
     into the table; for example, through |INSERT|, |LOAD DATA|, and
     |REPLACE| statements.

   *

     |UPDATE|: The trigger is activated whenever a row is modified; for
     example, through |UPDATE| statements.

   *

     |DELETE|: The trigger is activated whenever a row is deleted from
     the table; for example, through |DELETE| and |REPLACE| statements.
     However, |DROP TABLE| and |TRUNCATE| statements on the table do
     /not/ activate this trigger, because they do not use |DELETE|. See
     Section 13.2.9, “|TRUNCATE| Syntax”
     <http://dev.mysql.com/doc/refman/5.0/en/truncate.html>.

It is important to understand that the /|trigger_event|/ does not represent a literal type of SQL statement that activates the trigger so much as it represents a type of table operation. For example, an |INSERT| trigger is activated by not only |INSERT| statements but also |LOAD DATA| statements because both statements insert rows into a table.

A potentially confusing example of this is the |INSERT INTO ... ON DUPLICATE KEY UPDATE ...| syntax: a |BEFORE INSERT| trigger will activate for every row, followed by either an |AFTER INSERT| trigger or both the |BEFORE UPDATE| and |AFTER UPDATE| triggers, depending on whether there was a duplicate key for the row.

There cannot be two triggers for a given table that have the same trigger action time and event. For example, you cannot have two |BEFORE UPDATE| triggers for a table. But you can have a |BEFORE UPDATE| and a |BEFORE INSERT| trigger, or a |BEFORE UPDATE| and an |AFTER UPDATE| trigger.


From the IBM DB2 documentation a WHEN clause is not allowed on an INSTEAD OF trigger (see note 4):


Read syntax diagramSkip visual syntax diagram 
<http://publib.boulder.ibm.com/infocenter/db2luw/v9/topic/com.ibm.db2.udb.admin.doc/doc/r0000931.htm#skipsyn-200>
                                   .-NO CASCADE-.
-CREATE TRIGGER--/trigger-name/--+-+------------+--BEFORE-+----->
                                +-AFTER------------------+
                                '-INSTEAD OF-------------'

--+-INSERT--------------------------+--ON--+-/table-name/-+------>
  +-DELETE--------------------------+      '-/view-name/--'
  '-UPDATE--+---------------------+-'
            |     .-,-----------. |
            |     V             | |
            '-OF----/column-name/-+-'

--+------------------------------------------------------------------+-->
  |              .-------------------------------------------------. |
  |              V  (1)    (2)          .-AS-.                     | |
  '-REFERENCING------------------+-OLD--+----+--/correlation-name/-+-+-'
                                 |      .-AS-.                   |
                                 +-NEW--+----+--/correlation-name/-+
                                 |            .-AS-.             |
                                 +-OLD TABLE--+----+--/identifier/-+
                                 |            .-AS-.             |
                                 '-NEW TABLE--+----+--/identifier/-'

--+-FOR EACH ROW--------------+--| triggered-action |---------><
  |  (3)                      |
  '--------FOR EACH STATEMENT-'

triggered-action:

|--+-------------------------------------+---------------------->
  |  (4)                                |
  '--------WHEN--(--/search-condition/--)-'

--+--------+--| SQL-procedure-statement |----------------------|
  '-/label:/-'

SQL-procedure-statement:

|--+-/CALL/----------------------------------------------+--------|
  +-/Compound SQL (Dynamic)/----------------------------+
  +-/FOR/-----------------------------------------------+
  +-+-----------------------------------+--/fullselect/-+
  | |       .-,-----------------------. |             |
  | |       V                         | |             |
  | '-WITH----/common-table-expression/-+-'             |
  +-/GET DIAGNOSTICS/-----------------------------------+
  +-/IF/------------------------------------------------+
  +-/INSERT/--------------------------------------------+
  +-/ITERATE/-------------------------------------------+
  +-/LEAVE/---------------------------------------------+
  +-/MERGE/---------------------------------------------+
  +-/searched-delete/-----------------------------------+
  +-/searched-update/-----------------------------------+
  +-/SET Variable/--------------------------------------+
  +-/SIGNAL/--------------------------------------------+
  '-/WHILE/---------------------------------------------'



Notes:

  1. OLD and NEW can only be specified once each.
  2. OLD TABLE and NEW TABLE can only be specified once each, and only
     for AFTER triggers or INSTEAD OF triggers.
  3. FOR EACH STATEMENT may not be specified for BEFORE triggers or
     INSTEAD OF triggers.
  4. WHEN condition may not be specified for INSTEAD OF triggers.

INSTEAD OF
   Specifies that the associated triggered action replaces the action
   against the subject view. Only one INSTEAD OF trigger is allowed for
each kind of operation on a given subject view (SQLSTATE 428FP).
WHEN (search-condition)
   Specifies a condition that is true, false, or unknown. The
   search-condition provides a capability to determine whether or not a
   certain triggered action should be executed.

   The associated action is performed only if the specified search
   condition evaluates as true. If the WHEN clause is omitted, the
   associated SQL-procedure statement is always performed.

   The WHEN clause may not be specified for INSTEAD OF triggers
   (SQLSTATE 42613).


From the PostgreSQL documentation they don't support nonstandard instead of triggers:

CREATE TRIGGER /name/ { BEFORE | AFTER } { /event/ [ OR ... ] }
   ON /table/ [ FOR [ EACH ] { ROW | STATEMENT } ]
   EXECUTE PROCEDURE /funcname/ ( /arguments/ )




From the Oracle documentation they do not allow a WHEN clause on an INSTEAD OF trigger either:

*CREATE* [ *OR REPLACE* ] *TRIGGER* [ schema. ]trigger
  { *BEFORE* | *AFTER* | *INSTEAD OF* }
  { dml_event_clause
  | { ddl_event [ *OR* ddl_event ]...
    | database_event [ *OR* database_event ]...
    }
    *ON* { [ schema. ]*SCHEMA*
       | *DATABASE*
       }
  }
  [ *WHEN* (condition) ]
  { pl/sql_block | call_procedure_statement } ;

INSTEAD OF

Specify |INSTEAD| |OF| to cause Oracle Database to fire the trigger instead of executing the triggering event. |INSTEAD| |OF| triggers are valid for DML events on views. They are not valid for DDL or database events.

If a view is inherently updatable and has |INSTEAD| |OF| triggers, then the triggers take preference. In other words, the database fires the triggers instead of performing DML on the view.

If the view belongs to a hierarchy, then the trigger is not inherited by subviews.

Note:

Oracle Database fine-grained access control lets you define row-level security policies on views. These policies enforce specified rules in response to DML operations. If an |INSTEAD| |OF| trigger is also defined on the view, then the database will not enforce the row-level security policies, because the database fires the |INSTEAD| |OF| trigger instead of executing the DML on the view.

INSTEAD OF Triggers

   *

     |INSTEAD| |OF| triggers are valid only for views. You cannot
     specify an |INSTEAD| |OF| trigger on a table.

   *

     You can read both the :|OLD| and the :|NEW| value, but you cannot
     write either the :|OLD| or the :|NEW| value.

Note:

You can create multiple triggers of the same type (|BEFORE|, |AFTER|, or |INSTEAD| |OF|) that fire for the same statement on the same table. The order in which Oracle Database fires these triggers is indeterminate. If your application requires that one trigger be fired before another of the same type for the same statement, then combine these triggers into a single trigger whose trigger action performs the trigger actions of the original triggers in the appropriate order.

WHEN Clause

Specify the trigger condition, which is a SQL condition that must be satisfied for the database to fire the trigger. See the syntax description of |condition| in Chapter 7, "Conditions" <http://download-east.oracle.com/docs/cd/B19306_01/server.102/b14200/conditions.htm#g1077361>. This condition must contain correlation names and cannot contain a query.

The |NEW| and |OLD| keywords, when specified in the |WHEN| clause, are not considered bind variables, so are not preceded by a colon (:). However, you must precede |NEW| and |OLD| with a colon in all references other than the |WHEN| clause.

See Also:

"Calling a Procedure in a Trigger Body: Example" <http://download-east.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7004.htm#i2064401>

Restrictions on Trigger Conditions Trigger conditions are subject to the following restrictions:

   *

     If you specify this clause for a DML event trigger, then you must
     also specify |FOR| |EACH| |ROW|. Oracle Database evaluates this
     condition for each row affected by the triggering statement.

   *

     You cannot specify trigger conditions for |INSTEAD| |OF| trigger
     statements.

   *

     You can reference object columns or their attributes, or varray,
     nested table, or LOB columns. You cannot invoke PL/SQL functions
     or methods in the trigger condition.




Based on this survey I would say you can do pretty much whatever you want. I would be tempted to follow Oracle and IBM's lead and exclude WHEN clauses on an INSTEAD OF trigger but since SQLite already accepts it I think you are fine with your current implementation.

HTH
Dennis Cote

/||/

-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------

Reply via email to