La tua funzione potrebbe assomigliare a questa:
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;
IN PostgreSQL 9.1 o successivo è più semplice con format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
sfugge a identificatori come quote_ident()
.
Punti principali:
-
Stavi incontrando la limitazione dell'SQL dinamico che non puoi usare i parametri per gli identificatori. Devi creare la stringa di query con il nome della colonna e quindi eseguilo.
-
Puoi farlo con i valori però. Dimostro l'uso di
USING
clausola perEXECUTE
. Nota anche l'uso diquote_ident()
:impedisce l'iniezione SQL e alcuni errori di sintassi. -
Ho anche ampiamente semplificato la tua funzione.
[RETURN QUERY EXECUTE][3]
rende il tuo codice più breve e veloce. Non è necessario eseguire il ciclo se tutto ciò che fai è restituire la riga. -
Uso denominato
IN
parametri, in modo da non confondersi con la $-notazione nella stringa di query.$1
e$2
all'interno della stringa di query fare riferimento ai valori forniti inUSING
clausola, non ai parametri di input. -
Passo a
SELECT *
poiché devi comunque restituire l'intera riga in modo che corrisponda al tipo restituito dichiarato. -
Ultimo ma non meno importante:assicurati di considerare ciò che il manuale ha da dire sulle funzioni dichiarate
SECURITY DEFINER
.
TIPO DI RESO
Se non vuoi restituire l'intera riga, una comoda possibilità è:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Quindi non devi fornire un elenco di definizioni di colonna con ogni chiamata e puoi semplificare in:
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);