sql >> Database >  >> RDS >> PostgreSQL

Postgres bulk insert/update die injectieveilig is. Misschien een functie waarvoor een array nodig is?

Het is ochtend hier aan de Far South Coast van NSW, en ik dacht dat ik hier nog eens een poging toe zou doen. Ik had eerder moeten vermelden dat onze implementatieomgeving RDS is, wat COPY minder aantrekkelijk maakt. Maar het idee om een ​​array door te geven waarin elk element de rijgegevens bevat, is zeer aantrekkelijk. Het lijkt veel op een INSERT met meerdere waarden, maar met verschillende syntactische suikers. Ik heb een beetje naar arrays in Postgres geprikt en kom altijd verward weg door de syntaxis. Ik heb een paar echt uitstekende discussies gevonden met veel details van enkele topposters om te bestuderen:

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/

Van daaruit heb ik een werkende testfunctie:

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;

Om de cirkel te sluiten, is hier een voorbeeld van wat invoer:

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

Terugkomend op mijn testresultaten, deze presteert ongeveer net zo goed als mijn originele multi-value-insert. De andere twee methoden die ik oorspronkelijk heb gepost, zijn, laten we zeggen, 4x langzamer. (De resultaten zijn nogal grillig, maar ze zijn altijd een stuk langzamer.) Maar ik blijf met mijn oorspronkelijke vraag zitten:

Is deze injectie veilig?

Als dat niet het geval is, denk ik dat ik het in PL/pgSQL moet herschrijven met een FOREACH-lus en UITVOEREN... GEBRUIKEN of FORMATEREN om de functies voor het opschonen van tekstverwerking/interpolatie daar te krijgen. Weet iemand het?

Ik heb nog een heleboel andere vragen over deze functie (Moet het een procedure zijn om de transactie te kunnen beheren? Hoe kan ik de invoer willekeurig maken? Wat zou een verstandig resultaat zijn om terug te sturen?) Maar ik denk dat ik vervolg deze als hun eigen vragen.

Bedankt voor alle hulp!




  1. Hoe breng ik een BigDecimal in Hibernate in kaart, zodat ik dezelfde schaal terugkrijg die ik heb ingevoerd?

  2. Werk een rij bij in orakel met behulp van de OLEDB-opdracht (SSIS)

  3. Postgres:vacuümcommando ruimt dode tupels niet op

  4. Maak een afbeeldingstrackback voor een externe webuitgever om naar mijn site te linken