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


10

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')retourne un TEXT contenant "$user",publicpar défaut, ce qui n'est pas terriblement utile.

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

Réponses:


18

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 version antérieure, utilisez un cast pourregclass :

SELECT 'foo'::regclass;

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

Si 'foo'est trouvé, le oidest retourné dans sa textreprésentation. 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 sûr qu'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 lacunes :

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

  2. Une distribution qui regclassfonctionne pour tous les objets du catalogue système pg_class: index, vues, séquences, etc. Pas seulement les 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 ne l'utilisez pas current_setting('search_path'), ce 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 des schémas implicites

"$user"dans le chemin de recherche est résolu intelligemment. Si aucun schéma portant le nom de SESSION_USERn'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_cataloget éventuellement pg_temp) - mais je suppose que vous ne voulez pas ceux pour le cas présent, alors utilisez:

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


1

Vous pouvez convertir la valeur de configuration en un tableau et remplacer le $userpar 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), ','))

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.