10.3. 函數

函數調用的參數類型是用下面的步驟來解析的。

函數參數類型解析

  1. pg_proc 系統資料表中選擇要考慮的函數。 如果使用了未經修飾的名字,那麼則認為該函數是那些在目前搜索路徑中可見的, 擁有正確名字和參數個數的函數(參閱 Section 5.8.3)。 如果給出了一個帶修飾的函數名,那麼只考慮在聲明的模式中的函數。

    1. 如果在搜索路徑中找到多個函數有相同的參數類型, 那麼只考慮出現在搜索路徑最前面的那個。但是有不同參數類型的函數都以相同的態度看待, 而不管它們在搜索路徑中的位置。

  2. 找一個剛好接受完全一致的輸入參數類型的函數。 如果存在這麼一個(在考慮的函數集中可能只存在一個),用之。 (涉及到 unknown 類型的情況下在本步驟不會找到任何匹配。)

  3. 如果沒有找到準確的匹配,則看看函數調用是否明顯需要一個簡單的類型轉換。 如果函數調用只有一個參數並且函數名與某些資料類型的(內部)名稱相同,那麼就會出現這種情況。 另外,該函數的參數必須是一個未知類型的文本或者與命名資料類型二進制兼容。如果符合這些條件, 則該函數參數在不做任何實際函數調用的情況下轉換成這個命名的資料類型。

  4. 查找最優的匹配

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

    2. 遍歷所有候選函數,保留那些在輸入類型上有最多準確匹配的。 (在這種場合下域被認為和其基本類型一樣。) 如果沒有一個有準確匹配,則保留全部。 如果只剩下一個,用之;否則繼續下一步。

    3. 遍歷所有候選函數,保留那些在最多需要類型轉換的參數位置上接受優選類型的函數。 如果沒有哪個候選函數接受優選類型,則保留全部。 如果只剩下一個,用之;否則繼續下一步。

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

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

請注意,"最佳匹配" 規則對操作符和對函數的類型分析都是一樣的。 下面是一些例子。

Example 10-4. 圓整函數參數類型解析

只有一個round函數有兩個參數。(第一個參數是numeric, 第二個是 integer。)所以下面的查詢自動把第一個類型為 integer 的參數轉換成 numeric

SELECT round(4, 4);

 round
--------
 4.0000
(1 row)

實際上它被分析器轉換成:

SELECT round(CAST (4 AS numeric), 4);

因為帶小數點的數值常量初始時被賦予 numeric 類型,因此下面的查詢將不需要類型轉換,並且可能會略微高效一些:

SELECT round(4.0, 4);

Example 10-5. 子字串函數類型解析

有好幾個 substr 函數,其中一個接受類型 textinteger。如果用一個未聲明類型的字串常量調用它, 系統將選擇接受優選 string類型(也就是類型 text)的候選函數。

SELECT substr('1234', 3);

 substr
--------
     34
(1 row)

如果該字元串聲明為類型 varchar, 就像大多數從資料表中取來的資料一樣,分析器將試著將其轉換成 text

SELECT substr(varchar '1234', 3);

 substr
--------
     34
(1 row)

被分析器轉換後實際上變成:

SELECT substr(CAST(varchar '1234' AS text), 3);

 substr
--------
     34
(1 row)

Note: 分析器從pg_cast中瞭解到 textvarchar 是二進制兼容的, 意思是說其中一個可以傳遞給一個接受另外一個的函數而不需要做任何實際轉換。 因此,在這種情況下,實際上沒有做任何明確的類型轉換。

而且,如果以 integer為參數調用函數,分析器將試圖將其轉換成 text

SELECT substr(1234, 3);

 substr
--------
     34
(1 row)

實際上是這樣執行的

SELECT substr(CAST(1234 AS text), 3);

 substr
--------
     34
(1 row)

這種自動轉換能夠成功是因為存在一個從 integertext 的隱含轉換可以調用。