PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Inserção/atualização em massa do Postgres que é segura para injeção. Talvez uma função que recebe uma matriz?


É de manhã aqui no extremo sul da costa de NSW, e pensei em dar outra chance a isso. Eu deveria ter mencionado antes que nosso ambiente de implantação é RDS, o que torna o COPY menos atraente. Mas a ideia de passar um array onde cada elemento inclui os dados da linha é muito atraente. É muito parecido com um INSERT de vários valores, mas com diferentes açúcares sintáticos. Eu mexi um pouco em arrays no Postgres e sempre saio confuso com a sintaxe. Encontrei alguns tópicos realmente excelentes com muitos detalhes de alguns dos melhores pôsteres para estudar:

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 daí, tenho uma função de teste funcional:
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 fechar o círculo, aqui está um exemplo de algumas entradas:
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[]
    );

Voltando aos resultados do meu teste, isso funciona aproximadamente tão bem quanto minha inserção de vários valores original. Os outros dois métodos que postei originalmente são, digamos, 4x mais lentos. (Os resultados são bastante erráticos, mas são sempre muito mais lentos.) Mas ainda fico com minha pergunta original:

Esta injeção é segura?

Caso contrário, acho que preciso reescrevê-lo em PL/pgSQL com um loop FOREACH e EXECUTE...USING ou FORMAT para obter os recursos de processamento/interpolação de texto de limpeza de injeção lá. Alguém sabe?

Eu tenho muitas outras dúvidas sobre essa função (Deve ser um procedimento para que eu possa gerenciar a transação? Como faço para que a entrada seja qualquer array? Qual seria um resultado sensato para retornar?) Mas acho que vou ter que persegui-los como suas próprias questões.

Obrigado por qualquer ajuda!