Il n'y a rien de mal avec une fonction plpgsql pour tout ce qui est un peu plus complexe. La seule situation où les performances peuvent en pâtir est lorsqu'une fonction plpgsql est imbriquée, car le planificateur de requêtes ne peut pas optimiser davantage le code contenu dans le contexte de la requête externe, ce qui peut ou non la ralentir.
Plus de détails plus tard réponse :
- Différence entre le langage sql et le langage plpgsql dans les fonctions PostgreSQL
Dans le cas présent, c'est beaucoup plus simple que beaucoup de CASE
clauses dans une requête :
CREATE OR REPLACE FUNCTION get_stuff(_param text, _orderby text, _limit int)
RETURNS SETOF stuff AS
$func$
BEGIN
RETURN QUERY EXECUTE '
SELECT *
FROM stuff
WHERE col = $1
ORDER BY ' || quote_ident(_orderby) || ' ASC
LIMIT $2'
USING _param, _limit;
END
$func$ LANGUAGE plpgsql;
Appel :
SELECT * FROM get_stuff('hello', 'col2', 100);
Remarques
Utilisez RETURN QUERY EXECUTE
pour renvoyer les résultats de la requête en une seule fois.
Utilisez quote_ident()
pour les identifiants à protéger contre SQLi.
Ou format()
pour tout ce qui est plus complexe. Voir :
- Nom de table en tant que paramètre de fonction PostgreSQL
Passez les valeurs des paramètres avec le USING
clause pour éviter à nouveau de caster, de citer et SQLi.
Veillez à ne pas créer de conflits de nommage entre les paramètres et les noms de colonne. J'ai préfixé les noms de paramètres avec un trait de soulignement (_
) dans l'exemple. Juste ma préférence personnelle.
Votre deuxième fonction après la modification ne peut pas fonctionner, car vous ne renvoyez que parent
tandis que le type de retour est déclaré SETOF stuff
. Vous pouvez déclarer tout type de retour que vous aimez, mais les valeurs de retour réelles doivent correspondre à la déclaration. Vous voudrez peut-être utiliser RETURNS TABLE
pour ça.