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

Comment utiliser la saisie de texte comme nom(s) de colonne dans une fonction Postgres ?

La transmission de plusieurs noms de colonne sous forme de chaîne concaténée pour une exécution dynamique nécessite une décontamination urgente. Je suggère un VARIADIC paramètre de fonction à la place, avec des identifiants correctement cités (en utilisant quote_ident() dans ce cas):

CREATE OR REPLACE FUNCTION select_by_txt(z int, x int, y int, VARIADIC cols text[] = NULL, OUT res text)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format(
$$
SELECT ST_AsMVT(mvtgeom, 'public.select_by_txt')
FROM  (
   SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom%s
   FROM   table1 t
   JOIN  (SELECT ST_TileEnvelope($1, $2, $3)) AS bounds(geom)
          ON ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
   ) mvtgeom
$$, (SELECT ', ' || string_agg(quote_ident (col), ', ') FROM unnest(cols) col)
   )
   INTO  res
   USING z, x, y;
END
$func$;

db<>violon ici

Le spécificateur de format %I pour format() traite avec un célibataire identifiant. Vous devez travailler plus pour plusieurs identifiants, en particulier pour un nombre variable d'identifiants 0-n. Cette implémentation cite chaque nom de colonne et n'ajoute qu'un , si des noms de colonne ont été passés. Donc, cela fonctionne pour toutes les entrées possibles , même pas d'entrée du tout. Remarque VARIADIC cols text[] = NULL comme dernier paramètre d'entrée avec NULL comme valeur par défaut :

Connexe :

Les noms de colonne sont sensibles à la casse dans ce contexte !

Appelez pour votre exemple (important !) :

SELECT select_by_txt(10,32,33,'col1', 'col2');

Syntaxe alternative :

SELECT select_by_txt(10,32,33, VARIADIC '{col1,col2}');

Appel plus révélateur, avec un troisième nom de colonne et une intention malveillante (bien que futile) :

SELECT select_by_txt(10,32,33,'col1', 'col2', $$col3'); DROP TABLE table1;--$$);

À propos de ce nom de troisième colonne étrange et de l'injection SQL :

À propos de VAIRADIC paramètres :

Utiliser un OUT paramètre de simplicité. C'est totalement facultatif. Voir :

Ce que je ne ferais pas faire

Si vous faites vraiment, vraiment confiance à l'entrée pour qu'elle soit une liste correctement formatée d'un ou plusieurs noms de colonnes valides à tout moment - et vous avez affirmé que...

Vous pourriez simplifier :

CREATE OR REPLACE FUNCTION select_by_txt(z int, x int, y int, cols text, OUT res text)
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format(
$$
SELECT ST_AsMVT(mvtgeom, 'public.select_by_txt')
FROM  (
   SELECT ST_AsMVTGeom(ST_Transform(t.geom, 3857), bounds.geom) AS geom, %s
   FROM   table1 t
   JOIN  (SELECT ST_TileEnvelope($1, $2, $3)) AS bounds(geom)
          ON ST_Intersects(t.geom, ST_Transform(bounds.geom, 4326))
   ) mvtgeom
$$, cols
   )
   INTO  res
   USING z, x, y;
END
$func$;

(Comment pouvez-vous être si sûr que l'entrée sera toujours fiable ?)