無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

10.2. 演算子

演算式に参照される特定の演算子は、以下の手順を用いて決定されます。 関連する演算子の優先順位によりどの下位式をどの演算子の入力と見なすかが決定されますので、この手順はこの優先順位により間接的な影響を受けることに注意して下さい。 詳細は 項4.1.6 を参照してください。

演算子における型の解決

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

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

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

    1. 二項演算子の1つの引数が unknown 型であった場合、この検査のもう片方の引数と同一の型であると仮定します。 2つの unknown 入力、もしくは unknown 入力を伴う単項演算子が呼び出された場合、この段階では対を見つけることはありません。

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

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

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

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

    4. 入力引数で unknown のものがあった場合、それらの残った候補に引数位置で受け入れられる型カテゴリを検査します。 各位置において、候補が string カテゴリを受け付ける場合は、そのカテゴリを選択します (unknown 型のリテラルは文字列のようなものですので、この文字列への重み付けは適切です)。 そうでなければ、もし残った全ての候補が同じ型カテゴリを受け入れる場合はそのカテゴリを選択します。 そうでもなければ、さらに手掛かりがなければ正しい選択が演繹されることができませんので、失敗となります。 ここで、選択された型カテゴリを受け付けない演算子候補は破棄されます。 さらに、それらカテゴリ内の好ましい型を受け付ける候補が1つでもある場合、その引数の好ましい型ではないものを受け付ける候補は破棄されます。 これらの検査をどれも通らなかったら全ての候補を残します。 1つの候補しか残らない場合、それを使います。 それ以外の場合は次の段階に進みます。

    5. もし unknown と既知の型の引数の両方があり、そして全ての既知の型の引数が同じ型を持っていた場合、 unknown 引数も同じ型であると仮定し、 どの候補が unknown 引数の位置にある型を受け付けることができるかを検査します。 正確に1つの候補がこの検査を通過した場合、それを使います。それ以外は失敗します。

以下に例を示します。

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

階乗演算子として、 bigint を引数とするものが標準カタログ内に1つのみ定義されています( ! を後に付けます)。 スキャナは、以下の問い合わせ式の引数にまず integer 型を割り当てます。

SELECT 40 ! AS "40 factorial";

                   40 factorial
--------------------------------------------------
 815915283247897734345611269596115894272000000000
(1 row)

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

SELECT CAST(40 AS bigint) ! AS "40 factorial";

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

SELECT ~ '20' AS "negation";

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

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

SELECT ~ CAST('20' AS int8) AS "negation";

 negation
----------
      -21
(1 row)

例 10-4. 配列含有演算子の型解決

一方は既知でありもう一方は未知である入力を伴った演算子の解決のもう一つの例です。

SELECT array[1,2] <@ '{1,2,3}' as "is subset";

 is subset
-----------
 t
(1 row)

PostgreSQL の演算子カタログは、 <@ 中置演算子のためのいくつかのエントリを持っていますが、 数値型配列を左側に受け付けることができるのは配列含有( anyarray <@ anyarray )と範囲含有( anyelement <@ anyrange )の2つのみです。 これらの多様な擬似データ型 項8.19 を参照は好ましいと見なされないため、このような方法ではパーサは曖昧さを解決することができません。 しかし、最後の解決規則では、未知の型のリテラルを別の入力と同じ型であると仮定するために数値配列とみなします。 今のところ2つのうち一つの演算子だけがマッチできるため、配列含有が選択されます。(範囲含有が選択された場合、演算子の右側にある文字列は正しい範囲型のリテラルではないため、エラーとなるでしょう。)


powered by SEO.CUG.NET