Chapitre 6. Conversion de type

Table des matières
Vue d'ensemble
Opérateurs
Fonctions
Requêtes cibles
Requêtes UNION

Les requêtes SQL peuvent, intentionnellement ou non, nécessiter le mélange de différents types de données dans la même expression. Postgres possède des fonctionnalités pour évaluer ces expressions.

Dans certains cas l'utilisateur n'a pas besoin de comprendre les détails du mécanisme de conversion. Cependant, les conversions implicites faites par Postgres peuvent affecter les résultats apparents d'une requête, et ces résultats peuvent être façonnés par un utilisateur ou un programmeur utilisant un type coercition explicite.

Ce chapitre présente les mécanismes et conventions des conversions de type Postgres. Le guide du programmeur donne plus de détails sur les algorithmes utilisés pour les conversions de type et coercition.

Vue d'ensemble

SQL est un langage extrêment typé. De fait, chaque donnée a un type qui détermine son comportement et son usage. Postgres a un système de types extensibles qui est plus général et flexible que les autres implémentations SGBDR. Désormais le comportement de la plupart des types conversion dans Postgres sera régi par des règles générales plutôt que par des méthodes heuristiques ad-hoc pour permettre aux expressions d'être significatives, même avec les types utilisateur.

Le scanner/parser Postgres décode les éléments lexicaux en 5 catégories fondamentales seulement : integers (entiers), floats (décimaux), strings (chaînes), names (noms) et keywords (mots-clé). Les types les plus étendus sont présents en particulier dans les chaînes. La définition du langage SQL admet des types nom avec les chaînes, et ce mécanisme est utilisé par Postgres pour lancer le parser sur le bon chemin. Par exemple, la requête :
tgl=> SELECT text 'Origin' AS "Label", point '(0,0)' AS "Value";
Label |Value
------+-----
Origin|(0,0)
(1 row)
possède deux chaînes, de type text et point. Si un type n'est pas spécifié, le type inconnu est assigné initialement, pour être résolu dans une étape ultérieure, comme décrit plus bas.

Il y a quatre constructions SQL fondamentales qui requièrent des règles de conversion de type distinctes dans le parser Postgres :

Opérateurs

Postgres fournit des opérateurs avec des expressions left- et right-unary (un argument), aussi bien que binaire (deux arguments).

Appels fonctions

La majeure partie du système de types Postgres est construit autour d'un riche ensemble de fonctions. Les appels fonction ont un ou plusieurs arguments qui, pour chaque requête spécifique, doit être identique aux fonctions disponibles dans le catalogue du système.

Requête cibles (query targets)

Les clauses SQL INSERT placent les résultats de la requête dans une table. Les expressions dans la requête doivent être en accord avec, et peuvent être converties vers les colonnes cibles de l'insert.

Requêtes UNION

Depuis que tous les résultats d'un UNION SELECT doivent apparaître dans un seul ensemble de colonnes, les types de chaque clause SELECT doivent être assorties et converties en un ensemble uniforme.

Plusieurs règles générales de conversion de type utilisent de simples conventions construites sur la fonction Postgres et les tables opérateur systeme. Il existe certains comportements heuristiques inclus dans les règles de conversion pour un meilleur support des conventions pour les types natifs standards SQL92 comme smallint, integer, et float.

Le parser Postgres utilise comme convention que toute fonction type conversion prend un seul argument de type source et est nommé avec le même nom que le type cible. Chaque fonction rencontrant ce critère est considérée comme une fonction conversion valide, et peut être utilisée par le parser comme telle. Cette simple action donne au parser le pouvoir d'explorer les possibilités des types conversion, permettant aux types utilisateur étendus d'utiliser ces mêmes fonctionnalités de façon transparente.

Un heuristique additionel est inclut dans le parser pour fournir de meilleures estimations au propre comportement des types standards SQL. Il y a cinq catégories de types définis : booléen, chaîne, numérique, géométrique et utilisateur. Chaque catégorie, à l'exception du type utilisateur, a un "type préféré" qui est utilisé pour résoudre les ambiguïtés dans les candidats. Chaque type utilisateur a son propre "type préféré", ainsi des expressions ambiguës (celles avec de multiples solutions candidates) avec seulement un type utilisateur peuvent se résoudre vers un meilleur choix unique, tandis que celles avec de multiples types utilisateur seront ambiguës et empreintes d'erreurs.

Les expressions ambiguës qui ont des solutions candidates dans une catégorie de type seulement seront probablement résolues, tandis que les expressions ambiguës avec des candidats sur de multiples catégories vont générer une erreur et demanderont une clarification de la part de l'utilisateur.

Principes

Toutes les règles type conversion sont établies avec dans l'esprit plusieurs principes :

  • les conversions implicites ne doivent jamais avoir de résultats surprenants ou imprévisibles.

  • les types utilisateur, desquels le parser n'a pas à priori connaissance, doivent être au plus haut dans la hierarchie des types. Dans les expressions de types mélangés, les types natifs doivent toujours être convertis en type utilisateur (bien sûr, seulement si la conversion est nécessaire).

  • les types utilisateur ne sont pas reliés. Couramment, Postgres ne possède pas d'information sur les relations entre les types, autre que pour les types natifs et les relations implicites basées sur les fonctions disponibles dans le catalogue.

  • Il n'y aura pas de surcharge depuis le parser ou l'exécuteur si une requête n'a pas un besoin implicite de type conversion. Ceci étant, si une requête est bien formulée et les types déja assortis, alors la requête procédera sans perte de temps supplémentaire dans le parser et sans introduire des fonctions de conversion non nécessaires dans la requête.

    De plus, si une requête necessite habituellement une conversion implicite pour une fonction, et si l'utilisateur définit une fonction explicite avec les arguments types corrects, le parser utilisera cette nouvelle fonction et ne fera pas la conversion implicite en utilisant l'ancienne fonction.