web-dev-qa-db-ja.com

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')は、デフォルトでは_"$user",public_を含むTEXTを返すため、あまり役に立ちません。

他に考えられる唯一のことは、テーブルから選択して例外をキャッチすることです。それは仕事をしますが、それは非常にエレガントだとは思わず、使用するのは高価であると読みました(ただし、私は実行しているだけなので、このシナリオでは大丈夫でしょう)それは一度ですか?).

10
cimmanon

早くて汚い

Postgres9.4 +では

_SELECT to_regclass('foo');
_

識別子が検索パスで見つからない場合は、NULLを返します。
Postgres9.3以前ではcast to regclass を使用します:

_SELECT 'foo'::regclass;
_

オブジェクトが見つからない場合、これは例外を発生させます

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

オブジェクトが見つからない場合、sure検索パスのどこにも存在しないか、スキーマ修飾名(_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ステートメントで問題があります。

18

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

where n.nspname = any(string_to_array(replace(current_setting('search_path'), '$user', current_user), ','))
./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
0
Vishal Bendre