get written. In that case, the original query
tree does not contain a target list entry for
<literal>sl_avail</literal>, so <literal>NEW.sl_avail</literal> will get
replaced by <literal>shoelace_data.sl_avail</literal>. Thus, the extra
command generated by the rule is:
<programlisting>
INSERT INTO shoelace_log VALUES (
shoelace_data.sl_name, <emphasis>shoelace_data.sl_avail</emphasis>,
current_user, current_timestamp )
FROM shoelace_data
WHERE <emphasis>shoelace_data.sl_avail</emphasis> <> shoelace_data.sl_avail
AND shoelace_data.sl_name = 'sl7';
</programlisting>
and that qualification will never be true.
</para>
<para>
It will also work if the original query modifies multiple rows. So
if someone issued the command:
<programlisting>
UPDATE shoelace_data SET sl_avail = 0
WHERE sl_color = 'black';
</programlisting>
four rows in fact get updated (<literal>sl1</literal>, <literal>sl2</literal>, <literal>sl3</literal>, and <literal>sl4</literal>).
But <literal>sl3</literal> already has <literal>sl_avail = 0</literal>. In this case, the original
query trees qualification is different and that results
in the extra query tree:
<programlisting>
INSERT INTO shoelace_log
SELECT shoelace_data.sl_name, 0,
current_user, current_timestamp
FROM shoelace_data
WHERE 0 <> shoelace_data.sl_avail
AND <emphasis>shoelace_data.sl_color = 'black'</emphasis>;
</programlisting>
being generated by the rule. This query tree will surely insert
three new log entries. And that's absolutely correct.
</para>
<para>
Here we can see why it is important that the original query tree
is executed last. If the <command>UPDATE</command> had been
executed first, all the rows would have already been set to zero, so the
logging <command>INSERT</command> would not find any row where
<literal>0 <> shoelace_data.sl_avail</literal>.
</para>
</sect3>
</sect2>
<sect2 id="rules-update-views">
<title>Cooperation with Views</title>
<indexterm zone="rules-update-views"><primary>view</primary><secondary>updating</secondary></indexterm>
<para>
A simple way to protect view relations from the mentioned
possibility that someone can try to run <command>INSERT</command>,
<command>UPDATE</command>, or <command>DELETE</command> on them is
to let those query trees get thrown away. So we could create the rules:
<programlisting>
CREATE RULE shoe_ins_protect AS ON INSERT TO shoe
DO INSTEAD NOTHING;
CREATE RULE shoe_upd_protect AS ON UPDATE TO shoe
DO INSTEAD NOTHING;
CREATE RULE shoe_del_protect AS ON DELETE TO shoe
DO INSTEAD NOTHING;
</programlisting>
If someone now tries to do any of these operations on the view
relation <literal>shoe</literal>, the rule system will
apply these rules. Since the rules have
no actions and are <literal>INSTEAD</literal>, the resulting list of
query trees will be empty and the whole query will become
nothing because there is nothing left to be optimized or
executed after the rule system is done with it.
</para>
<para>
A more sophisticated way to use the rule system is to
create rules that rewrite the query tree into one that
does the right operation on the real tables. To do that
on the <literal>shoelace</literal> view, we create
the following rules:
<programlisting>
CREATE RULE shoelace_ins AS ON INSERT TO shoelace
DO INSTEAD
INSERT INTO shoelace_data VALUES (
NEW.sl_name,
NEW.sl_avail,
NEW.sl_color,
NEW.sl_len,
NEW.sl_unit
);
CREATE RULE shoelace_upd AS ON UPDATE TO shoelace
DO INSTEAD
UPDATE shoelace_data
SET sl_name = NEW.sl_name,
sl_avail = NEW.sl_avail,
sl_color = NEW.sl_color,
sl_len = NEW.sl_len,
sl_unit = NEW.sl_unit
WHERE sl_name = OLD.sl_name;
CREATE RULE shoelace_del AS ON DELETE TO shoelace