Si des utilisateurs pour lesquels nous n'avons pas confiance ont accès à
une base de données qui n'a pas adopté une méthode sécurisée d'usage des
schemas, commencez chaque session en supprimant les schémas
modifiables par tout le monde du paramètre search_path
.
Par exemple, ajoutez options=-c search_path=
à
ou exécutez
options
EXEC SQL SELECT pg_catalog.set_config('search_path', '',
false);
tout de suite après la connexion. Cette considération
n'est pas spécifique à ECPG ; elle s'applique à chaque interface
permettant d'exécuter des commandes SQL arbitraires.
Cette section explique comment ouvrir, fermer, et changer de connexion à la base.
On se connecte à la base de données avec l'ordre suivant:
EXEC SQL CONNECT TOcible
[ASnom-connexion
] [USERnom-utilisateur
];
La cible
peut être spécifiée des façons
suivantes:
nomdb
[@nomhôte
][:port
]
tcp:postgresql://nomhôte
[:port
][/nomdb
][?options
]
unix:postgresql://nomhôte[:port
][/nomdb
][?options
]
DEFAULT
La cible de connexion DEFAULT
initie une connexion à la
base de données par défaut avec l'utilisateur par défaut. Il n'est pas
nécessaire de préciser séparément un nom d'utilisateur ou un nom de
connexion dans ce cas.
Si vous spécifiez la chaîne de connexion de façon littérale (c'est-à-dire, pas
par une chaîne littérale ou une réference à une variable), alors
les constituants de la chaîne suivent les règles de grammaire de SQL normal ;
par exemple, le hostname
doit être similaire
à un ou plusieurs identifiants SQL séparés par des points, et ces identifiants
seront insensibles à la casse à moins d'être entre guillemets. Les valeurs
de n'importe quelles options
doivent être des
identifiants SQL, des entiers, ou des références de variables. Bien sûr,
vous pouvez mettre presque n'importe quoi dans un identifiant SQL en le plaçant
entre guillemets. En pratique, il y a probablement moins de risque d'erreur d'utiliser
une chaîne littérale (entre simples guillemets) ou une référence de variable que
d'écrire la chaîne de connexion directement.
Il y a aussi plusieurs façons de spécifier le nom de l'utilisateur :
nomutilisateur
nomutilisateur
/motdepasse
nomutilisateur
IDENTIFIED BY motdepasse
nomutilisateur
USING motdepasse
Comme précédemment, les paramètres nomutilisateur
et
motdepasse
peuvent être un identifiant SQL,
une chaîne SQL littérale, ou une référence à une variable caractère.
Si la cible de connexion inclut des options
,
cela consiste en des spécifications
séparées par des esperluettes (motclé
=valeur
&
). Les mots clés
autorisés sont les mêmes que ceux reconnus par
libpq (voir Section 34.1.2). Les espaces sont ignorés avant tout
mot-clé
ou valeur
,
mais pas à l'intérieur ou après. Notez qu'il n'existe pas de moyens
d'écrire &
à l'intérieur d'une
valeur
.
Notez qu'en spécifiant une connexion socket (avec le préfixe
unix:
), le nom d'hôte doit être exactement
localhost
. Pour choisir un répertoire de socket
autre que celui par défaut, écrivez le chemin complet du répertoire
comme valeur de l'option host
dans la section
options
de la cible.
Le nom-connexion
est utilisé pour gérer
plusieurs connexions dans un programme. Il peut être omis si le programme
n'utilise qu'une connexion. La connexion la plus récemment ouverte devient
la connexion courante, qui est utilisée par défaut quand un ordre SQL doit
être exécuté (voyez plus bas dans ce chapitre).
Voici quelques exemples d'ordres CONNECT
:
EXEC SQL CONNECT TO mabase@sql.mondomaine.com; EXEC SQL CONNECT TO tcp:postgresql://sql.mondomaine.com/mabase AS maconnexion USER john; EXEC SQL BEGIN DECLARE SECTION; const char *cible = "mabase@sql.mondomaine.com"; const char *utilisateur = "john"; const char *motdepasse = "secret"; EXEC SQL END DECLARE SECTION; ... EXEC SQL CONNECT TO :cible USER :utilisateur USING :motdepasse; /* or EXEC SQL CONNECT TO :cible USER :utilisateur/:motdepasse; */
Le dernier exemple utilise la fonctionnalité dont on parlait précédemment sous le nom de références de variable. Vous verrez dans les sections finales comment des variables C peuvent être utilisées dans des ordres SQL quand vous les préfixez par deux-points.
Notez que le format de la cible de connexion n'est pas spécifié dans le standard SQL. Par conséquent si vous voulez développer des applications portables, vous pourriez vouloir utiliser quelque chose ressemblant au dernier exemple pour encapsuler la cible de connexion quelque part.
Si des utilisateurs non fiables ont accès à une base de données qui n'a pas
adopté un modèle d'utilisation de schémas sécurisés,
alors commencez chaque session en retirant les schémas accessibles à l'écriture publique
du search_path
. Par exemple, ajoutez options=-c search_path=
aux
, ou
lancez options
EXEC SQL SELECT pg_catalog.set_config('search_path', '',
false);
après la connexion. Cette considération n'est pas spécifique à
ECPG ; elle s'applique à toute interface pour exécuter des commandes SQL arbitraires.
Les ordres des programmes SQL embarqué sont par défaut exécutés dans la connexion courante, c'est à dire la plus récemment ouverte. Si une application a besoin de gérer plusieurs connexions, alors il y a trois façons de le gérer.
La première solution est de choisir explicitement une connexion pour chaque ordre SQL, par exemple:
EXEC SQL AT nom-connexion
SELECT ...;
Cette option est particulièrement appropriée si l'application a besoin d'alterner les accès à plusieurs connexions.
Si votre application utilise plusieurs threads d'exécution, ils ne peuvent pas utiliser une connexion simultanément. Vous devez soit contrôler explicitement l'accès à la connexion (en utilisant des mutexes), ou utiliser une connexion pour chaque thread.
La seconde option est d'exécuter un ordre pour changer de connexion courante. Cet ordre est:
EXEC SQL SET CONNECTION nom-connexion
;
Cette option est particulièrement pratique si de nombreux ordres doivent être exécutés sur la même connexion.
Voici un programme exemple qui gère plusieurs connexions à base de données:
#include <stdio.h> EXEC SQL BEGIN DECLARE SECTION; char nomdb[1024]; EXEC SQL END DECLARE SECTION; int main() { EXEC SQL CONNECT TO basetest1 AS con1 USER utilisateurtest; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; EXEC SQL CONNECT TO basetest2 AS con2 USER utilisateurtest; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; EXEC SQL CONNECT TO basetest3 AS con3 USER utilisateurtest; EXEC SQL SELECT pg_catalog.set_config('search_path', '', false); EXEC SQL COMMIT; /* Cette requête serait exécuté dans la dernière base ouverte "basetest3". */ EXEC SQL SELECT current_database() INTO :nomdb; printf("courante=%s (devrait être basetest3)\n", nomdb); /* Utiliser "AT" pour exécuter une requête dans "basetest2" */ EXEC SQL AT con2 SELECT current_database() INTO :nomdb; printf("courante=%s (devrait être basetest2)\n", nomdb); /* Basculer la connexion courante à "basetest1". */ EXEC SQL SET CONNECTION con1; EXEC SQL SELECT current_database() INTO :nomdb; printf("courante=%s (devrait être basetest1)\n", nomdb); EXEC SQL DISCONNECT ALL; return 0; }
Cet exemple devrait produire cette sortie :
courante=basetest3 (devrait être basetest3) courante=basetest2 (devrait être basetest2) courante=basetest1 (devrait être basetest1)
La troisième option est de déclarer un identifiant SQL lié à la connexion, par exemple :
EXEC SQL ATconnection-name
DECLAREstatement-name
STATEMENT; EXEC SQL PREPAREstatement-name
FROM :dyn-string
;
Une fois que vous avez lié l'identifiant SQL à la connexion, vous exécutez le SQL dynamique sans clause AT. Notez que cette option se comporte comme les directives préprocesseurs, ainsi le lien n'est actif que dans le fichier.
Voici un exemple de programme utilisant cette option :
#include <stdio.h> EXEC SQL BEGIN DECLARE SECTION; char dbname[128]; char *dyn_sql = "SELECT current_database()"; EXEC SQL END DECLARE SECTION; int main(){ EXEC SQL CONNECT TO postgres AS con1; EXEC SQL CONNECT TO testdb AS con2; EXEC SQL AT con1 DECLARE stmt STATEMENT; EXEC SQL PREPARE stmt FROM :dyn_sql; EXEC SQL EXECUTE stmt INTO :dbname; printf("%s\n", dbname); EXEC SQL DISCONNECT ALL; return 0; }
Cet exemple produira cette sortie, même si la connexion par défaut est testdb :
postgres
Pour fermer une connexion, utilisez l'ordre suivant :
EXEC SQL DISCONNECT [connexion
];
La connexion
peut être spécifiée des façons
suivantes:
nom-connexion
CURRENT
ALL
Si aucun nom de connexion n'est spécifié, la connexion courante est fermée.
C'est une bonne pratique qu'une application ferme toujours explicitement toute connexion qu'elle a ouverte.