Postgresql 中文操作指南
41.2. Views and the Rule System #
PostgreSQL 中的视图使用规则系统实现。一个视图基本上是一个没有实际存储的空表,带有一个 ON SELECT DO INSTEAD 规则。习惯上,该规则被命名为 _RETURN。所以像这样的视图
Views in PostgreSQL are implemented using the rule system. A view is basically an empty table (having no actual storage) with an ON SELECT DO INSTEAD rule. Conventionally, that rule is named _RETURN. So a view like
CREATE VIEW myview AS SELECT * FROM mytab;
与
is very nearly the same thing as
CREATE TABLE myview (same column list as mytab);
CREATE RULE "_RETURN" AS ON SELECT TO myview DO INSTEAD
SELECT * FROM mytab;
虽然实际上你无法编写此文本,因为不允许在表格中拥有 ON SELECT 规则。
although you can’t actually write that, because tables are not allowed to have ON SELECT rules.
一个视图还可以有其他类型的 DO INSTEAD 规则,允许对视图执行 INSERT、 UPDATE 或 DELETE 命令,尽管它缺乏底层存储。这将在下面的 Section 41.2.4 中进一步讨论。
A view can also have other kinds of DO INSTEAD rules, allowing INSERT, UPDATE, or DELETE commands to be performed on the view despite its lack of underlying storage. This is discussed further below, in Section 41.2.4.
41.2.1. How SELECT Rules Work #
ON SELECT 规则会在最后一个步骤应用于所有查询,即使所给的命令是 INSERT、UPDATE 或 DELETE。这些规则与其他命令类型上的规则具有不同的语义,因为它们会修改查询树本身,而不是创建一个新的查询树。所以 SELECT 规则首先进行描述。
Rules ON SELECT are applied to all queries as the last step, even if the command given is an INSERT, UPDATE or DELETE. And they have different semantics from rules on the other command types in that they modify the query tree in place instead of creating a new one. So SELECT rules are described first.
当前,ON SELECT 规则中只能有一个操作,它必须是 INSTEAD 的无条件 SELECT 操作。要使规则足够安全供普通用户使用,则需要此限制,它限制 ON SELECT 规则像视图一样操作。
Currently, there can be only one action in an ON SELECT rule, and it must be an unconditional SELECT action that is INSTEAD. This restriction was required to make rules safe enough to open them for ordinary users, and it restricts ON SELECT rules to act like views.
本章中的示例是两个连接视图,它们会进行一些计算并使用更多视图。两个第一个视图中的一个后来会进行自定义,方法是添加用于 INSERT、UPDATE 和 DELETE 操作的规则,以便最终结果将是一个像带有某些魔法功能的真实表格那样的视图。这不是一个简单的示例,难以理解。但是,最好在逐步讨论所有要点时,只有一个示例,而不是拥有可能会混淆的多个不同的示例。
The examples for this chapter are two join views that do some calculations and some more views using them in turn. One of the two first views is customized later by adding rules for INSERT, UPDATE, and DELETE operations so that the final result will be a view that behaves like a real table with some magic functionality. This is not such a simple example to start from and this makes things harder to get into. But it’s better to have one example that covers all the points discussed step by step rather than having many different ones that might mix up in mind.
前两个规则系统描述中最需要的真实表格如下:
The real tables we need in the first two rule system descriptions are these:
CREATE TABLE shoe_data (
shoename text, -- primary key
sh_avail integer, -- available number of pairs
slcolor text, -- preferred shoelace color
slminlen real, -- minimum shoelace length
slmaxlen real, -- maximum shoelace length
slunit text -- length unit
);
CREATE TABLE shoelace_data (
sl_name text, -- primary key
sl_avail integer, -- available number of pairs
sl_color text, -- shoelace color
sl_len real, -- shoelace length
sl_unit text -- length unit
);
CREATE TABLE unit (
un_name text, -- primary key
un_fact real -- factor to transform to cm
);
如你所见,它们代表的是鞋店数据。
As you can see, they represent shoe-store data.
视图被创建为以下内容:
The views are created as:
CREATE VIEW shoe AS
SELECT sh.shoename,
sh.sh_avail,
sh.slcolor,
sh.slminlen,
sh.slminlen * un.un_fact AS slminlen_cm,
sh.slmaxlen,
sh.slmaxlen * un.un_fact AS slmaxlen_cm,
sh.slunit
FROM shoe_data sh, unit un
WHERE sh.slunit = un.un_name;
CREATE VIEW shoelace AS
SELECT s.sl_name,
s.sl_avail,
s.sl_color,
s.sl_len,
s.sl_unit,
s.sl_len * u.un_fact AS sl_len_cm
FROM shoelace_data s, unit u
WHERE s.sl_unit = u.un_name;
CREATE VIEW shoe_ready AS
SELECT rsh.shoename,
rsh.sh_avail,
rsl.sl_name,
rsl.sl_avail,
least(rsh.sh_avail, rsl.sl_avail) AS total_avail
FROM shoe rsh, shoelace rsl
WHERE rsl.sl_color = rsh.slcolor
AND rsl.sl_len_cm >= rsh.slminlen_cm
AND rsl.sl_len_cm <= rsh.slmaxlen_cm;
CREATE VIEW 命令(这是我们拥有的最简单的命令)用于 shoelace 视图,它将创建关系 shoelace 和 pg_rewrite 中的一个条目,表明无论何时在查询范围表中引用关系 shoelace,都必须应用重写规则。该规则没有规则限定条件(在非 SELECT 规则中稍后将讨论此限定条件,因为 SELECT 规则当前无法拥有限定条件),并且它是 INSTEAD。请注意,规则限定条件与查询限定条件不同。我们规则的操作有查询限定条件。规则的操作是一个查询树,它是视图创建命令中 SELECT 语句的一个副本。
The CREATE VIEW command for the shoelace view (which is the simplest one we have) will create a relation shoelace and an entry in pg_rewrite that tells that there is a rewrite rule that must be applied whenever the relation shoelace is referenced in a query’s range table. The rule has no rule qualification (discussed later, with the non-SELECT rules, since SELECT rules currently cannot have them) and it is INSTEAD. Note that rule qualifications are not the same as query qualifications. The action of our rule has a query qualification. The action of the rule is one query tree that is a copy of the SELECT statement in the view creation command.
Note
pg_rewrite 条目中可见的 NEW 和 OLD 的两个额外范围表条目与 SELECT 规则无关。
The two extra range table entries for NEW and OLD that you can see in the pg_rewrite entry aren’t of interest for SELECT rules.
现在,我们填充 unit、shoe_data 和 shoelace_data,并在视图上运行一个简单查询:
Now we populate unit, shoe_data and shoelace_data and run a simple query on a view:
INSERT INTO unit VALUES ('cm', 1.0);
INSERT INTO unit VALUES ('m', 100.0);
INSERT INTO unit VALUES ('inch', 2.54);
INSERT INTO shoe_data VALUES ('sh1', 2, 'black', 70.0, 90.0, 'cm');
INSERT INTO shoe_data VALUES ('sh2', 0, 'black', 30.0, 40.0, 'inch');
INSERT INTO shoe_data VALUES ('sh3', 4, 'brown', 50.0, 65.0, 'cm');
INSERT INTO shoe_data VALUES ('sh4', 3, 'brown', 40.0, 50.0, 'inch');
INSERT INTO shoelace_data VALUES ('sl1', 5, 'black', 80.0, 'cm');
INSERT INTO shoelace_data VALUES ('sl2', 6, 'black', 100.0, 'cm');
INSERT INTO shoelace_data VALUES ('sl3', 0, 'black', 35.0 , 'inch');
INSERT INTO shoelace_data VALUES ('sl4', 8, 'black', 40.0 , 'inch');
INSERT INTO shoelace_data VALUES ('sl5', 4, 'brown', 1.0 , 'm');
INSERT INTO shoelace_data VALUES ('sl6', 0, 'brown', 0.9 , 'm');
INSERT INTO shoelace_data VALUES ('sl7', 7, 'brown', 60 , 'cm');
INSERT INTO shoelace_data VALUES ('sl8', 1, 'brown', 40 , 'inch');
SELECT * FROM shoelace;
sl_name | sl_avail | sl_color | sl_len | sl_unit | sl_len_cm
-----------+----------+----------+--------+---------+-----------
sl1 | 5 | black | 80 | cm | 80
sl2 | 6 | black | 100 | cm | 100
sl7 | 7 | brown | 60 | cm | 60
sl3 | 0 | black | 35 | inch | 88.9
sl4 | 8 | black | 40 | inch | 101.6
sl8 | 1 | brown | 40 | inch | 101.6
sl5 | 4 | brown | 1 | m | 100
sl6 | 0 | brown | 0.9 | m | 90
(8 rows)
这是你能对我们的视图执行的最简单的 SELECT,所以我们借此机会解释视图规则的基础知识。SELECT * FROM shoelace 由解析器解释并生成了查询树:
This is the simplest SELECT you can do on our views, so we take this opportunity to explain the basics of view rules. The SELECT * FROM shoelace was interpreted by the parser and produced the query tree:
SELECT shoelace.sl_name, shoelace.sl_avail,
shoelace.sl_color, shoelace.sl_len,
shoelace.sl_unit, shoelace.sl_len_cm
FROM shoelace shoelace;
然后提供给规则系统。规则系统遍历范围表并检查是否存在任何关系的规则。在处理 shoelace 的范围表条目(到目前为止只有一个)时找到 _RETURN 规则和查询树:
and this is given to the rule system. The rule system walks through the range table and checks if there are rules for any relation. When processing the range table entry for shoelace (the only one up to now) it finds the _RETURN rule with the query tree:
SELECT s.sl_name, s.sl_avail,
s.sl_color, s.sl_len, s.sl_unit,
s.sl_len * u.un_fact AS sl_len_cm
FROM shoelace old, shoelace new,
shoelace_data s, unit u
WHERE s.sl_unit = u.un_name;
为了扩展视图,重写程序只需创建一个包含规则操作查询树的子查询范围表条目,并将此范围表条目替换指向该视图的原始条目。生成后的重写查询树几乎与你输入以下内容时相同:
To expand the view, the rewriter simply creates a subquery range-table entry containing the rule’s action query tree, and substitutes this range table entry for the original one that referenced the view. The resulting rewritten query tree is almost the same as if you had typed:
SELECT shoelace.sl_name, shoelace.sl_avail,
shoelace.sl_color, shoelace.sl_len,
shoelace.sl_unit, shoelace.sl_len_cm
FROM (SELECT s.sl_name,
s.sl_avail,
s.sl_color,
s.sl_len,
s.sl_unit,
s.sl_len * u.un_fact AS sl_len_cm
FROM shoelace_data s, unit u
WHERE s.sl_unit = u.un_name) shoelace;
但是,有一个不同:子查询的范围表有两个额外的条目 shoelace old 和 shoelace new。这些条目并未直接参与查询,因为子查询的连接树或目标列表未引用这些条目。重写程序使用这些条目来存储最初存在于引用该视图的范围表条目中的访问权限检查信息。这样,执行程序仍然会检查用户是否拥有足够的权限来访问视图,即使在重写的查询中不存在直接使用视图的情况。
There is one difference however: the subquery’s range table has two extra entries shoelace old and shoelace new. These entries don’t participate directly in the query, since they aren’t referenced by the subquery’s join tree or target list. The rewriter uses them to store the access privilege check information that was originally present in the range-table entry that referenced the view. In this way, the executor will still check that the user has proper privileges to access the view, even though there’s no direct use of the view in the rewritten query.
那是应用的第一个规则。规则系统将继续检查顶级查询中剩余的范围表条目(在本例中,没有更多),并将递归检查添加的子查询中的范围表条目,以查看其中是否有引用视图的条目。(但它不会展开 old 或 new —— 否则我们将无限递归!)在本例中,没有 shoelace_data 或 unit 的重写规则,所以重写完成并且上文是提供给规划程序的最终结果。
That was the first rule applied. The rule system will continue checking the remaining range-table entries in the top query (in this example there are no more), and it will recursively check the range-table entries in the added subquery to see if any of them reference views. (But it won’t expand old or new — otherwise we’d have infinite recursion!) In this example, there are no rewrite rules for shoelace_data or unit, so rewriting is complete and the above is the final result given to the planner.
现在,我们想要编写一个查询,找出商店中目前有哪些鞋子配有匹配的鞋带(颜色和长度),其中完全匹配的鞋带的总数大于或等于 2。
Now we want to write a query that finds out for which shoes currently in the store we have the matching shoelaces (color and length) and where the total number of exactly matching pairs is greater than or equal to two.
SELECT * FROM shoe_ready WHERE total_avail >= 2;
shoename | sh_avail | sl_name | sl_avail | total_avail
----------+----------+---------+----------+-------------
sh1 | 2 | sl1 | 5 | 2
sh3 | 4 | sl7 | 7 | 4
(2 rows)
这次,解析器的输出是查询树:
The output of the parser this time is the query tree:
SELECT shoe_ready.shoename, shoe_ready.sh_avail,
shoe_ready.sl_name, shoe_ready.sl_avail,
shoe_ready.total_avail
FROM shoe_ready shoe_ready
WHERE shoe_ready.total_avail >= 2;
将应用的第一个规则是 shoe_ready 视图的规则,并且它导致以下查询树:
The first rule applied will be the one for the shoe_ready view and it results in the query tree:
SELECT shoe_ready.shoename, shoe_ready.sh_avail,
shoe_ready.sl_name, shoe_ready.sl_avail,
shoe_ready.total_avail
FROM (SELECT rsh.shoename,
rsh.sh_avail,
rsl.sl_name,
rsl.sl_avail,
least(rsh.sh_avail, rsl.sl_avail) AS total_avail
FROM shoe rsh, shoelace rsl
WHERE rsl.sl_color = rsh.slcolor
AND rsl.sl_len_cm >= rsh.slminlen_cm
AND rsl.sl_len_cm <= rsh.slmaxlen_cm) shoe_ready
WHERE shoe_ready.total_avail >= 2;
类似地,shoe 和 shoelace 的规则被替换到子查询的范围表中,从而导致三层最终查询树:
Similarly, the rules for shoe and shoelace are substituted into the range table of the subquery, leading to a three-level final query tree:
SELECT shoe_ready.shoename, shoe_ready.sh_avail,
shoe_ready.sl_name, shoe_ready.sl_avail,
shoe_ready.total_avail
FROM (SELECT rsh.shoename,
rsh.sh_avail,
rsl.sl_name,
rsl.sl_avail,
least(rsh.sh_avail, rsl.sl_avail) AS total_avail
FROM (SELECT sh.shoename,
sh.sh_avail,
sh.slcolor,
sh.slminlen,
sh.slminlen * un.un_fact AS slminlen_cm,
sh.slmaxlen,
sh.slmaxlen * un.un_fact AS slmaxlen_cm,
sh.slunit
FROM shoe_data sh, unit un
WHERE sh.slunit = un.un_name) rsh,
(SELECT s.sl_name,
s.sl_avail,
s.sl_color,
s.sl_len,
s.sl_unit,
s.sl_len * u.un_fact AS sl_len_cm
FROM shoelace_data s, unit u
WHERE s.sl_unit = u.un_name) rsl
WHERE rsl.sl_color = rsh.slcolor
AND rsl.sl_len_cm >= rsh.slminlen_cm
AND rsl.sl_len_cm <= rsh.slmaxlen_cm) shoe_ready
WHERE shoe_ready.total_avail > 2;
这种做法看上去似乎效率低下,但是,规划器只能通过“向上提取”子查询将此压缩成单层查询树,然后,它将计划连接,就像我们手动编写它们一样。因此,压缩查询树是对重写系统不必关心的优化。
This might look inefficient, but the planner will collapse this into a single-level query tree by “pulling up” the subqueries, and then it will plan the joins just as if we’d written them out manually. So collapsing the query tree is an optimization that the rewrite system doesn’t have to concern itself with.
41.2.2. View Rules in Non-SELECT Statements #
上述视图规则的描述中未提及查询树的两个细节。它们命令类型和结果关联。实际上,视图规则不需要命令类型,但结果关联可能会影响查询重写器的工作方式,因为结果关联是视图时需要特别小心。
Two details of the query tree aren’t touched in the description of view rules above. These are the command type and the result relation. In fact, the command type is not needed by view rules, but the result relation may affect the way in which the query rewriter works, because special care needs to be taken if the result relation is a view.
@[1]和任何其他命令的查询树之间只有几个差异。显然,它们的命令类型不同,对于 @[2]之外的命令,结果关联指向结果应包含的范围表条目。其他所有内容完全相同。因此,有两个表 @[3]和 @[4],具有列 @[5]和 @[6],则两个语句的查询树:
There are only a few differences between a query tree for a SELECT and one for any other command. Obviously, they have a different command type and for a command other than a SELECT, 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 columns a and b, the query trees for the two statements:
SELECT t2.b FROM t1, t2 WHERE t1.a = t2.a;
UPDATE t1 SET b = t2.b FROM t2 WHERE t1.a = t2.a;
几乎相同。特别是:
are nearly identical. In particular:
结果是,两个查询树都产生相似的执行计划:它们都是关于两个表的连接。对于 @[7],规划器将 @[8]中缺少的列添加到目标列表中,并且最终查询树将读取为:
The consequence is, that both query trees result in similar execution plans: They are both joins over the two tables. For the UPDATE the missing columns from t1 are added to the target list by the planner and the final query tree will read as:
UPDATE t1 SET a = t1.a, b = t2.b FROM t2 WHERE t1.a = t2.a;
因此,执行器运行连接将产生与以下内容完全相同的结果集:
and thus the executor run over the join will produce exactly the same result set as:
SELECT t1.a, t2.b FROM t1, t2 WHERE t1.a = t2.a;
但是,@[9]中存在一个小问题:执行连接计划的部分不关心连接结果的用途。它只是产生行结果集。执行器高层处理一个为 @[10]命令,另一个为 @[11]的事实,在那里知道这是一个 @[12],并知道此结果应包含在表 @[13]中。但是,那里存在哪一行必须替换为新行呢?
But there is a little problem in UPDATE: the part of the executor plan that does the join does not care what the results from the join are meant for. It just produces a result set of rows. The fact that one is a SELECT command and the other is an UPDATE is handled higher up in the executor, where it knows that this is an UPDATE, and it knows that this result should go into table t1. But which of the rows that are there has to be replaced by the new row?
为了解决此问题,在 @[14](和 @[15])语句中,将另一个条目添加到目标列表:当前元组 ID (CTID)。这是一个系统列,其中包含行所在的文件块号和块中的位置。在了解该表后,可以使用 CTID 来检索要更新的 @[16]的原始行。将 CTID 添加到目标列表后,查询实际上看起来像:
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 column 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 row of t1 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;
现在,PostgreSQL 的另一个详细内容进入阶段。旧表行不会被覆盖,这就是 @[17]快速的原因。在 @[18]中,新的结果行插入表中(在删除 CTID 之后),并且在旧行(CTID 指向该行)的行头中,@[19]和 @[20]条目设置为当前命令计数器和当前事务 ID。因此,旧行被隐藏,并且在事务提交后,真空吸尘器最终可以删除死行。
Now another detail of PostgreSQL enters the stage. Old table rows aren’t overwritten, and this is why ROLLBACK is fast. In an UPDATE, the new result row is inserted into the table (after stripping the CTID) and in the row header of the old row, which the CTID pointed to, the cmax and xmax entries are set to the current command counter and current transaction ID. Thus the old row is hidden, and after the transaction commits the vacuum cleaner can eventually remove the dead row.
了解所有这些信息后,我们可以简单地以完全相同的方式将视图规则应用于任何命令。没有区别。
Knowing all that, we can simply apply view rules in absolutely the same way to any command. There is no difference.
41.2.3. The Power of Views in PostgreSQL #
上述内容演示了规则系统如何将视图定义合并到原始查询树中。在第二个示例中,一个视图中的简单 @[21]创建了一个最终查询树,该查询树是 4 个表的连接(@[22]两次使用不同的名称)。
The above demonstrates how the rule system incorporates view definitions into the original query tree. In the second example, a simple SELECT from one view created a final query tree that is a join of 4 tables (unit was used twice with different names).
使用规则系统实现视图的好处在于,规划器具有所有有关哪些表必须被扫描、这些表之间的关系以及视图的限制条件加上原始查询中条件在一个查询树中的信息。并且当原始查询已经是关于视图的连接时仍然是这种情况。规划器必须决定执行查询的最佳路径,并且规划器信息越多,此决策就越好。而且,PostgreSQL 中实现的规则系统可确保这是该查询到目前为止的所有可用信息。
The benefit of implementing views with the rule system is that the planner has all the information about which tables have to be scanned plus the relationships between these tables plus the restrictive qualifications from the views plus the qualifications from the original query in one single query tree. And this is still the situation when the original query is already a join over views. The planner has to decide which is the best path to execute the query, and the more information the planner has, the better this decision can be. And the rule system as implemented in PostgreSQL ensures that this is all information available about the query up to that point.
41.2.4. Updating a View #
如果视图被命名为 @[23]、@[24]或 @[25]的目标关联,该怎么办?执行上述替换将产生一个查询树,其中结果关联指向子查询范围表条目,而这将不起作用。不过,PostgreSQL 有很多种支持更新视图的方法。根据用户体验的复杂程度,这些方法包括:自动将视图中的基础表替代为,执行用户定义的触发器,或根据用户定义的规则重写查询。这些选项将在下面进行讨论。
What happens if a view is named as the target relation for an INSERT, UPDATE, or DELETE? Doing the substitutions described above would give a query tree in which the result relation points at a subquery range-table entry, which will not work. There are several ways in which PostgreSQL can support the appearance of updating a view, however. In order of user-experienced complexity those are: automatically substitute in the underlying table for the view, execute a user-defined trigger, or rewrite the query per a user-defined rule. These options are discussed below.
如果子查询从单个基本关系中选择,并且足够简单,则重写器可以自动将该子查询替换为基础的基本关系,以便 INSERT 、 UPDATE 或 DELETE 以适当方式应用于基本关系。能够进行此类自动更新的视图称为 automatically updatable 。有关可以自动更新的视图类型的详细信息,请参见 CREATE VIEW 。
If the subquery selects from a single base relation and is simple enough, the rewriter can automatically replace the subquery with the underlying base relation so that the INSERT, UPDATE, or DELETE is applied to the base relation in the appropriate way. Views that are “simple enough” for this are called automatically updatable. For detailed information on the kinds of view that can be automatically updated, see CREATE VIEW.
或者,可以通过视图上的用户提供 INSTEAD OF 触发器处理此操作(请参见 CREATE TRIGGER )。在此情况下,重写方式略有不同。对于 INSERT ,重写器完全不处理视图,将其作为查询的结果关系。对于 UPDATE 和 DELETE ,仍然需要扩展视图查询以生成该命令尝试更新或删除的“旧”行。因此会正常扩展视图,但会将另一个未扩展的范围表条目添加到查询中以表示该视图作为结果关系时的容量。
Alternatively, the operation may be handled by a user-provided INSTEAD OF trigger on the view (see CREATE TRIGGER). Rewriting works slightly differently in this case. For INSERT, the rewriter does nothing at all with the view, leaving it as the result relation for the query. For UPDATE and DELETE, it’s still necessary to expand the view query to produce the “old” rows that the command will attempt to update or delete. So the view is expanded as normal, but another unexpanded range-table entry is added to the query to represent the view in its capacity as the result relation.
现在出现的问题是如何标识要视图中更新的行。回想一下,当结果关联是表时,会将一个特殊 CTID 条目添加到目标列表中以标识要更新的行的物理位置。如果结果关联是视图,则此方法不起作用,因为视图没有 CTID,因为它的行没有实际物理位置。相反,对于 @[34]或 @[35]操作,将一个特殊的 @[36]条目添加到目标列表中,该条目将扩展为包括视图中的所有列。执行器使用此值将“旧”行提供给 @[37]触发器。触发器必须根据旧行和新行值得出要更新的内容。
The problem that now arises is how to identify the rows to be updated in the view. Recall that when the result relation is a table, a special CTID entry is added to the target list to identify the physical locations of the rows to be updated. This does not work if the result relation is a view, because a view does not have any CTID, since its rows do not have actual physical locations. Instead, for an UPDATE or DELETE operation, a special wholerow entry is added to the target list, which expands to include all columns from the view. The executor uses this value to supply the “old” row to the INSTEAD OF trigger. It is up to the trigger to work out what to update based on the old and new row values.
另外一种可能性是用户定义 @[38]规则,为视图上的 @[39]、@[40]和 @[41]命令指定替代动作。这些规则将重写命令,通常将其重写为一个更新一个或多个表而不是视图的命令。这是 @[42]的主题。
Another possibility is for the user to define INSTEAD rules that specify substitute actions for INSERT, UPDATE, and DELETE commands on a view. These rules will rewrite the command, typically into a command that updates one or more tables, rather than views. That is the topic of Section 41.4.
请注意,规则先经过评估,在计划和执行原始查询之前对其进行重写。因此,如果一个视图在 @[44]、@[45]或 @[46]上具有 @[43]触发器以及规则,则将首先评估规则,并且根据结果,可能根本不会使用触发器。
Note that rules are evaluated first, rewriting the original query before it is planned and executed. Therefore, if a view has INSTEAD OF triggers as well as rules on INSERT, UPDATE, or DELETE, then the rules will be evaluated first, and depending on the result, the triggers may not be used at all.
自动重写简单视图上的 @[47]、@[48]或 @[49]查询总是最后尝试。因此,如果视图具有规则或触发器,它们将覆盖自动可更新视图的默认行为。
Automatic rewriting of an INSERT, UPDATE, or DELETE query on a simple view is always tried last. Therefore, if a view has rules or triggers, they will override the default behavior of automatically updatable views.
如果视图没有 INSTEAD 规则或 INSTEAD OF 触发器,而重写程序无法自动将查询重写为对基础基础关系的更新,那么将会引发错误,因为执行程序无法以这种方式更新视图。
If there are no INSTEAD rules or INSTEAD OF triggers for the view, and the rewriter cannot automatically rewrite the query as an update on the underlying base relation, an error will be thrown because the executor cannot update a view as such.