IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

42.3. Valeur des données avec PL/Python

De manière générale, le but de PL/Python est de fournir une relation « naturelle » entre PostgreSQL et le monde Python. Ces règles relationelles sont décrites ci-dessous.

42.3.1. Type de données

Les paramètres de fonctions sont convertis de leur type PostgreSQL vers un type correspondant en Python :

  • Le type boolean PostgreSQL est converti en bool Python.

  • Les smallint et int de PostgreSQL sont convertis en int Python. Le bigint PostgreSQL est converti en long pour Python 2 et en int pour Python 3.

  • Les real, double et numeric de PostgreSQL sont convertis en float Python. Notez que pour numeric, cela entraine une perte d'information et peut aboutir à des résulats incorrects. Cela devrait être corrigé dans une future version.

  • Le bytea PostgreSQL est converti en str pour Python 2 et en bytes pour Python 3. Avec Python 2, la chaîne devrait être traitée comme une séquence d'octets sans encodage.

  • Tous les autres types de données, y compris les chaînes de caractères PostgreSQL, sont convertis en str Python. En Python 2, ces chaînes auront le même encodage de caractères que le serveur. En Python 3, ce seront des chaînes Unicode comme les autres.

  • Pour les données non scalaires, voir ci-dessous.

Les valeurs renvoyées par les fonctions sont converties en types de retour PostgreSQL comme suit:

  • Quand le type de la valeur PostgreSQL renvoyée est boolean, la valeur de retrour sera évaluée en fonction des règles Python. Ainsi, les 0 et les chaines vides sont fausses, mais la valeur 'f' est vraie.

  • Quand le type de la valeur PostgreSQL renvoyée est bytea, la valeur de retour sera convertie en chaine de caractères (Python 2) ou en octets (Python 3) en utilisant les mécanismes Python correspondants, le résultat étant ensuite converti en bytea.

  • Pour tous les autres types de retrour PostgreSQL, la valeur renvoyée par Python est convertie en chaine de caractères en utilisant la méthode Python str, et et le résultat est transmis à la fonction d'entrée du type de données PostgreSQL.

    Les chaines de caractères en Python 2 doivent être transmises dans le même encodage que celui du serveur PostgreSQL. Les chaines invalides dans l'encodage du serveur entraineront la levée d'une erreur, mais toutes les erreurs d'encodage ne sont pas detectées, ce qui peut aboutir à une corruption des données lorsque ces règles ne sont pas respéctée. Les chaines Unicode sont automatiquement converties dans le bon encodage, il est donc plus prudent de les utiliser. Dans Python 3, toutes les chaines sont en Unicode.

  • Pour les données non scalaires, voire ci dessous.

Notez que les erreurs logiques entre le type de retour déclaré dans PostgreSQL et le type de l'objet Python renvoyé ne sont pas détectées. La valeur sera convertie dans tous les cas.

[Astuce]

Astuce

Les fonctions PL/Python ne peuvent renvoyer les types RECORD ou SETOF RECORD. Une solution de contournement est d'écrire une fonction PL/pgSQL qui crée une table temporaire, d'appeler la fonction en PL/Python pour remplir cette table puis de laisser à la fonction PL/pgSQL le soin de renvoyer le type générique RECORD de cette table temporaire.

42.3.2. Null, None

Si une valeur SQL NULL est passée à une fonction, la valeur de l'argument apparaîtra comme None au niveau de Python. Par exemple, la définition de la fonction pymax montrée dans Section 42.2, « Fonctions PL/Python » renverra la mauvaise réponse pour les valeurs NULL. Nous pouvons ajouter STRICT à la définition de la fonction pour faire en sorte que PostgreSQL™ fasse quelque-chose de plus raisonnable : si une valeur NULL est passée, la fonction ne sera pas appelée du tout mais renverra juste un résultat NULL automatiquement. Sinon, vous pouver vérifier les entrées NULL dans le corps de la fonction :

CREATE FUNCTION pymax (a integer, b integer)
  RETURNS integer
AS $$
  if (a is None) or (b is None):
    return None
  if a > b:
    return a
  return b
$$ LANGUAGE plpythonu;

Comme montré ci-dessus, pour renvoyer une valeur SQL NULL à partir d'une fonction PL/Python, renvoyez la valeur None. Ceci peut se faire que la fonction soit stricte ou non.

42.3.3. Tableaux, Listes

Les valeurs de type tableaux SQL sont passées via PL/Python comme des listes Python. Pour renvoyer une valeur de type tableau SQL par une fonction PL/Python, renvoyez une séquence Python, par exemple une liste ou un tuple :

CREATE FUNCTION return_arr()
  RETURNS int[]
AS $$
return (1, 2, 3, 4, 5)
$$ LANGUAGE plpythonu;

SELECT return_arr();
 return_arr  
-------------
 {1,2,3,4,5}
(1 row)

Notez que, avec Python, les chaînes sont des séquences, ce qui peut avoir des effets indésirables qui peuvent être familiers aux codeurs Python :

CREATE FUNCTION return_str_arr()
  RETURNS varchar[]
AS $$
return "hello"
$$ LANGUAGE plpythonu;

SELECT return_str_arr();
 return_str_arr
----------------
 {h,e,l,l,o}
(1 row)

42.3.4. Types composites

Les arguments de type composite sont passés à la fonction via une correspondance Python. Les noms d'élément de la correspondance sont les noms d'attribut du type composite. Si un attribut a une valeur NULL dans la ligne traitée; il a la valeur NULL dans sa correspondance. Voici un exemple :

CREATE TABLE employe (
  nom text,
  salaire integer,
  age integer
);

CREATE FUNCTION trop_paye (e employe)
  RETURNS boolean
AS $$
  if e["salaire"] > 200000:
    return True
  if (e["age"] < 30) and (e["salaire"] > 100000):
    return True
  return False
$$ LANGUAGE plpythonu;

Il existe plusieurs façon de renvoyer une ligne ou des types composites à partir d'une fonction Python. Les exemples suivants supposent que nous avons :

CREATE TABLE valeur_nommee (
  nom   text,
  valeur  integer
);

ou

CREATE TYPE valeur_nommee AS (
  nom   text,
  valeur  integer
);

Une valeur composite peut être renvoyé comme :

Un type séquence (ligne ou liste), mais pas un ensemble parce que ce n'est pas indexable

Les objets séquences renvoyés doivent avoir le même nombre d'éléments que le type composite a de champs. L'élément d'index 0 est affecté au premier champ du type composite, 1 au second et ainsi de suite. Par exemple :

CREATE FUNCTION cree_paire (nom text, valeur integer)
  RETURNS valeur_nommee
AS $$
  return [ nom, valeur ]
  # ou autrement, en tant que ligne : return ( nom, valeur )
$$ LANGUAGE plpythonu;

Pour renvoyer NULL dans une colonne, insérez None à la position correspondante.

Correspondance (dictionnaire)

La valeur de chaque colonne du type résultat est récupérée à partir de la correspondance avec le nom de colonne comme clé. Exemple :

CREATE FUNCTION cree_paire (nom text, valeur integer)
  RETURNS valeur_nommee
AS $$
  return { "nom": nom, "valeur": valeur }
$$ LANGUAGE plpythonu;

Des paires clés/valeurs supplémentaires du dictionnaire sont ignorées. Les clés manquantes sont traitées comme des erreurs. Pour renvoyer NULL comme une colonne, insérez None avec le nom de la colonne correspondante comme clé.

Objet (tout objet fournissant la méthode __getattr__)

Ceci fonctionne de la même façon qu'une correspondance. Exemple :

CREATE FUNCTION cree_paire (nom text, valeur integer)
  RETURNS valeur_nommee
AS $$
  class valeur_nommee:
    def __init__ (self, n, v):
      self.nom = n
      self.valeur = v
  return valeur_nommee(nom, valeur)

  # ou simplement
  class nv: pass
  nv.nom = nom
  nv.valeur = valeur
  return nv
$$ LANGUAGE plpythonu;

42.3.5. Set-Returning Functions

Une fonction PL/Python peut aussi renvoyer des ensembles scalaires ou des types composites. Il existe plusieurs façon de faire ceci parce que l'objet renvoyé est transformé en interne en itérateur. Les exemples suivants supposent que nous avons le type composite :

CREATE TYPE greeting AS (
  how text,
  who text
);

Un résultat ensemble peut être renvoyé à partir de :

Un type séquence (ligne, liste, ensemble)
CREATE FUNCTION greet (how text)
  RETURNS SETOF greeting
AS $$
  # renvoie la ligne contenant les listes en tant que types composites
  # toutes les autres combinaisons fonctionnent aussi
  return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] )
$$ LANGUAGE plpythonu;
L'itérateur (tout objet fournissant les méthodes __iter__ et next)
CREATE FUNCTION greet (how text)
  RETURNS SETOF greeting
AS $$
  class producer:
    def __init__ (self, how, who):
      self.how = how
      self.who = who
      self.ndx = -1

    def __iter__ (self):
      return self

    def next (self):
      self.ndx += 1
      if self.ndx == len(self.who):
        raise StopIteration
      return ( self.how, self.who[self.ndx] )

  return producer(how, [ "World", "PostgreSQL", "PL/Python" ])
$$ LANGUAGE plpythonu;
Le générateur (yield)
CREATE FUNCTION greet (how text)
  RETURNS SETOF greeting
AS $$
  for who in [ "World", "PostgreSQL", "PL/Python" ]:
    yield ( how, who )
$$ LANGUAGE plpythonu;
[Avertissement]

Avertissement

À cause du bogue #1483133 de Python, certaines versions de débogage de Python 2.4 (configuré et compilé avec l'option --with-pydebug) sont connues pour arrêter brutalement le serveur PostgreSQL™ lors de l'utilisation d'un itérateur pour renvoyer un résultat ensemble. Les versions non corrigées de Fedora 4 contiennent ce bogue. Cela n'arrive pas dans les versions de production de Python et sur les versions corrigées de Fedora 4.