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
DO INSTEAD
DELETE FROM shoelace_data
WHERE sl_name = OLD.sl_name;
</programlisting>
</para>
<para>
If you want to support <literal>RETURNING</literal> queries on the view,
you need to make the rules include <literal>RETURNING</literal> clauses that
compute the view rows. This is usually pretty trivial for views on a
single table, but it's a bit tedious for join views such as
<literal>shoelace</literal>. An example for the insert case is:
<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
)
RETURNING
shoelace_data.*,
(SELECT shoelace_data.sl_len * u.un_fact
FROM unit u WHERE shoelace_data.sl_unit = u.un_name);
</programlisting>
Note that this one rule supports both <command>INSERT</command> and
<command>INSERT RETURNING</command> queries on the view — the
<literal>RETURNING</literal> clause is simply ignored for <command>INSERT</command>.
</para>
<para>
Note that in the <literal>RETURNING</literal> clause of a rule,
<literal>OLD</literal> and <literal>NEW</literal> refer to the
pseudorelations added as extra range table entries to the rewritten
query, rather than old/new rows in the result relation. Thus, for
example, in a rule supporting <command>UPDATE</command> queries on this
view, if the <literal>RETURNING</literal> clause contained
<literal>old.sl_name</literal>, the old name would always be returned,
regardless of whether the <literal>RETURNING</literal> clause in the
query on the view specified <literal>OLD</literal> or <literal>NEW</literal>,
which might be confusing. To avoid this confusion, and support returning
old and new values in queries on the view, the <literal>RETURNING</literal>
clause in the rule definition should refer to entries from the result
relation such as <literal>shoelace_data.sl_name</literal>, without
specifying <literal>OLD</literal> or <literal>NEW</literal>.
</para>
<para>
Now assume that once in a while, a pack of shoelaces arrives at
the shop and a big parts list along with it. But you don't want
to manually update the <literal>shoelace</literal> view every
time. Instead we set up two little tables: one where you can
insert the items from the part list, and one with a special
trick. The creation commands for these are:
<programlisting>
CREATE TABLE shoelace_arrive (
arr_name text,
arr_quant integer
);
CREATE TABLE shoelace_ok (
ok_name text,
ok_quant integer
);
CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok
DO INSTEAD
UPDATE shoelace
SET sl_avail = sl_avail + NEW.ok_quant
WHERE sl_name = NEW.ok_name;
</programlisting>
Now you can fill the table <literal>shoelace_arrive</literal>