10.2. 操作符

一次操作符調用的操作數類型是按照下面的過程解析的。 請注意這個過程受被調用操作符的優先級的間接影響。 參閱 Section 4.1.6 獲取更多訊息。

操作符類型解析

  1. pg_operator 系統資料表中選出要考慮的操作符。 如果使用了一個不帶修飾的操作符名(常見的狀況), 那麼認為該操作符是那些在目前的搜索路徑中名字和參數個數正確的函數(參閱 Section 5.8.3)。 如果給出一個帶修飾的操作符名,那麼只考慮指明的模式中的操作符。

    1. 如果搜索路徑中找到了多個相同參數類型的操作符,那麼只考慮最早出現在路徑中的。 但是不同參數類型的操作符將以相同的基礎進行考慮,而不管它們在路徑中的位置如何。

  2. 檢查一個操作符是否剛好接受輸入參數類型。 如果存在一個(在考慮的操作符中,可能只存在一個精確匹配的), 則用之。

    1. 如果一個雙目操作符調用中的一個參數是 unknown, 則在本次檢查中假設其與另一個參數類型相同。 其他涉及 unknown 的情況絕不會在這一步找到匹配。

  3. 尋找最優匹配。

    1. 拋棄那些輸入類型不匹配並且也不能強制轉換(使用隱含轉換函數)成匹配的候選操作符。 unknown 文本在這種情況下被認為是可以轉換成任何東西。如果只剩下一個候選項,用之; 否則繼續下一步。

    2. 遍歷所有候選操作符,保留那些輸入類型有最多準確匹配的。 (在這種情況下,域被看作和他們的基本類型相同。) 如果沒有完全準確匹配的操作符,保留所有候選。 如果只有一個,用之,否則繼續下一步。

    3. 遍歷所有候選操作符,保留那些需要類型轉換時最多位置接受(輸入資料類型的類型範疇的)首選類型的。 如果沒有接受首選選類型的操作符,則保留所有候選。 如果只有一個,用之,否則繼續下一步。

    4. 如果任何輸入參數是 unknown,檢查剩下的候選操作符對應參數位置的類型範疇。 如果任何候選操作符接受string類型,則在那些位置選string類型 (這個假設認為字串是合適的,因為 unknown 類型文本確實像字串)。 否則,如果所有剩下的候選操作符接受相同的類型,選擇該類型; 否則拋出一個錯誤,因為在沒有更多線索的條件下不能導出正確的選擇。 現在拋棄不接受選定的類型資料表的候選操作符;然後, 如果任意候選操作符在某個給定的參數位置接受一個優選類型, 則拋棄那些在該參數位置接受非優選類型的候選操作符。

    5. 如果只剩下一個操作符,用之。 如果還有超過一個的候選操作符或是沒有候選操作符,則產生一個錯誤。

下面是一些例子。

Example 10-1. 指數操作符類型解析

在分類裡只有一個指數操作符,它以 double precision 作為參數。掃瞄器給下面查詢資料表達式的兩個參數賦予 integer 的初始類型:

SELECT 2 ^ 3 AS "exp";

 exp
-----
   8
(1 row)

分析器對兩個參數都做類型轉換,查詢等效於:

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

Example 10-2. 字串連接操作符類型分析

一種類字元串的語法既可以用於字元串也可以用於複雜的擴展類型。 包含不明類型的字串使用可能的候選操作符匹配。

有一個未聲明的參數的例子:

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,作為解析未知類型文本的聲明類型。

Example 10-3. 絕對值和取反操作符類型分析

PostgreSQL 操作符資料表裡面有幾條記錄用於前綴操作符 @, 所有這些都是為各種數值類型實現絕對值操作的。其中有一條用於類型 float8, 它是數值資料表中的優選類型。因此, 在面對非數值輸入的時候,PostgreSQL 會使用該類型︰

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

在這裡系統在應用選定的操作符之前執行類一次textfloat8的轉換。我們可以驗證它是float8而不是其它什麼類型:

select @ text '-4.5e500' as "abs";

ERROR:  Input '-4.5e500' is out of range for float8

另一方面,前綴操作符 ~ (按位取反) 只為整數資料類型定義, 而不是為float8定義的。因此,如果我們用 ~ 做類似實驗,就有:

SELECT ~ '20' AS "negation";

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 "negation";

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