lundi 3 juin 2013

Le piège du null

Plantons le décor:
Une table "dépenses" créée avec l'instruction:
CREATE TABLE dépenses
(référence CHAR(9) PRIMARY KEY,
 date_exec DATE,
 montant NUMERIC(13,2),
 détails VARCHAR(50),
 code_u CHAR(2))
;
et dans laquelle quelques données ont été placées.

un code_u dont la signification est:

 code_u | signification     
--------+----------------
 01     | Médecin
 02     | Grande surface
 03     | Carburant
 04     | Restaurant

Voilà, le décor est planté.

Examinons le contenu de la table "dépenses", par exemple depuis un terminal psql si nous travaillons avec PostgreSQL:


Nous désirons mettre à jour code_u avec cette instruction:
UPDATE dépenses
SET code_u = '02'
WHERE (détails = 'Courrefar'
OR détails = 'Caro'
OR détails = 'Aupré'
)
AND code_u <> '02'
;
La ligne AND est là pour éviter les mises à jour inutiles (mise à jour des rangées avec code_u valant déjà '02').
En principe 3 rangées devraient être impactées: celles dont la référence se termine par 17, 21 et 22.
Vérifions s'il en sera bien ainsi:


Il manque la rangée 2013-0022. Pourtant rien ne semble la distinguer (par rapport aux critères de sélection) de la rangée 2013-0021.
Poussons plus loin  les investigations.
L'utilisation de la méta-commande \pset null nous permet de choisir ce qui sera imprimé dans le cas de la valeur NULL. Par défaut rien n'est imprimé


Nous voyons maintenant apparaître une différence essentielle entre les rangées 2013-0021 et 2013-0022. Pour la rangée 2013-0021, code_u est caractérisé par une chaîne de caractère vide, ce qui permet de dire que code_u n'est pas égal à 01, ni à 02, 03, 04.(ou sinon la chaîne ne serait pas vide).
Par contre dans le cas de la rangée 2013-0022, l'indication NULL signifie que la base de données ne contient aucune information concernant code_u. Pour cette rangée, code_u est inconnu: il peut très bien valoir '02', où pas. Il est donc impossible de mettre cette rangée dans l'ensemble de celles dont le code_u vaut '02' ou dans l'ensemble de celles dont le code_u est différent de '02'. L'union des 2 ensembles nous fournit 7 rangées (au lieu de 9):


Si le critère de sélection est code_u = '02', les rangées avec code_u NULL se sont pas reprises. Mais elles ne le sont pas non plus si le critère de sélection est code_u différent de '02'.
Et voilà le piège, le piège du NULL dans lequel il ne faut pas tomber! Y tomber, c'est être nul!
L'instruction à utiliser pour la mise à jour devrait être:
UPDATE dépenses
SET code_u = '02'
WHERE (détails = 'Courrefar'
OR détails = 'Caro'
OR détails = 'Aupré'
)
AND (code_u <> '02'
OR code_u IS NULL
)
;

Dans le cas d'une base de données avancée comme PostgreSQL, qui gère l'intégrité référentielle, nous aurions pu après avoir créé une table destinée à contenir les significations de code_u:
CREATE TABLE utilisations
(code_u CHAR(2) PRIMARY KEY,
 signification VARCHAR(20))
;
créer la table "dépenses" comme suit:
CREATE TABLE dépenses
(référence CHAR(9) PRIMARY KEY,
 date_exec DATE,
 montant NUMERIC(13,2),
 détails VARCHAR(50),
 code_u CHAR(2) REFERENCES utilisations)
;
Dans ce cas les seules valeurs autorisées pour code_u auraient été celles qui figurent dans la table "utilisations". Une rangée comme la 2013-0021 n'aurait pas pu exister, mais bien des rangées avec code_u à la valeur NULL.
La notion d'intégrité référentielle a été étudiée dans ce billet.

samedi 18 mai 2013

Passer à l'anglais

Lançant skype depuis un émulateur de terminal, nous obtenons l'avertissement suivant:
(skype:2618): Gtk-WARNING **: Impossible de trouver le moteur de thème dans module_path : « adwaita »
Bien sûr, il s'agit simplement d'un avertissement, mais nous aimerions qu'il n'apparaisse pas.
Une recherche dans google basée sur ce message donne des résultats qui ne permettent pas de trouver une solution au problème.
Peut-être avec comme critère de recherche le même message, mais en anglais, obtiendra-t-on plus de résultats pertinents?
Comment obtenir la version anglaise de ce message?
Voici une solution: dans notre terminal, avant le lancement de skype, exécutons la commande
export LC_ALL=C
Maintenant, nous recevons en retour les messages en anglais:
(skype:2720): Gtk-WARNING **: Unable to locate theme engine in module_path: "adwaita",
Illustration:


Cette manipulation n'est pas seulement utile dans le cas de figure évoqué ci-dessus (recherche basée sur des messages).
Elle permet par exemple d'avoir des pages "man" en anglais: en effet dans le cas où la traduction en français n'est pas très claire, il peut être utile de se rapporter à la langue originale.
Nous pouvons également depuis le terminal lancer la version anglaise des applications.
Par exemple pour libreoffice, on procédera en exécutant la commande soffice.
Afin de revenir à la localisation initiale, il suffit de faire:
unset LC_ALL
Une autre solution pour obtenir les messages de skype en anglais aurait été de taper:
LC_ALL=C skype
ce qui a pour avantage de ne rien changer au niveau du terminal (en fait du shell bash). Il n'est donc plus nécessaire d'utiliser unset.
Enfin, signalons à ceux qui ont atterri ici à partir d'une recherche sur le message d'erreur, la solution au problème était pour notre système fedora 18 64 bits, d'installer adwaita-gtk2-theme.i686.

jeudi 9 mai 2013

Formater une requête avec sed

Dans libreoffice base, nous créons une requête en mode SQL en veillant à la bonne lisibilité du code grâce à un formatage judicieux, comme illustré ci-dessous:


Cependant lorsque plus tard nous sommes amené à éditer cette requête, nous constatons (avec horreur) que notre magnifique formatage a disparu:

Qu'à cela ne tienne, introduisons dans un (émulateur de) terminal (virtuel) la commande

sed -r 's/\,|AND|WHERE|FROM|CASE|WHEN|END/\n&/g'

suivie d'un appui sur la touche ENTER:


Aucun nom de fichier ne lui ayant été fourni, sed est en attente des données qu'il doit traiter et qui vont lui être communiquées via l'entrée standard (stdin).
Dans libreoffice, nous sélectionnons puis coupons l'instruction SQL avant de la coller dans le terminal:


Un appui sur ENTER envoie les données vers sed et nous terminons avec CTRL-D:


Il reste à effectuer un copier-coller de la requête formatée vers la fenêtre d'édition de libreoffice:


Et voilà: nous pouvons maintenant travailler de manière plus agréable.
Si nous sommes intéressé par le procédé, il peut être utile de définir un alias:

alias fq="sed -r 's/AND|WHERE|FROM|CASE|END/\n&/g;s/WHEN/\n  &/g'"

dont la définition sera permanente si elle est ajoutée au fichier ~/.bashrc

(fq est mis pour format query)

Cette fois nous ne considérons pas les virgules car si les traiter était, dans notre exemple,  justifié (pour une meilleure lisibilité), ce ne serait plus le cas en de présence de fonctions dont les arguments sont séparés par des virgules

mardi 16 avril 2013

Bilans mensuels

Dans notre base de données de test (bdtest), nous créons la table opérations en exécutant l'instruction SQL:

CREATE TABLE opérations
(reference CHAR(9) PRIMARY KEY,
date_exec          DATE,
montant            NUMERIC(13,2),
contrepartie       CHAR(5))
;

S'agissant d'une base de données PostgreSQL, il nous suffit par exemple de coller cette instruction dans un terminal psql connecté à bdtest. Si l'instruction est contenue dans un fichier, nous pouvons également procéder avec la méta-commande \i:

bdtest=> \i fichier

Il nous reste à peupler cette table. Nous avons à cette fin constitué un fichier nommé opérations contenant quelques données:

2012-0458 2012-12-30 487.33  RN2
2013-0001 2013-01-03 1874.56 RN1
2013-0002 2013-01-03 -42.57  ceci
2013-0003 2013-01-14 -119.23 cela
2013-0006 2013-01-31 -956.00 Loyer
2013-0007 2013-01-31 1874.56 RN1
2013-0008 2013-02-01 -127.23 GS
2013-0009 2013-02-09 -47.00  Autre
2013-0010 2013-02-11 -845.99 TV
2013-0011 2013-02-14 -25.47  Div
2013-0012 2013-02-15 -49.00  Ceci
2013-0013 2013-02-20 -314.00 VOIT
2013-0014 2013-02-27 -103.49 Tél
2013-0015 2013-02-28 -956.00 Loyer
2013-0016 2013-02-28 1874.56 RN2
2013-0017 2013-03-01 -117.23 GS
2013-0018 2013-03-06 -43.00  Autre
2013-0019 2013-03-06 -76.84  Div
2013-0004 2013-01-14 -314.00 VOIT
2013-0005 2013-01-31 -114.23 Tél

Le caractère de séparation entre les colonnes est le caractère de tabulation et nous utilisons la méta-commande \copy:

bdtest=> \copy opérations from opérations

Si au lieu de travailler dans une base de données PostgreSQL nous préférons utiliser la base de données intégrées à Libreoffice base, nous pouvons tant pour la création de la table que pour son remplissage procéder comme montré dans ce message.

Nous allons créer une vue qui placera les montants positifs (crédits) dans une colonne et les montants négatifs (débits) dans une autre colonne.
Nous aurons aussi besoin de l'année et du mois de chaque opération. Ceux-ci peuvent être extraits de la date d'exécution comme ceci:
extract(year from date_exec) pour l'année
extract(mont from date_exec) pour le mois.

Mais comme montré ici:


le résultat n'est peut-être pas très heureux en ce qui concerne les numéros de mois: 01 au lieu de 1 serait plus esthétique.
Aussi, il est préférable d'utiliser la fonction to_char:
to_char(date_exec, 'YYYY') pour l'année
to_char(date_exec, 'MM') pour le numéro du mois
et nous pouvons même obtenir le nom du mois avec
to_char(date_exec, 'TMMONTH'):


Cela étant, créons la vue opérationsv à l'aide de l'instruction SQL suivante, en procédant comme pour la création de la table.

CREATE VIEW opérationsv
AS
SELECT
     to_char(date_exec, 'YYYY') AS an,
     to_char(date_exec, 'MM') AS mois_n,
     to_char(date_exec, 'TMMONTH') AS mois,
     reference,
     date_exec,
     CASE
       WHEN montant > 0 THEN montant
       ELSE 0.00
     END AS crédit,
     CASE
       WHEN montant < 0 THEN -montant
       ELSE 0.00
     END AS débit,
     montant AS solde,
     contrepartie
FROM opérations

Si nous travaillons dans la base de données intégrée à libreoffice, l'expression to_char(date_exec, 'TMMONTH') n'est pas reconnue. Il convient alors de la remplacer par:

CASE
  WHEN extract(month from date_exec) = 1 THEN 'Janvier'
  WHEN extract(month from date_exec) = 2 THEN 'Février'
  WHEN extract(month from date_exec) = 3 THEN 'Mars'
  WHEN extract(month from date_exec) = 4 THEN 'Avril'
  .....
END AS mois,

Et nous voilà paré pour sortir des bilans, par exemple avec une simple instruction SQL comme celle-ci:

select an, mois, count(*) as opérations,
sum(crédit) as crédit,
sum(débit) as débit,
sum(solde) as solde
from opérationsv
group by an, mois_n, mois
order by an, mois_n
;

Voici le résultat dans un terminal psql:


Il est possible d'améliorer l'output obtenu.
Plaçons dans un fichier bilan-mensuel.sql les commandes

\set QUIET
\pset numericlocale on
\pset footer off
\pset linestyle u
\pset title 'Bilan 2013'
\pset border 2
\o | awk -f bilan-mensuel.awk | tee rapport.txt
select mois_n, mois, count(*) as opérations,
sum(crédit) as crédit,
sum(débit) as débit,
sum(solde) as solde
from opérationsv
where an = '2013'
group by mois_n, mois
UNION
select 'TOTAL', '', count(*) as opérations,
sum(crédit) as crédit,
sum(débit) as débit,
sum(solde) as solde
from opérationsv
where an = '2013'
order by mois_n
;
\o
\pset footer
\pset title
\pset border 1
\unset QUIET


Et voici le résultat:


L'output a été redirigé vers la commande awk pour exécution du script bilan-mensuel.awk

# Impression du titre
NR == 1 {
print "\n" $0 "\n"
}
# Sauvegarde ligne de séparation dans y
NR == 4 {
y=$0
}
# Imression d'une ligne de séparation si
# la ligne en input contient TOTAL en position 3
/^..TOTAL/ {
print y
}
# Impression des lignes en input
# sauf le titre déjà imprimé
NR > 1

dont le rôle essentiel est d'imprimer une ligne de séparation avant la ligne 'TOTAL' et accessoirement d'imprimer une ligne vide avant et après le titre.
De plus, grâce à la commande 'tee', le fichier rapport.txt contient une copie de ce qui a été envoyé à l'écran. Ce fichier rapport.txt peut tout à fait être intégré dans un traitement de texte.
Nous avons déjà traité de la technique utilisée ici pour améliorer la présentation au niveau d'un terminal psql dans ce billet et le suivant.
Pour confectionner un rapport mieux présenté et où figurent en plus les lignes de détails, il convient de travailler dans libreoffice base avec ORB 'Oracle report builder'. Pour disposer de cette extension il suffit le plus souvent d'installer un paquet dont le nom est (ou ressemble à) 'libreoffice-report-builder'.
Si nos données figurent dans bdtest, il est évidemment nécessaire de connecter libreoffice à cette base de données, opération pour laquelle il est grandement conseillé d'installer le paquet 'libreoffice-sdbc-postgresql' (ou un paquet dont le nom ressemble à celui-là).
Dans le rapport que nous envisageons de confectionner, il est relativement inutile de placer dans les lignes 'détails' le contenu du champ 'solde' tel qu'il est défini dans la vue opérationsv, puisque que celui-ci est toujours égal à un des deux montants crédit ou débit. Par contre y mettre le solde résultant de toutes les opérations réalisées depuis le début du mois est nettement plus intéressant.
A cette fin, nous allons dans libreoffice base créer en mode SQL la requête opérationsr:

SELECT "A".*,
( SELECT SUM( "solde" )
  FROM "opérationsv" "B"
  WHERE "B"."reference" <= "A"."reference"
  AND "B"."an" = "A"."an"
  AND "B"."mois_n" = "A"."mois_n" 
) AS "solde_c"
FROM "opérationsv" "A"

Après avoir choisi 'Créer un rapport en mode ébauche', nous sélectionnons cette requête en tant que de source de données que nous filtrons sur une année:



Pour le reste,  nous allons procéder comme expliqué dans ce billet, le rapport réalisé alors nous servant de modèle.
Nous n'allons pas ici entrer dans les détails, mais fixer simplement quelques points de repères.

Dans la  fenêtre 'Tri et groupements' nous plaçons mois-n et reference:

Les données sont groupées suivant mois_n, mais cela ne nous empêche pas de faire figurer le nom du mois en clair dans l'en-tête de groupe:


Les valeurs dans la colonne 'solde' sont tirées de solde_c sauf pour la fonction 'Accumulation' qui porte sur  'solde'.

Et voici le résultat obtenu:


(EDIT: voir variante ici)

Dans le cas d'un rapport plus conséquent, il peut être utile de forcer une nouvelle page pour chaque changement de mois:



Nous pouvons également envisager d'introduire un groupement supplémentaire sur la date:


Établir un rapport tel que celui-ci


tenant compte de ce nouveau groupe ne pose aucun problème particulier.

La requête 'source de données' conduisant à ce résultat est cette fois:


SELECT "A".*,
( SELECT SUM( "solde" )
FROM "opérationsv" "B"
WHERE "B"."reference" <= "A"."reference"
AND   "B"."date_exec" = "A"."date_exec" ) AS "solde_c"
FROM "opérationsv" "A"



Comme auparavant les valeurs de la colonne 'solde' sont tirées de 'solde_c' sauf pour les fonctions 'Accumulation' (Total mois et Total) où intervient 'solde':


x

mercredi 2 janvier 2013

Import dans libreoffice base

Dans ce billet nous allons montrer comment facilement importer les données d'un fichier de type CSV dans une base données HSQL (base de donnée intégrée à libreoffice).
A l'ouverture de libreoffice base, nous choisissons de nous connecter à une base de données existante de type texte.
Tiens, on ne vient pas, là tout de suite, de parler de base de données HSQL?
Oui, mais cela ce sera pour plus tard.
Donc nous choisissons de nous connecter à une base de données existante de type texte:


Nous avons préalablement créé un dossier ~/Documents/bdcsv destiné à contenir les tables de notre base de données (qui sont en réalité des fichiers de type CSV) et nous en indiquons le chemin au moment de paramétrer la connexion vers les fichiers textes. Nous ne manquons pas de paramétrer le point-virgule comme étant le séparateur de champ (s'il en est ainsi pour nos fichiers CSV) et de choisir pour séparateur de décimales celui qui convient:


Nous terminons en enregistrant la base de données sous le nom bdcsv. 
A l'ouverture du fichier bdcsv.odb, nous constatons que la base de données ne contient aucune table.
Normal puisque ~/Documents/bdcsv est vide.
Nous y plaçons le fichier opérations.csv contenant les donnée à importer:

id_op;date_op;montant;contrepartie
2011-0458;2011-12-30;487.33;RN2
2012-0001;2012-01-03;1874.56;RN1
2012-0002;2012-01-03;-42.57;ceci
2012-0003;2012-01-14;-119.23;cela
2012-0004;2012-01-14;-314.00;VOIT
2012-0005;2012-01-31;-114.23;Tél
2012-0006;2012-01-31;-956.00;Loyer
2012-0007;2012-01-31;1874.56;RN1
2012-0008;2012-02-01;-127.23;GS
2012-0009;2012-02-09;-47.00;Autre
2012-0010;2012-02-11;-845.99;TV
2012-0011;2012-02-14;-25.47;Div
2012-0012;2012-02-15;-49.00;Ceci
2012-0013;2012-02-20;-314.00;VOIT
2012-0014;2012-02-27;-103.49;Tél
2012-0015;2012-02-29;-956.00;Loyer
2012-0016;2012-02-29;1874.56;RN2
2012-0017;2012-03-01;-117.23;GS
2012-0018;2012-03-06;-43.00;Autre
2012-0019;2012-03-06;-76.84;Div

Pour voir apparaître l'icône de la table, nous passons par le menu Affichage → Actualiser les tables :


Cliquant droit sur l'icône de la table qui est apparue


nous sélectionnons 'Éditer' dans le menu contextuel qui surgit  afin de vérifier quel type a été attribué aux différents champs de la table:


Nous vérifions que pour le champ 'montant' les décimales ont bien été prises en compte.
Nous constatons que date_op est bien au format 'Date'. Ce ne serait pas le cas si une seule rangée de la table contenait une date invalide : date_op serait alors au format 'Texte' ce qui ne manquerait pas de poser problème pour la suite.
La suite ? Quelle suite ?
Et bien, rappelons le,  le but est d'importer les données du fichier opérations.csv dans une base de données intégrée à libreoffice (HSQL).
bdcsv.odb est en fait une base de de données de transit, un réservoir de données à importer dans la véritable base de données finale. Chaque fois que nous disposerons de données au format CSV à importer, il nous suffira avant de procéder de placer le fichier de données dans ~/Documents/bdcsv.
Attention: si le fichier en question utilise le séparateur de texte, toutes les données concernées seront de type texte. Si ce n'est pas souhaité, il convient alors de supprimer le dit séparateur par exemple en utilisant sed:
sed -r -i.old 's/\"//g' fichier.csv
Lançons maintenant une deuxième instance de libreoffice en choisissant au niveau du menu d’accueil l'option 'Créer une base de données' et nous terminons en enregistrant cette base de données sous le nom 'opérations'. Et voici notre base de données finale sur les rails!
Ensuite, plutôt que d'utiliser le mode 'Ébauche' pour créer la table où placer les données à importer, nous procédons via le menu Outils → SQL:


Dans la fenêtre 'Instruction SQL', nous collons l'instruction:

CREATE TABLE opérations
(reference CHAR(9) PRIMARY KEY,
date_exec DATE,
montant NUMERIC(13,2),
contrepartie CHAR(5))
;

et nous appuyons sur le bouton exécuter:



La table nouvellement créée sera visible après utilisation du menu Affichage -> Actualiser les tables. Nous constatons que la table a été créée sous le nom 'OPÉRATIONS':


Effectuons un 'glisser-déposer' de l'icône bdcsv.odb->opérations dans la zone des Tables de opérations.odb. Dans la fenêtre qui surgit nous remplaçons le nom de la table source (opérations) par celui de la table cible (OPÉRATIONS) et nous cochons 'Ajouter des données' :


L'appui sur le bouton 'Suivant' nous permet de vérifier la correspondance des colonnes.


L'appui sur 'Créer' finalise l'opération d'importation.

Il est plus facile (comme nous l'avons fait) mais pas nécessaire de créer au préalable la table destinée à recevoir les données que nous souhaitons importer.
Si cette table n'existe pas, dans la fenêtre 'Copier la table', nous cochons 'Définition et données' ainsi que 'Créer une clé primaire' à laquelle nous donnons le nom id_op. Mais ceci nous conduit à une impasse:


Aussi nous recommençons après avoir remis le nom par défaut et après avoir décoché 'Créer une clé primaire':


Le bouton 'Suivant' nous donne le choix des colonnes à importer :


Nous pouvons ensuite modifier à notre guise le type des différents champs, par exemple pour id_op passer du type TEXTE[VARCHAR] au type TEXTE (FIXE)[CHAR].
Il ne faut pas oublier de mettre le nombre de décimales à 2 pour le champ 'montant' :


Après avoir appuyé sur 'Créer', nous répondons 'Oui' à la question 'Créer une clef primaire' car sans cela il nous sera impossible par la suite de définir id_op comme clé primaire:


Évidemment ceci ajoute une colonne supplémentaire (ID par défaut) à la table, colonne que nous supprimons illico.
Pour ce faire nous cliquons droit sur l'icône de la table qui vient d'être créée et nous sélectionnons 'Editer' dans le menu contextuel qui surgit. Ensuite dans la fenêtre 'Table design' nous cliquons droit en tête de la ligne définissant ID et nous choisissons 'Supprimer' :


Puis comme il nous faut une clef primaire pour pouvoir éditer les données, nous cliquons droit en tête de la ligne définissant id_op et nous choisissons 'Clef primaire' :


Et voilà!

jeudi 29 novembre 2012

Choix socket PostgreSQL

Lorsque le client Postgresql se trouve sur la même machine que le serveur, les communications entre le client et le serveur s'effectuent soit via la boucle locale, soit le plus souvent à travers un fichier de type spécial appelé socket.
L'emplacement du socket peut se choisir au niveau du fichier postgresql.conf. Supposons que ce fichier contienne la sentence
unix_socket_directory='/run/postgresql'
Vérifions quel est alors le contenu du dossier /run/postgresql:
Nous constatons que le dossier /run/postgresql possède les droits rwxrwsr-x (2775 en octal).
Il s'y trouve un fichier caché de type socket: celui avec la lettre s figurant en tête de la ligne le concernant.
Le choix de l'emplacement du socket tel que formulé dans le fichier postgresql.conf est inopérant pour une connexion vers le serveur postgresql depuis libreoffice base à l'aide du pilote natif sdbc.
Ainsi il se peut que la tentative de connexion échoue avec un message du genre:
could not connect to server: Aucun fichier ou dossier de ce type 
Is the server running locally and accepting 
connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
Ici le fichier socket est recherché dans /tmp alors qu'il se trouve dans /run/postgresql.
Une solution consite à modifier postgresql.conf de manière à ce que le socket soit effectivement dans /tmp.
Cependant il ne s'agit pas vraiment d'une bonne idée: en effet /tmp jouit de droits particuliers de type rwxrwxrwt (1777 en octal):


La lettre t qui figure en dernière position dans la chaîne des droits indique que le sticky bit est sur on, ce qui signifie que si chacun peut écrire dans le dossier, il ne peut modifier que les fichiers qui lui appartiennent.
Or il arrive que si postgresql.conf demande que le socket se trouve dans /tmp, alors les droits de /tmp soient modifiés de manière inopportune.
Une meilleure solution consiste à utiliser la variable d'environnement PGHOST.
Celle-ci peut avoir deux significations.
La plus évidente est que PGHOST contienne le nom du host, comme ici:


Du fait que le nom du host est précisé, psql se connecte non pas à l'aide du fichier socket, mais via la boucle locale:


Mais si la valeur de PGHOST commence par une barre oblique (/), elle indique alors l'emplacement du socket:


Voilà la solution: il suffit de s'arranger pour que PGHOST existe et contienne la bonne valeur, par exemple en plaçant dans /etc/profile.d un fichier postgresql.sh contenant:
export PGHOST=/run/postgresql

dimanche 4 novembre 2012

Ubuntu 12.10 et libreoffice base

La version 12.10 d'Ubuntu souffre du même mal que la version précédente: impossible dans libreoffice base d'exécuter un rapport réalisé avec ORB (Oracle Report Builder).
Rien de changé. On tombe sur le même message d'erreur que précédemment:


Mais cette fois la solution présentée dans ce billet conduit tout droit au crash.
Nous allons passer au plan B: ne plus utiliser la version packagée par Ubuntu et la remplacer par celle téléchargeable sur le site de libreoffice
EDIT : voir une autre solution en fin de billet
Donc nous téléchargeons les fichiers:
LibO_3.6.3_Linux_x86-64_install-deb_en-US.tar.gz
LibO_3.6.3_Linux_x86-64_langpack-deb_fr.tar.gz
LibO_3.6.3_Linux_x86-64_helppack-deb_fr.tar.gz
correspondant à notre architecture.
Et puis nous procédons depuis le dossier de téléchargement:
toto@rigel:~/Downloadssudo apt-get remove libreoffice* 
toto@rigel:~/Downloadstar xzvf LibO_3.6.3_Linux_x86-64_install-deb_en-US.tar.gz 
toto@rigel:~/Downloads$ tar xzvf LibO_3.6.3_Linux_x86-64_langpack-deb_fr.tar.gz 
toto@rigel:~/Downloads$ tar xzvf LibO_3.6.3_Linux_x86-64_helppack-deb_fr.tar.gz 
toto@rigel:~/Downloads$ cd LibO_3.6.3.2_Linux_x86-64_install-deb_en-US/DEBS/ 
toto@rigel:~/Downloads$ sudo dpkg -i *.deb 
toto@rigel:~/Downloads$ cd desktop-integration/ 
toto@rigel:~/Downloads$ sudo dpkg -i *.deb 
toto@rigel:~/Downloads$ cd ../../../LibO_3.6.3.2_Linux_x86-64_langpack-deb_fr/DEBS/ 
toto@rigel:~/Downloads$ sudo dpkg -i *.deb 
toto@rigel:~/Downloads$ cd ../../LibO_3.6.3.2_Linux_x86-64_helppack-deb_fr/DEBS 
toto@rigel:~/Downloads$ sudo dpkg -i *.deb
Et voilà!
L'extension ORB est déjà installée avec le paquet
libobasis3.6-extension-report-builder_3.6.3.2-2_amd64.deb
de même que le pilote sdbc pour une connexion à postgresql
libobasis3.6-postgresql-sdbc_3.6.3.2-2_amd64.deb
On ne doit plus s'occuper de rien de ce côté là: cool!
Il ne reste plus qu'à tenter l'exécution du fameux rapport.
Si nous travaillons avec la base de données intégrée à libreoffice, tout est OK.
Essayons maintenant avec une base de données postgresql.
Tout d'abord se connecter.
Aie:

Ça commence bien!
La réponse à la question posée
Is the server running locally and accepting
connections on Unix domain socket "/tmp/.s.PGSQL.5432"?
est nécessairement positive puisque avec la version Ubuntu de libreoffice la connexion s'effectuait sans problèmes.
Du moins c'est ce que nous pensions mais avec la version Ubuntu de libreoffice le message en cas de problème aurait été:
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
Et donc en fait la réponse est négative.
Pour que le socket qui convient soit utilisé, il suffit de remplacer dans le fichier /etc/postgresql/9.1/main/postgresql.conf
unix_socket_directory = '/var/run/postgresql'  
par
unix_socket_directory = '/tmp'  
et puis de redémarrer le serveur.
De la sorte tout est OK et le rapport s'exécute sans problèmes.
(EDIT: voir une meilleure solution ici.)
Il se peut que l'on ne souhaite pas changer l'emplacement du socket. Dans ce cas,  une façon de contourner le problème consiste à modifier les paramètres de connexion en ajoutant host=rigel à l'URL de la base de données (alors que ce n'est pas nécessaire puisque nous sommes sur la machine où tourne le serveur) de manière à forcer le passage par la boucle locale:


Cette fois nous recevons le message:


C'est normal car nous ne passons plus par le Unix domain socket et d'après le contenu du fichier /etc/postgresql/9.1/main/pg_hba.conf un mot de passe est nécessaire pour une connexion via la boucle locale:

# "local" is for Unix domain socket connections only
local   all             titine                                  peer map=map01
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
Pour avoir l'opportunité de fournir un mot de passe, il suffit de cocher "Mot de passe requis".
Attention, il s'agit d'un mot de passe postgresql et non pas d'un mot de passe système.
Bien évidement, de nouveau tout fonctionne nickel et nous avons le plaisir de voir s'afficher à l'écran un magnifique rapport.

EDIT:
Une autre possibilité consiste à installer le dépôt 'libreoffice' qui permet actuellement d'avoir directement une solution fonctionnelle sans qu'il soit nécessaire de télécharger les paquets depuis le site de libreoffice.
Les commandes à exécuter sont:

toto@rigel:~$ sudo add-apt-repository ppa:libreoffice/ppa
toto@rigel:~$ sudo apt-get update
toto@rigel:~$ sudo apt-get dist-upgrade

Les fichiers dont l'absence rendait impossible la lecture des rapports, à savoir les fichiers

.../program/librptlo.so
.../program/librptuilo.so
.../program/librptxmllo.so

sont fournis avec le paquet libreoffice-report-builder-bin qui devra donc être installé avec le paquet libreoffice-report-builder.