W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
CREATE FUNCTION — 定義一個(gè)新函數(shù)
CREATE [ OR REPLACE ] FUNCTION
name
( [ [ argmode
] [ argname
] argtype
[ { DEFAULT | = } default_expr
] [, ...] ] )
[ RETURNS rettype
| RETURNS TABLE ( column_name
column_type
[, ...] ) ]
{ LANGUAGE lang_name
| TRANSFORM { FOR TYPE type_name
} [, ... ]
| WINDOW
| IMMUTABLE | STABLE | VOLATILE | [ NOT ] LEAKPROOF
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
| PARALLEL { UNSAFE | RESTRICTED | SAFE }
| COST execution_cost
| ROWS result_rows
| SUPPORT support_function
| SET configuration_parameter
{ TO value
| = value
| FROM CURRENT }
| AS 'definition
'
| AS 'obj_file
', 'link_symbol
'
} ...
CREATE FUNCTION
定義一個(gè)新函數(shù)。CREATE OR REPLACE FUNCTION
將創(chuàng)建一個(gè)新函數(shù)或者替換一個(gè)現(xiàn)有的函數(shù)。要定義一個(gè)函數(shù),用戶必須具有該語(yǔ)言上的USAGE
特權(quán)。
如果包括了一個(gè)模式名,那么該函數(shù)會(huì)被創(chuàng)建在指定的模式中。否則,它會(huì)被創(chuàng)建在當(dāng)前模式中。新函數(shù)的名稱(chēng)不能匹配同一個(gè)模式中具有相同輸入?yún)?shù)類(lèi)型的任何現(xiàn)有函數(shù)或過(guò)程。不過(guò),不同參數(shù)類(lèi)型的函數(shù)和過(guò)程能夠共享一個(gè)名字(這被稱(chēng)作重載)。
要替換一個(gè)現(xiàn)有函數(shù)的當(dāng)前定義,可以使用CREATE OR REPLACE FUNCTION
。但不能用這種方式更改函數(shù)的名稱(chēng)或者參數(shù)類(lèi)型(如果嘗試這樣做,實(shí)際上就會(huì)創(chuàng)建一個(gè)新的不同的函數(shù))。還有,CREATE OR REPLACE FUNCTION
將不會(huì)讓你更改一個(gè)現(xiàn)有函數(shù)的返回類(lèi)型。要這樣做,你必須先刪除再重建該函數(shù)(在使用OUT
參數(shù)時(shí),這意味著除了刪除函數(shù)之外無(wú)法更改任何
OUT
參數(shù)的類(lèi)型)。
當(dāng)CREATE OR REPLACE FUNCTION
被用來(lái)替換一個(gè)現(xiàn)有的函數(shù),該函數(shù)的擁有權(quán)和權(quán)限不會(huì)改變。所有其他的函數(shù)屬性會(huì)按照該命令中所指定的或者隱含的來(lái)賦值。必須擁有(包括成為擁有角色的成員)該函數(shù)才能替換它。
如果你刪除并且重建一個(gè)函數(shù),新函數(shù)將和舊的不一樣,你將必須刪掉引用舊函數(shù)的現(xiàn)有規(guī)則、視圖、觸發(fā)器等。使用CREATE OR REPLACE FUNCTION
更改一個(gè)函數(shù)定義不會(huì)破壞引用該函數(shù)的對(duì)象。還有,ALTER FUNCTION
可以被用來(lái)更改一個(gè)現(xiàn)有函數(shù)的大部分輔助屬性。
創(chuàng)建該函數(shù)的用戶將成為該函數(shù)的擁有者。
要?jiǎng)?chuàng)建一個(gè)函數(shù),你必須擁有參數(shù)類(lèi)型和返回類(lèi)型上的USAGE
特權(quán)。
name
要?jiǎng)?chuàng)建的函數(shù)的名稱(chēng)(可以被模式限定)。
argmode
一個(gè)參數(shù)的模式:IN
、OUT
、INOUT
或者VARIADIC
。如果省略,默認(rèn)為IN
。只有OUT
參數(shù)能跟在一個(gè)VARIADIC
參數(shù)后面。還有,
OUT
和INOUT
參數(shù)不能和RETURNS TABLE
符號(hào)一起使用。
argname
一個(gè)參數(shù)的名稱(chēng)。一些語(yǔ)言(包括 SQL 和 PL/pgSQL)讓你在函數(shù)體中使用該名稱(chēng)。對(duì)于其他語(yǔ)言,一個(gè)輸入?yún)?shù)的名字只是額外的文字(就該函數(shù)本身所關(guān)心的來(lái)說(shuō))。但是你可以在調(diào)用一個(gè)函數(shù)時(shí)使用輸入?yún)?shù)名來(lái)提高可讀性(見(jiàn)第 4.3 節(jié))。在任何情況下,輸出參數(shù)的名稱(chēng)是有意義的,因?yàn)樗x了結(jié)果行類(lèi)型中的列名(如果忽略一個(gè)輸出參數(shù)的名稱(chēng),系統(tǒng)將選擇一個(gè)默認(rèn)的列名)。
argtype
該函數(shù)參數(shù)(如果有)的數(shù)據(jù)類(lèi)型(可以是模式限定的)。參數(shù)類(lèi)型可以是基本類(lèi)型、組合類(lèi)型或者域類(lèi)型,或者可以引用一個(gè)表列的類(lèi)型。
根據(jù)實(shí)現(xiàn)語(yǔ)言,也可以允許指定cstring
之類(lèi)的“偽類(lèi)型”。偽類(lèi)型表示實(shí)際參數(shù)類(lèi)型沒(méi)有被完整指定或者不屬于普通 SQL 數(shù)據(jù)類(lèi)型集合。
可以寫(xiě)
來(lái)引用一列的類(lèi)型。使用這種特性有時(shí)可以幫助創(chuàng)建一個(gè)不受表定義更改影響的函數(shù)。table_name
.column_name
%TYPE
default_expr
如果參數(shù)沒(méi)有被指定值時(shí)要用作默認(rèn)值的表達(dá)式。該表達(dá)式必須能被強(qiáng)制為該參數(shù)的參數(shù)類(lèi)型。只有輸入(包括INOUT
)參數(shù)可以具有默認(rèn)值。所有跟隨在一個(gè)具有默認(rèn)值的參數(shù)之后的輸入?yún)?shù)也必須有默認(rèn)值。
rettype
返回?cái)?shù)據(jù)類(lèi)型(可能被模式限定)。返回類(lèi)型可以是一種基本類(lèi)型、組合類(lèi)型或者域類(lèi)型,也可以引用一個(gè)表列的類(lèi)型。根據(jù)實(shí)現(xiàn)語(yǔ)言,也可以允許指定cstring
之類(lèi)的“偽類(lèi)型”。如果該函數(shù)不會(huì)返回一個(gè)值,可以指定返回類(lèi)型為void
。
當(dāng)有OUT
或者INOUT
參數(shù)時(shí),可以省略RETURNS
子句。如果存在,該子句必須和輸出參數(shù)所表示的結(jié)果類(lèi)型一致:如果有多個(gè)輸出參數(shù),則為RECORD
,否則與單個(gè)輸出參數(shù)的類(lèi)型相同。
SETOF
修飾符表示該函數(shù)將返回一個(gè)項(xiàng)的集合而不是一個(gè)單一項(xiàng)。
可以寫(xiě)
來(lái)引用一列的類(lèi)型。table_name
.column_name
%TYPE
column_name
RETURNS TABLE
語(yǔ)法中一個(gè)輸出列的名稱(chēng)。這實(shí)際上是另一種聲明OUT
參數(shù)的方法,不過(guò)RETURNS TABLE
也隱含了RETURNS SETOF
。
column_type
RETURNS TABLE
語(yǔ)法中的輸出列的數(shù)據(jù)類(lèi)型。
lang_name
用以實(shí)現(xiàn)該函數(shù)的語(yǔ)言的名稱(chēng)??梢允?code class="literal">sql、c
、internal
或者一個(gè)用戶定義的過(guò)程語(yǔ)言的名稱(chēng),例如plpgsql
。不推薦用單引號(hào)包圍該名稱(chēng),并且要求區(qū)分大小寫(xiě)。
TRANSFORM { FOR TYPE type_name
} [, ... ] }
一個(gè)由轉(zhuǎn)換構(gòu)成的列表,對(duì)該函數(shù)的調(diào)用適用于它們。轉(zhuǎn)換在 SQL 類(lèi)型和語(yǔ)言相關(guān)的數(shù)據(jù)類(lèi)型之間進(jìn)行變換,詳見(jiàn)CREATE TRANSFORM。過(guò)程語(yǔ)言實(shí)現(xiàn)通常把有關(guān)內(nèi)建類(lèi)型的知識(shí)硬編碼在代碼中,因此那些不需要列舉在這里。如果一種過(guò)程語(yǔ)言實(shí)現(xiàn)不知道如何處理一種類(lèi)型并且沒(méi)有轉(zhuǎn)換被提供,它將回退到一種默認(rèn)的行為來(lái)轉(zhuǎn)換數(shù)據(jù)類(lèi)型,但是這取決于具體實(shí)現(xiàn)。
WINDOW
WINDOW
表示該函數(shù)是一個(gè)窗口函數(shù)而不是一個(gè)普通函數(shù)。當(dāng)前只用于用 C 編寫(xiě)的函數(shù)。在替換一個(gè)現(xiàn)有函數(shù)定義時(shí),不能更改WINDOW
屬性。
IMMUTABLE
STABLE
VOLATILE
這些屬性告知查詢優(yōu)化器該函數(shù)的行為。最多只能指定其中一個(gè)。如果這些都不出現(xiàn),則會(huì)默認(rèn)為VOLATILE
。
IMMUTABLE
表示該函數(shù)不能修改數(shù)據(jù)庫(kù)并且對(duì)于給定的參數(shù)值總是會(huì)返回相同的值。也就是說(shuō),它不會(huì)做數(shù)據(jù)庫(kù)查找或者使用沒(méi)有在其參數(shù)列表中直接出現(xiàn)的信息。如果給定合格選項(xiàng),任何用全常量參數(shù)對(duì)該函數(shù)的額調(diào)用可以立刻用該函數(shù)值替換。
STABLE
表示該函數(shù)不能修改數(shù)據(jù)庫(kù),并且對(duì)于相同的參數(shù)值,它在一次表掃描中將返回相同的結(jié)果。但是這種結(jié)果在不同的 SQL 語(yǔ)句執(zhí)行期間可能會(huì)變化。對(duì)于那些結(jié)果依賴(lài)于數(shù)據(jù)庫(kù)查找、參數(shù)變量(例如當(dāng)前時(shí)區(qū))等的函數(shù)來(lái)說(shuō),這是合適的(對(duì)希望查詢被當(dāng)前命令修改的行的AFTER
觸發(fā)器不適合)。還要注意current_timestamp
函數(shù)族適合被標(biāo)記為穩(wěn)定,因?yàn)樗鼈兊闹翟谝粋€(gè)事務(wù)內(nèi)不會(huì)改變。
VOLATILE
表示該函數(shù)的值在一次表掃描中都有可能改變,因此不能做優(yōu)化。在這種意義上,相對(duì)較少的數(shù)據(jù)庫(kù)函數(shù)是不穩(wěn)定的,一些例子是random()
、currval()
、timeofday()
。但是注意任何有副作用的函數(shù)都必須被分類(lèi)為不穩(wěn)定的,即便其結(jié)果是可以預(yù)測(cè)的,這是為了調(diào)用被優(yōu)化掉。一個(gè)例子是
setval()
。
更多細(xì)節(jié)可見(jiàn)第 37.7 節(jié)。
LEAKPROOF
LEAKPROOF
表示該函數(shù)沒(méi)有副作用。它不會(huì)泄露有關(guān)其參數(shù)的信息(除了通過(guò)返回值)。例如,一個(gè)只對(duì)某些參數(shù)值拋出錯(cuò)誤消息而對(duì)另外一些卻不拋出錯(cuò)誤的函數(shù)不是防泄漏的,一個(gè)把參數(shù)值包括在任何錯(cuò)誤消息中的函數(shù)也不是防泄漏的。這會(huì)影響系統(tǒng)如何執(zhí)行在使用security_barrier
選項(xiàng)創(chuàng)建的視圖或者開(kāi)啟了行級(jí)安全性的表上執(zhí)行查詢。對(duì)于包含有非防泄漏函數(shù)的查詢,系統(tǒng)將在任何來(lái)自查詢本身的用戶提供條件之前強(qiáng)制來(lái)自安全策略或者安全屏障的條件,防止無(wú)意中的數(shù)據(jù)暴露。被標(biāo)記為防泄漏的函數(shù)和操作符被假定是可信的,并且可以在安全性策略和安全性屏障視圖的條件之前被執(zhí)行。此外,沒(méi)有參數(shù)的函數(shù)或者不從安全屏障視圖或表傳遞任何參數(shù)的函數(shù)不一定要被標(biāo)記為防泄漏的。詳見(jiàn)
CREATE VIEW
和第 40.5 節(jié)。這個(gè)選項(xiàng)只能由超級(jí)用戶設(shè)置。
CALLED ON NULL INPUT
RETURNS NULL ON NULL INPUT
STRICT
CALLED ON NULL INPUT
(默認(rèn))表示在某些參數(shù)為空值時(shí)應(yīng)正常調(diào)用該函數(shù)。如果有必要,函數(shù)的作者應(yīng)該負(fù)責(zé)檢查空值并且做出適當(dāng)?shù)南鄳?yīng)。
RETURNS NULL ON NULL INPUT
或STRICT
表示只要其任意參數(shù)為空值,該函數(shù)就會(huì)返回空值。如果指定了這個(gè)參數(shù),當(dāng)有空值參數(shù)時(shí)該函數(shù)不會(huì)被執(zhí)行,而是自動(dòng)返回一個(gè)空值結(jié)果。
[EXTERNAL] SECURITY INVOKER
[EXTERNAL] SECURITY DEFINER
SECURITY INVOKER
表示要用調(diào)用該函數(shù)的用戶的特權(quán)來(lái)執(zhí)行它。這是默認(rèn)值。SECURITY DEFINER
指定要用擁有該函數(shù)的用戶的特權(quán)來(lái)執(zhí)行該函數(shù)。
為了符合 SQL,允許使用關(guān)鍵詞EXTERNAL
。但是它是可選的,因?yàn)榕c SQL 中不同,這個(gè)特性適用于所有函數(shù)而不僅是那些外部函數(shù)。
PARALLEL
PARALLEL UNSAFE
表示該函數(shù)不能在并行模式中運(yùn)行并且 SQL 語(yǔ)句中存在一個(gè)這樣的函數(shù)會(huì)強(qiáng)制使用順序執(zhí)行計(jì)劃。這是默認(rèn)選項(xiàng)。PARALLEL RESTRICTED
表示該函數(shù)能在并行模式中運(yùn)行,但是其執(zhí)行被限制在并行組的領(lǐng)導(dǎo)者中。PARALLEL SAFE
表示該函數(shù)對(duì)于在并行模式中運(yùn)行是安全的并且不受限制。
如果函數(shù)修改任何數(shù)據(jù)庫(kù)狀態(tài)、會(huì)使用子事務(wù)之類(lèi)的方式改變事務(wù)、訪問(wèn)序列或者對(duì)設(shè)置(如setval
)做出持久性的更改,它們就應(yīng)該被標(biāo)記為并行不安全。如果它們?cè)L問(wèn)臨時(shí)表、客戶端連接狀態(tài)、游標(biāo)、預(yù)備語(yǔ)句或者系統(tǒng)無(wú)法在并行模式中同步的本地后端狀態(tài)(例如setseed
只能在組領(lǐng)導(dǎo)者中執(zhí)行,因?yàn)榱硪粋€(gè)進(jìn)程所作的更改不會(huì)在領(lǐng)導(dǎo)者中被反映出來(lái)),它們應(yīng)該被標(biāo)為并行受限。通常,如果一個(gè)函數(shù)是受限的或者不安全的卻被標(biāo)成了安全,或者它本來(lái)是不安全的卻被標(biāo)成了受限,在并行查詢中執(zhí)行時(shí)它可能會(huì)拋出錯(cuò)誤或者產(chǎn)生錯(cuò)誤的答案。如果被錯(cuò)誤的標(biāo)記,
C 語(yǔ)言函數(shù)理論上可能展現(xiàn)出完全無(wú)法定義的行為,因?yàn)橄到y(tǒng)沒(méi)有辦法保護(hù)自己不受任意的 C 代碼影響,但是在大部分情況下其結(jié)果也不會(huì)比任何其他函數(shù)差到哪里去。如果有疑問(wèn),函數(shù)應(yīng)該被標(biāo)為UNSAFE
,這也是默認(rèn)值。
COST
execution_cost
一個(gè)給出該函數(shù)的估計(jì)執(zhí)行代價(jià)的正數(shù),單位是cpu_operator_cost。如果該函數(shù)返回一個(gè)集合,這就是每個(gè)被返回行的代價(jià)。如果沒(méi)有指定代價(jià),對(duì) C 語(yǔ)言和內(nèi)部函數(shù)會(huì)指定為 1 個(gè)單位,對(duì)其他語(yǔ)言的函數(shù)則會(huì)指定為 100 單位。更大的值會(huì)導(dǎo)致規(guī)劃器嘗試避免對(duì)該函數(shù)的不必要的過(guò)多計(jì)算。
ROWS
result_rows
一個(gè)正數(shù),它給出規(guī)劃器期望該函數(shù)返回的行數(shù)估計(jì)。只有當(dāng)該函數(shù)被聲明為返回一個(gè)集合時(shí)才允許這個(gè)參數(shù)。默認(rèn)假設(shè)為 1000 行。
SUPPORT
support_function
用于此函數(shù)的planner support function的名稱(chēng)(可選的模式限定)。 詳請(qǐng)參見(jiàn)第 37.11 節(jié)。你必須是超級(jí)用戶才能使用此選項(xiàng)。
configuration_parameter
value
SET
子句導(dǎo)致進(jìn)入該函數(shù)時(shí)指定配置參數(shù)將被設(shè)置為指定值。并且在該函數(shù)退出時(shí)恢復(fù)到該參數(shù)之前的值。SET FROM CURRENT
會(huì)把CREATE FUNCTION
被執(zhí)行時(shí)該參數(shù)的當(dāng)前值保存為進(jìn)入該函數(shù)時(shí)將被應(yīng)用的值。
如果一個(gè)SET
子句被附加到一個(gè)函數(shù),那么在該函數(shù)內(nèi)為同一個(gè)變量執(zhí)行的SET LOCAL
命令會(huì)被限制于該函數(shù):在函數(shù)退出時(shí)該配置參數(shù)之前的值仍會(huì)被恢復(fù)。不過(guò),一個(gè)普通的SET
命令(沒(méi)有LOCAL
)會(huì)覆蓋SET
子句,更像一個(gè)之前的
SET LOCAL
命令所做的那樣:這種命令的效果在函數(shù)退出后將會(huì)持續(xù),除非當(dāng)前事務(wù)被回滾。
definition
一個(gè)定義該函數(shù)的字符串常量,其含義取決于語(yǔ)言。它可以是一個(gè)內(nèi)部函數(shù)名、一個(gè)對(duì)象文件的路徑、一個(gè) SQL 命令或者用一種過(guò)程語(yǔ)言編寫(xiě)的文本。
美元引用第 4.1.2.4 節(jié)通常對(duì)書(shū)寫(xiě)函數(shù)定義字符串有所幫助,而普通單引號(hào)語(yǔ)法則不會(huì)有用。如果沒(méi)有美元引用,函數(shù)定義中的任何單引號(hào)或者反斜線必須用雙寫(xiě)來(lái)轉(zhuǎn)義。
obj_file
, link_symbol
當(dāng) C 語(yǔ)言源代碼中該函數(shù)的名稱(chēng)與 SQL 函數(shù)的名稱(chēng)不同時(shí),這種形式的AS
子句被用于動(dòng)態(tài)可載入 C 語(yǔ)言函數(shù)。字符串obj_file
是包含編譯好的C函數(shù)的動(dòng)態(tài)庫(kù)文件的名稱(chēng),它會(huì)由LOAD命令解析。字符串
link_symbol
是該函數(shù)的鏈接符號(hào),也就是該函數(shù)在 C 語(yǔ)言源代碼中的名稱(chēng)。如果省略鏈接符號(hào),它將被假定為要定義的 SQL 函數(shù)的名稱(chēng)。所有函數(shù)的C名稱(chēng)都必須不同,因此必須為重載的C函數(shù)給出不同的C名稱(chēng)(例如把參數(shù)類(lèi)型作為C名稱(chēng)的一部分)。
在重復(fù)調(diào)用引用同一對(duì)象文件的CREATE FUNCTION
時(shí),對(duì)每個(gè)會(huì)話該文件只會(huì)被載入一次。要卸載并且重新裝載該文件(可能是在開(kāi)發(fā)期間),需要開(kāi)始一個(gè)新會(huì)話。
編寫(xiě)函數(shù)的進(jìn)一步信息可以參考第 37.3 節(jié)。
PostgreSQL允許函數(shù)重載,也就是說(shuō)同一個(gè)名稱(chēng)可以被用于多個(gè)不同的函數(shù),只要它們具有可區(qū)分的輸入?yún)?shù)類(lèi)型。不管是否使用它,在有些用戶不信任另一些用戶的數(shù)據(jù)庫(kù)中調(diào)用函數(shù)時(shí),這種兼容性需要安全性的預(yù)防措施,請(qǐng)參考第 10.3 節(jié)。
如果兩個(gè)函數(shù)具有相同的名稱(chēng)和輸入參數(shù)類(lèi)型,它們被認(rèn)為相同(不考慮任何OUT
參數(shù))。因此這些聲明會(huì)沖突:
CREATE FUNCTION foo(int) ...
CREATE FUNCTION foo(int, out text) ...
具有不同參數(shù)類(lèi)型列表的函數(shù)在創(chuàng)建時(shí)將不會(huì)被認(rèn)為是沖突的,但是如果默認(rèn)值被提供,在使用時(shí)它們有可能會(huì)沖突。例如,考慮
CREATE FUNCTION foo(int) ...
CREATE FUNCTION foo(int, int default 42) ...
調(diào)用foo(10)
將會(huì)失敗,因?yàn)樵谝獩Q定應(yīng)該調(diào)用哪個(gè)函數(shù)時(shí)會(huì)有歧義。
允許把完整的SQL類(lèi)型語(yǔ)法用于聲明一個(gè)函數(shù)的參數(shù)和返回值。不過(guò),CREATE FUNCTION
會(huì)拋棄帶圓括號(hào)的類(lèi)型修飾符(例如類(lèi)型numeric
的精度域)。例如CREATE FUNCTION foo (varchar(10)) ...
和CREATE FUNCTION foo (varchar) ...
完全一樣。
在用CREATE OR REPLACE FUNCTION
替換一個(gè)現(xiàn)有函數(shù)時(shí),對(duì)于更改參數(shù)名是有限制的。不能更改已經(jīng)分配給任何輸入?yún)?shù)的名稱(chēng)(不過(guò)可以給之前沒(méi)有名稱(chēng)的參數(shù)增加名稱(chēng))。如果有多于一個(gè)輸出參數(shù),不能更改輸出參數(shù)的名稱(chēng),因?yàn)榭赡軙?huì)改變描述函數(shù)結(jié)果的匿名組合類(lèi)型的列名。這些限制是為了確保函數(shù)被替換時(shí),已有的對(duì)該函數(shù)的調(diào)用不會(huì)停止工作。
如果一個(gè)被聲明為STRICT
的函數(shù)帶有一個(gè)VARIADIC
參數(shù),會(huì)嚴(yán)格檢查該可變數(shù)組作為一個(gè)整體是否為非空。如果該數(shù)組有空值元素,該函數(shù)仍將被調(diào)用。
這里是一些小例子,它們可以幫你了解函數(shù)創(chuàng)建。更多信息和例子可見(jiàn) 第 37.3 節(jié)。
CREATE FUNCTION add(integer, integer) RETURNS integer
AS 'select $1 + $2;'
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
在PL/pgSQL中,使用一個(gè)參數(shù)名稱(chēng)增加一個(gè)整數(shù):
CREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$
BEGIN
RETURN i + 1;
END;
$$ LANGUAGE plpgsql;
返回一個(gè)包含多個(gè)輸出參數(shù)的記錄:
CREATE FUNCTION dup(in int, out f1 int, out f2 text)
AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
LANGUAGE SQL;
SELECT * FROM dup(42);
你可以用更復(fù)雜的方式(用一個(gè)顯式命名的組合類(lèi)型)來(lái)做同樣的事情:
CREATE TYPE dup_result AS (f1 int, f2 text);
CREATE FUNCTION dup(int) RETURNS dup_result
AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
LANGUAGE SQL;
SELECT * FROM dup(42);
另一種返回多列的方法是使用一個(gè)TABLE
函數(shù):
CREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)
AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$
LANGUAGE SQL;
SELECT * FROM dup(42);
不過(guò),TABLE
函數(shù)與之前的例子不同,因?yàn)樗鼘?shí)際返回了一個(gè)記錄集合而不只是一個(gè)記錄。
SECURITY DEFINER
函數(shù)因?yàn)橐粋€(gè)SECURITY DEFINER
函數(shù)會(huì)被以創(chuàng)建它的用戶的特權(quán)來(lái)執(zhí)行,需要小心地確保該函數(shù)不會(huì)被誤用。為了安全,search_path應(yīng)該被設(shè)置為排除任何不可信用戶可寫(xiě)的模式。這可以阻止惡意用戶創(chuàng)建對(duì)象(例如表、函數(shù)以及操作符)來(lái)掩飾該函數(shù)所要用到的對(duì)象。在這方面特別重要的是臨時(shí)表模式,默認(rèn)情況下它會(huì)第一個(gè)被搜索并且通常對(duì)任何用戶都是可寫(xiě)的??梢酝ㄟ^(guò)強(qiáng)制最后搜索臨時(shí)模式來(lái)得到一種安全的布局。要這樣做,把
pg_temp
寫(xiě)成search_path
中的最后一項(xiàng)。這個(gè)函數(shù)展示了安全的用法:
CREATE FUNCTION check_password(uname TEXT, pass TEXT)
RETURNS BOOLEAN AS $$
DECLARE passed BOOLEAN;
BEGIN
SELECT (pwd = $2) INTO passed
FROM pwds
WHERE username = $1;
RETURN passed;
END;
$$ LANGUAGE plpgsql
SECURITY DEFINER
-- 設(shè)置一個(gè)安全的 search_path:受信的模式,然后是 'pg_temp'。
SET search_path = admin, pg_temp;
這個(gè)函數(shù)的目的是為了訪問(wèn)表admin.pwds
。但是如果沒(méi)有SET
子句或者帶有SET
子句卻只提到admin
,該函數(shù)會(huì)變成創(chuàng)建一個(gè)名為pwds
的臨時(shí)表。
在PostgreSQL 版本 8.3 之前,SET
子句不可用,因而較老的函數(shù)可能包含相當(dāng)復(fù)雜的邏輯來(lái)保存、設(shè)置以及恢復(fù)search_path
。對(duì)于這種目的,SET
子句更容易。
另一點(diǎn)要記住的是默認(rèn)情況下,會(huì)為新創(chuàng)建的函數(shù)給PUBLIC
授予執(zhí)行特權(quán)(詳見(jiàn)第 5.7 節(jié))。你常常會(huì)希望把安全定義器函數(shù)的使用限制在某些用戶中。要這樣做,你必須收回默認(rèn)的PUBLIC
特權(quán),然后選擇性地授予執(zhí)行特權(quán)。為了避免出現(xiàn)新函數(shù)能被所有人訪問(wèn)的時(shí)間窗口,應(yīng)在一個(gè)事務(wù)中創(chuàng)建它并且設(shè)置特權(quán)。例如:
BEGIN; CREATE FUNCTION check_password(uname TEXT, pass TEXT) ... SECURITY DEFINER; REVOKE ALL ON FUNCTION check_password(uname TEXT, pass TEXT) FROM PUBLIC; GRANT EXECUTE ON FUNCTION check_password(uname TEXT, pass TEXT) TO admins; COMMIT;
SQL標(biāo)準(zhǔn)中定義了CREATE FUNCTION
命令。PostgreSQL的版本與之類(lèi)似但不完全兼容。屬性是不可移植的,不同的可用語(yǔ)言也是不能移植的。
對(duì)于和一些其他數(shù)據(jù)庫(kù)系統(tǒng)的兼容性,argmode
可以被寫(xiě)在argname
之前或者之后。但只有第一種方式是兼容標(biāo)準(zhǔn)的。
對(duì)于參數(shù)默認(rèn)值,SQL 標(biāo)準(zhǔn)只指定帶有DEFAULT
關(guān)鍵詞的語(yǔ)法。帶有=
的語(yǔ)法被用在 T-SQL 和 Firebird 中。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: