Aller au contenu

Migration vers 9.1 et supérieures

standard_conforming_strings

La valeur par défaut du paramètre standard_conforming_strings est passée à on. Traditionnellement, PostgreSQL ne traitait pas les littéraux de types chaîne (..) comme le spécifie le standard SQL, car les anti-slashs (\) étaient considérés comme des caractères d’échappement, ce qui entraînait que le caractère suivant un \ était interprété. Par exemple, \n est un caractère newline, \\ est le caractère \ lui-même, etc… En 9.1, le paramètre standard_conforming_strings est maintenant par défaut à on, ce qui signifie que les littéraux de type chaîne sont maintenant traités comme spécifiés par le standard SQL. Le caractère apostrophe doit maintenant être protégé avec une deuxième apostrophe plutôt qu’un anti-slash, et les anti-slashs ne sont plus des caractères d’échappement. Par exemple, quand précédemment on écrivait 'l\'heure', on doit maintenant écrire 'l''heure'.

Certaines subtilités sont à connaître, même si elles ne sont pas apparues en 9.1:

  • l’ancienne syntaxe est toujours disponible : mettez simplement un E devant le guillemet de départ: E'l\'heure'
  • standard_conforming_strings peut toujours être remis à off
  • Beaucoup de langages de programmation font déjà ce qu’il faut si vous leur demandez de faire le travail d’échappement pour vous. Par exemple, la fonction PQescapeLiteral de la libpq détecte automatiquement la valeur de standard_conforming_strings et s’y adapte, pour peu qu’elle soit suffisamment récente.

Conversions de type composite

Les conversions de type de données de style fonction ou `attribut’ ne sont plus autorisées pour les types composites.

Depuis la version 8.4, il est possible de convertir à peu près n’importe quoi vers son format texte. Essayons cela avec une table statistical_data contenant deux colonnes numeric : texte. Essayons cela avec une table statistical_data contenant deux colonnes numeric:

SELECT cast(statistical_data as text) from statistical_data ;
  statistical_data 
 ------------------
  (0.1,0.2)
  (0.2,0.4)
  (0.3,0.9)
  (0.4,1.6)
 (4 rows)

Le problème est que les versions 8.4 et 9.0 nous donnent quatre syntaxes différentes pour effectuer cela :

SELECT cast(statistical_data as text) from statistical_data ;
SELECT statistical_data::text from statistical_data;
SELECT statistical_data.text from statistical_data;
SELECT text(statistical_data) from statistical_data;

Les deux dernières syntaxes ne sont plus autorisées pour les types composites (comme un enregistrement de table) : ils étaient bien trop faciles à utiliser accidentellement.

Vérification de contraintes sur des domaines de type tableau

Les vérifications de conversion sur les domaines définis à partir de tableaux ont été renforcées. Maintenant, PostgreSQL vérifie quand vous faites une mise à jour d’un élément d’une contrainte définie sur un tableau. Voici ce qui se passait en 9.0 :

CREATE DOMAIN test_dom as int[] check (value[1] > 0);
SELECT '{-1,0,0,0,0}'::test_dom;
ERROR:  value for domain test_dom violates check constraint "test_dom_check"

Jusque là, tout va bien.

CREATE TABLE test_dom_table (test test_dom);
INSERT INTO test_dom_table values ('{1,0,0,0,0}');
INSERT 0 1
UPDATE test_dom_table SET test[1]=-1;

Par contre, là, c’est anormal… la contrainte check nous interdit de le faire. C’est maintenant impossible en 9.1, la vérification est faite correctement.

Modification de string_to_array()

string_to_array() retourne maintenant un tableau vide pour une chaîne d’entrée de longueur zéro. Précédemment, cela retournait NULL.

SELECT string_to_array(,'whatever');
  string_to_array 
 -----------------
  {}

string_to_array() découpe maintenant une chaîne en ses caractères si le séparateur est NULL. Précédemment, cela retournait NULL :

SELECT string_to_array('foo',NULL);
  string_to_array 
 -----------------
  {f,o,o}

Modification de RAISE dans PL/pgSQL

RAISE dans PL/pgSQL sans paramètre a changé de comportement.

C’est un cas assez rare, mais qui piégeait les utilisateurs habitués au comportement d’Oracle sur ce point.

Voici un exemple :

CREATE OR REPLACE FUNCTION raise_demo () RETURNS void LANGUAGE plpgsql AS $$
 BEGIN
   RAISE NOTICE 'Main body';
   BEGIN
     RAISE NOTICE 'Sub-block';
     RAISE EXCEPTION serialization_failure; -- Simulate a problem
   EXCEPTION WHEN serialization_failure THEN
     BEGIN
       -- Maybe we had a serialization error
       -- Won't happen here of course
       RAISE DEBUG 'There was probably a serialization failure. It could be because of...';
       -- ..
       -- If I get there let's pretend I couldn't find a solution to the error
       RAISE; -- Let's forward the error
     EXCEPTION WHEN OTHERS THEN
         -- This should capture everything
         RAISE EXCEPTION 'Couldn t figure what to do with the error';
     END;
   END;
 END;
 $$
 ;

En 9.0, vous aurez ce résultat (avec client_min_messages à debug) :

SELECT raise_demo();
NOTICE:  Main body
NOTICE:  Sub-block
DEBUG:  There was probably a serialization failure. It could be because of...
ERROR:  serialization_failure

En 9.1 :

SELECT raise_demo();
NOTICE:  Main body
NOTICE:  Sub-block
DEBUG:  There was probably a serialization failure. It could be because of...
ERROR:  Couldn t figure what to do with the error

La différence est que RAISE sans paramètres, en 9.0, ramène le déroulement du code à l’endroit où l’EXCEPTION s’est déclenchée. En 9.1, le RAISE continue dans le bloc dans lequel il se produit, le bloc BEGIN intérieur n’est pas quitté quand le RAISE se déclenche. Son bloc d’exception est exécuté.