Come posso determinare se esiste una tabella nel percorso di ricerca corrente con PLPGSQL?


10

Sto scrivendo uno script di installazione per un'applicazione che è un componente aggiuntivo per un'altra applicazione, quindi voglio verificare se esistono le tabelle per l'altra applicazione. In caso contrario, voglio dare all'utente un errore utile. Tuttavia, non so quale schema conterrà le tabelle.

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

Tuttavia, current_setting('search_path')restituisce un TESTO contenente "$user",publicper impostazione predefinita, che non è molto utile.

L'unica altra cosa che mi viene in mente è provare a selezionare dalla tabella e catturare l'eccezione. Farebbe il lavoro, ma non penso che sia molto elegante e ho letto che è costoso da usare (anche se forse sarebbe ok in questo scenario poiché lo sto eseguendo solo una volta?).

Risposte:


18

Veloce e sporco

In Postgres 9.4+ utilizzare

SELECT to_regclass('foo');

Restituisce NULL se l'identificatore non viene trovato nel percorso di ricerca.
In Postgres 9.3 o precedenti usa un cast perregclass :

SELECT 'foo'::regclass;

Ciò solleva un'eccezione , se l'oggetto non viene trovato!

Se 'foo'viene trovato, oidviene restituito nella sua textrappresentazione. Questo è solo il nome della tabella, qualificato dallo schema in base al percorso di ricerca corrente e tra virgolette doppie, se necessario.

Se l'oggetto non viene trovato, si può essere certi che non esiste da nessuna parte nel percorso di ricerca - o che non sia affatto per un nome qualificato da schema ( schema.foo).

Se viene rilevato ci sono due carenze :

  1. La ricerca include schemi impliciti del percorso di ricerca , vale a dire pg_catalogepg_temp . Ma potresti voler escludere tabelle temporanee e di sistema per i tuoi scopi. (?)

  2. Un cast regclassfunziona per tutti gli oggetti nel catalogo di sistema pg_class: indici, viste, sequenze ecc. Non solo tabelle. Sembra che tu stia cercando esclusivamente un tavolo normale. Tuttavia, probabilmente avrai problemi anche con altri oggetti con lo stesso nome. Dettagli:

Lento e sicuro

Siamo tornati alla tua query, ma non utilizziamo current_setting('search_path'), che restituisce l'impostazione non elaborata. Utilizzare la funzione di informazioni di sistema dedicata current_schemas(). Per documentazione:

current_schemas(boolean) name[]
nomi di schemi nel percorso di ricerca, facoltativamente inclusi schemi impliciti

"$user"nel percorso di ricerca viene risolto in modo intelligente. Se non esiste uno schema con il nome di SESSION_USER, lo schema non viene restituito per cominciare. Inoltre, a seconda di cosa vuoi esattamente, puoi anche generare schemi impliciti ( pg_cataloge possibilmente pg_temp) - ma suppongo che tu non li voglia per il caso a portata di mano, quindi usa:

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 , dimostrando tutto tranne l'ultimaDOdichiarazione.
SQL Fiddle (JDBC) ha problemi con le DOistruzioni contenenti caratteri di terminazione.


1

È possibile convertire il valore di configurazione in un array e sostituirlo $usercon il nome utente corrente. L'array può quindi essere utilizzato nella condizione 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.