Home Explore Blog CI



postgresql

18th chunk of `doc/src/sgml/rules.sgml`
b22d135dc4b384a57da83e5012010c8d8b0099c25313d2e20000000100000fa2
  and a rule that conditionally writes a log entry when an
    <command>UPDATE</command> is performed on
    <literal>shoelace_data</literal>.

<programlisting>
CREATE TABLE shoelace_log (
    sl_name    text,          -- shoelace changed
    sl_avail   integer,       -- new available value
    log_who    text,          -- who did it
    log_when   timestamp      -- when
);

CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data
    WHERE NEW.sl_avail &lt;&gt; OLD.sl_avail
    DO INSERT INTO shoelace_log VALUES (
                                    NEW.sl_name,
                                    NEW.sl_avail,
                                    current_user,
                                    current_timestamp
                                );
</programlisting>
</para>

<para>
    Now someone does:

<programlisting>
UPDATE shoelace_data SET sl_avail = 6 WHERE sl_name = 'sl7';
</programlisting>

    and we look at the log table:

<programlisting>
SELECT * FROM shoelace_log;

 sl_name | sl_avail | log_who | log_when
---------+----------+---------+----------------------------------
 sl7     |        6 | Al      | Tue Oct 20 16:14:45 1998 MET DST
(1 row)
</programlisting>
   </para>

   <para>
    That's what we expected. What happened in the background is the following.
    The parser created the query tree:

<programlisting>
UPDATE shoelace_data SET sl_avail = 6
  FROM shoelace_data shoelace_data
 WHERE shoelace_data.sl_name = 'sl7';
</programlisting>

    There is a rule <literal>log_shoelace</literal> that is <literal>ON UPDATE</literal> with the rule
    qualification expression:

<programlisting>
NEW.sl_avail &lt;&gt; OLD.sl_avail
</programlisting>

    and the action:

<programlisting>
INSERT INTO shoelace_log VALUES (
       new.sl_name, new.sl_avail,
       current_user, current_timestamp )
  FROM shoelace_data new, shoelace_data old;
</programlisting>

    (This looks a little strange since you cannot normally write
    <literal>INSERT ... VALUES ... FROM</literal>.  The <literal>FROM</literal>
    clause here is just to indicate that there are range-table entries
    in the query tree for <literal>new</literal> and <literal>old</literal>.
    These are needed so that they can be referenced by variables in
    the <command>INSERT</command> command's query tree.)
</para>

<para>
    The rule is a qualified <literal>ALSO</literal> rule, so the rule system
    has to return two query trees: the modified rule action and the original
    query tree. In step 1, the range table of the original query is
    incorporated into the rule's action query tree. This results in:

<programlisting>
INSERT INTO shoelace_log VALUES (
       new.sl_name, new.sl_avail,
       current_user, current_timestamp )
  FROM shoelace_data new, shoelace_data old,
       <emphasis>shoelace_data shoelace_data</emphasis>;
</programlisting>

    In step 2, the rule qualification is added to it, so the result set
    is restricted to rows where <literal>sl_avail</literal> changes:

<programlisting>
INSERT INTO shoelace_log VALUES (
       new.sl_name, new.sl_avail,
       current_user, current_timestamp )
  FROM shoelace_data new, shoelace_data old,
       shoelace_data shoelace_data
 <emphasis>WHERE new.sl_avail &lt;&gt; old.sl_avail</emphasis>;
</programlisting>

    (This looks even stranger, since <literal>INSERT ... VALUES</literal> doesn't have
    a <literal>WHERE</literal> clause either, but the planner and executor will have no
    difficulty with it.  They need to support this same functionality
    anyway for <literal>INSERT ... SELECT</literal>.)
   </para>

   <para>
    In step 3, the original query tree's qualification is added,
    restricting the result set further to only the rows that would have been touched
    by the original query:

<programlisting>
INSERT INTO shoelace_log VALUES (
       new.sl_name, new.sl_avail,
       current_user, current_timestamp )
  FROM shoelace_data new, shoelace_data old,
       shoelace_data shoelace_data

Title: Applying an Update Rule
Summary
This section demonstrates how an update rule is applied to a table in PostgreSQL, using a specific example where a rule logs changes to a column in a table. It shows the original query tree created by the parser, the rule qualification and action, and how the rule system modifies the query tree to incorporate the rule's action and qualifications, resulting in a modified query tree that inserts log entries into a separate table.