10.2. 演算子

演算子呼び出しで使用される特定の演算子は以下の手順に従って解決されます。 この手順は事前に行われた演算子呼び出しによって間接的な影響を受けます。 より詳細については項4.1.6を参照して下さい。

演算子型の解決

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

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

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

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

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

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

    2. すべての侯補を検索し、入力型に最も正確に合うものを残します。 (この時、ドメインはその基本型と同一であると見做します。) 正確に合うものが何もなければすべての侯補を残します。 1つの侯補しか残らない場合、それを使います。 それ以外の場合は次の段階に進みます。

    3. すべての侯補を検索し、型変換が必要とされる所で(入力データ型カテゴリの)好ましい型を受け付けるものを残します。 好ましい型を受け付けるものが何もなければすべての侯補を残します。 1つの侯補しか残らない場合、それを使います。 それ以外の場合は次の段階に進みます。

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

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

以下に例を示します。

例 10-1. 羃乗演算子の型解決

羃乗演算子として、double precisionを引数として取るものがカタログ内に1つのみ定義されています。 スキャナは、以下の問い合わせ式の両引数にまずintegerを割り当てます。

SELECT 2 ^ 3 AS "exp";

 exp
-----
   8
(1 row)

パーサは両オペランドを型変換し、問い合わせは以下と等価になります。

SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "exp";

例 10-2. 文字列連結演算子の型解決

文字列類似構文は、文字列の作業の他、複雑な拡張型の作業にも使用されます。 型の指定がない文字列は、類似演算子候補に一致します。

例えば、以下は指定がない引数が1つあります。

SELECT text 'abc' || 'def' AS "text and unknown";

 text and unknown
------------------
 abcdef
(1 row)

この場合、パーサは両引数でtextを取る演算子があるかどうかを検索します。 この演算子は存在しますので、第二引数はtext型として解釈されるものと仮定されます。

以下は型の指定がない連結です。

SELECT 'abc' || 'def' AS "unspecified";

 unspecified
-------------
 abcdef
(1 row)

この場合、問い合わせ内に型が指定されていませんので、どの型を使用すべきかについての初期のヒントがありません。 ですから、パーサはすべての演算子候補を検索し、文字列カテゴリとビット列カテゴリ入力を受け付ける候補を見つけます。 使用できる場合は文字列カテゴリが優先されますので、文字列カテゴリが選択され、その好ましい型であるtextが、不明のリテラルを解決する型として使用されます。

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

PostgreSQLの演算子カタログには、前置演算子@用に複数の項目があります。 これはすべて各種数値データ型に対する絶対値計算を実装するものです。 その1つは、数値カテゴリの好ましい型であるfloat8型用の項目です。 したがって、PostgreSQLは、非数値の入力があった場合にこれを使用します。

SELECT @ '-4.5' AS "abs";
 abs
-----
 4.5
(1 row)

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

SELECT @ '-4.5e500' AS "abs";

ERROR:  "-4.5e500" is out of range for type double precision

一方、後置演算子! (階乗)は、整数データ型のみで定義され、float8用は定義されていません。 ですから、!における上と同様の場合では、以下のような結果になります。

SELECT '20' ! AS "factorial";

ERROR:  operator is not unique: "unknown" !
HINT:  Could not choose a best candidate operator. You may need to add explicit
type casts.

これは、システムが、複数の!演算子候補の内どれが好ましいかを決定することができなかったため発生します。 明示的なキャストを使用することで補助することができます。

SELECT CAST('20' AS int8) ! AS "factorial";

      factorial
---------------------
 2432902008176640000
(1 row)

アダルトレンタルサーバー