Postgresql

如何使用 PLPGSQL 確定目前 search_path 中是否存在表?

  • June 9, 2021

我正在為一個應用程序編寫一個安裝腳本,該應用程序是另一個應用程序的外掛,所以我想檢查另一個應用程序的表是否存在。如果沒有,我想給使用者一個有用的錯誤。但是,我不知道什麼模式將保存這些表。

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) 根本不存在。

如果發現有兩個缺點

  1. 搜尋包括search_path的隱式模式,即***pg_catalogpg_temp***。但是您可能希望出於您的目的排除臨時表和系統表。(?)
  2. 強制轉換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

sqlfiddle

引用自:https://dba.stackexchange.com/questions/86050