PLPGSQL ile geçerli arama yolunda bir tablonun olup olmadığını nasıl belirleyebilirim?


10

Başka bir uygulama için bir addon olan bir uygulama için bir kurulum komut dosyası yazıyorum, bu yüzden diğer uygulama için tablolar olup olmadığını kontrol etmek istiyorum. Değilse, kullanıcıya yararlı bir hata vermek istiyorum. Ancak, hangi şemanın tabloları tutacağını bilmiyorum.

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

Ancak, varsayılan olarak çok yararlı olmayan current_setting('search_path')bir METİN döndürür "$user",public.

Aklıma gelen tek şey tablodan seçim yapmak ve istisnayı yakalamak. İşi yapardı, ama çok zarif olduğunu düşünmüyorum ve kullanmanın pahalı olduğunu okudum (ancak sadece bir kez çalıştırdığımdan beri bu senaryoda bu sorun olur mu?).

Yanıtlar:


18

Hızlı ve kirli

Postgres 9.4+ kullanımı

SELECT to_regclass('foo');

Tanımlayıcı arama yolunda bulunmazsa NULL değerini döndürür.
Postgres 9.3 veya daha eski sürümlerde şunlar için oyuncu kadrosu kullanınregclass :

SELECT 'foo'::regclass;

Bu bir özel durum nesnesi bulunmazsa,!

Eğer 'foo'bulunursa, temsilinde oiddöndürülür text. Bu sadece tablo adı, geçerli arama yoluna göre şema nitelemeli ve gerektiğinde çift tırnaklı.

Nesne bulunmazsa, arama yolunun herhangi bir yerinde bulunmadığından emin olabilirsiniz - ya da şema nitelemeli bir ad için hiç yoktur ( schema.foo).

Eğer bulunursa iki eksiklik vardır :

  1. Arama, arama_yolunun örtülü şemalarını , yani pg_catalogve içerirpg_temp . Ancak temp ve sistem tablolarını amacınız için hariç tutmak isteyebilirsiniz. (?)

  2. Döküm regclass, sistem kataloğundaki tüm nesneler için çalışır pg_class: dizinler, görünümler, diziler vb . Sadece tablolar değil. Sadece düzenli bir masa arıyor gibi görünüyor. Ancak, muhtemelen aynı addaki diğer nesnelerle de sorun yaşayacaksınız. Detaylar:

Yavaş ve emin

Sorgunuza geri döndük, ancak current_setting('search_path')çıplak ayarı döndüren kullanmıyoruz . Özel sistem bilgi işlevini kullanın current_schemas(). Belgelere göre:

current_schemas(boolean) name[]
arama yolundaki şemaların adları, isteğe bağlı olarak örtük şemalar dahil

"$user"arama yolunda akıllıca çözülür. Eğer adında bir şema SESSION_USERyoksa, şema başlamak için döndürülmez. Ayrıca, tam olarak ne istediğinize bağlı olarak, ek olarak örtük şemalar ( pg_catalogve muhtemelen pg_temp) çıktısı alabilirsiniz - ancak eldeki durum için bunları istemediğinizi varsayalım, bu yüzden kullanın:

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 , sonDOifadehariç her şeyi gösterir.
SQL Fiddle (JDBC), DOsonlandırma karakterlerini içeren ifadelerde sorun yaşıyor .


1

Yapılandırma değerini bir diziye dönüştürebilir $userve geçerli kullanıcı adıyla değiştirebilirsiniz. Dizi daha sonra where koşulunda kullanılabilir:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.