PLPGSQLを使用して現在のsearch_pathにテーブルが存在するかどうかを確認するにはどうすればよいですか?


10

別のアプリケーションのアドオンであるアプリケーションのセットアップスクリプトを作成しているので、他のアプリケーションのテーブルが存在するかどうかを確認したいと思います。そうでない場合は、ユーザーに有用なエラーを提供します。ただし、テーブルを保持するスキーマがわかりません。

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それほど役に立ちません。

他に考えられる唯一のことは、テーブルから選択して例外をキャッチすることです。それはうまくいきますが、それは非常にエレガントだとは思わず、使用するにはコストかかると読みました(たぶん、このシナリオでは1回しか実行しないので、それで問題ないでしょうか?)。

回答:


18

早くて汚い

Postgres 9.4以降で使用

SELECT to_regclass('foo');

識別子が検索パスで見つからない場合は、NULLを返します。
Postgres 9.3以前では、次のキャストをregclass使用します。

SELECT 'foo'::regclass;

これは、例外が発生したオブジェクトが見つからない場合は、!

場合は'foo'発見され、oidその中に返されるtext表現。これは単なるテーブル名であり、現在の検索パスに従ってスキーマで修飾され、必要に応じて二重引用符で囲まれます。

オブジェクトが見つからない場合は、検索パスのどこにも存在しないか、スキーマ修飾名()のオブジェクトがまったく存在しないことを確認できますschema.foo

見つかった場合、2つの欠点があります。

  1. 検索には、search_pathの暗黙的なスキーマ、つまりpg_catalogおよびが含まれpg_tempます。ただし、目的で一時テーブルとシステムテーブルを除外することもできます。(?)

  2. インデックス、ビュー、シーケンスなど、regclassシステムカタログ内のすべてのオブジェクトに対して機能するキャスト。テーブルだけでなくpg_class、通常のテーブルのみを探しているようです。ただし、同じ名前の他のオブジェクトでも問題が発生する可能性があります。詳細:

ゆっくりと確実

クエリにcurrent_setting('search_path')戻りますが、ベア設定を返すを使用しないでください。専用のシステム情報機能を使用してくださいcurrent_schemas()。ドキュメントごと:

current_schemas(boolean) name[]
検索パス内のスキーマの名前、オプションで暗黙的なスキーマを含む

"$user"検索パス内のスマートに解決されます。という名前の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$;

SQL Fiddle、最後のDOステートメントを除くすべてを示します
SQL Fiddle(JDBC)には、DO終了文字を含むステートメントに関する問題があります。


1

構成値を配列に変換$userし、現在のユーザー名に置き換えることができます。その後、配列はwhere条件で使用できます。

where n.nspname = any(string_to_array(replace(current_setting('search_path'), '$user', current_user), ','))

0
./sshi.sh vb20deployment controller <<'HERE'
export PGPASSWORD="postgres"
cd logu/postgresql/bin
row=1
tableArray=(table1 table2 table3 table4 table5 table6)

for (( x=0 ; x<=5 ; x++)) ; do        

./psql.bin --port=5432 --username=postgres --host=hostname.rds.amazonaws.com --dbname=mydb -c "SELECT * FROM information_schema.tables WHERE '${tableArray[$x]}' = table_name" | while read -a Record ; do
  row=$((row + 1))
  if [[ $row -gt 3 ]]; then

     echo ${Record[4]}

   fi
done

done


HERE
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.