sql >> Databasteknik >  >> RDS >> PostgreSQL

Postgres bulkinsats/uppdatering som är injektionssäker. Kanske en funktion som tar en array?

Det är morgon här på den bortre södra kusten av NSW, och jag tänkte att jag skulle ta ett tag till på det här. Jag borde ha nämnt tidigare att vår distributionsmiljö är RDS, vilket gör COPY mindre tilltalande. Men idén med att skicka in en array där varje element inkluderar raddata är mycket lockande. Det är ungefär som en INSERT med flera värden, men med olika syntaktiska socker. Jag har petat på arrayer i Postgres lite och alltid kommit bort förvirrad av syntaxen. Jag hittade några riktigt utmärkta trådar med massor av detaljer från några toppaffischer att studera:

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/

Därifrån har jag en fungerande testfunktion:

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;

För att stänga cirkeln, här är ett exempel på indata:

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

Om vi ​​går tillbaka till mina testresultat, fungerar detta ungefär lika bra som min ursprungliga flervärdesinsats. De andra två metoderna jag publicerade ursprungligen är, låt oss säga, 4x långsammare. (Resultaten är ganska oberäkneliga, men de är alltid mycket långsammare.) Men jag har fortfarande min ursprungliga fråga:

Är denna injektion säker?

Om inte, antar jag att jag måste skriva om det i PL/pgSQL med en FOREACH-loop och UTFÖRA ... ANVÄNDA eller FORMATERA för att få de injektionsrengörande textbearbetnings-/interpolkationsfunktionerna där. Är det någon som vet?

Jag har många andra frågor om den här funktionen (ska det vara en procedur så att jag kan hantera transaktionen? Hur gör jag inmatningen anyarray? Vad skulle vara ett vettigt resultat att returnera?) Men jag tror att jag måste följ dessa som sina egna frågor.

Tack för all hjälp!




  1. Hur man tar bort upprepade rader i en Oracle SQL-fråga

  2. mysql_fetch_assoc()-fel när data i mysql-fältet ändras

  3. Använd SparkSession.sql() med JDBC

  4. PostgreSQL:prestanda för select null vs false