Votre fonction pourrait ressembler à ceci :
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS SETOF transactions AS
$BODY$
BEGIN
RETURN QUERY EXECUTE '
SELECT *
FROM transactions
WHERE ' || quote_ident(_col) || ' = $1
LIMIT $2'
USING _val, _limit;
END;
$BODY$
LANGUAGE plpgsql VOLATILE SECURITY DEFINER;
EN PostgreSQL 9.1 ou plus tard c'est plus simple avec le format format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
échappe les identifiants comme quote_ident()
.
Points majeurs :
-
Vous vous heurtiez à la limitation du SQL dynamique selon laquelle vous ne pouvez pas utiliser de paramètres pour les identificateurs. Vous devez construire la chaîne de requête avec le nom de la colonne et puis exécutez-le.
-
Vous pouvez cependant le faire avec des valeurs. Je démontre l'utilisation du
USING
clause pourEXECUTE
. Notez également l'utilisation dequote_ident()
:empêche l'injection SQL et certaines erreurs de syntaxe. -
J'ai aussi grandement simplifié votre fonction.
[RETURN QUERY EXECUTE][3]
rend votre code plus court et plus rapide. Pas besoin de boucler si tout ce que vous faites est de retourner la ligne. -
J'utilise nommé
IN
paramètres, afin de ne pas être confondu avec la notation $ dans la chaîne de requête.$1
et$2
à l'intérieur de la chaîne de requête, faites référence aux valeurs fournies dans leUSING
clause, pas aux paramètres d'entrée. -
Je passe à
SELECT *
car vous devez de toute façon renvoyer la ligne entière pour correspondre au type de retour déclaré. -
Dernier point mais non le moindre :assurez-vous de tenir compte de ce que le manuel a à dire sur les fonctions déclarées
SECURITY DEFINER
.
TYPE DE RETOUR
Si vous ne souhaitez pas renvoyer la ligne entière, une possibilité pratique est :
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Ainsi, vous n'êtes pas obligé de fournir une liste de définitions de colonne à chaque appel et vous pouvez simplifier :
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);