PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 18/01/2011 16:49:19

jacques
Membre

caractères d'échappement \n \f \r retour chariot ou à la ligne

Bonjour,

Je cherche à comprendre pourquoi les caractères d'échappement \f et \r ne sont pas interprétés correctement sur ma machine avec base PostgreSQL 8.4.

Tout d'abord, depuis mon PC Linux, je me connecte avec " ssh -X -l mon_user le_serveur " sur le serveur qui héberge la base bdd.

$ locale
LANG=C
LC_CTYPE="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_COLLATE="C"
LC_MONETARY="C"
LC_MESSAGES="C"
LC_PAPER="C"
LC_NAME="C"
LC_ADDRESS="C"
LC_TELEPHONE="C"
LC_MEASUREMENT="C"
LC_IDENTIFICATION="C"
LC_ALL=

$ export LANG=fr_FR.UTF-8

$ psql -d bdd
psql (8.4.5)
Saisissez « help » pour l'aide.

bdd=> show client_encoding;
client_encoding
-----------------
UTF8
(1 ligne)

bdd=> show server_encoding;
server_encoding
-----------------
UTF8
(1 ligne)

bdd=> create table table_test(
bdd(> pk numeric(2),
bdd(> a text,
bdd(> constraint pk_table_test primary key(pk)
bdd(> );
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "pk_table_test" for table "table_test"
CREATE TABLE
bdd=>
bdd=> INSERT INTO table_test VALUES (1,'ceci est un test \f avec antislash f');
WARNING:  nonstandard use of escape in a string literal
LIGNE 1 : INSERT INTO table_test VALUES (1,'ceci est un test \f avec a...
                                           ^
ASTUCE : Use the escape string syntax for escapes, e.g., E'\r\n'.
INSERT 0 1
bdd=> INSERT INTO table_test VALUES (2,E'ceci est un test \f avec antislash f');
INSERT 0 1
bdd=> INSERT INTO table_test VALUES (3,E'ceci est un test \n avec antislash n');
INSERT 0 1
bdd=> INSERT INTO table_test VALUES (4,E'ceci est un test \r avec antislash r');
INSERT 0 1
bdd=> INSERT INTO table_test VALUES (5,E'ceci est un test \f\r avec antislash f et r');
INSERT 0 1
bdd=>
bdd=> select * from table_test;
pk |                       a                       
----+-----------------------------------------------
  1 | ceci est un test \x0C avec antislash f
  2 | ceci est un test \x0C avec antislash f
  3 | ceci est un test
    :  avec antislash n
  4 | ceci est un test \r avec antislash r
  5 | ceci est un test \x0C\r avec antislash f et r
(5 lignes)


Sur cette machine et avec ma configuration, le caractère \n est bien visible mais \r ou \f ne sont pas interprétés comme on peut le souhaiter.

Avez-vous une explication ?
Bien cordialement

Hors ligne

#2 18/01/2011 18:50:30

Marc Cousin
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Je penche plus pour un problème d'affichage qu'un problème de données:

SELECT E'ceci est un test \f\r avec antislash f et r'::bytea;


                      bytea                     
-------------------------------------------------
ceci est un test \014\015 avec antislash f et r

Dernière modification par Marc Cousin (18/01/2011 18:50:46)


Marc.

Hors ligne

#3 19/01/2011 09:18:34

jacques
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

A priori, oui,
Mais quel paramétrage, configuration, environnement adopter pour obtenir un affichage correct pour les différentes séquences d'échappement ?
Alors que \n s'affiche correctement, il est surtout surprenant que \f et \r ne s'affichent pas de la même manière (valeur hexadécimale pour l'un et séquence d'échappement pour l'autre) :

bdd=> SELECT E'ceci est un test \f avec antislash f qui donne la valeur hexadécimale';
                                ?column?                                 
-------------------------------------------------------------------------
ceci est un test \x0C avec antislash f qui donne la valeur hexadécimale
(1 row)

bdd=> SELECT E'ceci est un test \r avec antislash r qui donne la séquence d''échappement';
                                 ?column?                                 
--------------------------------------------------------------------------
ceci est un test \r avec antislash r qui donne la séquence d'échappement
(1 row)

Hors ligne

#4 19/01/2011 10:19:09

Marc Cousin
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

\f c'est form feed. C'est une commande d'imprimante (matricielle à l'époque) il me semble. Comment voudriez vous qu'il vous l'affiche correctement à l'écran ?

\r n'a pas vraiment de sens non plus, sous Unix en tout cas.

En fait, ce que vous demandez, c'est d'afficher des caractères non imprimables. Je pense que vous allez devoir définir 'correct' de votre point de vue, avant que je puisse vous donner une réponse.


Marc.

Hors ligne

#5 19/01/2011 10:47:08

jacques
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Effectivement (sous PostgreSQL comme sous Linux) :
\f Form feed (ASCII 12)
\n Newline (ASCII 10)
\r Carriage return (ASCII 13)
Cela provient vraisemblablement des premières machines à écrire (avec ruban).

Sur mon PC ou sur le serveur Linux qui héberge la base bdd, voilà l'affichage " correct " :
$ echo -e "ceci est un test \f avec antislash f"
ceci est un test
                  avec antislash f
$ echo -e "ceci est un test \n avec antislash n"
ceci est un test
avec antislash n
$ echo -e "ceci est un test \r avec antislash r"
avec antislash r

\f produit, à l'affichage, un saut de ligne sans retour en début de ligne,
\n un saut de ligne avec retour en début de ligne,
\r un retour en début de ligne.

Hors ligne

#6 19/01/2011 11:31:24

Marc Cousin
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Ok, je comprends mieux votre problème.

Le problème est, si vous affichez 'correctement'  \r par exemple, que vous ne verrez pas toute la donnée du champ. Ce qui est le but de psql (et de postgres dans son ensemble).

Vous n'avez pas la possibilité, avec vos echo, de savoir exactement ce qui se trouvait dans le champ original.

PostgreSQL doit vous le permettre… ce qu'on veut, c'est moins un affichage 'correct' au point de vue de l'écran qu'un affichage 'correct' comme 'affichant toutes les données, dans la mesure du possible'. Si vous voulez ensuite un bel affichage effectuant vos \f, \r, à vous de le faire, dans une application cliente. Le but de psql est de vous retransmettre la chaîne telle quelle, d'une façon non ambiguë.


Marc.

Hors ligne

#7 19/01/2011 15:42:56

jacques
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Si l'on demande à la commande echo de ne pas interpréter les séquences d'échappement (valeur par défaut), elle ne les interprète pas :

Par exemple, sur le serveur avec bdd :
$ echo -E "ceci est un test \f avec antislash f"

ceci est un test \f avec antislash f

$ echo -E "ceci est un test \n avec antislash n"

ceci est un test \n avec antislash n

$ echo -E "ceci est un test \r avec antislash r"

ceci est un test \r avec antislash r


De même, pour PostgreSQL, comme vous me l'avez montré, il semble que l'on peut voir le contenu binaire codé en décimal (stockage interne) des séquences d'échappement par :
bdd=> SELECT E'ceci est un test \f\r avec antislash f et r'::bytea;

                      bytea                     

-------------------------------------------------

ceci est un test \014\015 avec antislash f et r

(1 row)



Sur mon PC Linux, j'ai installé un serveur PostgreSQL  8.1 :
-bash-3.2$ psql

Bienvenue dans psql 8.1.22, l'interface interactive de PostgreSQL.



postgres=# SELECT E'ceci est un test \f\r avec antislash f et r'::bytea;

                      bytea                     

-------------------------------------------------

ceci est un test \014\015 avec antislash f et r

(1 ligne)



=> même résultat que sur le serveur.

Par contre, sur mon PC, j'obtiens bien l'interprétation des séquences d'échappement :
postgres=# SELECT E'ceci est un test \f avec antislash f qui donne bien le form feed';

     ?column?     

-------------------

ceci est un test

                   avec antislash f qui donne bien le form feed

(1 ligne)



postgres=#

postgres=# SELECT E'ceci est un test \r avec antislash r qui donne bien le carriage return';

     ?column?     

-------------------

avec antislash r qui donne bien le carriage return

(1 ligne)



Il doit donc probablement s'agir d'une configuration, environnement PostgreSQL ou système à mettre en place.

Hors ligne

#8 20/01/2011 12:41:43

jacques
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Des tests ont montré que la non-interprétation des séquences d'échappement \f et \r provient du client posgreSQL et non du serveur ; par ailleurs, une version psql cliente 8.1 interprète bien les séquences d'échappement alors qu'une version 8.4 ne les interprète pas.

-bash-3.2$ psql -h la_machnie_hote -d bdd -p 5433 -U le_user
Password for user le_user:
Welcome to psql 8.1.22 (server 8.4.5), the PostgreSQL interactive terminal.

Type:  \copyright for distribution terms
       \h for help with SQL commands
       \? for help with psql commands
       \g or terminate with semicolon to execute query
       \q to quit

WARNING:  You are connected to a server with major version 8.4,
but your psql client is major version 8.1.  Some backslash commands,
such as \d, might not work properly.

bdd=> SELECT E'ceci est un test \f avec antislash f';
     ?column?     
-------------------
ceci est un test
                   avec antislash f
(1 row)


Avez-vous des éléments qui expliquent cette analyse (différences entre 8,1 et 8,4...) et comment peut-on configurer le client pour forcer l'interprétation ?

Hors ligne

#9 20/01/2011 13:44:55

gleu
Administrateur

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

La façon dont sont gérés les séquences d'échappement dépend principalement des décisions prises pour un meilleur affichage sur des écrans de taille différente. Il y a eu beaucoup de modifications à ce niveau-là, ainsi que pour les séparateurs suivant la raison du retour à la ligne. Et il n'y a aucun moyen de changer ce comportement.


Guillaume.

Hors ligne

#10 20/01/2011 13:50:39

gilles
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Bonjour,

A partir de la version 8.2 des efforts ont été réalisés dans le code de psql pour limiter l'impact des caractères spéciaux dans l'affichage ceci en vu d'améliorer la lisibilité des données. Il n'existe pas d'option à psql permettant de ne pas interpréter les caractères spéciaux à ma connaissance.

Je ne comprends pas trop ou vous voulez en venir; en 8.1 saviez vous faire la différence entre un \n\t et un \f à l'affichage ? Avec les nouvelles versions vous avez directement l'information. Ou alors peut-être cherchez vous à récupérer la sortie du psql pour son utilisation dans un script dans ce cas effectivement cela peut être gênant.

Hors ligne

#11 20/01/2011 16:15:34

jacques
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Tout d'abord, je vous remercie de vous intéresser, en apportant des réponses, à cette discussion.

L'interprétation des séquences d'échappement a effectivement changé entre la version 8.1 et 8.4 ou plus précisément 8.2 d'après Gilles.
J'ai bien lu les réponses de Guillaume et Gilles, à savoir qu'il s'agit de " décisions prises pour un meilleur affichage sur des écrans de taille différente " et de la volonté d'" améliorer la lisibilité des données " et je comprends bien que cela résulte d'efforts de la part de l'équipe des programmeurs.
Guillaume répond à ma dernière question en indiquant qu' " il n'y a aucun moyen de changer ce comportement ".
Je pense toutefois qu'il serait intéressant d'avoir la possibilité de choisir de récupérer, soit la séquence d'échappement (par exemple \f), soit le code d'échappement.
Peut-être une proposition à faire pour une version ultérieure ?

Pour répondre à Gilles, dans le cas qui m'intéresse, l'interrogation de la bdd a pour but de réaliser un produit (basé sur une application Java) avec une zone texte et une mise en page adéquate s'appuyant sur le contenu d'une colonne de type VARCHAR.
Quant à la différence entre une séquence d'échappement ou une autre à l'affichage, cela n'a pas d'importance pour moi, ce qui m'intéresse, c'est d'avoir l'affichage souhaité par les séquences que j'ai indiquées et de ne pas les " neutraliser ".
Par ailleurs, à l'affichage, il y a une différence entre \n\t et \f ; mais pas entre \f\r et \n.
Mais, si je veux le code pour faire la différence, j'écris, comme indiqué précédemment, par exemple,
en client 8.1 :
postgres=# SELECT E'ceci est un test pour Gilles \f\r avec antislash f et r'::bytea;
                            bytea                           
-------------------------------------------------------------
ceci est un test pour Gilles \014\015 avec antislash f et r
(1 ligne)
car effectivement, l'affichage avec une requête sans ::bytea ne donne pas de différence entre \f\r et \n :
        1 | ceci est un test pour Gilles
avec antislash f et r |      111
(1 ligne)
ou bien :
postgres=# SELECT 1, E'ceci est un test pour Gilles \n avec antislash n', 111;
?column? |           ?column?            | ?column?
----------+-------------------------------+----------
        1 | ceci est un test pour Gilles
avec antislash n |      111




Juste pour information, sous Oracle 9.2 ou 11.2, le résultat se présente de la sorte :
SQL*Plus: Release 11.2.0.2.0
SQL> select 111, 'ceci est un test '||chr(12)||' avec antislash f', 'Troisième colonne' from dual;

       111 'CECIESTUNTEST'||CHR(12)||'AVECANTISLASHF'                                                                'TROISIÈMECOLONNE'
---------- --------------------------------------------------------------------------------------------------------- ---------------------------------------------------
       111 ceci est un test
                             avec antislash f                                                                       Troisième colonne

SQL> select 222, 'ceci est un test '||chr(10)||' avec antislash n', 'Troisième colonne' from dual;

       222 'CECIESTUNTEST'||CHR(10)||'AVECANTISLASHN'                                                                'TROISIÈMECOLONNE'
---------- --------------------------------------------------------------------------------------------------------- ---------------------------------------------------
       222 ceci est un test                                                                                          Troisième colonne
            avec antislash n


SQL> select 333, 'ceci est un test '||chr(13)||' avec antislash r', 'Troisième colonne' from dual;

       333 'CECIESTUNTEST'||CHR(13)||'AVECANTISLASHR'                                                                'TROISIÈMECOLONNE'
---------- --------------------------------------------------------------------------------------------------------- ---------------------------------------------------
avec antislash r                                                                       Troisième colonne


Assez logiquement, sous client psql 8.4.5 :
$ psql -h la_machine_hote -d bdd -p 5433 -U le_user -o toooo -c " SELECT E'ceci est un test \f avec antislash f'"
$ more toooo
                ?column?               
----------------------------------------
ceci est un test \x0C avec antislash f
(1 row)

$ psql -h la_machine_hote -d bdd -p 5433 -U le_user -o toooo -c " SELECT E'ceci est un test \n avec antislash n'"
$ more toooo
     ?column?     
-------------------
ceci est un test
  avec antislash n
(1 row)


Sous client postgreSQL psql 8.4.5, on peut toutefois écrire :
bdd=> COPY (SELECT 111, 'ceci est un test '||chr(12)||' avec antislash f', 'Troisième colonne') to stdout with csv;
111,ceci est un test
                      avec antislash f,Troisième colonne
bdd=> COPY (SELECT 222, 'ceci est un test '||chr(10)||' avec antislash n', 'Troisième colonne') to stdout with csv;
222,"ceci est un test
avec antislash n",Troisième colonne
bdd=> COPY (SELECT 333, 'ceci est un test '||chr(13)||' avec antislash r', 'Troisième colonne') to stdout with csv;
avec antislash r",Troisième colonne

L'interprétation des séquences d'échappement se fait grâce au COPY (non standard SQL) et non au SELECT.

Encore une fois, je vous (les remerciements s'adressent aussi à un collègue) remercie sincèrement et, bien sûr, si vous avez des éléments nouveaux, je suis preneur.

Hors ligne

#12 20/01/2011 17:28:44

gleu
Administrateur

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Peut-être une proposition à faire pour une version ultérieure ?

Le meilleur moyen pour cela est que vous proposiez un patch aux développeurs.

Pour répondre à Gilles, dans le cas qui m'intéresse, l'interrogation de la bdd a pour but de réaliser un produit (basé sur une application Java) avec une zone texte et une mise en page adéquate s'appuyant sur le contenu d'une colonne de type VARCHAR.

Dans ce cas, vous ne passez pas par psql, ce qui fait que l'affichage de psql n'a aucune importance. L'affichage des données sera du fait de votre programme.


Guillaume.

Hors ligne

#13 20/01/2011 20:53:29

jacques
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Effectivement, l'accès par driver JDBC (postgresql-9.0-801.jdbc4.jar) ne s'appuie pas sur psql et n'applique pas les mêmes règles d'interprétation des séquences d'échappement.

J'ai fait un test sur une base postgreSQL 8.3.13,
en interrogeant une table toto :
Bienvenue dans psql 8.3.13, l'interface interactive de PostgreSQL.
toto=# select * from toto;
pk |                       a                       
----+-----------------------------------------------
  1 | ceci est un test \x0C avec antislash f
  2 | ceci est un test
    :  avec antislash n
  3 | ceci est un test \r avec antislash r
  4 | ceci est un test \r\x0C avec antislash r et f
(4 lignes)


L'accès à l'aide du driver postgresql-9.0-801.jdbc4.jar donne en affichant (en java : System.out.println(rs.getInt("pk")+" "+rs.getString("a"));) la valeur de la première colonne suivie d'un espace puis la valeur de la 2ème colonne :
Début du test :
1  ceci est un test
                     avec antislash f
2  ceci est un test
avec antislash n
avec antislash rst
4  ceci est un test
avec antislash r et f

Merci encore

Dernière modification par jacques (21/01/2011 10:37:53)

Hors ligne

#14 20/01/2011 21:22:15

Marc Cousin
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Oui. psql est avant tout un outil d'administration. Son but n'est pas d'interpréter ce qui se trouve dans les champs. C'est de vous les afficher d'une façon qui vous permette de comprendre ce qu'ils contiennent.


Marc.

Hors ligne

#15 21/01/2011 10:35:02

jacques
Membre

Re : caractères d'échappement \n \f \r retour chariot ou à la ligne

Je note bien que le client PostgreSQL, " psql est avant tout un outil d'administration. Son but n'est pas d'interpréter ce qui se trouve dans les champs."

Ceci dit, psql est aussi (je pense, communément) utilisé dans des shell car il s'agit d'un outil simple, léger, robuste et facile à mettre en place.
cf. précédemment :
$ psql -h la_machine_hote -d bdd -p 5433 -U le_user -o toooo -c " SELECT E'ceci est un test \n avec antislash n'"
...

En utilisant psql, je me suis alors interrogé sur le fait que la séquence d'échappement \n ou encore \t était interprétée mais pas \f par exemple.
Mais, je comprends, comme le précise Guillaume, que " La façon dont sont gérés les séquences d'échappement dépend principalement des décisions prises ".

Hors ligne

Pied de page des forums