Opérateurs

Procédure de conversion

Opérateur évaluation

  1. Recherche d'un appariement exact dans le pg_operator du catalogue système.

    1. si un argument ou un opérateur binaire est inconnu, il est supposé qu'il s'agit du même type que l'autre argument.

    2. inverse les arguments, et recherche un appariement exact avec l'opérateur qui pointe vers lui-même comme étant commutatif. Si il trouve, alors il inverse les arguments dans la hiérarchie grammaticale et utilise cet opérateur.

  2. recherche du meilleur appariement

    1. crée une liste de tous les opérateurs du même nom.

    2. si seulement un opérateur est dans la liste, il est utilisé si le type entrée peut être contraint, et retourne une erreur si le type ne peut pas être contraint.

    3. garde tous les opérateurs avec l'appariement le plus explicite pour les types. Garde tout si il n'y a pas d'appariement explicite et passe à l'étape suivante. Si seulement un candidat reste, l'utilise si le type peut être contraint.

    4. si certains arguments entrée sont "inconnu", catégorise les entrées candidates comme boolean, numeric, string, geometric, ou user (utilisateur). Si il y a un mélange de catégories, ou plus d'un type utilisateur, renvoie une erreur parce que le choix correct ne peut pas être déduit sans plus d'indications. Si seulement une catégorie est présente, assigne le type préférentiel à la colonne résultat qui a été précédemment "inconnu".

    5. choisit le candidat avec l'appariement de type le plus exact, lequel apparie le "prefered type" pour chaque catégorie de colonne depuis l'étape précédente. Si il y a encore plus d'un candidat, ou s'il y en a plus, renvoie une erreur.

Exemples

Opérateur Exponentiel

Il y a un seul opérateur exponentiel défini dans le catalogue, et il prend les arguments float8. Le scanner assigne un type int4 initial aux deux arguments de cette requête :
tgl=> select 2 ^ 3 AS "Exp";
Exp
---
  8
(1 row)
Ainsi le parser fait un type conversion sur les deux opérandes et la requête est équivalente à
tgl=> select float8(2) ^ float8(3) AS "Exp";
Exp
---
  8
(1 row)
ou
tgl=> select 2.0 ^ 3.0 AS "Exp";
Exp
---
  8
(1 row)

Note

cette dernière forme est la moins lourde, aucune fonction n'est appelée pour rendre le type conversion implicite. Ce n'est pas un problème pour les petites requêtes, mais peut avoir un impact sur la performance de requêtes engageant de grandes tables.

Concaténation de chaîne

Une syntaxe string-like est utilisée pour travailler avec les types chaîne aussi bien que pour travailler avec des types étendus complexes. Les chaînes avec un type non spécifié sont appariées avec les opérateurs candidats probables.

Un argument non spécifié :
tgl=> SELECT text 'abc' || 'def' AS "Text and Unknown";
Text and Unknown
----------------
abcdef
(1 row)

Dans ce cas le parser recherche pour voir si il y a un opérateur prenant text pour les deux arguments. Il suppose que le second argument doit être interprété comme étant de type text.

Concaténation sur les types non spécifiés :
tgl=> SELECT 'abc' || 'def' AS "Unspecified";
Unspecified
-----------
abcdef
(1 row)

Dans ce cas il n'y a pas d'indication initiale pour quel type utiliser, car pas de types sprécifiés dans la requête. Ainsi, le parser recherche tous les opérateurs candidats et trouve que tous les arguments pour tous les candidats sont de type chaîne. Il choisit le type préférentiel pour les chaînes, text, pour cette requête.

Note

si un utilisateur définit un nouveau type et définit un opérateur "||" pour travailler avec lui, cette requête ne fonctionnerait plus comme écrit. Le programme d'analyse syntaxique aura maintenant des types candidats venant de deux catégories, et ne pourra pas décider lequel utiliser.

Factoriel

Cet exemple illustre un résultat intéressant. Traditionnellement, l'opérateur factoriel est défini pour les entiers seulement. La catalogue d'opérateurs Postgres possède seulement une entrée pour le factoriel, prenant un entier opérande. S'il est donné un argument numérique non-entier, Postgres essaiera de convertir cet argument en un entier pour l'évaluation du factoriel.
tgl=> select (4.3 !);
?column?
--------
      24
(1 row)

Note

bien sûr, ceci conduit à un résultat mathématique suspect, puisque en principe le factoriel d'un non-entier n'est pas défini. Cependant, le rôle de la base de données n'est pas d'apprendre les mathématiques, mais d'être un outil de manipulation de données. Si un utilisateur choisi de prendre le factoriel d'un nombre décimal, Postgres tentera de l'obliger.