2025年9月25日: PostgreSQL 18 釋出!
支援的版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1

36.17. 將相關物件打包到擴充套件中 #

一個有用的 PostgreSQL 擴充套件通常包含多個 SQL 物件;例如,一種新的資料型別需要新的函式、新的運算子,可能還需要新的索引運算子類。將所有這些物件收集到一個包中可以簡化資料庫管理。 PostgreSQL 將這種包稱為 擴充套件。要定義一個擴充套件,您至少需要一個 指令碼檔案,其中包含用於建立擴充套件物件的SQL命令,以及一個 控制檔案,用於指定擴充套件本身的一些基本屬性。如果擴充套件包含 C 程式碼,通常還會有一個共享庫檔案,C 程式碼將被構建到其中。一旦您擁有了這些檔案,一個簡單的 CREATE EXTENSION 命令就可以將這些物件載入到您的資料庫中。

使用擴充套件的主要優點是,而不是僅僅執行SQL指令碼將一堆“鬆散”物件載入到資料庫中,PostgreSQL 將會理解擴充套件的物件是相關的。您可以使用單個 DROP EXTENSION 命令刪除所有物件(無需維護單獨的“解除安裝”指令碼)。更有用的是,pg_dump 知道它不應該轉儲擴充套件的單個成員物件——它將只在轉儲中包含一個 CREATE EXTENSION 命令。這極大地簡化了遷移到擴充套件的新版本,而新版本可能包含比舊版本更多或不同的物件。請注意,在將此類轉儲載入到新資料庫時,您必須有擴充套件的控制檔案、指令碼檔案和其他檔案可用。

PostgreSQL 不允許您刪除擴充套件中包含的單個物件,除非刪除整個擴充套件。此外,雖然您可以更改擴充套件成員物件的定義(例如,透過 CREATE OR REPLACE FUNCTION 定義函式),但請記住,修改後的定義不會被 pg_dump 轉儲。這種更改通常只有在您同時在擴充套件的指令碼檔案中進行相同的更改時才有意義。(但對於包含配置資料的表有特殊規定;請參閱 第 36.17.3 節。)在生產環境中,通常最好建立擴充套件更新指令碼來執行對擴充套件成員物件的更改。

擴充套件指令碼可以使用 GRANTREVOKE 語句為屬於擴充套件的物件設定許可權。每個物件的最終許可權集(如果設定了任何許可權)將儲存在 pg_init_privs 系統目錄中。當使用 pg_dump 時,轉儲中將包含 CREATE EXTENSION 命令,然後是必要的 GRANTREVOKE 語句集,以將物件許可權設定為轉儲時獲得的許可權。

PostgreSQL 目前不支援擴充套件指令碼發出 CREATE POLICYSECURITY LABEL 語句。這些語句應在擴充套件建立後設置。所有 RLS 策略和安全標籤將在 pg_dump 建立的轉儲中包含。

擴充套件機制還提供了打包修改指令碼的機制,這些指令碼可以調整擴充套件中包含的 SQL 物件定義。例如,如果擴充套件的 1.1 版本與 1.0 版本相比增加了一個函式並更改了另一個函式的正文,擴充套件作者可以提供一個 更新指令碼 來僅進行這兩個更改。然後可以使用 ALTER EXTENSION UPDATE 命令來應用這些更改並跟蹤實際安裝在給定資料庫中的擴充套件版本。

可以在 ALTER EXTENSION 的描述中找到可以作為擴充套件成員的 SQL 物件型別。特別是,資料庫叢集範圍的物件,如資料庫、角色和表空間,不能成為擴充套件成員,因為擴充套件只在一個數據庫內已知。(儘管擴充套件指令碼不禁止建立此類物件,但如果建立了,它們也不會被跟蹤為擴充套件的一部分。)還要注意,雖然表可以成為擴充套件的成員,但其附屬物件(如索引)不直接被視為擴充套件的成員。另一個重要的點是,模式可以屬於擴充套件,反之則不然:擴充套件本身具有不限定的名稱,並且不存在於任何模式“之內”。然而,擴充套件的成員物件將在適當的時候屬於模式,具體取決於其物件型別。擴充套件可能擁有其成員物件所在的模式,也可能不擁有。

如果擴充套件指令碼建立了任何臨時物件(如臨時表),則這些物件在當前會話的剩餘時間內被視為擴充套件成員,但會在會話結束時自動刪除,就像任何臨時物件一樣。這是擴充套件成員物件不能在不刪除整個擴充套件的情況下刪除的規則的一個例外。

36.17.1. 擴充套件檔案 #

CREATE EXTENSION 命令依賴於每個擴充套件的控制檔案,該檔案必須命名為與副檔名相同,並以 .control 作為字尾,並且必須放置在安裝的 SHAREDIR/extension 目錄中。還必須至少有一個SQL指令碼檔案,其命名模式為 extension--version.sql(例如,擴充套件 foo1.0 版本為 foo--1.0.sql)。預設情況下,指令碼檔案也放置在 SHAREDIR/extension 目錄中;但控制檔案可以為指令碼檔案指定不同的目錄。

可以使用引數 extension_control_path 配置擴充套件控制檔案的其他位置。

擴充套件控制檔案的檔案格式與 postgresql.conf 檔案相同,即每行一個 parameter_name = value 賦值。允許空行和以 # 開頭的註釋。請確保引用任何不是單個單詞或數字的值。

控制檔案可以設定以下引數

directory (string) #

包含擴充套件SQL指令碼檔案的目錄。除非給出絕對路徑,否則名稱相對於找到控制檔案的目錄。預設情況下,指令碼檔案在找到控制檔案的同一目錄中查詢。

default_version (string) #

擴充套件的預設版本(如果 CREATE EXTENSION 中未指定版本,則安裝該版本)。儘管可以省略此項,但如果 CREATE EXTENSION 中未出現 VERSION 選項,則會導致 CREATE EXTENSION 失敗,因此通常不應這樣做。

comment (string) #

關於擴充套件的註釋(任意字串)。在首次建立擴充套件時應用註釋,但在擴充套件更新期間不應用(因為這可能會覆蓋使用者新增的註釋)。或者,可以透過在指令碼檔案中編寫 COMMENT 命令來設定擴充套件的註釋。

encoding (string) #

指令碼檔案使用的字元集編碼。如果指令碼檔案包含任何非 ASCII 字元,則應指定此項。否則,假定檔案採用資料庫編碼。

module_pathname (string) #

此引數的值將替換指令碼檔案中的每個 MODULE_PATHNAME 出現。如果未設定,則不進行替換。通常,此引數設定為 shared_library_name,然後在 C 語言函式的 CREATE FUNCTION 命令中使用 MODULE_PATHNAME,這樣指令碼檔案就不需要硬編碼共享庫的名稱。

requires (string) #

此擴充套件依賴的副檔名稱列表,例如 requires = 'foo, bar'。這些擴充套件必須先安裝,然後才能安裝此擴充套件。

no_relocate (string) #

此擴充套件依賴的副檔名稱列表,這些擴充套件應被阻止透過 ALTER EXTENSION ... SET SCHEMA 更改其模式。如果此擴充套件的指令碼引用了必需擴充套件的模式名稱(使用 @extschema:name@ 語法)且無法跟蹤重新命名,則需要此項。

superuser (boolean) #

如果此引數為 true(這是預設值),則只有超級使用者才能建立該擴充套件或將其更新到新版本(但另請參閱下面的 trusted)。如果設定為 false,則只需要執行安裝或更新指令碼中的命令所需的許可權。如果指令碼中的任何命令需要超級使用者許可權,則此引數通常應設定為 true。(這些命令無論如何都會失敗,但提前給出錯誤會更方便使用者。)

trusted (boolean) #

此引數如果設定為 true(這不是預設值),則允許一些非超級使用者安裝具有 superuser 設定為 true 的擴充套件。具體來說,只要對當前資料庫具有 CREATE 許可權的使用者就可以安裝。當執行 CREATE EXTENSION 的使用者不是超級使用者但由於此引數而允許安裝時,安裝或更新指令碼將以引導超級使用者的身份執行,而不是以呼叫使用者的身份執行。如果 superuserfalse,則此引數無關緊要。通常,不應為可能允許訪問通常只有超級使用者才能訪問的功能(如檔案系統訪問)的擴充套件將此引數設定為 true。此外,將擴充套件標記為受信任需要大量額外工作來安全地編寫擴充套件的安裝和更新指令碼;請參閱 第 36.17.6 節

relocatable (boolean) #

如果一個擴充套件可以在初始建立後將其包含的物件移動到不同的模式中,那麼它就是一個 可重定位 的擴充套件。預設值為 false,即該擴充套件不可重定位。有關更多資訊,請參閱 第 36.17.2 節

schema (string) #

此引數只能為不可重定位的擴充套件設定。它強制擴充套件載入到指定的模式中,而不是任何其他模式。 schema 引數僅在首次建立擴充套件時使用,而在擴充套件更新期間不使用。有關更多資訊,請參閱 第 36.17.2 節

除了主控制檔案 extension.control 之外,擴充套件還可以擁有命名為 extension--version.control 風格的輔助控制檔案。如果提供了這些檔案,它們必須位於指令碼檔案目錄中。輔助控制檔案遵循與主控制檔案相同的格式。在安裝或更新到該擴充套件版本時,輔助控制檔案中設定的任何引數都會覆蓋主控制檔案。但是,directorydefault_version 引數不能在輔助控制檔案中設定。

擴充套件的SQL指令碼檔案可以包含任何 SQL 命令,但事務控制命令(BEGINCOMMIT 等)和不能在事務塊內執行的命令(如 VACUUM)除外。這是因為指令碼檔案是隱式在事務塊內執行的。

擴充套件的SQL指令碼檔案還可以包含以 \echo 開頭的行,這些行將被擴充套件機制忽略(視為註釋)。此約定通常用於在指令碼檔案被饋送到 psql 而不是透過 CREATE EXTENSION 載入時丟擲錯誤(參見 第 36.17.7 節 中的示例指令碼)。如果沒有這個,使用者可能會意外地將擴充套件內容載入為“鬆散”物件而不是作為擴充套件,這種情況恢復起來有些麻煩。

如果擴充套件指令碼包含字串 @extowner@,則該字串將被替換為呼叫 CREATE EXTENSIONALTER EXTENSION 的使用者的(適當加引號的)名稱。通常,此功能由標記為受信任的擴充套件使用,用於將選定物件的擁有權分配給呼叫使用者而不是引導超級使用者。(不過,這樣做應該小心。例如,將 C 語言函式的擁有權分配給非超級使用者將為該使用者建立特權提升路徑。)

雖然指令碼檔案可以包含指定編碼允許的任何字元,但控制檔案應僅包含純 ASCII,因為 PostgreSQL 無法知道控制檔案的編碼。實際上,這隻在您想在擴充套件的註釋中使用非 ASCII 字元時才是一個問題。在這種情況下,建議的做法是不使用控制檔案的 comment 引數,而是使用指令碼檔案中的 COMMENT ON EXTENSION 來設定註釋。

36.17.2. 擴充套件的可重定位性 #

使用者通常希望將擴充套件中包含的物件載入到與擴充套件作者設想的不同模式中。有三種支援的可重定位級別

  • 完全可重定位的擴充套件可以在任何時候移動到另一個模式中,即使它已經被載入到資料庫中。這是透過 ALTER EXTENSION SET SCHEMA 命令完成的,該命令會自動將所有成員物件重新命名到新模式中。通常,只有當擴充套件不包含關於其任何物件位於哪個模式中的內部假設時,才可能這樣做。此外,擴充套件的物件必須全部位於一個模式中(忽略不屬於任何模式的物件,如過程語言)。透過在其控制檔案中設定 relocatable = true 來標記完全可重定位的擴充套件。

  • 擴充套件在安裝時可能可重定位,但之後不可。這通常是由於擴充套件指令碼需要顯式引用目標模式,例如在為 SQL 函式設定 search_path 屬性時。對於此類擴充套件,在其控制檔案中設定 relocatable = false,並在指令碼檔案中使用 @extschema@ 來引用目標模式。在指令碼執行之前,此字串的所有出現都將替換為實際目標模式的名稱(如果需要,會加上雙引號)。使用者可以使用 CREATE EXTENSIONSCHEMA 選項來設定目標模式。

  • 如果擴充套件根本不支援重定位,請在其控制檔案中設定 relocatable = false,並設定 schema 為目標模式的名稱。這將阻止使用 CREATE EXTENSIONSCHEMA 選項,除非它指定了控制檔案中命名的相同模式。當擴充套件包含無法透過使用 @extschema@ 替換的模式名稱的內部假設時,通常需要此選項。在這種情況下,@extschema@ 替換機制也可用,儘管它的用處有限,因為模式名稱由控制檔案確定。

在所有情況下,指令碼檔案都將以 search_path 初始化為指向目標模式來執行;也就是說,CREATE EXTENSION 會執行等效於此的操作

SET LOCAL search_path TO @extschema@, pg_temp;

這允許指令碼檔案建立的物件進入目標模式。指令碼檔案可以根據需要更改 search_path,但這通常是不希望的。search_pathCREATE EXTENSION 完成後會恢復到其先前的設定。

目標模式由控制檔案中的 schema 引數(如果給定)確定,否則由 CREATE EXTENSIONSCHEMA 選項(如果給定)確定,否則為當前的預設物件建立模式(呼叫者的 search_path 中的第一個)。當使用控制檔案 schema 引數時,如果目標模式不存在,將被建立,但在其他兩種情況下,它必須已經存在。

如果任何先決擴充套件在控制檔案中的 requires 中列出,則它們的目標模式將新增到 search_path 的初始設定中,位於新擴充套件的目標模式之後。這允許新擴充套件的指令碼檔案可見它們的中的物件。

出於安全原因,pg_temp 會自動新增到所有情況下的 search_path 末尾。

儘管不可重定位的擴充套件可能包含分佈在多個模式中的物件,但通常最好將所有打算供外部使用的物件放在一個模式中,該模式被視為擴充套件的目標模式。這種安排與依賴擴充套件建立期間的 search_path 預設設定非常方便。

如果擴充套件引用屬於另一個擴充套件的物件,建議對這些引用進行模式限定。為此,請在擴充套件的指令碼檔案中寫入 @extschema:name@,其中 name 是另一個擴充套件的名稱(必須在此擴充套件的 requires 列表中)。此字串將被替換為該擴充套件的目標模式的名稱(如果需要,加上雙引號)。雖然這種表示法避免了在擴充套件指令碼檔案中對模式名稱進行硬編碼的假設,但它的使用可能會將其他擴充套件的模式名稱嵌入到此擴充套件的已安裝物件中。(通常,當 @extschema:name@ 在字串字面量中使用時,例如函式體或 search_path 設定。在其他情況下,物件引用在解析時會簡化為 OID,並且不需要後續查詢。)如果其他擴充套件的模式名稱以這種方式嵌入,您應該防止在您的擴充套件安裝後重新定位其他擴充套件,方法是將其他擴充套件的名稱新增到此擴充套件的 no_relocate 列表中。

36.17.3. 擴充套件配置檔案 #

一些擴充套件包含配置檔案,其中包含使用者在擴充套件安裝後可能新增或更改的資料。通常,如果一個表屬於一個擴充套件,那麼 pg_dump 不會轉儲該表的定義或其內容。但對於配置檔案來說,這種行為是不希望的;使用者對資料所做的任何更改都需要包含在轉儲中,否則擴充套件在轉儲和恢復後將表現不同。

為了解決這個問題,擴充套件的指令碼檔案可以將它建立的表或序列標記為配置關係,這將導致 pg_dump 在轉儲中包含表或序列的內容(而不是其定義)。要做到這一點,請在建立表或序列後呼叫函式 pg_extension_config_dump(regclass, text),例如

CREATE TABLE my_config (key text, value text);
CREATE SEQUENCE my_config_seq;

SELECT pg_catalog.pg_extension_config_dump('my_config', '');
SELECT pg_catalog.pg_extension_config_dump('my_config_seq', '');

可以以這種方式標記任意數量的表或序列。與 serialbigserial 列關聯的序列也可以被標記。

pg_extension_config_dump 的第二個引數為空字串時,pg_dump 會轉儲表的所有內容。這通常只有在表最初是空的時才正確,就像它由擴充套件指令碼建立的那樣。如果表中存在初始資料和使用者提供的資料的混合,pg_extension_config_dump 的第二個引數提供一個 WHERE 條件來選擇要轉儲的資料。例如,您可以這樣做

CREATE TABLE my_config (key text, value text, standard_entry boolean);

SELECT pg_catalog.pg_extension_config_dump('my_config', 'WHERE NOT standard_entry');

然後確保 standard_entry 僅在擴充套件指令碼建立的行中為 true。

對於序列,pg_extension_config_dump 的第二個引數沒有影響。

更復雜的情況,例如使用者可能會修改的初始提供的行,可以透過在配置表上建立觸發器來處理,以確保修改後的行被正確標記。

您可以透過再次呼叫 pg_extension_config_dump 來更改與配置表關聯的過濾條件。(這通常在擴充套件更新指令碼中有用。)將表標記為不再是配置表的唯一方法是使用 ALTER EXTENSION ... DROP TABLE 將其與擴充套件分離。

請注意,這些表之間的外部索引鍵關係將決定 pg_dump 轉儲這些表的順序。具體來說,pg_dump 將嘗試先轉儲被引用表,然後再轉儲引用表。由於外部索引鍵關係是在 CREATE EXTENSION 時建立的(在資料載入到表中之前),因此不支援迴圈依賴。當存在迴圈依賴時,資料仍會被轉儲,但轉儲將無法直接恢復,需要使用者干預。

serialbigserial 列關聯的序列需要直接標記才能轉儲其狀態。僅標記其父關係不足以達到此目的。

36.17.4. 擴充套件更新 #

擴充套件機制的一個優點是它提供了管理擴充套件物件定義 SQL 命令更新的便捷方法。這是透過為擴充套件安裝指令碼的每個釋出版本關聯一個版本名稱或編號來實現的。此外,如果您希望使用者能夠動態地從一個版本更新到下一個版本,您應該提供 更新指令碼,這些指令碼進行必要的更改以從一個版本到下一個版本。更新指令碼的名稱遵循 extension--old_version--target_version.sql 的模式(例如,foo--1.0--1.1.sql 包含將擴充套件 foo1.0 版本修改為 1.1 版本的命令)。

鑑於存在合適的更新指令碼,ALTER EXTENSION UPDATE 命令可以將已安裝的擴充套件更新到指定的最新版本。更新指令碼在與 CREATE EXTENSION 為安裝指令碼提供的相同環境中執行:特別是,search_path 以相同的方式設定,指令碼建立的任何新物件都會自動新增到擴充套件中。此外,如果指令碼選擇刪除擴充套件成員物件,它們將自動與擴充套件分離。

如果擴充套件具有輔助控制檔案,則用於更新指令碼的控制引數是與指令碼的目標(新)版本關聯的引數。

ALTER EXTENSION 能夠執行一系列更新指令碼檔案來實現請求的更新。例如,如果只有 foo--1.0--1.1.sqlfoo--1.1--2.0.sql 可用,噹噹前安裝的是 1.0 而請求更新到 2.0 時,ALTER EXTENSION 將按順序應用它們。

PostgreSQL 不假定版本名稱的屬性:例如,它不知道 1.1 是否遵循 1.0。它只是匹配可用版本名稱,並遵循需要應用最少更新指令碼的路徑。(版本名稱實際上可以是任何不包含 -- 或前導/尾隨 - 的字串。)

有時提供“降級”指令碼很有用,例如 foo--1.1--1.0.sql 以允許撤銷與版本 1.1 相關的更改。如果您這樣做,請注意降級指令碼可能會意外應用的可能性がある,因為它會產生更短的路徑。風險情況是存在一個“快速路徑”更新指令碼,該指令碼可以跳過幾個版本,還有一個降級指令碼可以回到快速路徑的起點。應用降級然後再應用快速路徑可能比逐個版本向前移動需要更少的步驟。如果降級指令碼刪除了任何不可替換的物件,這將產生不期望的結果。

要檢查意外的更新路徑,請使用此命令

SELECT * FROM pg_extension_update_paths('extension_name');

這會顯示指定擴充套件的每對不同的已知版本名稱,以及從源版本到目標版本將要採取的更新路徑序列,或者如果不存在可用的更新路徑,則顯示 NULL。路徑以文字形式顯示,使用 -- 分隔符。如果您更喜歡陣列格式,可以使用 regexp_split_to_array(path,'--')

36.17.5. 使用更新指令碼安裝擴充套件 #

一個存在已久的擴充套件可能存在多個版本,作者需要為這些版本編寫更新指令碼。例如,如果您釋出了一個 foo 擴充套件,版本為 1.01.11.2,則應該有更新指令碼 foo--1.0--1.1.sqlfoo--1.1--1.2.sql。在 PostgreSQL 10 之前,還必須建立新的指令碼檔案 foo--1.1.sqlfoo--1.2.sql,這些檔案直接構建較新的擴充套件版本,否則較新版本只能透過安裝 1.0 然後更新來安裝。這很麻煩且重複,但現在不再需要了,因為 CREATE EXTENSION 可以自動跟蹤更新鏈。例如,如果只有指令碼檔案 foo--1.0.sqlfoo--1.0--1.1.sqlfoo--1.1--1.2.sql 可用,那麼安裝版本 1.2 的請求將透過按順序執行這三個指令碼來處理。處理方式與您先安裝 1.0 然後更新到 1.2 相同。(與 ALTER EXTENSION UPDATE 類似,如果有多個可用路徑,則首選最短路徑。)以這種方式組織擴充套件的指令碼檔案可以減少生成小更新所需的維護工作。

如果您在以這種風格維護的擴充套件中使用輔助(版本特定)控制檔案,請記住每個版本都需要一個控制檔案,即使它沒有獨立的安裝指令碼,因為該控制檔案將決定如何執行到該版本的隱式更新。例如,如果 foo--1.0.control 指定了 requires = 'bar'foo 的其他控制檔案沒有,則在從 1.0 更新到其他版本時,擴充套件對 bar 的依賴關係將被刪除。

36.17.6. 擴充套件的安全性注意事項 #

廣泛分發的擴充套件應假定其所在的資料庫非常少。因此,以安全的方式編寫擴充套件提供的函式是合適的,這種方式無法被基於搜尋路徑的攻擊所破壞。

如果擴充套件的 superuser 屬性設定為 true,則還必須考慮其安裝和更新指令碼中操作的安全性風險。惡意使用者很容易建立特洛伊木馬物件,這些物件會破壞粗心編寫的擴充套件指令碼的後續執行,從而允許該使用者獲得超級使用者許可權。

如果一個擴充套件被標記為 trusted,那麼它的安裝模式可以由安裝使用者選擇,安裝使用者可能故意使用不安全的模式,希望獲得超級使用者許可權。因此,受信任的擴充套件從安全形度來看非常危險,並且必須仔細檢查其所有指令碼命令,以確保不會發生任何安全漏洞。

關於安全編寫函式的建議在下面的 第 36.17.6.1 節 中提供,關於安全編寫安裝指令碼的建議在下面的 第 36.17.6.2 節 中提供。

36.17.6.1. 擴充套件函式的安全性注意事項 #

SQL 語言和 PL 語言函式存在被搜尋路徑攻擊的風險,因為這些函式的解析發生在執行時而不是建立時。

CREATE FUNCTION 參考頁包含關於安全編寫 SECURITY DEFINER 函式的建議。對於由擴充套件提供的任何函式,應用這些技術都是一個好習慣,因為該函式可能由具有高許可權的使用者呼叫。

如果無法將 search_path 設定為僅包含安全模式,則假定每個不限定名稱的物件都可以解析為惡意使用者定義的另一個物件。注意那些隱式依賴於 search_path 的構造;例如,INCASE expression WHEN 總是使用搜索路徑選擇運算子。在它們的位置,使用 OPERATOR(schema.=) ANYCASE WHEN expression

通用擴充套件通常不應假定它已安裝到安全模式中,這意味著即使是對其自身物件的模式限定引用也不是完全安全的。例如,如果擴充套件定義了一個函式 myschema.myfunc(bigint),那麼呼叫 myschema.myfunc(42) 可能會被一個惡意的函式 myschema.myfunc(integer) 捕獲。請注意,函式和運算子引數的資料型別必須與宣告的引數型別完全匹配,並在必要時使用顯式轉換。

36.17.6.2. 擴充套件指令碼的安全性注意事項 #

應編寫擴充套件安裝或更新指令碼,以防範指令碼執行時發生的基於搜尋路徑的攻擊。如果指令碼中的物件引用可以解析為與指令碼作者意圖不同的物件,那麼可能會立即發生安全漏洞,或者在誤定義的擴充套件物件使用時發生。

DDL 命令如 CREATE FUNCTIONCREATE OPERATOR CLASS 通常是安全的,但要注意任何將通用表示式作為元件的命令。例如,CREATE VIEW 需要審查,CREATE FUNCTION 中的 DEFAULT 表示式也需要審查。

有時擴充套件指令碼可能需要執行通用 SQL,例如進行無法透過 DDL 實現的目錄調整。請注意使用安全的 search_path 來執行此類命令;*不要* 信任 CREATE/ALTER EXTENSION 提供的路徑是安全的。最佳實踐是暫時將 search_path 設定為 pg_catalog, pg_temp,並在需要時顯式插入對擴充套件安裝模式的引用。(這種做法也可能有助於建立檢視。)示例可以在 PostgreSQL 原始碼發行版的 contrib 模組中找到。

安全的跨擴充套件引用通常需要對其他擴充套件的物件名稱進行模式限定,使用 @extschema:name@ 語法,此外還需要仔細匹配函式和運算子的引數型別。

36.17.7. 擴充套件示例 #

這是一個完整的示例,用於一個SQL-only 擴充套件,一個可以將其槽中的任何型別的值儲存的二維複合型別,這些槽被命名為“k”和“v”。非文字值會自動強制轉換為文字進行儲存。

指令碼檔案 pair--1.0.sql 如下所示

-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION pair" to load this file. \quit

CREATE TYPE pair AS ( k text, v text );

CREATE FUNCTION pair(text, text)
RETURNS pair LANGUAGE SQL AS 'SELECT ROW($1, $2)::@extschema@.pair;';

CREATE OPERATOR ~> (LEFTARG = text, RIGHTARG = text, FUNCTION = pair);

-- "SET search_path" is easy to get right, but qualified names perform better.
CREATE FUNCTION lower(pair)
RETURNS pair LANGUAGE SQL
AS 'SELECT ROW(lower($1.k), lower($1.v))::@extschema@.pair;'
SET search_path = pg_temp;

CREATE FUNCTION pair_concat(pair, pair)
RETURNS pair LANGUAGE SQL
AS 'SELECT ROW($1.k OPERATOR(pg_catalog.||) $2.k,
               $1.v OPERATOR(pg_catalog.||) $2.v)::@extschema@.pair;';

控制檔案 pair.control 如下所示

# pair extension
comment = 'A key/value pair data type'
default_version = '1.0'
# cannot be relocatable because of use of @extschema@
relocatable = false

雖然您幾乎不需要 makefile 將這兩個檔案安裝到正確目錄,但您可以使用包含此內容的 Makefile

EXTENSION = pair
DATA = pair--1.0.sql

PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)

此 makefile 依賴於PGXS,其描述在 第 36.18 節 中。 make install 命令將把控制檔案和指令碼檔案安裝到 pg_config 報告的正確目錄中。

檔案安裝完成後,使用 CREATE EXTENSION 命令將物件載入到任何特定的資料庫中。

提交更正

如果您在文件中發現任何不正確、與您對特定功能的體驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。