如何使用 PLPGSQL 確定目前 search_path 中是否存在表?
我正在為一個應用程序編寫一個安裝腳本,該應用程序是另一個應用程序的外掛,所以我想檢查另一個應用程序的表是否存在。如果沒有,我想給使用者一個有用的錯誤。但是,我不知道什麼模式將保存這些表。
DO LANGUAGE plpgsql $$ BEGIN PERFORM 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = current_setting('search_path') AND c.relname = 'foo' AND c.relkind = 'r'; -- not sure if I actually need this or not... IF NOT FOUND THEN RAISE 'This application depends on tables created by another application'; END IF; END; $$;
但是,預設情況下
current_setting('search_path')
返回一個 TEXT 包含"$user",public
,這不是非常有用。我能想到的唯一另一件事是嘗試從表中選擇並擷取異常。它可以完成這項工作,但我認為它不是很優雅,而且我讀過它使用起來很昂貴(儘管在這種情況下可能沒問題,因為我只執行一次?)。
快速(又髒?)
在 Postgres 9.4 或更新版本中使用
to_regclass()
:SELECT to_regclass('foo');
如果搜尋路徑中沒有該名稱的關係,則返回 NULL。
在 Postgres 9.3 或更早版本(或任何版本)中,使用強制轉換
regclass
:SELECT 'foo'::regclass;
如果找不到對象,則會引發異常!
看:
如果
'foo'
找到,oid
則返回 - 表示為文本。這是關係名稱,根據目前搜尋路徑進行模式限定,並在必要時使用雙引號。如果未找到該關係,您可以確定它在搜尋路徑中的任何位置都不存在 - 或者對於模式限定名稱 (
schema.foo
) 根本不存在。如果發現有兩個缺點:
- 搜尋包括search_path的隱式模式,即***
pg_catalog
和pg_temp
***。但是您可能希望出於您的目的排除臨時表和系統表。(?)- 強制轉換
regclass
在系統目錄中查找任何關係(類似表的對象)pg_class
:表、索引、視圖、序列等。***不僅僅是正常表。***其他同名對象可能會產生誤報。緩慢而肯定(仍然很快,真的)
我們回到了類似您的查詢的問題。但不要使用
current_setting('search_path')
,它會返回裸設置。使用專用的系統資訊功能current_schemas()
。手冊:
current_schemas(boolean)
name[]
搜尋路徑中的模式名稱,可選地包括隱式模式
"$user"
在中search_path
被巧妙地解決了。如果不存在具有目前名稱的模式SESSION_USER
,則它解析為空。您還可以輸出隱式模式(pg_catalog
並且可能pg_temp
) - 但我假設不適用於手頭的情況,所以:DO $do$ BEGIN IF EXISTS ( SELECT -- list can be empty FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = ANY(current_schemas(FALSE)) AND n.nspname NOT LIKE 'pg_%' -- exclude system schemas! AND c.relname = 'foo' AND c.relkind = 'r') -- you probably need this THEN RAISE 'This application depends on tables created by another application'; END IF; END $do$;
db<>fiddle here