È 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
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!