Eu faria assim:
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$;
Recurso principal:use o formato
format()
para concatenar com segurança e elegância sua string de consulta. Relacionado:- INSERT com nome da tabela dinâmica na função de gatilho
- Especificador de formato para variáveis inteiras em format() para EXECUTE?
ASC
/ DESC
(ou ASCENDING
/ DESCENDING
) são palavras-chave fixas. Adicionei uma verificação manual (IF ...
) e depois concatenar com um simples %s
. Isso é um maneira de afirmar a entrada legal. Por conveniência, adicionei uma mensagem de erro para entrada inesperada e um parâmetro padrão, para que a função padrão seja ASC
se o último parâmetro for omitido na chamada. Relacionado:- Argumento opcional no PL função /pgSQL
- ERRO:os parâmetros de entrada após um com um valor padrão também devem ter padrões no Postgres
Abordando Pavel é válido comentar , eu concateno
_limit
e _offset
diretamente, então a consulta já está planejada com esses parâmetros. _limit
e _offset
são integer
parâmetros, para que possamos usar %s
simples sem o perigo de injeção de SQL. Você pode querer afirmar valores razoáveis (excluir valores negativos e valores muito altos) antes de concatenar... Outras notas:
-
Use uma convenção de nomenclatura consistente. Prefixei todos os parâmetros e variáveis com um sublinhado_
, não apenas algumas .
-
Não usando qualificação de tabela dentro deEXECUTE
, já que há apenas uma única tabela envolvida e oEXECUTE
tem seu escopo separado.
-
Renomeei alguns parâmetros para esclarecer._order_by
em vez de_sort_by
;_order_asc_desc
em vez de_order
.