PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Postgres-Masseneinfügung/-aktualisierung, die injektionssicher ist. Vielleicht eine Funktion, die ein Array übernimmt?

Es ist Morgen hier an der fernen Südküste von NSW, und ich dachte mir, ich probiere es noch einmal aus. Ich hätte vorher erwähnen sollen, dass unsere Bereitstellungsumgebung RDS ist, was COPY weniger attraktiv macht. Aber die Idee, ein Array zu übergeben, in dem jedes Element die Zeilendaten enthält, ist sehr reizvoll. Es ist ähnlich wie ein mehrwertiges INSERT, aber mit unterschiedlichem syntaktischem Zucker. Ich habe ein bisschen in Arrays in Postgres gestöbert und bin immer wieder verwirrt von der Syntax. Ich habe ein paar wirklich hervorragende Threads mit vielen Details von einigen Top-Postern zum Studieren gefunden:

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/

Von dort habe ich eine funktionierende 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;

Um den Kreis zu schließen, hier ein Beispiel für eine Eingabe:

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

Zurück zu meinen Testergebnissen, die Leistung ist ungefähr so ​​gut wie meine ursprüngliche Multi-Value-Einlage. Die anderen beiden Methoden, die ich ursprünglich gepostet habe, sind, sagen wir mal, 4x langsamer. (Die Ergebnisse sind ziemlich unregelmäßig, aber sie sind immer viel langsamer.) Aber ich bleibe immer noch bei meiner ursprünglichen Frage:

Ist diese Injektion sicher?

Wenn nicht, muss ich es wohl in PL/pgSQL mit einer FOREACH-Schleife und EXECUTE...USING oder FORMAT neu schreiben, um dort die Textverarbeitungs-/Interpolationsfunktionen zur Injektionsreinigung zu erhalten. Weiß jemand?

Ich habe viele andere Fragen zu dieser Funktion (Sollte es eine Prozedur sein, mit der ich die Transaktion verwalten kann? Wie mache ich die Eingabe für ein beliebiges Array? Was wäre ein vernünftiges Ergebnis für die Rückgabe?) Aber ich denke, ich muss es tun diesen als eigene Fragen nachgehen.

Danke für jede Hilfe!