他のバージョンの文書 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

5.3. 演算子

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

演算子型の解決

  1. pg_operator システムカタログ内で正確に一致するかどうかを点検します。

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

  2. 最も合うものを検索します。

    1. 入力型が合う、もしくは合うように型強制することができる、同じ名前を持つ全演算子の一覧を作成します(unknownリテラルはこの目的では何にでも型強制できるとみなされます)。もし1つしかない場合はそれを使います。それ以外の場合は次の段階に進みます。

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

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

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

    5. 入力引数が全て "unknown" の場合は、残る候補でその引数の位置で受け付けられる型カテゴリをチェックします。候補が"文字列"カテゴリを受け付ける場合は、そのカテゴリを選択します。(unknown 型のリテラルは文字列のようなものですので、この文字列への重みづけは適切です。)さもなくば、残る全ての候補が同一の型カテゴリを受け付ける場合、その型を選択します。さもなくば、これ以上の手がかりがないと正確な選択肢を導き出すことができませんので失敗とします。また、その候補の中で選択されたカテゴリにおける好ましいデータ型を受け付けるものがあるかチェックされます。ここで、選択された型カテゴリを受け付けない演算子候補は破棄されます。そして、与えられた引数の位置上の好ましい型を受け付ける候補が1つでもある場合、その引数の好ましい型ではないものを受け付ける候補は破棄されます。

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

Example 5-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)

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

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

Example 5-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 5-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 '44' ! 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 '44' as int8) ! as "factorial";
      factorial
---------------------
 2673996885588443136
(1 row)