Debe defenderse contra la inyección SQL siempre que convierta la entrada del usuario en código. Eso incluye nombres de tablas y columnas provenientes de catálogos del sistema o de la entrada directa del usuario por igual. De esta manera, también evita excepciones triviales con identificadores no estándar. Básicamente hay tres métodos integrados:
1. format()
1ra consulta, desinfectada:
CREATE OR REPLACE FUNCTION foo(_t text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('
ALTER TABLE %I ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)', _t);
END
$func$;
format()
requiere Postgres 9.1 o posterior. Úselo con el %I
especificador de formato.
El nombre de la tabla solo puede ser ambiguo. Es posible que deba proporcionar el nombre del esquema para evitar cambiar la tabla incorrecta por accidente. Relacionado:
- INSERTAR con el nombre de la tabla dinámica en la función de activación
- ¿Cómo influye search_path en la resolución del identificador y el "esquema actual"?
Aparte:agregando múltiples columnas con una sola ALTER TABLE
el comando es más barato.
2. regclass
También puede usar una conversión a una clase registrada (regclass
) para el caso especial de existente nombres de tablas Opcionalmente calificado por esquema. Esto falla inmediatamente y con gracia para los nombres de tablas que no son válidos ni visibles para el usuario que llama. La primera consulta desinfectada con un envío a regclass
:
CREATE OR REPLACE FUNCTION foo(_t regclass)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'ALTER TABLE ' || _t || ' ADD COLUMN c1 varchar(20)
, ADD COLUMN c2 varchar(20)';
END
$func$;
Llamar:
SELECT foo('table_name');
O:
SELECT foo('my_schema.table_name'::regclass);
Aparte:considere usar solo text
en lugar de varchar(20)
.
3. quote_ident()
La segunda consulta desinfectada:
CREATE OR REPLACE FUNCTION foo(_t regclass, _c text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE 'UPDATE ' || _t -- sanitized with regclass
|| ' SET ' || quote_ident(_c) || ' = ''This is a test''';
END
$func$;
Para múltiples concatenaciones/interpolaciones, format()
es más limpio...
Respuestas relacionadas:
- Nombre de tabla como parámetro de función de PostgreSQL
- Funciones de Postgres frente a consultas preparadas
¡Sensible a mayúsculas y minúsculas!
Tenga en cuenta que los identificadores sin comillas no echado a minúsculas aquí. Cuando se usa como identificador en SQL [Postgres convierte a minúsculas automáticamente][7]. Pero aquí pasamos cadenas para SQL dinámico. Cuando se escapa como se muestra, los identificadores de caso de CaMel (como UserS
) se conservará entre comillas dobles ("UserS"
), al igual que otros nombres no estándar como "name with space"
"SELECT"
etc. Por lo tanto, los nombres distinguen entre mayúsculas y minúsculas en este contexto.
Mi consejo permanente es usar identificadores legales en minúsculas exclusivamente y nunca preocuparse por eso.
Aparte:las comillas simples son para valores, las comillas dobles son para identificadores. Ver:
- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS