Le protocole a différentes phases pour le démarrage et les opérations normales. Dans la phase de démarrage, le client ouvre une connexion au serveur et s'authentifie à la satisfaction du serveur. (Cela pourrait ne nécessiter qu'un seul message ou plusieurs messages, suivant la méthode d'authentification utilisée.) Si tout va bien, le serveur envoie ensuite une information de statut au client, et entre enfin dans les opérations normales. Sauf pour le message initial startup-request, cette partie du protocole est conduite par le serveur.
Lors des opérations normales, le client envoie des requêtes et d'autres
commandes au backend, et le backend envoie les résultats des requêtes ainsi
que d'autres réponses. Il existe quelques cas (comme par exemple
NOTIFY
) où le backend enverra des messages non sollicités
mais pour la plupart, cette portion d'une session est conduite par des
demandes du client.
La fin d'une session est normalement le choix du client mais elle peut être forcée par le backend dans certains cas. Dans tous les cas, quand le backend ferme la connexion, cela annulera toute transaction ouverte (incomplète) avant de quitter.
Lors des opérations normales, les commandes SQL peuvent être exécutées via deux sous-protocoles. Dans le protocole « simple query » (requête simple), le client envoie simplement une chaîne de caractères contenant la requête. Cette chaîne est immédiatement analysée puis exécutée par le backend. Dans le protocole « extended query » (requête étendue), le traitement des requêtes est séparé en plusieurs étapes : l'analyse, le lien avec les valeurs des paramètres, et l'exécution. Ceci offre des bénéfices de flexibilité et de performance, au prix d'une complexité plus importante.
Les opérations normales ont des sous-protocoles supplémentaires pour les
opérations spéciales comme COPY
.
Toute la communication se fait via un flux de message. Le premier octet d'un message identifie le type de message, et les quatre prochains octets précisent la longueur du message (cette longueur s'inclut elle-même, mais pas l'octet de type de message). Le contenu restant du message est déterminé par le type de message. Pour des raisons historiques, le tout premier message envoyé par le client (le message de démarrage) n'a pas d'octet initial de type de message.
Pour éviter de perdre la synchronisation avec le flux de message, les serveurs et les clients lisent typiquement un message entier (en utilisant le nombre d'octets) avant de commencer l'analyse de son contenu. Ceci permet une récupération facilitée si une erreur est détectée lors du traitement du contenu. Dans les situations extrêmes (comme un manque mémoire pour mettre en cache le message), le receveur peut utiliser le nombre d'octets pour déterminer la quantité de données à ignorer avant de continuer la lecture des messages.
Inversement, serveurs et clients doivent faire attention à ne jamais envoyer un message partiel. Ceci se fait habituellement en construisant le message entier dans un cache avant de l'envoyer. Si un échec de communication survient lors d'un envoi ou de la réception d'un message, la seule réaction sensible est d'abandonner la connexion parce qu'il y a très peu d'espoir de récupérer la synchronisation entre messages.
Dans le protocole de requête étendue, l'exécution de commandes SQL est
divisée en plusieurs étapes. L'état conservé entre les étapes est représenté
par deux types d'objets : les requêtes préparées
et les portails. Une requête préparée représente le
résultat de l'analyse sémantique d'une chaîne de caractères contenant une
requête. Une requête préparée n'est pas prête à s'exécuter parce qu'elle
pourrait manquer des valeurs spécifiques pour ses
paramètres. Un portail représente une instruction
prête à être exécutée ou une requête déjà partiellement exécutée, avec
toutes valeurs manquantes de paramètres renseignées. (Pour les requêtes
SELECT
, un portail est équivalent à un curseur ouvert
mais nous pouvons choisir d'utiliser un terme différent vu que les curseurs
ne gèrent pas les requêtes autres que SELECT
.)
En aperçu, le cycle d'exécution consiste en une étape
parse, qui crée une requête préparée à partir d'une
chaîne de caractères contenant la requête ; une étape
bind, qui crée un portail à partir d'une requête
préparée et des valeurs nécessaires pour les paramètres ; et une étape
execute qui exécute la requête d'un portail. Dans le
cas d'une requête qui renvoie des lignes (SELECT
,
SHOW
, etc.), l'étape d'exécution doit connaître le nombre
limité de lignes à récupérer, si bien que plusieurs étapes d'exécution
pourraient être nécessaires pour terminer l'opération.
Le backend peut garder trace de plusieurs requêtes préparées et portails (mais notez qu'ils n'existent que dans une session et ne sont jamais partagés entre sessions). Les requêtes préparées et les portails existants sont référencés par des noms assignés lors de leur création. De plus, les requêtes préparées et portails « sans nom » existent. Bien que ces derniers se comportement largement de la même façon que des objets nommés, les opérations les concernant sont optimisées dans le cas d'une requête exécutée une seule fois, puis annulée, alors que les opérations sur des objets nommés sont optimisées dans un contexte d'utilisation multiple.
Les données d'un type de données particulier pourraient être transmises dans un format parmi plusieurs. Depuis PostgreSQL 7.4, les seuls formats acceptés sont « text » et « binary », mais le protocole permet des extensions futures. Le format désiré pour toute valeur est indiqué par un code format. Les clients peuvent spécifier un code format pour chaque valeur transmise de paramètre et pour chaque colonne d'un résultat de requête. Le texte a le code format zéro, le binaire a le code format un, et tous les autres codes format sont réservés pour une définition future.
La représentation textuelle des valeurs correspond à la façon dont un type de données est représenté sous forme de chaîne de caractères par les fonction de conversion d'entrée/sortie. Dans la représentation transmise, il n'existe pas de caractère nul en fin de chaîne ; le client doit ajouter un aux valeurs reçues s'il veut les traiter comme des chaînes de caractères du langage C. (Le format texte n'autorise pas les NULL embarqués.)
Les représentations binaires pour les entiers utiliser l'ordre d'octet réseau (l'octet le plus significatif en premier). Pour les autres types de données, consultez la documentation ou le code source pour apprendre leur représentation binaire. Gardez en tête que les représentations binaires des types de données complexes pourraient changer au fur et à mesure des versions du serveur ; le format texte est généralement le choix le plus portable.
La version actuelle du protocole est la version 3.2. Néanmoins, pour une compatibilité ascendante avec les anciennes versions du serveur et les middlewares qui ne supportent pas encore la négociation de la version, libpq accepte toujours d'utiliser le protocole version 3.0 par défaut.
Un serveur simple peut supporter plusieurs versions du protocole. Le message startup-request initial indique au serveur la version de protocole que le client souhaite utiliser. Si la version majeure demandée par le client n'est pas acceptée par le serveur, la connexion sera rejetée (par exemple, ceci survient si le client a réclamé la version 4.0 du protocole, qui n'existe pas actuellement). Si la version mineure demandée par le client n'est pas supportée par le serveur (par exemple, le client demande la version 3.2 3.2, mais le serveur n'accepte que la version 3.0), le serveur pourrait soit rejeter la connexion soit répondre avec un message NegotiateProtocolVersion contenant la version mineure la plus haute qu'il supporte). Le client pourrait alors choisir soit de continuer avec la connexion en utilisant la version de protocole indiquée soit d'annuler la connexion.
La négociation du protocole a été introduit dans PostgreSQL version 9.3.21. Les versions plus anciennes pourraient rejeter la connexion si le client a réclamé une version mineure qui n'était pas supportée par le serveur.
Tableau 54.1 montre les versions actuellement acceptées du protocole.
Tableau 54.1. Versions de protocole
Version | Supporté par | Description |
---|---|---|
3.2 | PostgreSQL 18 et ultérieures | Version actuelle. La clé secrète utilisée dans l'annulation de requête a été élargi de 4 octets à un champ de longueur variable. Le message BackendKeyData a été changé pour être compatible, et le message CancelRequest a été redéfini pour avoir une charge de longueur variable. |
3.1 | - | Réservé. La version 3.1 n'a été utilisée par aucune version de PostgreSQL mais elle a été sautée parce que les anciennes versions de l'application pgbouncer avait un bug dans la négociation du protocole qui indiquait de façon erronée qu'elle supportait la version 3.1. |
3.0 | PostgreSQL 7.4 et ultérieures | |
2.0 | jusqu'à PostgreSQL 13 | Voir les versions précédentes de la documentation de PostgreSQL pour les détails |