sql >> Base de Datos >  >> RDS >> PostgreSQL

Inserción/actualización masiva de Postgres que es segura para inyección. ¿Quizás una función que toma una matriz?

Es de mañana aquí en la costa sur de Nueva Gales del Sur, y pensé que le daría otra oportunidad a esto. Debería haber mencionado antes que nuestro entorno de implementación es RDS, lo que hace que COPY sea menos atractivo. Pero la idea de pasar una matriz donde cada elemento incluye los datos de la fila es muy atractivo. Es muy parecido a un INSERTO de valores múltiples, pero con azúcar sintáctico diferente. He hurgado un poco en las matrices en Postgres, y siempre salgo confundido por la sintaxis. Encontré algunos hilos realmente excelentes con muchos detalles de algunos de los mejores carteles para estudiar:

https://dba.stackexchange .com/questions/224785/pass-array-of-mixed-type-into-stored-function

https ://dba.stackexchange.com/questions/131505/use-array-of-composite-type-as-function-parameter-and-access-it

https://dba.stackexchange.com/questions/225176/how-to-pass-an-array-to-a-plpgsql-function-with-variadic-parameter/

A partir de ahí, tengo una función de prueba de trabajo:

DROP FUNCTION IF EXISTS data.item_insert_array (item[]);

CREATE OR REPLACE FUNCTION data.item_insert_array (data_in item[]) 
  RETURNS int
AS $$
INSERT INTO item (
    id, 
    marked_for_deletion, 
    name_)

SELECT
    d.id, 
    d.marked_for_deletion,
    d.name_

FROM unnest(data_in) d

ON CONFLICT(id) DO UPDATE SET 
    marked_for_deletion = EXCLUDED.marked_for_deletion,
    name_ = EXCLUDED.name_;

SELECT cardinality(data_in); -- array_length() doesn't work. ¯\_(ツ)_/¯

$$ LANGUAGE sql;

ALTER FUNCTION data.item_insert_array(item[]) OWNER TO user_bender;

Para cerrar el círculo, aquí hay un ejemplo de alguna entrada:

select * from item_insert_array(

    array[
        ('2f888809-2777-524b-abb7-13df413440f5',true,'Salad fork'),
        ('f2924dda-8e63-264b-be55-2f366d9c3caa',false,'Melon baller'),
        ('d9ecd18d-34fd-5548-90ea-0183a72de849',true,'Fondue fork')
        ]::item[]
    );

Volviendo a los resultados de mi prueba, esto funciona más o menos tan bien como mi inserción original de valores múltiples. Los otros dos métodos que publiqué originalmente son, digamos, 4 veces más lentos. (Los resultados son bastante erráticos, pero siempre mucho más lentos). Pero aún me queda mi pregunta original:

¿Es segura esta inyección?

Si no, supongo que necesito reescribirlo en PL/pgSQL con un bucle FOREACH y EJECUTAR... USAR o FORMATO para obtener las funciones de interpolación/procesamiento de texto de limpieza por inyección allí. ¿Alguien sabe?

Tengo muchas otras preguntas sobre esta función (¿Debería ser un procedimiento para poder administrar la transacción? ¿Cómo hago que la entrada sea una matriz? ¿Cuál sería un resultado sensato para devolver?) Pero creo que tendré que perseguirlos como sus propias preguntas.

¡Gracias por cualquier ayuda!