7.2. 演算子

演算子呼び出しのオペランドの型は以下の手順に従って解決されます。この手順は事前に行われた演算子呼び出しによる直接影響されません。より詳細については Section 1.1.6 を参照して下さい。

演算子型の解決

  1. pg_operator システムカタログから、調査の対象とする演算子を選択します。 修飾されていない演算子名が使用される場合 (通常のケース)、調査の対象となる演算子は、現行の検索パスで可視になっている、名前と引数の数が正しい演算子です。(Section 2.8.3 参照) 修飾された演算子名が与えられている場合、指定されたスキーマの演算子のみを調べることができます。

    1. 検索パスで、引数のデータ型が同じである複数の演算子を検出した場合、そのパスで最初に検出された演算子のみを調べることができます。 ただし、引数のデータ型が異なる演算子は、検索パス内の位置に関係なく、同じように調べられます。

  2. 正確に入力引数型を受け取っている演算子があるかどうかチェックしてください。 該当する演算子があれば (調査される演算子のセット内で正確に一致するものは 1 つしか有り得ません)、それを使用してください。

    1. 二項演算子の1つの引数がunknown型であった場合、このチェックのもう片方の引数と同一の型であると仮定します。他のunknownを含む場合は、この段階では対を見つけることはありません。

  3. 最もよく合うものを検索します。

    1. 演算子の候補のうち、入力値のデータ型が一致せず、また、(暗黙的強制関数を使用して) 一致を強制できないものを破棄してください。 unknown リテラルは、上記の目的で何にでも強制的に変更できるとみなされます。1つの侯補しか残らない場合、それを使います。 それ以外の場合は次の段階に進みます。

    2. すべての侯補を検索し、入力型に最も正確に合うものを残します。正確に合うものが何もなければすべての侯補を残します。1つの侯補しか残らない場合、それを使います。 それ以外の場合は次の段階に進みます。

    3. すべての侯補を検索し、入力型に最も正確に合う、もしくはバイナリ互換性のあるものを残します。もし正確に合うものかバイナリ互換性のあるものがなければすべての侯補を残します。1つの侯補しか残らない場合、それを使います。 それ以外の場合は次の段階に進みます。

    4. すべての侯補を検索し、型強制が要求される最も多くの引数位置で好ましい型を受け入れるものを残します。好ましい型を受け入れるものがなければすべての侯補を残します。1つの侯補しか残らない場合、それを使います。 それ以外の場合は次の段階に進みます。

    5. 入力引数で"unknown"のものがあった場合、それらの残った侯補に引数位置で受け入れられる型カテゴリをチェックします。候補が"文字列"カテゴリを受け付ける場合は、そのカテゴリを選択します。 (unknown 型のリテラルは文字列のようなものですので、この文字列への重みづけは適切です。)そうでなければ、もし残ったすべての侯補が同じ型カテゴリを受け入れる場合はそのカテゴリを選択します。 そうでもなければ失敗します。 なぜならさらに手掛りがなければ正しい選択が演繹されることができないからです。さらに、侯補の中で、選択されたカテゴリ内で好ましい型を受け入れるものがあるかどうか注意します。ここで、選択された型カテゴリを受け付けない演算子候補は破棄されます。 そして、与えられた引数の位置上の好ましい型を受け付ける候補が1つでもある場合、その引数の好ましい型ではないものを受け付ける候補は破棄されます。

    6. 1つの侯補しか残らない場合、それを使います。もし侯補がない、もしくは1つより多い侯補が残る場合は失敗します。

Example 7-1. 指数演算子型の解決

カタログ内に定義された指数演算子は1つだけ存在し、double 精度型の引数をとります。スキャナは、次の問い合わせの式の両方の引数にintegerという初期段階での型を割り当てます。

tgl=> SELECT 2 ^ 3 AS "Exp";
 Exp
-----
   8
(1 row)

ゆえに、パーサは両オペランドに型変換を行い、上の問い合わせは以下の2つのどちらかと同じものになります。

tgl=> SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "Exp";
 Exp
-----
   8
(1 row)

or

tgl=> SELECT 2.0 ^ 3.0 AS "Exp";
 Exp
-----
   8
(1 row)

Note: 暗黙的な型変換を行う関数を呼び出すことがありませんので、最後の形式が最もオーバヘッドの少ないものになります。これは小さな問い合わせでは問題にはなりませんが、大きなテーブルを伴う問い合わせの性能に影響を与える可能性があります。

Example 7-2. 文字列の結合演算子型の解決

文字列のような構文は、文字列型だけではなく、複雑な拡張された型の処理にも使われます。型指定のない文字列は演算子候補と同様の一致がなされます。

1つの引数の型が指定されない引数の例を示します。

tgl=> SELECT text 'abc' || 'def' AS "Text and Unknown";
 Text and Unknown
------------------
 abcdef
(1 row)

この場合、パーサは、textを両引数にとる演算子が存在するかどうかを検索します。これは存在しますので、パーサーは2番目の引数はtext型として解釈すべきであると仮定をします。

引数の型が指定されない引数の例を示します。

tgl=> SELECT 'abc' || 'def' AS "Unspecified";
 Unspecified
-------------
 abcdef
(1 row)

この場合、問い合わせに型が何も指定されていませんので、使用すべき型についてのヒントが初期段階において存在しません。ですので、パーサはすべての侯補となる演算子を検索し、文字列カテゴリとビット文字列カテゴリの両方の入力を受け入れる侯補があることを発見します。有効である場合は文字列カテゴリのほうが好ましいので、そのカテゴリが選択されます。 そして文字列の"好ましい型"であるtextがunknownのリテラルを解決する特定の型として使われます。

Example 7-3. 絶対値と階乗演算子の型解決

PostgreSQL 演算子カタログには、複数の、各種数値データ型の絶対値算出を行う、@ 前置演算子のエントリがあります。その中には、数値カテゴリにおける好ましい型である float8 型用のエントリがあります。そのため、PostgreSQL は数値以外の入力があった場合、このエントリを使用します。

tgl=> select @ text '-4.5' as "abs";
 abs
-----
 4.5
(1 row)

ここでシステムは選択した演算子を適用する前に暗黙的なテキストから float8への変換を行います。以下のようにして他の型ではなく float8 が使用されることを確認することができます。

tgl=> select @ text '-4.5e500' as "abs";
ERROR:Input '-4.5e500' is out of range for float8

一方、! (factorial)後置演算子(階乗)は、integer データ型用のものしか定義されておらず、float8 用はありません。ですので、! (factorial) における上のような場合は、以下のようになります。

tgl=> select text '20' ! as "factorial";
ERROR:Unable to identify a postfix operator '!' for type 'text'
        You may need to add parentheses or an explicit cast

システムが複数の使用可能な ! (factorial) 演算子の内どれが好ましいかどうかを決定できなかったことが原因で起こります。明示的なキャストを行うことでこれを防止することができます。

tgl=> select cast(text '20' as int8) ! as "factorial";
      factorial
---------------------
 2432902008176640000
(1 row)