Fungsi Anda dapat terlihat seperti ini:
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;
DI PostgreSQL 9.1 atau lebih baru yang lebih sederhana dengan format format()
...
RETURN QUERY EXECUTE format('
SELECT *
FROM transactions
WHERE %I = $1
LIMIT $2', _col)
USING _val, _limit;
...
%I
lolos dari pengidentifikasi seperti quote_ident()
.
Poin utama:
-
Anda menabrak batasan SQL dinamis sehingga Anda tidak dapat menggunakan parameter untuk pengidentifikasi. Anda harus membuat string kueri dengan nama kolom dan lalu jalankan.
-
Anda dapat melakukannya dengan nilai. Saya mendemonstrasikan penggunaan
USING
klausa untukEXECUTE
. Perhatikan juga penggunaanquote_ident()
:mencegah injeksi SQL dan kesalahan sintaks tertentu. -
Saya juga sangat menyederhanakan fungsi Anda.
[RETURN QUERY EXECUTE][3]
membuat kode Anda lebih pendek dan lebih cepat. Tidak perlu mengulang jika yang Anda lakukan hanyalah mengembalikan baris. -
Saya menggunakan nama
IN
parameter, sehingga Anda tidak bingung dengan $-notasi dalam string kueri.$1
dan$2
di dalam string kueri merujuk ke nilai yang disediakan diUSING
klausa, bukan ke parameter input. -
Saya mengubah ke
SELECT *
karena Anda harus mengembalikan seluruh baris agar sesuai dengan jenis pengembalian yang dideklarasikan. -
Last but not least:Pastikan untuk mempertimbangkan apa yang dikatakan manual tentang fungsi yang dideklarasikan
SECURITY DEFINER
.
JENIS PENGEMBALIAN
Jika Anda tidak ingin mengembalikan seluruh baris, satu kemungkinan yang mudah adalah:
CREATE FUNCTION select_transactions3(_col text, _val text, _limit int)
RETURNS TABLE (invoice_no varchar(125), amount numeric(12,2) AS ...
Maka Anda tidak perlu memberikan daftar definisi kolom dengan setiap panggilan dan dapat menyederhanakannya menjadi:
SELECT * FROM select_to_transactions3('invoice_no', '1103300105472', 1);