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.