PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Insertion/mise à jour en masse Postgres sécurisée par injection. Peut-être une fonction qui prend un tableau ?

C'est le matin ici sur la côte extrême sud de la Nouvelle-Galles du Sud, et j'ai pensé que je prendrais une autre chance. J'aurais dû mentionner auparavant que notre environnement de déploiement est RDS, ce qui rend COPY moins attrayant. Mais l'idée de passer dans un tableau où chaque élément inclut les données de ligne est très attirant. C'est un peu comme un INSERT à plusieurs valeurs, mais avec un sucre syntaxique différent. J'ai un peu fouillé les tableaux dans Postgres et je repars toujours embrouillé par la syntaxe. J'ai trouvé quelques fils de discussion vraiment excellents avec beaucoup de détails sur certaines des meilleures affiches à étudier :

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/

À partir de là, j'ai une fonction de test qui fonctionne :

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;

Pour boucler la boucle, voici un exemple de saisie :

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

Pour en revenir à mes résultats de test, cela fonctionne à peu près aussi bien que mon insert multi-valeur d'origine. Les deux autres méthodes que j'ai publiées à l'origine sont, disons, 4 fois plus lentes. (Les résultats sont assez erratiques, mais ils sont toujours beaucoup plus lents.) Mais il me reste toujours ma question initiale :

Cette injection est-elle sûre ?

Sinon, je suppose que je dois le réécrire en PL/pgSQL avec une boucle FOREACH et EXECUTE...USING ou FORMAT pour obtenir les fonctionnalités de traitement/interpolcation de texte par injection. Est-ce que quelqu'un sait ?

J'ai beaucoup d'autres questions sur cette fonction (Devrait-il s'agir d'une procédure pour que je puisse gérer la transaction? Comment puis-je rendre l'entrée anyarray? Quel serait un résultat sensé à renvoyer?) Mais je pense que je vais devoir les poursuivre comme leurs propres questions.

Merci pour toute aide !