Hi,
I've been playing around with the idea of supporting automatically
updatable views, and I have a working proof of concept. I've taken a
different approach than the previous attempts to implement this
feature (e.g., http://archives.postgresql.org/pgsql-hackers/2009-01/msg01746.php),
instead doing all the work in the rewriter, substituting the view for
its base relation rather than attempting to auto-generate any rules or
triggers.
Basically what it does is this: in the first stage of query rewriting,
just after any non-SELECT rules are applied, the new code kicks in -
if the target relation is a view, and there were no unqualified
INSTEAD rules, and there are no INSTEAD OF triggers, it tests if the
view is simply updatable. If so, the target view is replaced by its
base relation and columns are re-mapped. Then the remainder of the
rewriting process continues, recursively handling any further
non-SELECT rules or additional simply updatable views. This handles
the case of views on top of views, with or without rules and/or
triggers.
Here's a simple example:
CREATE TABLE my_table(id int primary key, val text);
CREATE VIEW my_view AS SELECT * FROM my_table WHERE id > 0;
then any modifications to the view get redirected to underlying table:
EXPLAIN ANALYSE INSERT INTO my_view VALUES(1, 'Test row');
QUERY PLAN
------------------------------------------------------------------------------------------------
Insert on my_table (cost=0.00..0.01 rows=1 width=0) (actual
time=0.208..0.208 rows=0 loops=1)
-> Result (cost=0.00..0.01 rows=1 width=0) (actual
time=0.004..0.004 rows=1 loops=1)
Total runtime: 0.327 ms
(3 rows)
EXPLAIN ANALYSE UPDATE my_view SET val='Updated' WHERE id=1;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------
Update on my_table (cost=0.00..8.27 rows=1 width=10) (actual
time=0.039..0.039 rows=0 loops=1)
-> Index Scan using my_table_pkey on my_table (cost=0.00..8.27
rows=1 width=10) (actual time=0.014..0.015 rows=1 loops=1)
Index Cond: ((id > 0) AND (id = 1))
Total runtime: 0.090 ms
(4 rows)
EXPLAIN ANALYSE DELETE FROM my_view;
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Delete on my_table (cost=0.00..1.01 rows=1 width=6) (actual
time=0.030..0.030 rows=0 loops=1)
-> Seq Scan on my_table (cost=0.00..1.01 rows=1 width=6) (actual
time=0.015..0.016 rows=1 loops=1)
Filter: (id > 0)
Total runtime: 0.063 ms
(4 rows)
The patch is currently very strict about what kinds of views can be
updated (based on SQL-92), and there is no support for WITH CHECK
OPTION, because I wanted to keep this patch as simple as possible.
The consensus last time seemed to be that backwards compatibility
should be offered through a new GUC variable to allow this feature to
be disabled globally, which I've not implemented yet.
I'm also aware that my new function ChangeVarAttnos() is almost
identical to the function map_variable_attnos() that Tom recently
added, but I couldn't immediately see a neat way to merge the two. My
function handles whole-row references to the view by mapping them to a
generic RowExpr based on the view definition. I don't think a
ConvertRowtypeExpr can be used in this case, because the column names
don't necessarily match.
Obviously there's still more work to do but the early signs seem to be
encouraging.
Thoughts?
Regards,
Dean