Vous n'êtes pas identifié(e).
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
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
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
\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
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
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
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
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
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
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
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
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
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
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
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