Yo lo haría así:
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$;
Característica principal:use format()
para concatenar de forma segura y elegante su cadena de consulta. Relacionado:
- INSERTAR con nombre de la tabla dinámica en la función de activación
- Especificador de formato para variables enteras en format() para EXECUTE?
ASC
/ DESC
(o ASCENDING
/ DESCENDING
) son palabras clave fijas. Agregué una verificación manual (IF ...
) y luego concatenar con un simple %s
. Ese es uno manera de hacer valer la entrada legal. Para mayor comodidad, agregué un mensaje de error para entradas inesperadas y un valor predeterminado de parámetro, por lo que la función tiene como valor predeterminado ASC
si se omite el último parámetro en la llamada. Relacionado:
- Argumento opcional en PL Función /pgSQL
- ERROR:los parámetros de entrada después de uno con un valor predeterminado también deben tener valores predeterminados en Postgres
Abordar Pavel's valid comentario
, concateno _limit
y _offset
directamente, por lo que la consulta ya está planificada con esos parámetros.
_limit
y _offset
son integer
parámetros, por lo que podemos usar %s
simple sin el peligro de inyección SQL. Es posible que desee afirmar valores razonables (excluir valores negativos y valores demasiado altos) antes de concatenar...
-
Utilice una convención de nomenclatura coherente. Prefijé todos los parámetros y variables con un guión bajo
_
, no solo algunos . -
No usar calificación de tabla dentro de
EXECUTE
, ya que solo hay una tabla involucrada y elEXECUTE
tiene su alcance separado. -
Cambié el nombre de algunos parámetros para aclarar.
_order_by
en lugar de_sort_by
;_order_asc_desc
en lugar de_order
.