web-dev-qa-db-fra.com

Comment puis-je déterminer si une table existe dans le chemin de recherche actuel avec PLPGSQL?

J'écris un script de configuration pour une application qui est un addon pour une autre application, donc je veux vérifier si les tables de l'autre application existent. Sinon, je veux donner à l'utilisateur une erreur utile. Cependant, je ne sais pas quel schéma contiendra les tables.

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

Cependant, current_setting('search_path') renvoie un TEXTE contenant "$user",public Par défaut, ce qui n'est pas très utile.

La seule autre chose à laquelle je peux penser est d'essayer de sélectionner dans le tableau et de saisir l'exception. Cela ferait l'affaire, mais je ne pense pas qu'il soit très élégant et j'ai lu qu'il est cher à utiliser (bien que ce serait peut-être correct dans ce scénario car je ne fais que courir une fois?).

10
cimmanon

Rapide et sale

Dans Postgres 9.4 + utilisez

SELECT to_regclass('foo');

Renvoie NULL si l'identifiant n'est pas trouvé dans le chemin de recherche.
Dans Postgres 9.3 ou plus ancien utilisez un transtypé en regclass :

SELECT 'foo'::regclass;

Ceci déclenche une exception, si l'objet n'est pas trouvé!

Si 'foo' est trouvé, le oid est retourné dans sa représentation text. C'est juste le nom de la table, qualifié par le schéma en fonction du chemin de recherche actuel et placé entre guillemets si nécessaire.

Si l'objet n'est pas trouvé, vous pouvez être bien sûr il n'existe nulle part dans le chemin de recherche - ou pas du tout pour un nom qualifié par le schéma (schema.foo).

S'il est trouvé, il y a deux défauts :

  1. La recherche inclut des schémas implicites de search_path , à savoir pg_catalog et pg_temp. Mais vous souhaiterez peut-être exclure les tables temporaires et système pour votre usage. (?)

  2. Un transtypage en regclass fonctionne pour tous les objets du catalogue système pg_class : index, vues, séquences etc. Pas seulement des tables. Vous semblez rechercher une table régulière exclusivement. Cependant, vous aurez probablement aussi des problèmes avec d'autres objets du même nom. Détails:

Lent et sûr

Nous revenons à votre requête, mais n'utilisez pas current_setting('search_path'), qui renvoie le paramètre nu. Utilisez la fonction d'informations système dédiée current_schemas() . Par documentation:

current_schemas(boolean)name[]
noms des schémas dans le chemin de recherche, y compris éventuellement les schémas implicites

"$user" dans le chemin de recherche est résolu intelligemment. Si aucun schéma portant le nom de SESSION_USER n'existe, le schéma n'est pas renvoyé pour commencer. En outre, selon ce que vous voulez exactement, vous pouvez également générer des schémas implicites (pg_catalog et éventuellement pg_temp) - mais je suppose que vous ne les voulez pas pour le cas présent, donc utilisation:

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 , montrant tout sauf la dernière instruction DO.
SQL Fiddle (JDBC) a des problèmes avec les instructions DO contenant des caractères de terminaison.

18
Erwin Brandstetter

Vous pouvez convertir la valeur de configuration en un tableau et remplacer le $user avec le nom d'utilisateur actuel. Le tableau peut ensuite être utilisé dans la condition where:

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