Dans PostgreSQL, je voudrais créer un mécanisme de wrapping sécurisé qui renvoie un résultat vide si une exception se produit. Considérer ce qui suit:
SELECT * FROM myschema.mytable;
Je pourrais faire le wrapping en toute sécurité dans l'application cliente:
try {
result = execute_query('SELECT value FROM myschema.mytable').fetchall();
}
catch(pg_exception) {
result = []
}
Mais pourrais-je faire une telle chose directement dans SQL? Je voudrais faire fonctionner le code suivant, mais il semble qu'il devrait être mis en bloc DO $$ ... $$
et ici je me perds.
BEGIN
SELECT * FROM myschema.mytable;
EXCEPTION WHEN others THEN
SELECT unnest(ARRAY[]::TEXT[])
END
Généralement, le code plpgsql est toujours encapsulé dans un bloc BEGIN .. END
. Cela peut être à l'intérieur du corps d'une instruction DO
ou d'une fonction. Les blocs peuvent être imbriqués à l'intérieur - mais ils ne peuvent pas exister en dehors de, ne confondez pas ceci avec du SQL pur.
Chaque bloc BEGIN
peut éventuellement inclure une clause EXCEPTION
pour gérer les exceptions, mais les fonctions devant intercepter des exceptions sont considérablement plus coûteuses. Il est donc préférable d'éviter les exceptions a priori.
Plus d'information:
Le manuel sur comment intercepter les erreurs (gérer les exceptions) dans PL/pgSQL } _
Exemple: SELECT ou INSERT dans une fonction sujette à des conditions de concurrence?
Une instruction DO
ne peut rien retourner. Créez une fonction qui prend les noms de table et de schéma en tant que paramètres et vous renvoie tout ce que vous voulez:
CREATE OR REPLACE FUNCTION f_tbl_value(_tbl text, _schema text = 'public')
RETURNS TABLE (value text) AS
$func$
DECLARE
_t regclass := to_regclass(_schema || '.' || _tbl);
BEGIN
IF _t IS NULL THEN
value := ''; RETURN NEXT; -- return single empty string
ELSE
RETURN QUERY EXECUTE
'SELECT value FROM ' || _t; -- return set of values
END
$func$ LANGUAGE plpgsql;
Appel:
SELECT * FROM f_tbl_value('my_table');
Ou:
SELECT * FROM f_tbl_value('my_table', 'my_schema');
En supposant que vous souhaitiez un ensemble de lignes avec une seule colonne text
ou une chaîne vide si la table n'existe pas.
En supposant également qu’une colonne value
existe si la table donnée existe. Vous pouvez également tester cela, mais vous ne l'avez pas demandé.
Les deux paramètres sont sensibles à la cassetext
. C'est légèrement différent de la façon dont les identifiants dans les instructions SQL sont gérés . Si vous ne doublez jamais les identificateurs, transmettez les noms en minuscules et tout va bien.
Le nom de schéma par défaut est 'public'
dans mon exemple. Adaptez-vous à vos besoins. Vous pouvez même ignorer complètement le schéma et utiliser par défaut le search_path
actuel.
to_regclass()
est nouvelle dans Postgres 9.4. Pour les versions plus anciennes, remplacez:
IF EXISTS (
SELECT 1
FROM information_schema.tables
WHERE table_schema = _schema
AND table_name = _tbl
);
Ceci est en fait plus précis, car il teste exactement ce dont vous avez besoin ..__ Plus d'options et une explication détaillée:
Défendez-vous toujours contre l'injection SQL lorsque vous travaillez avec du SQL dynamique! Le casting de regclass
fait le tour ici. Plus de détails:
Si vous ne sélectionnez qu'une colonne, la fonction COALESCE () devrait pouvoir vous aider.
SELECT COALESCE( value, '{}'::text[] ) FROM myschema.mytable
Si vous avez besoin de plus de lignes, vous devrez peut-être créer une fonction avec des types.