Jag skulle göra så här:
CREATE OR REPLACE FUNCTION list(
_category varchar(100)
, _limit int
, _offset int
, _order_by varchar(100)
, _order_asc_desc text = 'ASC') -- last param with default value
RETURNS TABLE(id int, name varchar, clientname varchar, totalcount bigint)
LANGUAGE plpgsql AS
$func$
DECLARE
_empty text := '';
BEGIN
-- Assert valid _order_asc_desc
IF upper(_order_asc_desc) IN ('ASC', 'DESC', 'ASCENDING', 'DESCENDING') THEN
-- proceed
ELSE
RAISE EXCEPTION 'Unexpected value for parameter _order_asc_desc.
Allowed: ASC, DESC, ASCENDING, DESCENDING. Default: ASC';
END IF;
RETURN QUERY EXECUTE format(
'SELECT id, name, clientname, count(*) OVER() AS full_count
FROM design_list
WHERE ($1 = $2 OR category ILIKE $1)
ORDER BY %I %s
LIMIT %s
OFFSET %s'
, _order_by, _order_asc_desc, _limit, _offset)
USING _category, _empty;
END
$func$;
Kärnfunktion:använd format()
för att säkert och elegant sammanfoga din frågesträng. Relaterat:
- INSERT med dynamiskt tabellnamn i triggerfunktionen
- Formatspecifikation för heltalsvariabler i format() för EXECUTE?
ASC
/ DESC
(eller ASCENDING
/ DESCENDING
) är fasta nyckelord. Jag lade till en manuell kontroll (IF ...
) och senare sammanfoga med en enkel %s
. Det är ett sätt att hävda juridisk input. För enkelhetens skull lade jag till ett felmeddelande för oväntad inmatning och en parameterstandard, så funktionen är som standard ASC
om den sista parametern utelämnas i anropet. Relaterat:
- Valfritt argument i PL /pgSQL-funktion
- FEL:inmatningsparametrar efter en med ett standardvärde måste också ha standardvärden i Postgres
Adresserar Pavel kommentar
, jag sammanfogar _limit
och _offset
direkt, så frågan är redan planerad med dessa parametrar.
_limit
och _offset
är integer
parametrar, så att vi kan använda vanlig %s
utan fara för SQL-injektion. Du kanske vill hävda rimliga värden (uteslut negativa värden och värden för höga) innan du sammanfogar ...
-
Använd en konsekvent namnkonvention. Jag prefixerade alla parametrar och variabler med ett understreck
_
, inte bara en del . -
Använder inte tabellkvalificering i
EXECUTE
, eftersom det bara är en enda tabell involverad ochEXECUTE
har sin separata räckvidd. -
Jag bytte namn på några parametrar för att förtydliga.
_order_by
istället för_sort_by
;_order_asc_desc
istället för_order
.