<Chapter Id="rules">
<!-- <Title>The <ProductName>Postgres</ProductName> Rule System</Title> -->
<Title><ProductName>Postgres</ProductName>のルールシステム</Title>
<indexterm><primary sortas="るーる">ルール</primary></indexterm><indexterm><primary>PostgreSQL</primary><secondary sortas="るーる">ルール</secondary></indexterm>

   <note>
    <!-- <title>Author</title> -->
    <title>著者</title>
    <para>
     <!-- Written by Jan Wieck.  Updates for 7.1 by Tom Lane. -->
     Jan Wieckによって書かれました。7.1用にTom Laneが更新しました。
    </para>
   </note>

<para>
     <!-- Production rule systems are conceptually simple, but
     there are many subtle points involved in actually using
     them. Some of these points and
     the theoretical foundations of the <ProductName>Postgres</ProductName>
     rule system can be found in
[<XRef LinkEnd="STON90b" EndTerm="STON90b">]. -->

     本番で稼働するルールシステムは概念としては単純ですが、実際に使ってみると、わかりにくいところが少なからずあります。これらいくつかのわかりにくいところと、<ProductName>Postgres</ProductName>のルールシステムにおける基本的な理論については<XRef LinkEnd="STON90b" EndTerm="STON90b">に書かれています。

</para>

<para>
     <!-- Some other database systems define active database rules. These
     are usually stored procedures and triggers and are implemented
     in <ProductName>Postgres</ProductName> as functions and triggers. -->
     他のいくつかのデータベースシステムは能動的データベースルールを定義しています。通常それらは格納されたプロシージャとトリガで、<ProductName>Postgres</ProductName>では関数とトリガとして実装されています。

</para>

<para>
     <!-- The query rewrite rule system (the "rule system" from now on) 
     is totally different from stored procedures and triggers.
     It modifies  queries  to
     take rules into consideration, and then passes the modified 
     query to the query planner for planning and execution.   It
     is  very powerful, and can be used for many things such
     as query language procedures, views, and versions.  The
     power  of  this  rule system is discussed in 
[<XRef LinkEnd="ONG90" EndTerm="ONG90">]
 as well as
[<XRef LinkEnd="STON90b" EndTerm="STON90b">]. -->

     問い合わせリライトシステム（以降「ルールシステム」と呼びます）は内蔵プロシージャとトリガとはまったく異なります。ルールシステムはルールを参照して問い合わせを修正し、修正した問い合わせを、プラン作成と実行のためにクエリプランナに渡します。これは非常に強力なため、問い合わせ言語プロシージャ、ビューあるいはバージョンなど多くのパターンでしようすることができます。このルールシステムの能力は<XRef LinkEnd="ONG90" EndTerm="ONG90">や<XRef LinkEnd="STON90b" EndTerm="STON90b">で解説されています。<indexterm><primary sortas="といあわせりらいとしすてむ">問い合わせリライトシステム</primary></indexterm><indexterm><primary sortas="くえりぷらんな">クエリプランナ</primary></indexterm>

</para>
<Sect1 id="querytree">
<!-- <Title>What is a Querytree?</Title> -->
<Title>問い合わせツリーとは</Title>
<indexterm><primary sortas="といあわせつりー">問い合わせツリー</primary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary sortas="といあわせつりー">問い合わせツリー</secondary></indexterm>
<para>
    <!-- To understand how the rule system works it is necessary to know
    when it is invoked and what its input and results are. -->
    どのようにルールシステムが機能するかを理解するためにはまず、ルールがどのように起動され、その入力と結果は何かを理解しなければなりません。

</para>

<para>
    <!-- The rule system is located between the query parser and the planner.
    It takes the output of the parser, one querytree, and the rewrite
    rules from the <FileName>pg_rewrite</FileName> catalog, which are
    querytrees too with some extra information, and creates zero or many
    querytrees as result. So its input and output are always things
    the parser itself could have produced and thus, anything it sees
    is basically representable as an <Acronym>SQL</Acronym> statement.-->

    ルールシステムは問い合わせのパーサーとオプティマイザの中間に位置します。ルールシステムは、入力としてパーサーの出力と単一の問い合わせツリーと<FileName>pg_rewrite</FileName>カタログから、何らかの特別な情報を持つ問い合わせツリーでもある書き換えルールを取得し、結果として0から複数個の問い合わせツリーを生成します。ルールシステムの入力と出力は常にパーサー自体でも生成することができるもので、参照する対象は基本的に<Acronym>SQL</Acronym>文による式として表現できるものです。<indexterm><primary>pg_rewrite</primary></indexterm><indexterm><primary sortas="しすてむかたろぐ">システムカタログ</primary><secondary>pg_rewrite</secondary></indexterm>

</para>

<para>
    <!-- Now what is a querytree? It is an internal representation of an
    <Acronym>SQL</Acronym> statement where the single parts that built
    it are stored separately. These querytrees are visible when starting
    the <ProductName>Postgres</ProductName> backend with debuglevel 4
    and typing queries into the interactive backend interface. The rule
    actions in the <FileName>pg_rewrite</FileName> system catalog are
    also stored as querytrees. They are not formatted like the debug
    output, but they contain exactly the same information. -->

    では問い合わせツリーとは何でしょうか。それは生成された1つ1つのパーツが別々にどこに記憶される<Acronym>SQL</Acronym>文の内部表現です。<ProductName>Postgres</ProductName>バックエンドをデバッグレベル4で起動し、対話型バックエンドインターフェイスを使って問い合わせを入力することによって問い合わせツリーを見ることができます。<FileName>pg_rewrite</FileName>システムカタログ内のルールアクションは同時に、問い合わせツリーとして記憶されます。それらはデバッグの出力のようにフォーマットされてはいませんがまったく同じ情報を持っています。

</para>

<para>
    <!-- Reading a querytree requires some experience and it was a hard
    time when I started to work on the rule system. I can remember
    that I was standing at the coffee machine and I saw the cup
    in a targetlist, water and coffee powder in a rangetable and all
    the buttons in a qualification expression. Since 
    <Acronym>SQL</Acronym> representations of querytrees are
    sufficient to understand the rule system, this document will
    not teach how to read them. It might help to learn
    it and the naming conventions are required in the later following
    descriptions. -->

    問い合わせツリーを読むためにはある程度の経験が必要になり、著者自身、ルールシステムを始めた頃は大変でした。今でも覚えていますが、コーヒーマシンの前に立っていたとき、コップが目的リストに、水とコーヒーの粉は範囲テーブルに、そしてすべてのボタンは制約式に見えたものです。<Acronym>SQL</Acronym>の問い合わせツリー表現形式はルールシステムを理解するためには十分なので、ここではその読み方までは教えません。自分で勉強しておけば役に立つでしょうし、名前付けの慣習は後に出てくる説明で必要になります。

</para>

<Sect2>
<!-- <Title>The Parts of a Querytree</Title> -->
<Title>問い合わせツリーのパーツ</Title>

<para>
    <!-- When reading the <Acronym>SQL</Acronym> representations of the 
    querytrees in this document it is necessary to be able to identify
    the parts the statement is broken into when it is in the querytree
    structure. The parts of a querytree are -->

    本稿の問い合わせツリーの<Acronym>SQL</Acronym>表現形式を読むときに必要なのは、問い合わせツリー構造の中にある文が分解される部分を識別できることです。問い合わせツリーには以下のパーツがあります。

</para>

<VariableList>
    <VarListEntry>
    <Term>
        <!-- the commandtype -->
        コマンド型<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="こまんどがた">コマンド型</secondary></indexterm>
    </Term>
    <ListItem>
    <para>
        <!-- This is a simple value telling which command
	(SELECT, INSERT, UPDATE, DELETE) produced the parsetree. -->

        これはどのコマンド（SELECT、INSERT、UPDATE、DELETE）が構文解析ツリーを作ったかを示す単純な値です。

    </para>
    </ListItem>
    </VarListEntry>

    <VarListEntry>
    <Term>
        <!-- the rangetable -->
        範囲テーブル<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="はんいてーぶる">範囲テーブル</secondary></indexterm><indexterm><primary sortas="はんいてーぶる">範囲テーブル</primary></indexterm>
    </Term>
    <ListItem>
    <para>
        <!-- The rangetable is a list of relations that are used in the query.
	In a SELECT statement these are the relations given after
	the FROM keyword. -->

        範囲テーブルは問い合わせで使われるリレーションのリストです。SELECT文ではこれはFROMキーワードの後で与えられるリレーションになります。

    </para>

    <para>
        <!-- Every rangetable entry identifies a table or view and tells
	by which name it is called in the other parts of the query.
	In the querytree the rangetable entries are referenced by
	index rather than by name, so here it doesn't matter if there
	are duplicate names as it would in an <Acronym>SQL</Acronym>
	statement. This can happen after the rangetables of rules
	have been merged in. The examples in this document will not have
	this situation. -->

        範囲テーブルのそれぞれの項目はテーブルもしくはビューを識別し、問い合わせの別のパーツではどんな名前で呼び出されるかを示します。問い合わせツリーでは範囲テーブルの項目は名前よりもインデックスで参照されることが多いため、ここでは<Acronym>SQL</Acronym>文とは違い、2とおりの名前があるかということは関係ありません。それはルールの範囲テーブルがマージされたあとに起こる可能性があります。本稿での例はその状況を含んでいません。

    </para>
    </ListItem>
    </VarListEntry>

    <VarListEntry>
    <Term>
        <!-- the resultrelation -->
        結果リレーション<indexterm><primary sortas="けっかりれーしょん">結果リレーション</primary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary sortas="けっかりれーしょん">結果リレーション</secondary></indexterm>
    </Term>
    <ListItem>
    <para>
        <!-- This is an index into the rangetable that identifies the
	relation where the results of the query go. -->

        問い合わせの結果が格納されるリレーションを識別する範囲テーブルへのインデックスです。

    </para>

    <para>
	<!-- SELECT queries
	normally don't have a result relation. The special case
	of a SELECT INTO is mostly identical to a CREATE TABLE,
	INSERT ... SELECT sequence and is not discussed separately
	here. -->

        SELECT問い合わせは通常は結果リレーションを持ちません。特別なSELECT INTOの場合はCREATE TABLE、INSERT ... SELECTシーケンスとほぼ同じなので、ここでは個別には説明しません。

    </para>

    <para>
        <!-- On INSERT, UPDATE and DELETE queries the resultrelation
	is the table (or view!) where the changes take effect. -->
        INSERT、UPDATE、DELETE問い合わせでは、結果は変化が有効になるテーブル（もしくはビュー）です。

    </para>
    </ListItem>
    </VarListEntry>

    <VarListEntry>
    <Term>
        <!-- the targetlist -->
        目的リスト<indexterm><primary sortas="もくてきりすと">目的リスト</primary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary sortas="もくてきりすと">目的リスト</secondary></indexterm>
    </Term>
    <ListItem>
    <para>
        <!-- The targetlist is a list of expressions that define the result
	of the query. In the case of a SELECT, the expressions are what
	builds the final output of the query. They are the expressions
	between the SELECT and the FROM keywords.  (* is just an
	abbreviation for all the attribute names of a relation.  It is
	expanded by the parser into the individual attributes, so the
	rule system never sees it.) -->

        目的リストは問い合わせの結果を定義する式のリストです。SELECTの場合、式は問い合わせの最終結果を構築するものです。これらはSELECTとFROMキーワードの間にある式です（「*」は単にリレーションのすべての属性名の省略です。それはパーサーによって個別の属性に拡張されるので、ルールシステムが見ることはありません）。

    </para>

    <para>
       <!--  DELETE queries don't need a targetlist because they don't
	produce any result. In fact the planner will add a special CTID
	entry to the empty targetlist. But this is after the rule
	system and will be discussed later. For the rule system the
	targetlist is empty. -->

        DELETE問い合わせは結果を返さないので目的リストが必要ありません。実際にはプランナが空の目的リストに特別なCTID項目を追加します。しかしこれはルールシステムの後で、のちに説明します。ルールシステムでは目的リストは空です。 

    </para>

    <para>
        <!-- In INSERT queries the targetlist describes the new rows that
	should go into the resultrelation. It is the expressions in the VALUES
	clause or the ones from the SELECT clause in INSERT ... SELECT.
	Missing columns of the resultrelation will be filled in by the
	planner with a constant NULL expression. -->

        INSERTでは目的リストは結果のリレーションへ行く新規の行を記述します。それはVALUES句かINSERT ... SELECTの中のSELECT句の式です。結果のリレーションで抜けているカラムはプランナが定数NULL式によって埋めます。

    </para>

    <para>
        <!-- In UPDATE queries, the targetlist describes the new rows that
        should replace the old ones. In the rule system, it contains just the
	expressions from the SET attribute = expression part of the query.
	The planner will add missing columns by inserting expressions that
	copy the values from the old row into the new one. And it will add
	the special CTID entry just as for DELETE too. -->

        UPDATEでは、古いものを置き換えるべき新しい行を目的リストが示します。ルールシステムでは問い合わせの「SET 属性 = 式」の部分からの式だけを持っています。プランナは、古い行から新しいものへ値をコピーする式を挿入することにより抜けているカラムを追加します。そして特別なCTID項目をDELETE用にも追加します。
    </para>

    <para>
        <!-- Every entry in the targetlist contains an expression that can
	be a constant value, a variable pointing to an attribute of one
	of the relations in the rangetable, a parameter, or an expression
	tree made of function calls, constants, variables, operators etc. -->

        目的リストの各項目は、定数値、範囲テーブル内のリレーションのうちの1つの属性を指し示す変数、関数呼び出しにより作られたパラメータ、式のツリー、定数、変数、演算子を含む式を保持します。

    </para>
    </ListItem>
    </VarListEntry>

    <VarListEntry>
    <Term>
        <!-- the qualification -->
         条件<indexterm><primary sortas="じょうけん">条件</primary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary sortas="じょうけん">条件</secondary></indexterm>
    </Term>
    <ListItem>
    <para>
        <!-- The query's qualification is an expression much like one of those
	contained in the targetlist entries. The result value of this
	expression is a boolean that tells if the operation
	(INSERT, UPDATE, DELETE or SELECT) for the final result row should be
	executed or not. It is the WHERE clause of an
	<Acronym>SQL</Acronym> statement. -->

        問い合わせの条件の式は目的リストの項目に含まれている式によく似ています。この式の結果は（INSERT、UPDATE、DELETE、SELECT）演算によって最終行が処理されたかどうかを示すブール値です。それは<Acronym>SQL</Acronym>文の中のWHERE句です。

    </para>
    </ListItem>
    </VarListEntry>

    <VarListEntry>
    <Term>
        <!-- the join tree -->
        結合ツリー<indexterm><primary sortas="けつごうつりー">結合ツリー</primary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary sortas="けつごうつりー">結合ツリー</secondary></indexterm>
    </Term>
    <ListItem>
    <para>
        <!-- The query's join tree shows the structure of the FROM clause.
	For a simple query like SELECT FROM a, b, c the join tree is just
	a list of the FROM items, because we are allowed to join them in
	any order.  But when JOIN expressions ___ particularly outer joins
	___ are used, we have to join in the order shown by the JOINs.
	The join tree shows the structure of the JOIN expressions.  The
	restrictions associated with particular JOIN clauses (from ON or
	USING expressions) are stored as qualification expressions attached
	to those join tree nodes.  It turns out to be convenient to store
	the top-level WHERE expression as a qualification attached to the
	top-level join tree item, too.  So really the join tree represents
	both the FROM and WHERE clauses of a SELECT. -->

        問い合わせの結合ツリーはFROM句の構造を表します。SELECT FROM a, b, cのような単純な問い合わせでは、結合ツリーは単なるFROM項目のリストです。なぜならどんな順番で結合しても構わないためです。しかしJOIN文、特に外部結合が使われた場合は、JOINが示す順番どおりに結合しなければいけません。結合ツリーはJOIN式の構造を表します。特定のJOIN句（ONもしくはUSING式からのもの）と関連付けられた制約はこれらの結合ツリーノードに付加された条件として格納されます。頂点レベルのWHERE式を頂点レベルの結合ツリー項目に付加された条件として格納することも便利です。ですから、結合ツリーはSELECTのFROM句とWHERE句の両方を表しているわけです。

    </para>
    </ListItem>
    </VarListEntry>

    <VarListEntry>
    <Term>
        <!-- the others -->
        その他
    </Term>
    <ListItem>
    <para>
        <!-- The other parts of the querytree like the ORDER BY 
	clause aren't of interest here. The rule system
	substitutes entries there while applying rules, but that
	doesn't have much to do with the fundamentals of the rule
	system. -->

        ORDER BY句のような問い合わせツリーのその他のパーツはここでは取り上げません。ルールシステムはルールを適用しているときにそこの場所で項目を入れ換えますが、これはルールシステムの基本とはあまり関係しません。

    </para>
    </ListItem>
    </VarListEntry>

</VariableList>
</Sect2>
</Sect1>

<Sect1 id="rules-views">
<!-- <Title>Views and the Rule System</Title> -->
<Title>ビューとルールシステム</Title>
<indexterm><primary sortas="びゅー">ビュー</primary><secondary sortas="るーる">ルール</secondary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary sortas="びゅー">ビュー</secondary></indexterm>
<Sect2>
<!-- <Title>Implementation of Views in <ProductName>Postgres</ProductName>
 </Title> -->
<Title><ProductName>Postgres</ProductName>におけるビューの実装</Title>

<para>
    <!-- Views in <ProductName>Postgres</ProductName> are implemented
    using the rule system. In fact there is absolutely no difference
    between a -->

    <ProductName>Postgres</ProductName>におけるビューはルールシステムを使って実装されています。たとえば以下のようなCREAT VIEW文があるとします。
</para>

<programlisting>
    CREATE VIEW myview AS SELECT * FROM mytab;
</programlisting>

<para>
    <!-- compared against the two commands -->
    実際、これと、以下の2つのコマンドの間にはまったく違いがありません。
</para>

<programlisting>
    CREATE TABLE myview (<Replaceable>same attribute list as for mytab</Replaceable>);
    CREATE RULE "_RETmyview" AS ON SELECT TO myview DO INSTEAD
        SELECT * FROM mytab;
</programlisting>
    
<para>
    <!-- because this is exactly what the CREATE VIEW command does internally.
    This has some side effects. One of them is that
    the information about a view in the <ProductName>Postgres</ProductName>
    system catalogs is exactly the same as it is for a table. So for the
    query parser, there is absolutely no difference between
    a table and a view. They are the same thing - relations. That is the
    important one for now. -->

    というのは、CREATE VIEWコマンドによって内部的にまったく同じ処理が行われるからです。しかし副作用もあります。その1つは<ProductName>Postgres</ProductName>システムカタログのビューについての情報はテーブルの情報と同一なので、パーサーにとってもテーブルとビューは同じものになるということです。リレーションについても同じです。これは現時点の重要課題です。

</para>
</Sect2>

<Sect2>
<!-- <Title>How SELECT Rules Work</Title> -->
<Title>SELECTルールの動き</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary>SELECT</secondary></indexterm>
<para>
    <!-- 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 the others in that they modify the parsetree in
    place instead of creating a new one.
    So SELECT rules are described first. -->

    たとえコマンドがINSERT、UPDATE、DELETEなどであっても、ON SELECTルールはすべての問い合わせに対し最後に適用されます。そして、それぞれは他と異なるセマンティックを持っていてパースツリーを新規に生成せずに、そこにあるものを修正します。したがってSELECTルールが一番初めに評価されなければいけません。<indexterm><primary sortas="るーる">ルール</primary><secondary>ON SELECT</secondary></indexterm>

</para>

<para>
    <!-- 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 rules ON SELECT to real view rules.
    -->

    現在のところ、ON SELECTルールでは1つのアクションしか許されず、それはINSTEADである無条件のSELECTアクションでなければいけません。この制約は一般のユーザーが何をしてもルールシステムが堅牢であるために必要性であり、ON SELECTのルールは実質的にviewのルールのみに限定されます。<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="あくしょん">アクション</secondary></indexterm>

</para>

<para>
    <!-- The examples for this document 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.
    It 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. -->

    このドキュメントの例として挙げているのは、ちょっとした演算をする2つの結合のビューと、次にこれらの機能を利用するいくつかのビューです。最終結果が何らかの魔法の機能によりあたかも実テーブルのように振る舞うビューになるように、始めの2つのビューの内の1つがINSERT、UPDATE、DELETE操作に対するルールを後で追加することでカスタマイズされます。始めて学ぶための例としては決して簡単ではなく先に進むことを躊躇させるかもしれませんが、多くの別々の例を持ち出して頭の混乱を招くよりも、すべての論点をステップごとに追う1つの例を挙げるほうがおいでしょう。

</para>

<para>
    <!-- The database needed to play with the examples is named al_bundy.
    You'll see soon why this is the database name. And it needs the
    procedural language PL/pgSQL installed, because
    we need a little min() function returning the lower of 2
    integer values. We create that as -->
    例として操作するデータベースの名前はal_bundyです。なぜこのような名前なのかはすぐにわかるでしょう。下位の2つの整数値を返すちょっとしたmin()関数を必要としますので、手続き言語PL/pgSQLがインストールされている必要があります。関数の生成は以下のようにします。
</para>

<programlisting>
    CREATE FUNCTION min(integer, integer) RETURNS integer AS
        'BEGIN
            IF $1 < $2 THEN
                RETURN $1;
            END IF;
            RETURN $2;
        END;'
    LANGUAGE 'plpgsql';
</programlisting>

<para>
    <!-- The real tables we need in the first two rule system descriptions
    are these: -->
    始めの2つのルールシステムの評価に必要な実際のテーブルは以下のものです。
</para>

<programlisting>
    CREATE TABLE shoe_data (
        shoename   char(10),      -- <!--primary key-->主キー
        sh_avail   integer,       -- <!--available # of pairs-->在庫
        slcolor    char(10),      -- <!--preferred shoelace color-->望ましい靴紐の色
        slminlen   float,         -- <!--miminum shoelace length-->靴紐の最短サイズ
        slmaxlen   float,         -- <!--maximum shoelace length-->靴紐の最長サイズ
        slunit     char(8)        -- <!--length unit-->長さの単位
    );

    CREATE TABLE shoelace_data (
        sl_name    char(10),      -- <!--primary key-->主キー
        sl_avail   integer,       -- <!--available # of pairs-->在庫
        sl_color   char(10),      -- <!--shoelace color-->靴紐の色
        sl_len     float,         -- <!--shoelace length-->靴紐の長さ
        sl_unit    char(8)        -- <!--length unit-->長さの単位
    );

    CREATE TABLE unit (
        un_name    char(8),       -- <!--the primary key-->主キー
        un_fact    float          -- <!--factor to transform to cm-->cmに変換するファクタ
    );
</programlisting>

<para>
    <!-- I think most of us wear shoes and can realize that this is
    really useful data. Well there are shoes out in the world
    that don't require shoelaces, but this doesn't make Al's
    life easier and so we ignore it. -->

    読者のほとんどが靴を履くでしょうからこのデータは確かに使えるはずです。もちろん世の中には靴紐のいらない靴もありますが、それではアルの生活が成り立ちませんので無視することにします。

</para>

<para>
    <!-- The views are created as -->
    ビューは次のようにして作られます。
</para>

<programlisting>
    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,
               min(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;
</programlisting>

<para>
    <!-- The CREATE VIEW command for the <Filename>shoelace</Filename> 
    view (which is the simplest one we have)
    will create a relation shoelace and an entry 
    in <FileName>pg_rewrite</FileName>
    that tells that there is a rewrite rule that must be applied
    whenever the relation shoelace is referenced in a query's rangetable.
    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 rule's action has a query qualification. -->

    <Filename>shoelace</Filename>ビュー（今ある一番簡単なビュー）用のCREATE VIEWコマンドは、リレーションshoelaceと問い合わせ範囲テーブルの中でリレーションshoelaceが参照されるときはいつでも、適用されるべき書き換えルールの存在を示す項目を<FileName>pg_rewrite</FileName>に作ります。ルールはルール条件を持たないINSTEADです（SELECTルールは現在規定されていないので、非SELECTルールのところで取りあげられます）。ルールの条件は、問い合わせの条件とは異なることに注意してください!　ルールアクションは条件を持っています。

</para>

<para>
    <!-- The rule's action is one querytree that is a copy of the
    SELECT statement in the view creation command. -->

    ルールアクションはビュー生成コマンドのSELECT文とまったく同じ問い合わせツリーです。
</para>

    <Note>
    <!-- <Title>Note</Title> -->
    <!--<Title>注意</Title>-->
    <para>
    <!-- The two extra range
    table entries for NEW and OLD (named *NEW* and *CURRENT* for
    historical reasons in the printed querytree) you can see in
    the <Filename>pg_rewrite</Filename> entry aren't of interest
    for SELECT rules. -->

    <Filename>pg_rewrite</Filename>項目のNEWとOLD（歴史的な理由により、出力用の問い合わせツリーではそれは*NEW*や*CURRENT*という名前が付いています）に対する2つの特別な範囲テーブル項目はSELECTルールには関係ないことがわかります。<indexterm><primary>NEW</primary></indexterm><indexterm><primary>OLD</primary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary>NEW</secondary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary>OLD</secondary></indexterm>

    </para>
    </Note>


<para>
    <!-- Now we populate <Filename>unit</Filename>, 
    <Filename>shoe_data</Filename>
    and <Filename>shoelace_data</Filename> and Al types the first 
    SELECT in his life: -->

    ではここで<Filename>unit</Filename>、<Filename>shoe_data</Filename>、<Filename>shoelace_data</Filename>にデータを入れます。アルはここで人生初のSELECTを入力します。
</para>

<programlisting>
    al_bundy=> <userinput>INSERT INTO unit VALUES ('cm', 1.0);</userinput>
    al_bundy=> <userinput>INSERT INTO unit VALUES ('m', 100.0);</userinput>
    al_bundy=> <userinput>INSERT INTO unit VALUES ('inch', 2.54);</userinput>
    al_bundy=> 
    al_bundy=> <userinput>INSERT INTO shoe_data VALUES </userinput>
    al_bundy->     <userinput>('sh1', 2, 'black', 70.0, 90.0, 'cm');</userinput>
    al_bundy=> <userinput>INSERT INTO shoe_data VALUES </userinput>
    al_bundy->     <userinput>('sh2', 0, 'black', 30.0, 40.0, 'inch');</userinput>
    al_bundy=> <userinput>INSERT INTO shoe_data VALUES </userinput>
    al_bundy->     <userinput>('sh3', 4, 'brown', 50.0, 65.0, 'cm');</userinput>
    al_bundy=> <userinput>INSERT INTO shoe_data VALUES </userinput>
    al_bundy->     <userinput>('sh4', 3, 'brown', 40.0, 50.0, 'inch');</userinput>
    al_bundy=> 
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl1', 5, 'black', 80.0, 'cm');</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl2', 6, 'black', 100.0, 'cm');</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl3', 0, 'black', 35.0 , 'inch');</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl4', 8, 'black', 40.0 , 'inch');</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl5', 4, 'brown', 1.0 , 'm');</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl6', 0, 'brown', 0.9 , 'm');</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl7', 7, 'brown', 60 , 'cm');</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace_data VALUES </userinput>
    al_bundy->     <userinput>('sl8', 1, 'brown', 40 , 'inch');</userinput>
    al_bundy=> 
    al_bundy=> <userinput>SELECT * FROM shoelace;</userinput>
    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)
</programlisting>

<para>
    <!-- It's the simplest SELECT Al can do on our views, so we take this
    to explain the basics of view rules.
    The 'SELECT * FROM shoelace' was interpreted by the parser and
    produced the parsetree -->

    アルが行うビューに対する最も簡単なSELECTですので、これでビューの基本ルールを説明します。「SELECT * FROM shoelace」はパーサーによって処理され、次のパースツリーが生成されます。
</para>

<programlisting>
    SELECT shoelace.sl_name, shoelace.sl_avail,
           shoelace.sl_color, shoelace.sl_len,
           shoelace.sl_unit, shoelace.sl_len_cm
      FROM shoelace shoelace;
</programlisting>

<para>
    <!-- 
    and this is given to the rule system. The rule system walks through the
    rangetable and checks if there are rules in <Filename>pg_rewrite</Filename>
    for any relation. When processing the rangetable entry for
    <Filename>shoelace</Filename> (the only one up to now) it finds the
    rule '_RETshoelace' with the parsetree -->

    この操作はルールシステムに伝えられます。ルールシステムは範囲テーブルを参照し、何らかのリレーションに対してルールが<Filename>pg_rewrite</Filename>に存在するか調べます。<Filename>shoelace</Filename>（現時点ではたった1つのテーブル）に対する範囲テーブル項目を処理するときに、構文解析ツリーでルール「_RETshoelace」を見つけ出します。
</para>
<!--
<programlisting>
    <FirstTerm>SELECT s.sl_name, s.sl_avail,
           s.sl_color, s.sl_len, s.sl_unit,
           float8mul(s.sl_len, u.un_fact) AS sl_len_cm
      FROM shoelace *OLD*, shoelace *NEW*,
           shoelace_data s, unit u
     WHERE bpchareq(s.sl_unit, u.un_name);</FirstTerm>
</programlisting>
-->

<programlisting>
    SELECT s.sl_name, s.sl_avail,
           s.sl_color, s.sl_len, s.sl_unit,
           float8mul(s.sl_len, u.un_fact) AS sl_len_cm
      FROM shoelace *OLD*, shoelace *NEW*,
           shoelace_data s, unit u
     WHERE bpchareq(s.sl_unit, u.un_name);
</programlisting>

<para>
    <!-- 
    Note that the parser changed the calculation and qualification into
    calls to the appropriate functions. But
    in fact this changes nothing. -->

   パーサーが、演算と検索条件を適切な関数の呼び出しに変換したことに注目してください。しかし実際は、これは何も変更しません。

</para>

<para>
    <!-- To expand the view, the rewriter simply creates a subselect rangetable
    entry containing the rule's action parsetree, and substitutes this
    rangetable entry for the original one that referenced the view.  The 
    resulting rewritten parsetree is almost the same as if Al had typed
    -->

    ビューを展開するために、システムでは単純にルールのアクション構文解析ツリーを持つ副問い合わせ範囲テーブルの項目を作り、ビューを参照していた元の範囲テーブルを置き換えます。書き換えられた結果の構文解析ツリーはアルが以下のように入力した場合とほぼおなじです。
</para>

<programlisting>
    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;
</programlisting>

<para>
     <!-- 
     There is one difference however: the sub-query's rangetable has two
     extra entries shoelace *OLD*, shoelace *NEW*.  These entries don't
     participate directly in the query, since they aren't referenced by
     the sub-query's join tree or targetlist.  The rewriter uses them
     to store the access permission check info that was originally present
     in the rangetable entry that referenced the view.  In this way, the
     executor will still check that the user has proper permissions to access
     the view, even though there's no direct use of the view in the rewritten
     query. -->

     しかし1つだけ違いがあります。副問い合わせの範囲テーブルが2つの余分な項目shoelace *OLD*とshoelace *NEW*を持っていることです。これらの項目は副問い合わせの結合ツリーや目的リストに参照されないので、直接問い合わせでは使われません。書き換えシステムではそれらを、ビューを参照した範囲テーブルの項目にもともと存在したアクセス権限確認情報を格納するために使います。この方法だと、書き換えられた問い合わせには直接の使用法はありませんが、エクゼキュータはユーザーがビューにアクセスするための正しい権限を確認します。<indexterm><primary sortas="えぐぜきゅーた">エグゼキュータ</primary></indexterm><indexterm><primary sortas="るーる">ルール</primary><secondary sortas="えぐぜきゅーた">エグゼキュータ</secondary></indexterm>

</para>

<para>
    <!--
    That was the first rule applied.  The rule system will continue checking
    the remaining rangetable entries in the top query (in this example there
    are no more), and it will recursively check the rangetable entries in
    the added sub-query 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. -->

    これが最初に適用されるルールです。ルールシステムは頂点の問い合わせ（この例ではそれ以上はありません）の残りの範囲テーブルの項目をチェックし続けます。そしてルールシステムは、追加された副問い合わせの項目がビューを参照するかを再帰的に確認します（しかし*OLD*や*NEW*は展開しません。そうでなければ無限再帰になってしまいます！）。この例ではshoelace_dataやunitのための書き換えルールはありません。ですから書き換えは完結し、上記がプランナに渡される最終的な結果となります。
</para>

<para>
    <!-- 
    Now we face Al with the problem that the Blues Brothers appear
    in his shop and
    want to buy some new shoes, and as the Blues Brothers are,
    they want to wear the same shoes. And they want to wear them
    immediately, so they need shoelaces too. -->

    ここで、ブルースブラザーズが靴を買いにお店にやって来て、ブルースブラザーズですから、同じ靴を履きたいと言います。すぐに履きたいので靴紐も必要です。

</para>

<para>
    <!-- Al needs to know for which shoes currently in the store
    he has the matching shoelaces (color and size) and where the
    total number of exactly matching pairs is greater or equal to two.
    We teach him what to do and he asks his database: -->

    店に置いてある靴紐（の色とサイズ）に一致する靴がどれで、完全に一致するものの在庫が2組以上あるかどうかをアルは知らなければいけません。アルはデータベースに問い合わせることが必要です。
</para>

<programlisting>
    al_bundy=> <userinput>SELECT * FROM shoe_ready WHERE total_avail >= 2;</userinput>
    shoename  |sh_avail|sl_name   |sl_avail|total_avail
    ----------+--------+----------+--------+-----------
    sh1       |       2|sl1       |       5|          2
    sh3       |       4|sl7       |       7|          4
    (2 rows)
</programlisting>

<para>
    <!-- Al is a shoe guru and so he knows that only shoes of type sh1
    would fit (shoelace sl7 is brown and shoes that need brown shoelaces
    aren't shoes the Blues Brothers would ever wear). -->

    アルは靴についての専門家ですので、sh1型の靴が該当することがわかります（sl7の靴紐は茶色で、それに合う茶色の靴はブルースブラザーズの好みではありません）。

</para>

<para>
    <!-- The output of the parser this time is the parsetree -->
    今回のパーサーの出力は以下の構文解析ツリーです。
</para>

<programlisting>
    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 int4ge(shoe_ready.total_avail, 2);
</programlisting>

<para>
    <!-- 
    The first rule applied will be the one for the 
    <Filename>shoe_ready</Filename> view and it results in the
    parsetree -->

    一番始めに適用されるルールは<Filename>shoe_ready</Filename>ビュー用のもので構文解析ツリーにおける結果は以下のようになります。
</para>

<programlisting>
    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,
                   min(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 int4ge(shoe_ready.total_avail, 2);
</programlisting>

<para>
    <!-- 
    Similarly, the rules for <Filename>shoe</Filename> and
    <Filename>shoelace</Filename> are substituted into the rangetable of
    the sub-query, leading to a three-level final querytree: -->

    同じように、<Filename>shoe</Filename>と<Filename>shoelace</Filename>のルールは副問い合わせの範囲テーブルとして代用され、レベル3の最終問い合わせツリーへと導きます。
</para>

<programlisting>
    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,
                   min(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 int4ge(shoe_ready.total_avail, 2);
</programlisting>

<para>
    <!-- 
    It turns out that the planner will collapse this tree into a two-level
    querytree: the bottommost selects will be "pulled up" into the middle
    select since there's no need to process them separately.  But the
    middle select will remain separate from the top, because it contains
    aggregate functions.  If we pulled those up it would change the behavior
    of the topmost select, which we don't want.  However, collapsing the
    query tree is an optimization that the rewrite system doesn't
    have to concern itself with. -->

    プランナはこのツリーを2レベルの問い合わせツリーに縮めます。一番下のselectはバラバラに処理する必要がないので2つ目selectに「引っ張り上げ」られます。しかし2つ目のセレクトは集約関数を持つため、頂点からは区別されます。もしそれらを引っ張り上げてしまうと一番上のselectの動作を変えてしまうことになり、それはしたくありません。しかし、問い合わせツリーを縮めることは書き換えシステムが自分で意識する必要がありません。
</para>

    <Note>
    <!-- <Title>Note</Title> -->
    <!--<Title>注意</Title>-->
    <para>
    <!-- There is currently no recursion stopping mechanism for view
    rules in the rule system (only for the other kinds of rules).
    This doesn't hurt much, because the only way to push this
    into an endless loop (blowing up the
    backend until it reaches the memory limit)
    is to create tables and then setup the
    view rules by hand with CREATE RULE in such a way, that
    one selects from the other that selects from the one.
    This could never happen if CREATE VIEW is used because
    for the first CREATE VIEW, the second relation does not exist
    and thus the first view cannot select from the second. -->

    ルールシステムにおいて（他のルールは別ですが）ビュールールの再帰処理を中止する機構はありません。この無限ループ（メモリの限界に到達してバックエンドが破壊される）を引き起こすには、テーブルを作成しCREATE RULEにより手作業でビュールールを他からの選択が、その他からのを選択するように設定することによりのみ可能ですから、さほど深刻な問題ではありません。始めのCREATE VIEWでは、2番目のリレーションは存在せず第1のビューを第2のビューが選択することはありえませんからこのような状況はCREATE VIEWでは起こり得ません。

    </para>
    </Note>

</Sect2>

<Sect2>
<!-- <Title>View Rules in Non-SELECT Statements</Title> -->
<Title>非SELECT文のビュールール</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="ひSELECT">非SELECT</secondary></indexterm>
<para>
    <!-- Two details of the parsetree aren't touched in the description of
    view rules above. These are the commandtype and the resultrelation.
    In fact, view rules don't need this information. -->

    これまでのビュールールの説明では構文解析ツリーの2つの詳細について触れませんでした。それらは、コマンドタイプと結果リレーションです。実際、ビューのルールはこれらの情報を必要としません。

</para>

<para>
    <!-- There are only a few differences between a parsetree for a SELECT
    and one for any other command. Obviously they have another commandtype
    and this time the resultrelation points to the rangetable 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 parsetrees for the two statements -->

    SELECTと他のコマンドに対する構文解析ツリーの間には大きな違いはありません。それらは明らかに違うコマンドタイプを持っていて、今回は結果リレーションは結果がどこに行くのかを示す範囲テーブルの項目を指し示します。それ以外ではまったく同じです。ですから、aとbの属性を持つテーブルt1、t2に対対する以下の2つの命令文の構文解析ツリーはほとんど同等です。
</para>

<programlisting>
    SELECT t2.b FROM t1, t2 WHERE t1.a = t2.a;

    UPDATE t1 SET b = t2.b WHERE t1.a = t2.a;
</programlisting>

    <!-- are nearly identical. -->


    <ItemizedList>
        <ListItem>
	<para>
	    <!-- The rangetables contain entries for the tables t1 and t2. -->
            範囲テーブルにはテーブルt1とt2に対する項目があります。
	</para>
        </ListItem>

        <ListItem>
	<para>
	  <!--   The targetlists contain one variable that points to attribute
	    b of the rangetable entry for table t2. -->
          目的リストにはテーブルt2に対する範囲テーブル項目の属性bを指し示す1つの変数があります。 
	</para>
        </ListItem>

        <ListItem>
	<para>
	    <!-- The qualification expressions compare the attributes a of both
	    ranges for equality. -->

            条件式に両方のテーブルの属性aが比較されます。
	</para>
        </ListItem>

        <ListItem>
	<para>
	    <!-- The jointrees show a simple join between t1 and t2. -->
            これらの結合ツリーはt1とt2の単純な結合を表しています。
 
	</para>
        </ListItem>
    </ItemizedList>

<para>
    <!-- 
    The consequence is, that both parsetrees 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 targetlist by the planner 
    and the final parsetree will read as -->

    結果として、両方の構文解析ツリーが似たような実行プランになります。それらは共に2つのテーブルの結合です。UPDATEに対してt1から抜けているカラムはプランナが目的リストに追加し、最終のパースツリーは、以下のようになります。
</para>

<programlisting>
    UPDATE t1 SET a = t1.a, b = t2.b WHERE t1.a = t2.a;
</programlisting>

<para>
    <!-- and thus the executor run over the join will produce exactly the
    same result set as a -->
    結合を実行したエクゼキュータは、以下のようになり、まったく同じ結果のセットを作成します。
</para>

<programlisting>
    SELECT t1.a, t2.b FROM t1, t2 WHERE t1.a = t2.a;
</programlisting>

<para>
    <!-- 
    will do. But there is a little problem in UPDATE. The executor does
    not care what the results from the join it is doing are meant
    for. It just produces a result set of rows. The difference that one
    is a SELECT command and the other is an UPDATE is handled in the
    caller of the executor. The caller still knows (looking at the
    parsetree) that this is an UPDATE, and he 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?  -->

    とはいってもUPDATEにはちょっとした問題があります。エクゼキュータは、結合が行う処理の結果が何を意味しているかに関与しません。エクゼキュータは単に結果となる行のセットを作成するだけです。1つはSELECTコマンドでもう1つはUPDATEコマンドですが、違いはエクゼキュータを呼び出す側で扱われることです。呼び出し側は（構文解析ツリーを見て）、これがUPDATEであるとわかっていて、この結果がテーブルt1に入らなければいけないことを知っています。しかし、どの行が新しい行によって置換されなければならないのでしょうか。

</para>

<para>
    <!-- To resolve this problem, another entry is added to the targetlist
    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 targetlist, the query actually looks like
    -->

    この問題を解決するため、UPDATE文（DELETE文も）の目的リストに別の項目が付け加えられます。それは現在のタプルID（ctid）です。これはファイルのブロック数とその行のブロック中の位置を持つシステムの属性です。テーブルがわかっている場合、ctidは元のt1行の更新を抽出するために使うことができます。ctidを目的リストに追加した後は、問い合わせは以下のようになります。
</para>

<programlisting>
    SELECT t1.a, t2.b, t1.ctid FROM t1, t2 WHERE t1.a = t2.a;
</programlisting>

<para>
    <!--   
    Now another detail of <ProductName>Postgres</ProductName> enters the
    stage. At this moment, table rows aren't overwritten and this is why
    ABORT TRANSACTION is fast. In an UPDATE, the new result row is inserted
    into the table (after stripping ctid) and in the tuple header of the row 
    that 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 commited the vacuum cleaner can really move
    it out. -->

    では、<ProductName>Postgres</ProductName>の別の詳細説明に入りましょう。今のところ、テーブルの行は上書きされないのでABORT TRANSACTION処理は速いのです。UPDATEでは、（ctidを取り除いたあと）テーブルに新しい結果の行が挿入され、その行のタプルヘッダー内ではcmaxを指し示すctidとxmaxの項目が現在のコマンドカウンタと現在のトランザクションIDにセットされます。このようにして、古い行は隠されトランザクションがコミットされたあとにvacuumが実際に削除することができます。

</para>

<para>
    <!-- Knowing all that, we can simply apply view rules in absolutely
    the same way to any command. There is no difference. -->
    これらの詳細が全部理解できれば、どんなコマンドに対してもまったく同じようにしてビューのルールを簡単に適用することができます。そこには差異がありません。

</para>
</Sect2>

<Sect2>
<!-- <Title>The Power of Views in <ProductName>Postgres</ProductName>
  </Title> -->
<Title><ProductName>Postgres</ProductName>におけるビューの能力</Title>

<para>
    <!-- The above demonstrates how the rule system incorporates
    view definitions into the original parsetree. In the second example
    a simple SELECT from one view created a final parsetree that is
    a join of 4 tables (unit is used twice with different names). -->

    ここまでで、ビューの諸定義がオリジナルの構文解析ツリーにどのように関与するかを解説しました。第2の例では、最終的に4つのテーブルを結合するパースツリーを生成するようなviewからの単純なSELECTを使います（事例は違った名前で2回使われます）。

</para>

<Sect3>
<!-- <Title>Benefits</Title> -->
<Title>利点</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="りてん">利点</secondary></indexterm>
<para>
    <!-- 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 parsetree. And this is still the situation
    when the original query is already a join over views.
    Now the planner has to decide which is
    the best path to execute the query. The more information
    the planner has, the better this decision can be. And
    the rule system as implemented in <ProductName>Postgres</ProductName>
    ensures, that this is all information available about the query
    up to now. -->

    ビューをルールシステムとともに実装する利点は、オプティマイザが、どのテーブルをスキャンすべきか、それらのテーブル間の関連性、ビューからの制約条件、オリジナルの問い合わせ条件、これらを1つのパースツリーに持っていることです。ことです。オリジナルの問い合わせがすでにビューに対する結合であるときも同様です。オプティマイザはここでどれが問い合わせ処理の最適経路かを決定しなければなりません。情報が多ければ多いほど、オプティマイザはよりよい決定を下すことができます。そして<ProductName>Postgres</ProductName>に実装されているルールシステムはこれが現時点で、提供されているすべての情報であることを保障します。

</para>
</Sect3>
</Sect2>

<Sect2>
<!-- <Title>What about updating a view?</Title> -->
<Title>ビューの更新について</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="びゅーのこうしん">ビューの更新</secondary></indexterm>
<para>
    <!-- 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 querytree in which the resultrelation points at a
    subquery rangetable entry.  This will not work, so the rewriter throws
    an error if it sees it has produced such a thing. -->

    ビューがINSERT、UPDATE、DELETEなどの目的リレーションとして名付けられた場合はどうなるのでしょうか？ 上で説明したような置換をしたあとに、結果リレーションが副問い合わせの範囲テーブル項目を指す問い合わせツリーができます。これでは使えませんので、書き換えシステムがそのようなものを見つけるとエラーを発生します。

</para>

<para>
    <!-- To change this we can define rules that modify the behaviour
    of non-SELECT queries. This is the topic of the next section. -->

    これを変えるためには非SELECT問い合わせの動作を変えるルールを定義することができます。それが次の節の論題になります。

</para>
</Sect2>

</Sect1>

<Sect1 id="rules-insert">
<!-- <Title>Rules on INSERT, UPDATE and DELETE</Title> -->
<Title>INSERT、UPDATE、DELETEについてのルール</Title>

<Sect2>
<!-- <Title>Differences from View Rules</Title> -->
<Title>ビュールールに対しての差異</Title>

<para>
    <!-- Rules that are defined ON INSERT, UPDATE and DELETE are
    totally different from the view rules described
    in the previous section. First, their CREATE RULE
    command allows more: -->

    INSERT、UPDATE、DELETEでのルールは前節で解説したビューのルールとはまったく異なります。第一点として、これらのCREATE RULEコマンドでは以下のケースがあり得ます。
</para>

    <ItemizedList>
        <ListItem>
	<para>
	    <!-- They can have no action. -->
            アクションがないルールも可能です。
	</para>
	</ListItem>

        <ListItem>
	<para>
	    <!-- They can have multiple actions. -->
            複数のアクションを持てます。
	</para>
	</ListItem>

        <ListItem>
	<para>
	    <!-- The keyword INSTEAD is optional. -->
            キーワードINSTEADはなくてもかまいません。<indexterm><primary sortas="るーる">ルール</primary><secondary>INSTEAD</secondary></indexterm>
	</para>
	</ListItem>

        <ListItem>
	<para>
	    <!-- The pseudo relations NEW and OLD become useful. -->
            疑似リレーションNEWとOLDが役立つようになります。
	</para>
	</ListItem>

        <ListItem>
	<para>
	    <!-- They can have rule qualifications. -->
            ルールにルール条件を持たせることができます。
	</para>
	</ListItem>
    </ItemizedList>

<para>
    <!-- 
    Second, they don't modify the parsetree in place. Instead they
    create zero or many new parsetrees and can throw away the
    original one. -->

    第2の点として、その場所で構文解析ツリーを変更しません。そのかわりに新規の複数（0の場合もありますが）の構文解析ツリーを生成して、オリジナルを破棄します。

</para>
</sect2>
<Sect2>
<!-- <Title>How These Rules Work</Title> -->
<Title>これらのルールの動作</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="どうさ">動作</secondary></indexterm>
    <!-- Keep the syntax -->

<programlisting>
    CREATE RULE rule_name AS ON event
        TO object [WHERE rule_qualification]
        DO [INSTEAD] [action | (actions) | NOTHING];
</programlisting>
  
<para>
    <!-- in mind.
    In the following, "update rules" means rules that are defined
    ON INSERT, UPDATE or DELETE. -->

    上記の構文を覚えておいてください。以下では、「更新ルール」はINSERT、UPDATE、DELETEに定義されたルールを意味します。<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="こうしんるーる">更新ルール</secondary></indexterm>

</para>

<para>
    <!-- Update rules get applied by the rule system when the result
    relation and the commandtype of a parsetree are equal to the
    object and event given in the CREATE RULE command.
    For update rules, the rule system creates a list of parsetrees.
    Initially the parsetree list is empty.
    There can be zero (NOTHING keyword), one or multiple actions.
    To simplify, we look at a rule with one action. This rule
    can have a qualification or not and it can be INSTEAD or not. -->

    更新ルールは、結果リレーションと構文解析ツリーのコマンドタイプがCREATE RULEで与えられるオブジェクトとイベントと等しい場合にルールシステムによって適用されます。更新ルールに対してルールシステムは構文解析ツリーのリストを生成します。最初は構文解析ツリーリストは空です。0（キーワードがNOTHING）か、1つまたは複数のアクションが有効です。簡単にするため、ここでは1つのアクションのルールを取り上げます。このルールは条件を持っていても持っていなくても、またINSTEADであっても、なくても構いません。

</para>

<para>
    <!-- What is a rule qualification? It is a restriction that tells
    when the actions of the rule should be done and when not. This
    qualification can only reference the NEW and/or OLD pseudo relations
    which are basically the relation given as object (but with a
    special meaning). -->

    ルール条件とはどんなものでしょうか。それはルールのアクションを行わなければならないときと、行ってはならないときを指定する条件です。基本的に（特別な意味合いを持った）オブジェクトとして与えられるリレーションであるNEW疑似リレーション、あるいはOLD疑似リレーションのみを、この条件は参照します。
</para>

<para>
    <!-- So we have four cases that produce the following parsetrees for
    a one-action rule. -->
    1つのアクションルールに対し、以下の構文解析ツリーを生成する4つの事例が挙げられます。
 
</para>

    <ItemizedList>
    <ListItem>
    <para>
        <!-- No qualification and not INSTEAD: -->
<!--        <ItemizedList>
	    <ListItem>
	    <para>
	         The parsetree from the rule action where the
		original parsetree's qualification has been added. 
	    </para>
	    </ListItem>
	</ItemizedList>-->

        条件なしでINSTEADでない場合――オリジナル構文解析ツリーの条件が付け加えられたルールアクションからの構文解析ツリー。
    </para>
    </ListItem>

    <ListItem>
    <para>
        <!-- No qualification but INSTEAD: -->
<!--        <ItemizedList>
	    <ListItem>
	    <para>
	         The parsetree from the rule action where the
		original parsetree's qualification has been added. -->
        条件なしでINSTEADの場合――オリジナル構文解析ツリーの条件が付け加えられたルールアクションからの構文解析ツリー。

<!--	    </para>
	    </ListItem>
	</ItemizedList>-->
    </para>
    </ListItem>

    <ListItem>
    <para>
        <!-- Qualification given and not INSTEAD: -->
<!--        <ItemizedList>
	    <ListItem>
	    <para>
	         The parsetree from the rule action where the rule
		qualification and the original parsetree's 
		qualification have been added. -->

         条件付きでINSTEADでない場合――ルール条件とオリジナル構文解析ツリーの条件が付け加えられたルールアクションからの構文解析ツリー。

<!--	    </para>
	    </ListItem>
	</ItemizedList>-->
    </para>
    </ListItem>

    <ListItem>
    <para>
        <!-- Qualification given and INSTEAD: -->
        条件つきでINSTEADの場合
</para>
        <ItemizedList>
	    <ListItem>
	    <para>
	        <!-- The parsetree from the rule action where the rule
		qualification and the original parsetree's 
		qualification have been added. -->
                ルール条件とオリジナル構文解析ツリーの条件が付け加えられたルールアクションからの構文解析ツリー。

	    </para>
	    </ListItem>

	    <ListItem>
	    <para>
	        <!-- The original parsetree where the negated rule
		qualification has been added. -->
                否定されたルール条件が付け加えられたオリジナルの構文解析ツリー。

	    </para>
	    </ListItem>
	</ItemizedList>
    </ListItem>
    </ItemizedList>

<para>
    <!-- Finally, if the rule is not INSTEAD, the unchanged original 
    parsetree is added to the list. Since only qualified INSTEAD rules
     already add the original parsetree, we end up with either one or 
    two output parsetrees for a rule with one action.-->
    最後に、もしルールがINSTEADでない場合、変更されていないオリジナルの構文解析ツリーがリストに付け加えられます。条件に合ったINSTEADルールのみがすでにオリジナルの構文解析ツリーに追加をしているので、最後は1つのアクションに対して最大合わせて2つの構文解析ツリーにたどり着きます。

</para>

<para>
    <!-- The parsetrees generated from rule actions are thrown into the
    rewrite system again and maybe more rules get applied resulting
    in more or less parsetrees.
    So the parsetrees in the rule actions must have either another commandtype
    or another resultrelation. Otherwise this recursive process will end up 
    in a loop.
    There is a compiled in recursion limit of currently 10 iterations.
    If after 10 iterations there are still update rules to apply the
    rule system assumes a loop over multiple rule definitions and aborts the
    transaction. -->

    ルールアクションで生成された構文解析ツリーは書き換えシステムに再度手渡され、相当数の構文解析ツリーの結果をもたらす、より多くのルールの適用を受けることもあります。ですから、ルールアクションにおける構文解析ツリーは別のコマンドタイプか、別の結果リレーションを持っていなければなりません。さもないとこの再帰的手順はループになってしまいます。現在10回までの再帰処理反復制限が組み込まれています。10回反復処理を行った後にもまだ適用すべき更新ルールがあった場合は、ルールシステムは複数のルール定義にまたがったループであると想定し、そのトランザクションを停止します。

</para>

<para>
    <!-- 
    The parsetrees found in the actions of the <Filename>pg_rewrite</Filename>
    system catalog are only templates. Since they can reference the
    rangetable entries for NEW and OLD, some substitutions have to be made
    before they can be used. For any reference to NEW, the targetlist of
    the original query is searched for a corresponding entry. If found,
    that entry's expression replaces the reference. Otherwise
    NEW means the same as OLD (for an UPDATE) or is replaced by NULL
    (for an INSERT). Any reference to OLD is replaced by a
    reference to the rangetable entry which is the resultrelation. -->

    <Filename>pg_rewrite</Filename>システムカタログのアクションにある構文解析ツリーは単なるテンプレートです。これらはNEWとOLDに対する範囲テーブルの項目を参照することができるため使用される前に何らかの置換措置がとられていなければなりません。NEWに対するどんな参照でも、オリジナルの問い合わせの目的リストは関連する項目があるかどうか検索されます。項目が見つかった場合には、その項目式が参照と置き換えられます。項目がなかった場合、NEWはOLDと同じ意味になる（UPDATEの場合）か、NULLによって置き換えられます（INSERTの場合）。OLDに対する参照はすべて結果リレーションである範囲テーブルの項目に対する参照に置き換えられます。
</para>

<para>
    <!-- 
    After we are done applying update rules, we apply view rules to the
    produced parsetree(s).  Views cannot insert new update actions so
    there is no need to apply update rules to the output of view rewriting.
    -->

    更新ルールの適用が終わると、そこで作られた構文解析ツリーにビュールールを適用します。ビューは新しい更新アクションを挿入できないため、ビュー書き換えの結果に更新ルールを適用する必要はありません。

</para>

<Sect3>
<!-- <Title>A First Rule Step by Step</Title>-->
<Title>最初のルール――ステップバイステップ</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="すてっぷばいすてっぷ">ステップバイステップ</secondary></indexterm>
<para>
    <!-- We want to trace changes to the sl_avail column in the
    <Filename>shoelace_data</Filename> relation. So we setup a
    log table and a rule that conditionally writes a log entry when
    an UPDATE is performed on <Filename>shoelace_data</Filename>. -->

    <Filename>shoelace_data</Filename>リレーションのsl_availカラムの変化を追跡してみたいと思います。そこでログ用テーブルと、毎回の入力、<Filename>shoelace_data</Filename>に対して行われるUPDATEを記録するルールを用意しました。
</para>

<programlisting>
    CREATE TABLE shoelace_log (
        sl_name    char(10),      -- shoelace changed
        sl_avail   integer,       -- new available value
        log_who    text,          -- who did it
        log_when   timestamp      -- when
    );

    CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data
        WHERE NEW.sl_avail != OLD.sl_avail
        DO INSERT INTO shoelace_log VALUES (
                                        NEW.sl_name,
                                        NEW.sl_avail,
                                        current_user,
                                        current_timestamp
                                    );
</programlisting>

<para>
    <!-- Now Al does -->
    ここでアルは以下を実行します。
</para>

<programlisting>
    al_bundy=> <userinput>UPDATE shoelace_data SET sl_avail = 6</userinput>
    al_bundy->     <userinput>WHERE sl_name = 'sl7';</userinput>
</programlisting>

<para>
    <!-- and we look at the logtable. -->
    ログテーブルを見てみましょう。
</para>

<programlisting>
    al_bundy=> <userinput>SELECT * FROM shoelace_log;</userinput>
    sl_name   |sl_avail|log_who|log_when
    ----------+--------+-------+--------------------------------
    sl7       |       6|Al     |Tue Oct 20 16:14:45 1998 MET DST
    (1 row)
</programlisting>

<para>
    <!-- 
    That's what we expected. What happened in the background is the following.
    The parser created the parsetree (this time the parts of the original
    parsetree are highlighted because the base of operations is the
    rule action for update rules). -->

    思ったとおりの結果が出ました。裏ではパーサーが構文解析ツリーを生成しました（今回、操作の基本は更新ルールに対するルールアクションのため、元となった構文解析ツリーの部分部分は強調されています）。
</para>

<programlisting>
    <emphasis>UPDATE shoelace_data SET sl_avail = 6
      FROM shoelace_data shoelace_data
     WHERE bpchareq(shoelace_data.sl_name, 'sl7');</emphasis>
</programlisting>

<para>
    <!-- 
    There is a rule 'log_shoelace' that is ON UPDATE with the rule
    qualification expression -->

    ルールの条件式を持つON UPDATEの「log_shoelace」ルールがあります。
</para>

<programlisting>
    int4ne(NEW.sl_avail, OLD.sl_avail)
</programlisting>

<para>
    <!-- and one action -->
    また、1つのアクションがあります。
</para>

<programlisting>
    INSERT INTO shoelace_log VALUES(
           *NEW*.sl_name, *NEW*.sl_avail,
           current_user, current_timestamp
      FROM shoelace_data *NEW*, shoelace_data *OLD*;
</programlisting>

<para>
    <!--  
    This is a little strange-looking since you can't normally write
    INSERT ... VALUES ... FROM.  The FROM clause here is just to indicate
    that there are rangetable entries in the parsetree for *NEW* and *OLD*.
    These are needed so that they can be referenced by variables in the
    INSERT command's querytree. -->

    通常ではINSERT ... VALUES ... FROMを書くことはできないのでちょっと奇妙に見えるかもしれません。ここのFROM句は単に*NEW*と*OLD*の構文解析ツリーの範囲テーブル項目があることを示しているだけです。これらはINSERTコマンドの問い合わせツリー中の変数から参照されるために必要なのです。

</para>

<para>
    <!-- 
    The rule is a qualified non-INSTEAD rule, so the rule system
    has to return two parsetrees: the modified rule action and the original
    parsetree. In the first step the rangetable of the original query is
    incorporated into the rule's action parsetree. This results in -->

    ルールは非INSTEADルールで条件付けられるため、ルールシステムは2つの構文解析ツリーを戻さなければなりません。変更されたルールアクションと元の構文解析ツリーです。第一の段階で元の問い合わせの範囲テーブルはルールアクション構文解析ツリーに取りこまれます。そして、次の結果を生みます。
</para>

<programlisting>
    INSERT INTO shoelace_log VALUES(
           *NEW*.sl_name, *NEW*.sl_avail,
           current_user, current_timestamp
      FROM shoelace_data *NEW*, shoelace_data *OLD*,
           <emphasis>shoelace_data shoelace_data</emphasis>;
</programlisting>

<para>
    <!-- 
    In step 2 the rule qualification is added to it, so the result set
    is restricted to rows where sl_avail changes. -->

    第2段階で、ルールの条件が付け加えられ、結果セットはsl_availが変更した行に限定されます。
</para>

<programlisting>
    INSERT INTO shoelace_log VALUES(
           *NEW*.sl_name, *NEW*.sl_avail,
           current_user, current_timestamp
      FROM shoelace_data *NEW*, shoelace_data *OLD*,
           shoelace_data shoelace_data
     <emphasis>WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail)</emphasis>;
</programlisting>

<para>
    <!-- 
    This is even stranger-looking, since INSERT ... VALUES doesn't have
    a WHERE clause either, but the planner and executor will have no
    difficulty with it.  They need to support this same functionality
    anyway for INSERT ... SELECT. -->

INSERT ... VALUESがWHERE句を持たないため、これはさらに奇妙です。しかし、プランナとエクゼキュータには問題ではありません。これらはどのみちINSERT ... SELECTのために同じ機能をサポートしています。

    <!-- 
    In step 3 the original parsetree's qualification is added,
    restricting the resultset further to only the rows touched
    by the original parsetree. -->
第3ステップで、元の構文解析ツリーの条件が付け加えられ、結果セットはさらに元の構文解析ツリーが処理対象とする行のみに制限をかけます。
</para>

<programlisting>
    INSERT INTO shoelace_log VALUES(
           *NEW*.sl_name, *NEW*.sl_avail,
           current_user, current_timestamp
      FROM shoelace_data *NEW*, shoelace_data *OLD*,
           shoelace_data shoelace_data
     WHERE int4ne(*NEW*.sl_avail, *OLD*.sl_avail)
       <emphasis>AND bpchareq(shoelace_data.sl_name, 'sl7')</emphasis>;
</programlisting>

<para>
    <!-- 
    Step 4 substitutes NEW references by the targetlist entries from the
    original parsetree or with the matching variable references
    from the result relation. -->

    第4段階は、オリジナルの構文解析ツリーの目的リスト項目または結果リレーションの該当する変数参照でNEWの参照を置換します。
</para>

<programlisting>
    INSERT INTO shoelace_log VALUES(
           <emphasis>shoelace_data.sl_name</emphasis>, <emphasis>6</emphasis>,
           current_user, current_timestamp
      FROM shoelace_data *NEW*, shoelace_data *OLD*,
           shoelace_data shoelace_data
     WHERE int4ne(<emphasis>6</emphasis>, *OLD*.sl_avail)
       AND bpchareq(shoelace_data.sl_name, 'sl7');
</programlisting>

<para>
<!-- Step 5 changes OLD references into resultrelation references. -->
    第5段階は、OLD参照を結果リレーション参照に置き換えます。
</para>

<programlisting>
    INSERT INTO shoelace_log VALUES(
           shoelace_data.sl_name, 6,
           current_user, current_timestamp
      FROM shoelace_data *NEW*, shoelace_data *OLD*,
           shoelace_data shoelace_data
     WHERE int4ne(6, <emphasis>shoelace_data.sl_avail</emphasis>)
       AND bpchareq(shoelace_data.sl_name, 'sl7');
</programlisting>

<para>
    <!-- 
    That's it.  Since the rule is not INSTEAD, we also output the
    original parsetree.  In short, the output from the rule system
    is a list of two parsetrees that are the same as the statements: -->

    これで終わりです。このルールはINSTEADではないため、オリジナルの構文解析ツリーも出力します。簡単にいえば、ルールシステムからの出力はステートメントと同じ2つの構文解析ツリーのリストです。
</para>

<programlisting>
    INSERT INTO shoelace_log VALUES(
           shoelace_data.sl_name, 6,
           current_user, current_timestamp
      FROM shoelace_data
     WHERE 6 != shoelace_data.sl_avail
       AND shoelace_data.sl_name = 'sl7';

    UPDATE shoelace_data SET sl_avail = 6
     WHERE sl_name = 'sl7';
</programlisting>

<para>
    <!-- 
    These are executed in this order and that is exactly what
    the rule defines. The substitutions and the qualifications
    added ensure that if the original query would be, say, -->

    この2つは順番どおりに処理され、正確にルールが定義したとおりです。追加された置換と条件はオリジナルの問い合わせが下記のようであったか確認します。
</para>

<programlisting>
    UPDATE shoelace_data SET sl_color = 'green'
     WHERE sl_name = 'sl7';
</programlisting>

<para>
    <!--
    no log entry would get written.  This
    time the original parsetree does not contain a targetlist
    entry for sl_avail, so NEW.sl_avail will get replaced by
    shoelace_data.sl_avail resulting in the extra query -->

    ログには何も項目が書かれません。ここではオリジナルの構文解析ツリーsl_availの目的リスト項目を持たないため、NEW.sl_availがshoelace_data.sl_availに置き換えられて、特別の問い合わせになります。
</para>

<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>

<para>
    <!-- 
    and that qualification will never be true. It will also
    work if the original query modifies multiple rows. So if Al
    would issue the command -->

    そしてその条件は真実ではありえません。もし元の問い合わせが複数の行を変更してもうまくいきます。ですから、たとえばアルが下記のようなコマンドを実行したとします。
</para>

<programlisting>
    UPDATE shoelace_data SET sl_avail = 0
     WHERE sl_color = 'black';
</programlisting>

<para>
    <!-- 
    four rows in fact get updated (sl1, sl2, sl3 and sl4).
    But sl3 already has sl_avail = 0. This time, the original
    parsetrees qualification is different and that results
    in the extra parsetree -->
    この場合、実際には4行が更新されます（sl1、sl2、sl3、sl4）。しかしs13はすでにsl_avail = 0を持っています。ここでは、元の構文解析ツリーの条件は異なっており、その結果特別の構文解析ツリーが作られます。
</para>

<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>

<para>
    <!-- 
    This parsetree will surely insert three new log entries. And
    that's absolutely correct. -->
    この構文解析ツリーは確実に3つの新しいログ項目を挿入します。これはまったく正しい動作です。
 
</para>

<para>
    <!-- It is important, that the original parsetree is executed last.
    The <ProductName>Postgres</ProductName> "traffic cop" does
    a command counter increment between the execution of the two
    parsetrees so the second one can see changes made by the first.
    If the UPDATE would have been executed first, all the rows
    are already set to zero, so the logging INSERT
    would not find any row where 0 != shoelace_data.sl_avail. -->

    オリジナルの構文解析ツリーが最後に実行されるということは重要です。<ProductName>Postgres</ProductName>の「交通警官」は、2つの構文解析ツリーの実行の間のコマンドカウンタを増やし、最初のパースツリーが行った変更が2番目のパースツリーから見えるようにします。もしUPDATEが先に実行されたとしたら、すべての行は0にセットされて、0 != shoelace_data.sl_availである行をINSERTの段階で見つけられなくなります。

</para>
</Sect3>

</Sect2>

<Sect2>
<!-- <Title>Cooperation with Views</Title> -->
<Title>ビューとの協調</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="びゅーとのきょうちょう">ビューとの強調</secondary></indexterm><indexterm><primary sortas="びゅー">ビュー</primary><secondary sortas="るーるとのきょうちょう">ルールとの強調</secondary></indexterm>
<para>
    <!-- A simple way to protect view relations from the mentioned
    possibility that someone can try to INSERT, UPDATE and DELETE
    on them is to let those parsetrees get
    thrown away. We create the rules -->

    どこかのユーザーが見えないデータに対しINSERT、UPDATE、DELETEを発行するといった、前に述べた可能性からビューリレーションを守る簡単な方法は、それらの構文解析ツリーを破棄してしまうことです。ルールを作ります。
</para>

<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>

<para>
    <!-- 
    If Al now tries to do any of these operations on the view
    relation <Filename>shoe</Filename>, the rule system will
    apply the rules. Since the rules have
    no actions and are INSTEAD, the resulting list of
    parsetrees 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. -->

    アルがビューのリレーション<Filename>shoe</Filename>に上記の操作を加えようとすると、ルールシステムはルールを適用します。ルールにはアクションがなくINSTEADですから、結果の構文解析ツリーリストは空で、ルールシステムの処理が完了した後に最適化されるものや実行されるべきものが何も残っていませんので、すべての問い合わせは無効となります。
</para>

    <Note>
    <!-- <Title>Note</Title> -->
    <!--<Title>注意</Title>-->
    <para>
    <!-- This way might irritate frontend applications because
    absolutely nothing happened on the database and thus, the
    backend will not return anything for the query. Not
    even a PGRES_EMPTY_QUERY will be available in libpq.
    In psql, nothing happens. This might change in the future. -->

    この事実はデータベースに何の変化ももたらさず、したがってバックエンドは問い合わせに対する回答を何も返さないため、フロントエンドアプリケーションが問題を起こす可能性があります。libpqではPGRES_EMPTY_QUERYさえも返却されません。psqlでは何も起こりません。これは将来変更されるかもしません。

    </para>
    </Note>


<para>
    <!-- A more sophisticated way to use the rule system is to
    create rules that rewrite the parsetree into one that
    does the right operation on the real tables. To do that
    on the <Filename>shoelace</Filename> view, we create
    the following rules: -->

    より洗練されたルールシステムの使用法は、実テーブルに適当な操作を行うパースツリーへの書き換えを行うルールを作ることです。<Filename>shoelace</Filename>ビューにこのことを適用するため以下のルールを作ります。
</para>

<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>
    <!-- 
    Now there is a pack of shoelaces arriving in Al's shop and it has
    a big partlist. Al is not that good in calculating and so
    we don't want him to manually update the shoelace view.
    Instead we setup two little tables, one where he can
    insert the items from the partlist and one with a special
    trick. The create commands for these are: -->

    ここでアルの店に靴紐のケースが分厚い送り状とともに届けられました。アルは計算が得意でないので、shoelaceのビューの更新を手作業でさせるわけにはいきません。代わりに、送り状から品目を挿入するテーブルと特殊な仕掛けのテーブルの2つの小さなテーブルを用意しました。それらのcreateコマンドは以下です。
</para>

<programlisting>
    CREATE TABLE shoelace_arrive (
        arr_name    char(10),
        arr_quant   integer
    );

    CREATE TABLE shoelace_ok (
        ok_name     char(10),
        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>

<para>
    <!-- Now Al can sit down and do whatever until -->
    アルのすることは特にないので、以下の結果を入手するまでは何をしていても構いません。
</para>

<programlisting>
    al_bundy=> <userinput>SELECT * FROM shoelace_arrive;</userinput>
    arr_name  |arr_quant
    ----------+---------
    sl3       |       10
    sl6       |       20
    sl8       |       20
    (3 rows)
</programlisting>

<para>
    <!-- is exactly what's on the part list. We take a quick look
    at the current data, -->
    結果は送り状に記載されたものとまったく同じになっています。現在のデータをちょっと見てみましょう。
</para>

<programlisting>
    al_bundy=> <userinput>SELECT * FROM shoelace;</userinput>
    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       |       6|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)
</programlisting>

<para>
   <!--  move the arrived shoelaces in -->
   入荷した靴紐のデータを移動させます。
</para>

<programlisting>
    al_bundy=> <userinput>INSERT INTO shoelace_ok SELECT * FROM shoelace_arrive;</userinput>
</programlisting>

<para>
    <!-- and check the results -->
    そして結果をチェックします。
</para>

<programlisting>
    al_bundy=> <userinput>SELECT * FROM shoelace ORDER BY sl_name;</userinput>
    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       |       6|brown     |    60|cm      |       60
    sl4       |       8|black     |    40|inch    |    101.6
    sl3       |      10|black     |    35|inch    |     88.9
    sl8       |      21|brown     |    40|inch    |    101.6
    sl5       |       4|brown     |     1|m       |      100
    sl6       |      20|brown     |   0.9|m       |       90
    (8 rows)

    al_bundy=> <userinput>SELECT * FROM shoelace_log;</userinput>
    sl_name   |sl_avail|log_who|log_when
    ----------+--------+-------+--------------------------------
    sl7       |       6|Al     |Tue Oct 20 19:14:45 1998 MET DST
    sl3       |      10|Al     |Tue Oct 20 19:25:16 1998 MET DST
    sl6       |      20|Al     |Tue Oct 20 19:25:16 1998 MET DST
    sl8       |      21|Al     |Tue Oct 20 19:25:16 1998 MET DST
    (4 rows)
</programlisting>

<para>
    <!-- It's a long way from the one INSERT ... SELECT to these
    results. And its description will be the last in this
    document (but not the last example :-). First there was the parsers output
    -->
    1つのINSERT ... SELECTから3つの結果まで長い道のりでした。このドキュメントでの解説はこれが最後です（最後の例ではありませんが）。始めにパーサーの出力があります。
</para>

<programlisting>
    INSERT INTO shoelace_ok SELECT
           shoelace_arrive.arr_name, shoelace_arrive.arr_quant
      FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok;
</programlisting>

<para>
    <!-- Now the first rule 'shoelace_ok_ins' is applied and turns it
    into -->
    最初のルール「shoelace_ok_ins」が適用され、結果は以下のようになります。
</para>

<programlisting>
    UPDATE shoelace SET
           sl_avail = int4pl(shoelace.sl_avail, shoelace_arrive.arr_quant)
      FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
           shoelace_ok *OLD*, shoelace_ok *NEW*,
           shoelace shoelace
     WHERE bpchareq(shoelace.sl_name, showlace_arrive.arr_name);
</programlisting>

<para>
    <!--
    and throws away the original INSERT on <Filename>shoelace_ok</Filename>.
    This rewritten query is passed to the rule system again and
    the second applied rule 'shoelace_upd' produced -->
    そして、<Filename>shoelace_ok</Filename>に対する元のINSERTを破棄します。この書き換えられた問い合わせは再びルールシステムに渡されて、2番目に適用される「shoelace_upd」ルールが生成されました。
</para>

<programlisting>
    UPDATE shoelace_data SET
           sl_name = shoelace.sl_name,
           sl_avail = int4pl(shoelace.sl_avail, shoelace_arrive.arr_quant),
           sl_color = shoelace.sl_color,
           sl_len = shoelace.sl_len,
           sl_unit = shoelace.sl_unit
      FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
           shoelace_ok *OLD*, shoelace_ok *NEW*,
           shoelace shoelace, shoelace *OLD*,
           shoelace *NEW*, shoelace_data showlace_data
     WHERE bpchareq(shoelace.sl_name, showlace_arrive.arr_name)
       AND bpchareq(shoelace_data.sl_name, shoelace.sl_name);
</programlisting>

<para>
    <!-- 
    Again it's an INSTEAD rule and the previous parsetree is trashed.
    Note that this query still uses the view <Filename>shoelace</Filename>.
    But the rule system isn't finished with this loop so it continues
    and applies the rule '_RETshoelace' on it and we get -->

    再びINSTEADルールで、以前の構文解析ツリーは破棄されます。この問い合わせはビュー<Filename>shoelace</Filename>を引き続き使用しますが、このループによるルールシステムは終了していないのでルール「_RETshoelace」の摘要を継続して下記を得ます。
</para>

<programlisting>
    UPDATE shoelace_data SET
           sl_name = s.sl_name,
           sl_avail = int4pl(s.sl_avail, shoelace_arrive.arr_quant),
           sl_color = s.sl_color,
           sl_len = s.sl_len,
           sl_unit = s.sl_unit
      FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
           shoelace_ok *OLD*, shoelace_ok *NEW*,
           shoelace shoelace, shoelace *OLD*,
           shoelace *NEW*, shoelace_data showlace_data,
           shoelace *OLD*, shoelace *NEW*,
           shoelace_data s, unit u
     WHERE bpchareq(s.sl_name, showlace_arrive.arr_name)
       AND bpchareq(shoelace_data.sl_name, s.sl_name);
</programlisting>

<para>
    <!-- 
    Again an update rule has been applied and so the wheel
    turns on and we are in rewrite round 3. This time rule
    'log_shoelace' gets applied what produces the extra
    parsetree -->
    再度更新ルールが適用されました。方向転換をして書き換え第3ラウンドに突入です。ここではルール「log_shoelace」が特別の構文解析ツリーを生成したものに適用されます。
</para>

<programlisting>
    INSERT INTO shoelace_log SELECT
           s.sl_name,
           int4pl(s.sl_avail, shoelace_arrive.arr_quant),
           current_user,
           current_timestamp
      FROM shoelace_arrive shoelace_arrive, shoelace_ok shoelace_ok,
           shoelace_ok *OLD*, shoelace_ok *NEW*,
           shoelace shoelace, shoelace *OLD*,
           shoelace *NEW*, shoelace_data showlace_data,
           shoelace *OLD*, shoelace *NEW*,
           shoelace_data s, unit u,
           shoelace_data *OLD*, shoelace_data *NEW*
           shoelace_log shoelace_log
     WHERE bpchareq(s.sl_name,  showlace_arrive.arr_name)
       AND bpchareq(shoelace_data.sl_name, s.sl_name);
       AND int4ne(int4pl(s.sl_avail, shoelace_arrive.arr_quant),
                                                    s.sl_avail);
</programlisting>

<para>
   <!--  
    After that the rule system runs out of rules and returns the 
    generated parsetrees.
    So we end up with two final parsetrees that are equal to the
    <Acronym>SQL</Acronym> statements -->
    その後、ルールシステムはルールを使いきって生成された構文解析ツリーを返します。そして、<Acronym>SQL</Acronym>文と同じ2つの最終構文解析ツリーで終結します。
</para>

<programlisting>
    INSERT INTO shoelace_log SELECT
           s.sl_name,
           s.sl_avail + shoelace_arrive.arr_quant,
           current_user,
           current_timestamp
      FROM shoelace_arrive shoelace_arrive, shoelace_data shoelace_data,
           shoelace_data s
     WHERE s.sl_name = shoelace_arrive.arr_name
       AND shoelace_data.sl_name = s.sl_name
       AND s.sl_avail + shoelace_arrive.arr_quant != s.sl_avail;
           
    UPDATE shoelace_data SET
           sl_avail = shoelace_data.sl_avail + shoelace_arrive.arr_quant
     FROM shoelace_arrive shoelace_arrive,
          shoelace_data shoelace_data,
          shoelace_data s
    WHERE s.sl_name = shoelace_arrive.sl_name
      AND shoelace_data.sl_name = s.sl_name;
</programlisting>

<para>
    <!-- 
    The result is that data coming from one relation inserted into another,
    changed into updates on a third, changed into updating
    a fourth plus logging that final update in a fifth
    gets reduced into two queries. -->
    結果は、1つのリレーションから来たデータが別のリレーションに挿入され、3つ目のリレーションの更新に変更され、4つ目のために更新され、5つ目の最終更新のログ記録となって、最終的に2つの問い合わせに縮小されます。

</para>

<para>
    <!-- 
    There is a little detail that's a bit ugly. Looking at
    the two queries turns out, that the <Filename>shoelace_data</Filename>
    relation appears twice in the rangetable where it could definitely
    be reduced to one. The planner does not handle it and so the
    execution plan for the rule systems output of the INSERT will be
    -->
    ちょっと見苦しい小さな事項があります。できてきた2つの問い合わせを見ると、1つに縮小されたはずの<Filename>shoelace_data</Filename>リレーションが範囲テーブルに2度出てきます。オプティマイザは処理をしないので、INSERTのルールシステムの出力に対する実行プランは次のようになります。
</para>

<programlisting>
<!-- Nested Loop
  ->  Merge Join
        ->  Seq Scan
              ->  Sort
                    ->  Seq Scan on s
        ->  Seq Scan
              ->  Sort
                    ->  Seq Scan on shoelace_arrive
  ->  Seq Scan on shoelace_data -->
ネストしたループ
  ->  マージ結合
        ->  順スキャン
              ->  ソート
                    ->  s を順スキャン
        ->  順スキャン
              ->  ソート
                    ->  shoelace_arrive を順スキャン
  ->  shoelace_data を順スキャン
</programlisting>

<para>
    <!-- while omitting the extra rangetable entry would result in a -->
    一方特別な範囲テーブル項目を落すことで以下のようにログリレーションにまったく同じ項目が作られます。
</para>

<!-- <programlisting>
Merge Join
  ->  Seq Scan
        ->  Sort
              ->  Seq Scan on s
  ->  Seq Scan
        ->  Sort
              ->  Seq Scan on shoelace_arrive
</programlisting>

    that totally produces the same entries in the log relation.
    Thus, the rule system caused one extra scan on the
    <Filename>shoelace_data</Filename> relation that is
    absolutely not necessary. And the same obsolete scan
    is done once more in the UPDATE. But it was a really hard
    job to make that all possible at all. -->

<programlisting>
マージ結合
  ->  順スキャン
        ->  ソート
              ->  s を順スキャン
  ->  順スキャン
        ->  ソート
              ->  shoelace_arrive を順スキャン
</programlisting>   

<para>
   ですから、ルールシステムはまったく必要のない<Filename>shoelace_data</Filename>リレーションに対する1つの特別なスキャンを行うことになります。そしてUPDATEでも同様な不用のスキャンが再度実行されます。しかしながら、これらをすべて可能にするのは大変な仕事です。

</para>

<para>
    <!-- 
    A final demonstration of the <ProductName>Postgres</ProductName>
    rule system and its power. There is a cute blonde that
    sells shoelaces. And what Al could never realize, she's not
    only cute, she's smart too - a little too smart. Thus, it
    happens from time to time that Al orders shoelaces that
    are absolutely not sellable. This time he ordered 1000 pairs
    of magenta shoelaces and since another kind is currently not
    available but he committed to buy some, he also prepared
    his database for pink ones. -->

    最後に<ProductName>Postgres</ProductName>のルールシステムとその効力を示しましょう。靴紐を売っている可愛いブロンドの女の子がいます。アルがわかっていないことは、彼女は可愛いだけでなくとても賢いということです。ちょっと賢すぎるほどなのです。ですから、ときとしてアルはまったく売れない靴紐を注文してしまいます。今回はマゼンタ色の靴紐1,000組を注文しましたし、他の種類が現在在庫にないので、それは後で購入する約束までしました。データベースにはピンクの靴紐を用意しました。
</para>

<programlisting>
    al_bundy=> <userinput>INSERT INTO shoelace VALUES </userinput>
    al_bundy->     <userinput>('sl9', 0, 'pink', 35.0, 'inch', 0.0);</userinput>
    al_bundy=> <userinput>INSERT INTO shoelace VALUES </userinput>
    al_bundy->     <userinput>('sl10', 1000, 'magenta', 40.0, 'inch', 0.0);</userinput>
</programlisting>

<para>
    <!-- 
    Since this happens often, we must lookup for shoelace entries,
    that fit for absolutely no shoe sometimes. We could do that in
    a complicated statement every time, or we can setup a view
    for it. The view for this is -->
    こんなことがたびたび起こるので、お店にない靴用の靴紐の項目を見なくてはなりません。毎回複雑な構文を打ち込むか、またはビューを作ります。ビューはこうなります。
</para>

<programlisting>
    CREATE VIEW shoelace_obsolete AS
        SELECT * FROM shoelace WHERE NOT EXISTS
            (SELECT shoename FROM shoe WHERE slcolor = sl_color);
</programlisting>

<para>
    <!-- Its output is -->
    その出力は以下となります。
</para>

<programlisting>
    al_bundy=> <userinput>SELECT * FROM shoelace_obsolete;</userinput>
    sl_name   |sl_avail|sl_color  |sl_len|sl_unit |sl_len_cm
    ----------+--------+----------+------+--------+---------
    sl9       |       0|pink      |    35|inch    |     88.9
    sl10      |    1000|magenta   |    40|inch    |    101.6
</programlisting>

<para>
   <!-- 
    For the 1000 magenta shoelaces we must debt Al before we can
    throw 'em away, but that's another problem. The pink entry we delete.
    To make it a little harder for <ProductName>Postgres</ProductName>,
    we don't delete it directly. Instead we create one more view -->

    1,000組のマゼンタ色の靴紐を捨てる前にアルに債務をおわせなければなりませんが、それは別の問題です。ピンクの項目を削除します。<ProductName>Postgres</ProductName>でちょっと面倒なことは、直接削除をしないということです。代わりにもう1つ別のビューを作ります。
</para>

<programlisting>
    CREATE VIEW shoelace_candelete AS
        SELECT * FROM shoelace_obsolete WHERE sl_avail = 0;
</programlisting>

<para>
<!--     and do it this way: -->
    そしてこのようにします。
</para>

<programlisting>
    DELETE FROM shoelace WHERE EXISTS
        (SELECT * FROM shoelace_candelete
                 WHERE sl_name = shoelace.sl_name);
</programlisting>

<para>
    <!-- Voila: -->
    さあ、できました。
</para>

<programlisting>
    al_bundy=> <userinput>SELECT * FROM shoelace;</userinput>
    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       |       6|brown     |    60|cm      |       60
    sl4       |       8|black     |    40|inch    |    101.6
    sl3       |      10|black     |    35|inch    |     88.9
    sl8       |      21|brown     |    40|inch    |    101.6
    sl10      |    1000|magenta   |    40|inch    |    101.6
    sl5       |       4|brown     |     1|m       |      100
    sl6       |      20|brown     |   0.9|m       |       90
    (9 rows)
</programlisting>

<para>
    <!-- A DELETE on a view, with a subselect qualification that
    in total uses 4 nesting/joined views, where one of them
    itself has a subselect qualification containing a view
    and where calculated view columns are used,
    gets rewritten into 
    one single parsetree that deletes the requested data
    from a real table. -->

    ビュー上での合計4つのネスト/結合されたビューで、その中の1つはビューを含むsubselect条件があって、かつ演算を施されたビューのカラムが使われる場合、subselect条件のついたビューへのDELETEは実テーブルから、要求されたデータを削除する単一の構文解析ツリーに書き換えられます。

</para>

<para>
    <!-- I think there are only a few situations out in the real
    world, where such a construct is necessary. But
    it makes me feel comfortable that it works. -->

    このような構造が必要な状況は実社会ではほとんどないと思われますが、実際に動くことを確認できれば安心できます。
</para>

<!--
    <Note>
    <!&bsol;-&bsol;- <Title>The truth is</Title> &bsol;-&bsol;->
    <Title>裏話</Title>
    <para>
    <!&bsol;-&bsol;- Doing this I found one more bug while writing this document.
    But after fixing that I was a little amazed that it works at all. &bsol;-&bsol;->
    このドキュメントを書きながらこのようなことをしていて、もう1つのバグを見つけました。バグを修正するとちゃんと動いたので驚きました。
    </para>
    </Note>
-->
</Sect2>

</Sect1>

<Sect1 id="rules-permissions">
<!-- <Title>Rules and Permissions</Title> -->
<Title>ルールと権限</Title>
<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="けんげん">権限</secondary></indexterm>
<para>
    <!-- 
    Due to rewriting of queries by the <ProductName>Postgres</ProductName>
    rule system, other tables/views than those used in the original
    query get accessed. Using update rules, this can include write access
    to tables. -->

    <ProductName>Postgres</ProductName>のルールシステムによる問い合わせの書き換えによって、オリジナルの問い合わせで使われたものではない他のテーブル/ビューがアクセスされます。更新ルールを使うことによってテーブルへの書き込みアクセスを包含することができます。

</para>

<para>
    <!-- Rewrite rules don't have a separate owner. The owner of
    a relation (table or view) is automatically the owner of the
    rewrite rules that are defined for it.
    The <ProductName>Postgres</ProductName> rule system changes the
    behaviour of the default access control system. Relations that
    are used due to rules get checked against the
    permissions of the rule owner, not the user invoking the rule.
    This means, that a user does only need the required permissions
    for the tables/views he names in his queries.  -->

    書き換えルールに別々の所有者はいません。リレーション（テーブルまたはビュー）の所有者は自動的にそれを定義した書き換えルールの所有者となります。<ProductName>Postgres</ProductName>のルールシステムはデフォルトのアクセス制御システムの振る舞いを変更します。ルールが適用されるリレーションはルール所有者のパーミッションでチェックされます。ルールを起動したユーザーのパーミッションではありません。このことは、ユーザーは問い合わせで記述するテーブル/ビューに対してのパーミッションだけあればよいことを示しています。<indexterm><primary sortas="るーる">ルール</primary><secondary sortas="しょゆうしゃ">所有者</secondary></indexterm>

</para>

<para>
    <!-- For example: A user has a list of phone numbers where some of
    them are private, the others are of interest for the secretary of the office.
    He can construct the following: -->

    たとえば、あるユーザーがいくつかは個人的な、その他は事務所で秘書が利用する電話番号のリストを持っていたとします。そのユーザーは次のようにして構築することができます。
</para>

<programlisting>
    CREATE TABLE phone_data (person text, phone text, private bool);
    CREATE VIEW phone_number AS
        SELECT person, phone FROM phone_data WHERE NOT private;
    GRANT SELECT ON phone_number TO secretary;
</programlisting>

<para>
    <!-- Nobody except him (and the database superusers) can access the
    phone_data table. But due to the GRANT, the secretary can SELECT from the
    phone_number view. The rule system will rewrite
    the SELECT from phone_number into a SELECT from phone_data and add the qualification
    that only entries where private is false are wanted. Since the
    user is the owner of phone_number, the read access to phone_data
    is now checked against his permissions and the query is considered
    granted. The check for accessing phone_number is also performed,
    but this is done against the invoking user, so nobody but the user and the
    secretary can use it. -->

    そのユーザー（とデータベースのスーパーユーザー）以外はphone_dataテーブルにアクセスできません。しかし、GRANTにより秘書はphone_numberビューに対しSELECT fromできます。ルールシステムはSELECT from phone_numberをSELECT from phone_dataに書き換え、privateが偽となっている項目のみを使用するという条件を付け加えます。そのユーザーはphone_numberの所有者ですから、phone_dataの読み込みに対するアクセスはそのユーザーのパーミッションにしたがってチェックされ、問い合わせを受け付けてもよいことになります。phone_numberへのアクセスはチェックされ続けられますので、秘書とユーザー以外は使うことができません。

</para>

<para>
    <!--
    The permissions are checked rule by rule. So the secretary is for now the
    only one who can see the public phone numbers. But the secretary can setup
    another view and grant access to that to public. Then, anyone
    can see the phone_number data through the secretaries view.
    What the secretary cannot do is to create a view that directly
    accesses phone_data (actually he can, but it will not work since
    every access aborts the transaction during the permission checks).
    And as soon as the user will notice, that the secretary opened
    his phone_number view, he can REVOKE his access. Immediately any
    access to the secretaries view will fail. -->

    パーミッションはルールごとにチェックされます。ですから秘書だけが今のところ一般の電話番号を参照することができます。しかし、秘書が別のビューを作成し、それを一般にたいしアクセス許可を与えれば、秘書のビューを通して誰もがphone_numberデータを見ることができます。秘書ができないことはphone_dataに直接アクセスするビューを作ることです（実際にはできますが、それぞれのアクセスについてのパーミッションチェックでトランザクションがアボートします）。そしてユーザーが気づいた時点で、秘書が開いたphone_numberビューを秘書からREVOKEできます。秘書のビューへのアクセスは即座に失敗に終わります。

</para>

<para>
   <!-- 
    Someone might think that this rule by rule checking is a security
    hole, but in fact it isn't. If this would not work, the secretary
    could setup a table with the same columns as phone_number and
    copy the data to there once per day. Then it's his own data and
    he can grant access to everyone he wants. A GRANT means "I trust you".
    If someone you trust does the thing above, it's time to
    think it over and then REVOKE. -->

    このルールごとのチェックがセキュリティホールになると考える人がいるかも知れませんが、実際にはそうではありません。もし機能しないと秘書は1日1回phone_numberと同じカラムを持ったテーブルを用意して、データをそこにコピーしなければなりません。データはそのユーザーのものですから、誰にアクセス権をを与えようが彼の自由です。GRANTは「あなたを信用しています」ということです。信用している誰かがこのようなことを行った場合は、考えを変えてREVOKEすることです。

</para>

<para>
    <!-- 
    This mechanism does also work for update rules. In the examples
    of the previous section, the owner of the tables in Al's database
    could GRANT SELECT, INSERT, UPDATE and DELETE on the shoelace view to al.
    But only SELECT on shoelace_log. The rule action to write log entries
    will still be executed successfully. And Al could see the log entries.
    But he cannot create fake entries, nor could he manipulate or remove
    existing ones. -->

    この機構は更新ルールにも適用できます。前節の例において、アルのデータベースの所有者はshoelaceビューにたいし、誰もがGRANT SELECT、INSERT、UPDATE、DELETEができました。しかし、shoelace_logに対してはSELECTだけです。ログ項目を書き込むルールアクションは支障なく実行されているでしょう。アルはログ項目を見ることができますが、項目を捏造したり、すでに存在する項目を操作したりあるいは削除することはできません。
</para>

    <warning>
    <!-- <Title>Warning</Title> -->
    <!--<Title>警告</Title>-->
    <para>
    <!-- GRANT ALL currently includes RULE permission. This means the granted
    user could drop the rule, do the changes and reinstall it. I think
    this should get changed quickly. -->

    現在GRANT ALLにはRULEパーミッションが含まれています。ということは、認可されたユーザーはルールを消去したり、変更したりまた再インストールすることができます。著者はこれが早急に変更されるべきと考えます。

    </para>
    </warning>
</Sect1>

<Sect1 id="rules-triggers">
<!-- <Title>Rules versus Triggers</Title> -->
<Title>ルール対トリガ</Title>

<para>
    <!--Many things that can be done using triggers can also be
    implemented using the <ProductName>Postgres</ProductName>
    rule system. What currently cannot be implemented by
    rules are some kinds of constraints. It is possible,
    to place a qualified rule that rewrites a query to NOTHING
    if the value of a column does not appear in another table.
    But then the data is silently thrown away and that's
    not a good idea. If checks for valid values are required,
    and in the case of an invalid value an error message should
    be generated, it must be done by a trigger for now. -->

    トリガによって行われる多くの操作は<ProductName>Postgres</ProductName>のルールシステムで実装可能です。現在実際にルールで実装できないものはある種の制約に関してです。もし他のテーブルにカラム値がなかった場合、条件ルールで問い合わせをNOTHINGに書き換えてしまうことも可能ですが、これではデータがだまって消去されてしまい、よいアイディアとはいえません。有効な値かどうかのチェックが必要で、無効な値についてはエラーメッセージを表示する必要があるなら、このことは今のところトリガを使って行わなければなりません。

</para>

<para>
    <!-- On the other hand a trigger that is fired on INSERT 
    on a view can do the same as a rule, put the data somewhere
    else and suppress the insert in the view. But it cannot
    do the same thing on UPDATE or DELETE, because there is
    no real data in the view relation that could be scanned
    and thus the trigger would never get called. Only a rule
    will help. -->

    一方、ビュー上でINSERTによって起動されたトリガは、データをどこかに退避させ、ビューへの挿入を禁止するルールと同じことができます。しかしUPDATEまたはDELETEではスキャンされる実データがビューリレーションに存在しないのでトリガが呼ばれることがない点で相違しています。ルールで解決するしかありません。


</para>

<para>
    <!-- For the things that can be implemented by both,
    it depends on the usage of the database, which is the best.
    A trigger is fired for any row affected once. A rule manipulates
    the parsetree or generates an additional one. So if many
    rows are affected in one statement, a rule issuing one extra
    query would usually do a better job than a trigger that is
    called for any single row and must execute his operations
    this many times. -->

    いずれによっても実装されるこれらの機能に関してどちらがベストかはデータベースの使用法によります。トリガはどの行にたいしても一度だけ起動します。ルールはパースツリーを操作するか追加のパースツリーを生成します。ですから、1つの命令文が多くの行に影響を与える場合、1つの行を処理するたびに呼び出し操作の実行を何回も行わなければならないトリガよりも、1つの別の問い合わせを発行するルールのほうが通常よい働きをします。

</para>

<para>
    <!-- For example: There are two tables -->
    たとえば、2つのテーブルがあるとします。
</para>


<programlisting>
    CREATE TABLE computer (
        hostname        text,    -- indexed
        manufacturer    text     -- indexed
    );

    CREATE TABLE software (
        software        text,    -- indexed
        hostname        text     -- indexed
    );
</programlisting>

<para>
    <!-- Both tables have many
    thousands of rows and the index on hostname is unique.
    The hostname column contains the full qualified domain
    name of the computer. The rule/trigger should constraint
    delete rows from software that reference the deleted host.
    Since the trigger is called for each individual row
    deleted from computer, it can use the statement -->

    2つのテーブルには共に数千の行があって、hostname上の索引は一意です。hostnameのカラムにはコンピュータのFQDN（絶対ドメイン名）があります。ルール/トリガは削除されたホストを参照するsoftwareによる行削除を制限しなければなりません。トリガはcomputerから削除されたそれぞれの独立した行で呼び出されますので、以下のような命令文を、準備され保存されたプランの中で使用し、パラメータ中にhostnameを引き渡すことができます。
</para>

<programlisting>
    DELETE FROM software WHERE hostname = $1;
</programlisting>

<para>
    <!-- in a prepared and saved plan and pass the hostname in
    the parameter. The rule would be written as -->

    このときのルールは以下のように書き表すことができます。
</para>

<programlisting>
    CREATE RULE computer_del AS ON DELETE TO computer
        DO DELETE FROM software WHERE hostname = OLD.hostname;
</programlisting>

<para>
    <!-- Now we look at different types of deletes. In the case of a -->
    ここで、異なった種類の削除について見てみましょう。 
 </para>

<programlisting>
    DELETE FROM computer WHERE hostname = 'mypc.local.net';
</programlisting>

<para>
   <!--  the table computer is scanned by index (fast) and the
    query issued by the trigger would also be an index scan (fast too).
    The extra query from the rule would be a -->

    この場合、テーブルcomputerはインデックスでスキャンされ（高速です）、トリガによって発行された問い合わせも同様インデックススキャンとなります（これも高速です）。ルールからの特別の問い合わせは以下のようになります。
</para>

<programlisting>
    DELETE FROM software WHERE computer.hostname = 'mypc.local.net'
                           AND software.hostname = computer.hostname;
</programlisting>

<para>
    <!-- Since there are appropriate indices setup, the planner
    will create a plan of -->

    そこには適切なインデックスが用意されているので、プランナは以下のプランを生成します。
</para>


<programlisting>
    <!-- Nestloop
      ->  Index Scan using comp_hostidx on computer
      ->  Index Scan using soft_hostidx on software -->
    ネストしたループ
      ->  computer 上で comp_hostidx を使ったインデックススキャン
      ->  software 上で soft_hostidx を使ったインデックススキャン
</programlisting>

<para>
    <!-- So there would be not that much difference in speed between
    the trigger and the rule implementation. With the next delete
    we want to get rid of all the 2000 computers where the hostname starts
    with 'old'. There are two possible queries to do that. One is -->

    トリガとルール実装の間で処理速度の差はそれほどはないでしょう。次の削除処理ではhostnameが「old」で始まる2,000台すべてのcomputerを削除しようと思います。方法として2つの有効な問い合わせがあって、1つは 以下のようなものです。
</para>

<programlisting>
    DELETE FROM computer WHERE hostname >= 'old'
                           AND hostname <  'ole'
</programlisting>

<para>
    <!-- Where the plan for the rule query will be a -->
     ここで問い合わせのルールに対するプランは以下のようなものです。
</para>

<programlisting>
    <!-- Hash Join
      ->  Seq Scan on software
      ->  Hash
	    ->  Index Scan using comp_hostidx on computer -->
    ハッシュ結合
      ->  software 上で順スキャン
      ->  ハッシュ
           -> computer 上で comp_hostidx を使ったインデックススキャン
</programlisting>

<para>
    <!-- The other possible query is a -->
    もう1つの可能な問い合わせは以下のようなものです。
</para>

<programlisting>
    DELETE FROM computer WHERE hostname ~ '^old';
</programlisting>

<para>
    <!-- with the execution plan -->
    これは以下の実行プランを持っています。
</para>

<programlisting>
<!--     Nestloop
      ->  Index Scan using comp_hostidx on computer
      ->  Index Scan using soft_hostidx on software -->
   ネストしたループ
      ->  computer 上で comp_hostidx を使ったインデックススキャン
      ->  software 上で soft_hostidx を使ったインデックススキャン   
</programlisting>

<para>
    <!-- This shows, that the planner does not realize that the
    qualification for the hostname on computer could also be
    used for an index scan on software when there are
    multiple qualification expressions combined with AND, what
    he does in the regexp version of the query. The trigger will
    get invoked once for any of the 2000 old computers that
    have to be deleted and that will result in one index scan
    over computer and 2000 index scans for the software. The
    rule implementation will do it with two queries over indices.
    And it depends on the overall size of the software table if
    the rule will still be faster in the seqscan situation. 2000
    query executions over the SPI manager take some time, even
    if all the index blocks to look them up will soon appear in
    the cache. -->

    これが示していることは、プランナは、regexpバージョンでは行った、ANDで結合された複数の検索条件が存在する場合computer上のhostnameに対する検索条件で、software上のインデックススキャンにも同様に使用できることを、わかっていないということです。トリガは削除されるべき2,000台の旧式コンピュータのいずれかによって1回呼び出され、結果computer上で1回のインデックススキャンとsoftwareに対して2,000回のインデックススキャンが行われます。ルールの実装ではインデックス上で2つの問い合わせによって実行されます。逐次スキャンでもルールがより速いかどうかはsoftwareテーブルの大きさに依存します。参照するすべてのインデックスブロックが間もなくキャッシュに現れるとしても、SPIマネージャに対する2,000回の問い合わせの実行には時間を要します。

</para>

<para>
    <!-- The last query we look at is a -->
    最後の問い合わせを見てみましょう。
</para>

<programlisting>
    DELETE FROM computer WHERE manufacurer = 'bim';
</programlisting>

<para>
    <!-- Again this could result in many rows to be deleted from
    computer. So the trigger will again fire many queries into
    the executor. But the rule plan will again be the Nestloop over
    two IndexScan's. Only using another index on computer: -->

    この文でもcomputerからたくさんの行が削除される結果となります。ここでもトリガはエクゼキュータの実行中に多くの問い合わせを起動することになります。ルールプランもまた前回同様2つのインデックススキャンのネストループとなります。computerの別のインデックスを使えば、以下のようになります。
</para>

<programlisting>
<!--     Nestloop
      ->  Index Scan using comp_manufidx on computer
      ->  Index Scan using soft_hostidx on software -->
   ネストループ
      ->  computer に対して comp_manufidx を使用したインデックススキャン
      ->  software に対して soft_hostidx を使用したインデックススキャン 
</programlisting>

<para>
    <!-- resulting from the rules query -->
    これらのルール問い合わせの結果は、以下のようなものです。
</para>

<programlisting>
    DELETE FROM software WHERE computer.manufacurer = 'bim'
                           AND software.hostname = computer.hostname;
</programlisting>

<para>
    <!-- 
    In any of these cases, the extra queries from the rule system will be
    more or less independent from the number of affected rows
    in a query. -->

    いずれの場合においても、ルールシステムが生成する余分な問い合わせは影響を受ける行数からは多かれ少なかれ独立しています。
 
</para>

<para>
    <!-- 
    Another situation is cases on UPDATE where it depends on the
    change of an attribute if an action should be performed or
    not. In <ProductName>Postgres</ProductName> version 6.4, the
    attribute specification for rule events is disabled (it will have
    its comeback latest in 6.5, maybe earlier 
    - stay tuned). So for now the only way to
    create a rule as in the shoelace_log example is to do it with
    a rule qualification. That results in an extra query that is
    performed always, even if the attribute of interest cannot
    change at all because it does not appear in the targetlist
    of the initial query. When this is enabled again, it will be
    one more advantage of rules over triggers. Optimization of
    a trigger must fail by definition in this case, because the
    fact that its actions will only be done when a specific attribute
    is updated is hidden in its functionality. The definition of
    a trigger only allows to specify it on row level, so whenever a
    row is touched, the trigger must be called to make its
    decision. The rule system will know it by looking up the
    targetlist and will suppress the additional query completely
    if the attribute isn't touched. So the rule, qualified or not,
    will only do its scans if there ever could be something to do. -->

   別の状況として、アクションを実行すべきか否かが変更された属性に依存する、UPDATEの場合があります。<ProductName>Postgres</ProductName> 6.4では、ルールイベントにおける属性指定はできなくなっています（遅くとも6.5あるいはもう少し早くに使えるようになるでしょう。しばらくお待ち下さい）。したがって、現時点でshoelace_logの例のようなルールを作成する唯一の方法は、ルール条件を使用することです。初めの問い合わせの目的リストに出てこないため、これは対象とする属性が変更されなくても常に実行される特別な問い合わせとなります。再度使えるようになった場合はトリガに対するルールのもう1つの強みになります。この場合、トリガの最適化はその定義により不可能です。特定の属性が変更されたときにのみそのアクションを行うという処理自体はその（トリガ）関数内部に隠されているからです。トリガの定義は行レベルのみに対して認められるので、行が触られるとトリガが決定が下せるようにトリガが呼び出されなければなりません。ルールシステムの場合は対象リストを検索することで変更されたかどうかわかりますので、属性が触られていなければその後の問い合わせをすべて中止することができます。条件の有無にかかわらず、ルールは実行しなければならないことがあればスキャンを実行します。

</para>

<para>
    <!-- Rules will only be significantly slower than triggers if
    their actions result in large and bad qualified joins, a situation
    where the planner fails. They are a big hammer.
    Using a big hammer without caution can cause big damage. But
    used with the right touch, they can hit any nail on the head. -->


    問い合わせ結果が大きく、プランナがうまく結合条件を設定できないような状況下でのみルールはトリガに比べて明らかに遅くなります。ルールは大きな金槌のようなもので、注意を怠ると大怪我をしますがうまく使えばどんな釘でもうまく打ち込めるのです。
</para>
</Sect1>

</Chapter>

<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"./reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->
