10.2. Opérateurs

L'opérateur spécifique à employer dans un appel d'opérateurs est déterminé par la procédure ci-dessous. Notez que cette procédure est indirectement affectée par l'ordre d'insertion des opérateurs. Regardez la Section 4.1.6 pour plus de détails.

Résolution de types pour les opérateurs

  1. Sélectionner les opérateurs à examiner depuis le catalogue système pg_operator. Si un nom non-qualifié d'opérateur était utilisé (le cas habituel), les opérateurs examinés sont ceux avec un nom et un nombre d'arguments corrects et qui sont visibles dans le chemin de recherche courant (regardez la Section 5.8.3). Si un nom qualifié d'opérateur a été donné, seuls les opérateurs dans le schéma spécifique sont examinés.

    1. Si un chemin de recherche trouve de nombreux opérateurs avec des types d'arguments identiques, seul celui apparaissant le plus tôt dans le chemin sera examiné. Mais les opérateurs avec des types d'arguments différents sont examinés sur une base d'égalité indépendamment de leur position dans le chemin de recherche.

  2. Vérifier que l'opérateur accepte le type exact des arguments en entrée. Si un opérateur existe (il peut en avoir uniquement un qui corresponde exactement dans l'ensemble des opérateurs considérés), utiliser cet opérateur.

    1. Si un argument lors d'une invocation d'opérateur binaire est de type inconnu, alors considérer pour ce contrôle que c'est le même type que l'autre argument. Les autres cas impliquant le type inconnu ne trouveront jamais une correspondance à ce niveau.

  3. Regarder pour la meilleure correspondance.

    1. Se débarrasser des opérateurs candidats pour lesquels les types en entrée ne correspondent pas et qui ne peuvent pas être convertis (en utilisant une conversion implicite) pour correspondre. Le type inconnu est supposé être convertible vers n'importe quoi. Si un candidat reste, l'utiliser, sinon aller à la prochaine étape.

    2. Parcourir tous les candidats et garder ceux avec la correspondance la plus exacte par rapport aux types en entrée. (Les domaines sont considérés de la même façon que leur type de base pour cette étape.) Garder tous les candidats si aucun n'a de correspondances exactes. Si seulement un candidat reste, l'utiliser ; sinon aller à la prochaine étape.

    3. Parcourir tous les candidats et garder ceux qui acceptent les types préférés (de la catégorie des types de données en entrée) aux positions où la conversion de types aurait été requise. Garder tous les candidats si aucun n'accepte les types préférés. Si seulement un candidat reste, l'utiliser ; sinon aller à la prochaine étape.

    4. Si des arguments en entrée sont inconnus, vérifier la catégorie des types acceptés à la position de ces arguments par les candidats restants. À chaque position, sélectionner la catégorie chaîne de caractères si un des candidats accepte cette catégorie. (Cette préférence envers les chaînes de caractères est appropriée car le terme type-inconnu ressemble à une chaîne de caractères.) Dans le cas contraire, si tous les candidats restants acceptent la même catégorie de types, sélectionner cette catégorie. Dans le cas contraire échouer car le choix correct ne peut pas être déduit sans plus d'indices. Se débarrasser maintenant des candidats qui n'acceptent pas la catégorie sélectionnée. De plus, si des candidats acceptent un type préféré comme argument donné, se débarrasser des candidats qui acceptent, pour cet argument, les types qui ne sont pas préférés.

    5. Si seulement un candidat reste, l'utiliser. Si aucun candidat ou si plus d'un candidat reste, alors échouer.

Quelques exemples suivent.

Exemple 10-1. Résolution de types pour l'opérateur exponentiel

Il n'y a qu'un seul opérateur exponentiel défini dans le catalogue et il prend deux arguments de type double precision (double précision). L'analyseur assigne initialement le type integer (entier) aux deux arguments de cette expression :

SELECT 2 ^ 3 AS "exp";

 exp
-----
   8
(1 row)

L'analyseur fait donc une conversion de types sur les deux opérandes et la requête est équivalente à

SELECT CAST(2 AS double precision) ^ CAST(3 AS double precision) AS "exp";

Exemple 10-2. Résolution de types pour les opérateurs de concaténation de chaînes

La syntaxe d'une chaîne de caractères est utilisée pour travailler avec les types chaînes mais aussi avec les types d'extensions complexes. Les chaînes de caractères avec un type non spécifié sont comparées avec les opérateurs candidats probables.

Un exemple avec un argument non spécifié :

SELECT text 'abc' || 'def' AS "text and unknown";

 text and unknown
------------------
 abcdef
(1 row)

Dans ce cas, l'analyseur cherche à voir s'il existe un opérateur prenant text pour ses deux arguments. Comme il y en a un, il suppose que le second argument devrait être interprété comme un type text.

Voici une concaténation sur des types non spécifiés :

SELECT 'abc' || 'def' AS "unspecified";

 unspecified
-------------
 abcdef
(1 row)

Dans ce cas, il n'y a aucune allusion initiale sur quel type utiliser puisqu'aucun type n'est spécifié dans la requête. Donc l'analyseur regarde pour tous les opérateurs candidats et trouve qu'il existe des candidats acceptant en entrée la catégorie chaîne de caractères (string) et la catégorie morceaux de chaînes (bit-string). Puisque la catégorie chaînes de caractères est préférée quand elle est disponible, cette catégorie est sélectionnée. Le type préféré pour la catégorie chaînes étant texte (text), ce type est utilisé comme le type spécifique pour résoudre les types inconnus.

Exemple 10-3. Résolution de types pour les opérateurs de valeur absolue et de négation

Le catalogue d'opérateurs de PostgreSQL a plusieurs entrées pour l'opérateur de préfixe @. Ces entrées implémentent toutes des opérations de valeur absolue pour des types de données numériques variées. Une de ces entrées est pour le type float8 (réel) qui est le type préféré dans la catégorie des numériques. Par conséquent, PostgreSQL utilisera cette entrée quand il sera en face d'un argument non numérique :

SELECT @ '-4.5' AS "abs";
 abs
-----
 4.5
(1 row)

Ici le système a effectué une conversion implicite du type text (texte) au type float8 (réel) avant d'appliquer l'opérateur choisi. Nous pouvons vérifier que float8 et pas un autre type a été utilisé :

SELECT @ '-4.5e500' AS "abs";

ERROR:  "-4.5e500" is out of range for type double precision

D'un autre côté, l'opérateur préfixe ~ (négation bit par bit) est défini seulement pour les types entiers et non pas pour float8 (réel). Ainsi, si nous essayons un cas similaire avec ~, nous obtenons :

SELECT ~ '20' AS "negation";

ERROR:  operator is not unique: ~ "unknown"
HINT:  Could not choose a best candidate operator. You may need to add explicit
type casts.

Ceci se produit parce que le système ne peut pas décider quel opérateur doit être préféré parmi les différents opérateurs ~ possibles. Nous pouvons l'aider avec une conversion explicite :

SELECT ~ CAST('20' AS int8) AS "negation";

 negation
----------
      -21
(1 row)