Bagaimana saya bisa menentukan apakah ada tabel di search_path saat ini dengan PLPGSQL?

10

Saya sedang menulis skrip pengaturan untuk aplikasi yang merupakan tambahan untuk aplikasi lain, jadi saya ingin memeriksa apakah tabel untuk aplikasi lain ada. Jika tidak, saya ingin memberikan kesalahan bermanfaat kepada pengguna. Namun, saya tidak tahu skema apa yang akan menahan tabel.

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;
$$;

Namun, current_setting('search_path')mengembalikan TEXT yang berisi "$user",publicsecara default, yang tidak terlalu berguna.

Satu-satunya hal lain yang dapat saya pikirkan adalah mencoba memilih dari tabel dan menangkap pengecualian. Itu akan melakukan pekerjaan, tetapi saya tidak berpikir itu sangat elegan dan saya sudah membaca bahwa itu mahal untuk digunakan (meskipun mungkin itu akan baik-baik saja dalam skenario ini karena saya hanya menjalankannya sekali?).

cimmanon
sumber

Jawaban:

18

Cepat dan kotor

Dalam Postgres 9.4+ digunakan

SELECT to_regclass('foo');

Mengembalikan NULL jika pengidentifikasi tidak ditemukan di jalur pencarian.
Di Postgres 9.3 atau lebih lama gunakan gips untukregclass :

SELECT 'foo'::regclass;

Ini menimbulkan pengecualian , jika objek tidak ditemukan!

Jika 'foo'ditemukan, oiddikembalikan dalam textperwakilannya. Itu hanya nama tabel, skema-kualifikasi sesuai dengan jalur pencarian saat ini dan dikutip ganda jika perlu.

Jika objek tidak ditemukan, Anda dapat yakin itu tidak ada di mana pun di jalur pencarian - atau tidak sama sekali untuk nama yang memenuhi syarat skema ( schema.foo).

Jika ditemukan ada dua kekurangan :

  1. Pencarian termasuk skema implisit dari search_path , yaitu pg_catalogdanpg_temp . Tetapi Anda mungkin ingin mengecualikan temp dan tabel sistem untuk tujuan Anda. (?)

  2. Gips regclassberfungsi untuk semua objek dalam katalog sistem pg_class: indeks, tampilan, urutan, dll. Bukan hanya tabel. Anda tampaknya mencari meja biasa secara eksklusif. Namun, Anda mungkin akan memiliki masalah dengan objek lain dengan nama yang sama juga. Detail:

Lambat dan pasti

Kami kembali ke permintaan Anda, tetapi jangan gunakan current_setting('search_path'), yang mengembalikan pengaturan kosong. Gunakan fungsi informasi sistem khusus current_schemas(). Per dokumentasi:

current_schemas(boolean) name[]
nama skema di jalur pencarian, opsional termasuk skema implisit

"$user"di jalur pencarian diselesaikan dengan cerdas. Jika tidak ada skema dengan nama SESSION_USERada, skema tidak dikembalikan untuk memulai. Juga, tergantung pada apa yang Anda inginkan secara tepat, Anda juga dapat menghasilkan skema implisit ( pg_catalogdan mungkin pg_temp) - tapi saya berasumsi Anda tidak menginginkannya untuk kasing, jadi gunakan:

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 , menunjukkan semua kecuali untukDOpernyataanterakhir.
SQL Fiddle (JDBC) memiliki masalah dengan DOpernyataan yang berisi karakter terminasi.

Erwin Brandstetter
sumber
1

Anda dapat mengonversi nilai konfigurasi ke array dan mengganti $userdengan nama pengguna saat ini. Array kemudian dapat digunakan dalam kondisi di mana:

where n.nspname = any(string_to_array(replace(current_setting('search_path'), '$user', current_user), ','))
seekor kuda tanpa nama
sumber
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
Vishal Bendre
sumber