Two details of the parse tree are not touched in the description of view rules above. These are the command type and the result relation. In fact, view rules do not need this information.
There are only a few differences between a parse tree for a SELECT and one for any other command. Obviously they have another command type and this time the result relation points to the range table entry where the result should go. Everything else is absolutely the same. So having two tables t1 and t2 with attributes a and b, the parse trees for the two statements
SELECT t2.b FROM t1, t2 WHERE t1.a = t2.a; UPDATE t1 SET b = t2.b WHERE t1.a = t2.a; |
The range tables contain entries for the tables t1 and t2.
The target lists contain one variable that points to attribute b of the range table entry for table t2.
The qualification expressions compare the attributes a of both ranges for equality.
The join trees show a simple join between t1 and t2.
UPDATE t1 SET a = t1.a, b = t2.b WHERE t1.a = t2.a; |
SELECT t1.a, t2.b FROM t1, t2 WHERE t1.a = t2.a; |
To resolve this problem, another entry is added to the target list in UPDATE (and also in DELETE) statements: the current tuple ID (CTID). This is a system attribute containing the file block number and position in the block for the row. Knowing the table, the CTID can be used to retrieve the original t1 row to be updated. After adding the CTID to the target list, the query actually looks like
SELECT t1.a, t2.b, t1.ctid FROM t1, t2 WHERE t1.a = t2.a; |
Knowing all that, we can simply apply view rules in absolutely the same way to any command.
What happens if a view is named as the target relation for an INSERT, UPDATE, or DELETE? After doing the substitutions described above, we will have a query tree in which the result relation points at a subquery range table entry. This will not work, so the rewriter throws an error if it sees it has produced such a thing.
To change this we can define rules that modify the behavior of non-SELECT queries. This is the topic of the next section.