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

Existe-t-il une syntaxe d'échappement pour la variable psql dans les fonctions PostgreSQL ?

PSQL SET les variables ne sont pas interpolées à l'intérieur des chaînes entre guillemets en dollars. Je ne le sais pas avec certitude, mais je pense qu'il n'y a pas d'échappatoire ou autre tromperie pour activer SET interpolation variable là-dedans.

On pourrait penser que vous pourriez coincer un :user sans guillemets entre deux portions de PL/pgSQL cotées en dollars pour obtenir l'effet désiré. Mais cela ne semble pas fonctionner ... Je pense que la syntaxe nécessite une seule chaîne et non une expression concaténant des chaînes. Peut-être se trompe-t-il.

Quoi qu'il en soit, cela n'a pas d'importance. Il existe une autre approche (comme Pasco l'a noté):écrivez la procédure stockée pour accepter un argument PL/pgSQL. Voici à quoi cela ressemblerait.

CREATE OR REPLACE FUNCTION foo("user" TEXT) RETURNS void AS
$$
BEGIN
        EXECUTE 'GRANT SELECT ON my_table TO GROUP ' || quote_ident(user);
END;    
$$ LANGUAGE plpgsql;

Remarques sur cette fonction :

  1. EXECUTE génère un GRANT approprié sur chaque invocation en utilisant sur notre argument de procédure. La section du manuel PG appelée "Exécuter des commandes dynamiques " explique EXECUTE en détail.
  2. La déclaration de l'argument de la procédure user doit être entre guillemets. Les guillemets doubles l'obligent à être interprété comme un identifiant.

Une fois que vous avez défini la fonction comme celle-ci, vous pouvez l'appeler en utilisant des variables PSQL interpolées. Voici un aperçu.

  1. Exécutez psql --variable user="'whoever'" --file=myscript.sql . Des guillemets simples sont requis autour du nom d'utilisateur !
  2. Dans myscript.sql, définissez la fonction comme ci-dessus.
  3. Dans myscript.sql, mettez select foo(:user); . C'est là que nous nous appuyons sur ces guillemets simples que nous mettons dans la valeur de user .

Bien que cela semble fonctionner, cela me semble plutôt étrange. Je pensais SET les variables étaient destinées à la configuration d'exécution. Transporter des données dans SET semble étrange.

Modifier  :voici une raison concrète pour ne pas utilisez SET variables. D'après la page de manuel :"Ces affectations sont effectuées à un stade très précoce du démarrage, de sorte que les variables réservées à des fins internes peuvent être écrasées ultérieurement." Si Postgres décide d'utiliser une variable nommée user (ou quoi que vous choisissiez), cela pourrait écraser votre argument de script avec quelque chose que vous n'aviez jamais prévu. En fait, psql prend déjà USER pour lui-même - cela ne fonctionne que parce que SET est sensible à la casse. Cela a failli casser les choses dès le départ !