PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Inserimento/aggiornamento in blocco di Postgres sicuro per l'iniezione. Forse una funzione che accetta un array?

È mattina qui sull'estremo sud costa del NSW, e ho pensato di fare un altro tentativo. Avrei dovuto menzionare prima che il nostro ambiente di distribuzione è RDS, il che rende COPY meno interessante. Ma l'idea di passare un array in cui ogni elemento include i dati della riga è molto attraente. È molto simile a un INSERT multivalore, ma con zucchero sintattico diverso. Ho dato un'occhiata agli array in Postgres e sono sempre rimasto confuso dalla sintassi. Ho trovato alcuni thread davvero eccellenti con molti dettagli da alcuni dei migliori poster da studiare:

https://dba.stackexchange .com/questions/224785/pass-array-of-mixed-type-in-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/

Da lì, ho una funzione di test funzionante:

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;

Per chiudere il cerchio, ecco un esempio di input:

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[]
    );

Tornando ai risultati dei miei test, questo funziona più o meno come il mio inserto multivalore originale. Gli altri due metodi che ho pubblicato originariamente sono, diciamo, 4 volte più lenti. (I risultati sono piuttosto irregolari, ma sono sempre molto più lenti.) Ma rimango ancora con la mia domanda originale:

Questa iniezione è sicura?

In caso contrario, immagino di dover riscriverlo in PL/pgSQL con un ciclo FOREACH ed ESEGUIRE... USING o FORMAT per ottenere lì le funzionalità di elaborazione/interpolazione del testo per la pulizia dell'iniezione. Qualcuno lo sa?

Ho molte altre domande su questa funzione (dovrebbe essere una procedura in modo da poter gestire la transazione? Come faccio a fare l'input anyarray? Quale sarebbe un risultato sensato da restituire?) Ma penso che dovrò persegui queste domande come loro stesse.

Grazie per qualsiasi aiuto!