Vous n'êtes pas identifié(e).
- Contributions : Récentes | Sans réponse
#301 Re : Général » Import CSV: droits, clé primaire, choix champs - sql ou psql et batch? » 07/04/2017 14:35:26
Pour les droits d'accès, il faut être superutilisateur pour utiliser COPY avec les fichiers sur le serveur, et il faut que les fichiers soient à un endroit du disque que postgresql a le droit de lire.
Le "État SQL :42501" n'est pas suffisamment parlant mais normalement il devrait être accompagné d'un vrai message d'erreur.
Par example si je fais un COPY avec pgadmin3 sans être superutilisateur, voici ce qu'il m'affiche dans le panneau "Messages":
ERROR: must be superuser to COPY to or from a file
HINT: Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone.
********** Erreur **********
ERROR: must be superuser to COPY to or from a file
État SQL :42501
Astuce : Anyone can COPY to stdout or from stdin. psql's \copy command also works for anyone.Je ne sais pas trop comment on peut arriver à la situation où on a uniquement "État SQL :42501". Peut-être avoir client_min_messages sous le niveau ERROR mais il faut vraiment le vouloir, ou peut-être un problème de traduction du message au niveau du serveur dans la langue de Molière, mais là je m'attendrais plutôt à ce que le message sorte en anglais au lieu d'être carrément absent.
#302 Re : Général » [resolu] Performance de \copy » 06/04/2017 18:06:18
pg_bulkload peut être plus rapide en prenant des libertés avec certaines contraintes et en parallélisant
Voir http://ossc-db.github.io/pg_bulkload/index.html
Sinon copy sera d'autant plus rapide qu'il écrit dans une table sans contrainte d'intégrité référentielle, sans index, sans trigger.
Si la table est créée à vide, ou qu'elle subit un TRUNCATE, il est préférable de supprimer ces propriétés pour le chargement et les remettre après. S'il y a déjà des données dedans ça dépend combien il y en a en proportion des nouvelles, et si d'autres sessions peuvent en avoir besoin pendant l'import.
Si la table n'existe pas au départ, l'option FREEZE peut aider aussi, voir la doc de COPY relative à la version de PostgreSQL utilisée.
#303 Re : Général » ExclusiveLock infini sur un SELECT pg_stat_get_backend_pid » 04/04/2017 18:27:44
Ces requêtes n'ont pas l'air d'avoir un rapport avec des INSERTs. Il est normal d'avoir plein de verrous dans une base active, tant qu'ils ne sont pas pris indéfiniment.
Il faudrait commencer par
select * from pg_stat_activity;pour avoir une vue d'ensemble des sessions en cours.
A part ça, si les 10000 INSERTs sont réellement simultanés, c'est excessif. Très schématiquement, diviser ça par le nombre de threads effectifs des CPUs du serveur et ça donne une idée du ratio de surcharge.
#304 Re : Général » Import CSV: droits, clé primaire, choix champs - sql ou psql et batch? » 24/03/2017 14:05:55
État SQL :22P02
Sous quel logiciel le COPY est-il lancé?
J'ai pas mal cherché et j'ai cru qu'il était possible de n'importer que quelques champs du csv, par exemple en faisant bien correspondre les noms des champs du csv (header) avec ceux de la table créée ? Mais je n'ai pas trouvé l'astuce.
Ça me serait très utile pour éviter de traiter le csv (qui a 109 colonnes dont seulement une vingtaine à conserver pour cet exemple)...
Il y a 2 choses ici que le COPY de postgresql ne sait pas faire:
- interpréter les champs du header csv pour les associer avec des noms de colonne de la table. Quand on met l'option HEADER, ça veut juste dire que la 1ere ligne sera filtrée au lieu d'être considérée comme une ligne de données. Le contenu de cette 1ere ligne est ignoré.
- éliminer des colonnes du contenu. En ajoutant des noms de colonnes derrière le nom de table, on indique que la destination du COPY ne comprend pas toutes les colonnes de la table, mais ça ne change pas la source. Dans la source du COPY, toutes les colonnes sont prises en compte.
Il faut préfiltrer le fichier avant de le donner à COPY pour supprimer des colonnes, ou bien il faut utiliser qqch de plus avancé que copy, comme pgloader: http://pgloader.io/howto/csv.html
Je ne sais pas si pgloader existe prêt à l'emploi sous Windows.
#305 Re : Sécurité » ssl et fichiers postgresql.* sur le client » 07/03/2017 20:12:52
Le client doit positionner en fonction du serveur auquel il veut se connecter,
soit les variables d'environnement PGSSL* mentionnées ici:
https://www.postgresql.org/docs/current … nvars.html
soit les options de connexion équivalentes sslcert / sslkey / sslrootcert / sslcrl dans la chaine de connexion.
#306 Re : PL/pgSQL » Trigger + variable old. + sql dynamique » 02/03/2017 18:28:01
Donc, si je vous comprends bien, il n'y a pas moyen de faire un old.pk_name où pk_name est calculé par la fonction.
C'est un problème de syntaxe et de capacité du langage. Si OLD.pk_name était possible il faudrait que pk_name soit une variable contenant un nom de colonne.
Mais OLD est une variable d'un type composite avec des champs du genre OLD.col1, OLD.col2 etc. et ces champs ne sont pas des variables, ce sont des eux-mêmes des identifiants que plpgsql attend en dur.
#307 Re : PL/pgSQL » Trigger + variable old. + sql dynamique » 02/03/2017 18:19:45
Oui effectivement Guillaume,dire que le CTID ne change pas dans une transaction c'est tellement un raccourci que c'est faux. En particulier en READ COMMITTED.
Mais dans le cas du trigger mentionné ici, je ne pense pas qu'il soit possible que OLD.ctid désigne une autre ligne que celle pour laquelle le trigger a été déclenché. Je ne pense pas non plus que cette ligne puisse disparaitre à ce moment car elle est verrouillée. Au pire l'UPDATE n'arriverait pas à l'atteindre si elle n'est plus visible.
#308 Re : PL/pgSQL » Trigger + variable old. + sql dynamique » 02/03/2017 17:39:11
Dans le SQL dynamique il faut utiliser la fonction format() avec les formats %L et %I pour se simplifier la syntaxe.
Par exemple
stmt := format('UPDATE public.%I SET deleted_when=now(), deleted_by=current_user WHERE %I=%L',
TG_TABLE_NAME, nom_de_la_colonne_pk, valeur_de_la_pk);Pour obtenir la valeur de la PK, si le trigger est multi-utilisé pour plusieurs tables et que la PK s'appelle différemment suivant les tables, c'est un problème.
L'ennui en plpgsql est que derrière OLD. ou NEW. on ne peut pas mettre une variable désignant un nom de colonne, c'est le côté statique de plpgsql (contrairement à plv8 ou plperl ou sûrement d'autres pl qui sont plus dynamiques mais ont d'autres inconvénients).
Mais est-ce que ce trigger a vraiment besoin de connaître le nom de la PK?
On peut se référer à une ligne via la pseudo-colonne CTID qui identifie sa position physique dans la table. Cette position peut changer d'une transaction à l'autre, mais pas en pleine transaction.
Pour moi une fonction comme ça devrait marcher de manière générique:
CREATE OR REPLACE FUNCTION softdelete()
RETURNS trigger LANGUAGE plpgsql
AS $function$
BEGIN
execute format('UPDATE %I.%I SET deleted_when=now(), deleted_by=current_user WHERE ctid=$1',
TG_TABLE_SCHEMA, TG_TABLE_NAME) USING OLD.ctid;
RETURN null;
END
$function$Le RETURN null est indispensable pour que le DELETE soit annulé étant donné qu'on veut le remplacer par un UPDATE.
Le lier à la table en évènement BEFORE DELETE:
CREATE TRIGGER softdelete BEFORE DELETE ON la_table FOR EACH ROW EXECUTE PROCEDURE softdelete();#309 Re : PL/pgSQL » trigger or rule on delete » 02/03/2017 17:15:45
Oui dans les versions récentes de postgres en tout cas, il est possible d'insérer directement dans une vue, lorsque la requête de la vue est un simple filtre mono-table. Quand c'est plus compliqué il faut faire des triggers INSTEAD OF dont le code embarque l'intelligence de comment les mises à jours de vues doivent remonter dans les tables.
Exemple sur une instance 9.5:
test=# create table la_table(champ text, actif bool default true);
CREATE TABLE
test=# insert into la_table(champ) values('foo');
INSERT 0 1
test=# create view la_vue as select champ from la_table where actif=true;
CREATE VIEW
test=# insert into la_vue(champ) values('bar');
INSERT 0 1
test=# select * from la_table;
champ | actif
-------+-------
foo | t
bar | t
(2 rows)
test=# select * from la_vue;
champ
-------
foo
bar
(2 rows)
test=# delete from la_vue where champ='foo';
DELETE 1
test=# select * from la_vue;
champ
-------
barEt le front-end saura-t-il retrouver les relations pk/fk des tables sous-jacentes.
Je ne sais pas. Ca fait bien longtemps que je n'ai plus utilisé Access pour ma part, et je ne me souviens pas exactement de ce qu'il faisait avec l'intégrité référentielle sur des tables liées en ODBC. C'est dans l'éditeur de requêtes qu'il pré-positionne automatiquement les liens entre PK et FK? J'imagine qu'on peut s'en passer. L'intégrité référentielle sur les écritures sera contrôlée par postgres de toute manière.
Je vais répondre dans l'autre discussion pour l'écriture du SQL dynamique dans les triggers.
#310 Re : PL/pgSQL » trigger or rule on delete » 01/03/2017 16:26:28
Cette fonctionnalité s'appelle souvent "soft delete" en anglais (je dis ça pour les recherches sur le web) et elle est généralement mise en oeuvre en donnant aux utilisateurs accès à une vue qui fait essentiellement
"SELECT * FROM table WHERE deleted=false", par opposition au fait de donner accès à la table.
Dans le cas contraire, la situation est absurde du point de vue d'une application qui ferait un DELETE dans la table suivi d'un SELECT et se retrouverait à relire les données qu'elle vient d'effacer.
Avec une vue, il faut faire des triggers INSTEAD OF pour mettre en oeuvre les écritures.
Sinon il y a une approche complètement différente qui consiste à ne pas empêcher les DELETE mais à sauver les lignes effacées via un INSERT en trigger. Ca ne nécessite pas de vue et c'est plus simple mais il faut un double de toutes les tables.
#311 Re : PSQL » substitution de variables » 28/02/2017 15:25:27
La manière la plus simple est d'utiliser \set pour construire une nouvelle variable, car \set va concaténer les éléments sans séparateur.
Attention il n'y a aucun signe "égal" à mettre entre la variable et l'expression, sinon il va le prendre comme faisant partie de l'expression.
Exemple:
test=> \set app agu
test=> \set rolename r_ :app _dba
test=> \echo :rolename
r_agu_dba
test=> create role :"rolename";
CREATE ROLE
test=> select rolname from pg_roles order by oid desc limit 1;
rolname
-----------
r_agu_dba
(1 row)#312 Re : PSQL » psql/problème mot de passe » 21/02/2017 11:54:48
ou alors c'est l'invite de commandes type de Windows?
Oui. Voir par exemple http://fr.wikihow.com/ouvrir-l'Invite-de-commandes-sous-Windows
pour plus d'info ou chercher "cmd.exe windows 8" dans google.
Sinon effectivement le fait de double-cliquer directement sur psql.exe ou les autres commandes n'est pas jouable, car ça les lance sans paramètre, ce qui n'est pas le mode d'usage de ces commandes.
#313 Re : PSQL » psql/problème mot de passe » 20/02/2017 19:34:04
Les commandes du genre createuser ou psql prennent un argument -U où l'on peut spécifier un utilisateur.
En mettant -U postgres il n'utilisera pas "Jean-Louis" mais postgres, qui est le super-utilisateur que l'installation
a dû créer.
Si de plus pg_hba.conf a été changé dans ce sens il ne demandera pas de mot passe.
Dans le cas de createuser le -U ne désigne pas l'utilisateur à créer mais bien d'un utilisateur existant
avec lequel se connecter pour pouvoir en créer un autre. Il est impossible de créer un nouvel
utilisateur si on n'a pas déjà la faculté de se connecter avec un utilisateur existant, et qui plus est,
qui a le droit d'en créer d'autres.
Ceci dit pour ma part je ne comprends pas ce que sont: les prompts "prêts à l'emploi"
Quand j'installe pg9.6 sur Windows 8.1 téléchargé de entreprisedb, je ne vois rien à cliquer nulle part
une fois l'install terminée. J'ouvre une invite de commandes cmd.exe, puis dedans
cd c:\Program Files\PostgreSQL\9.6\bin et je lance les commandes à la main à partir de là.
Evidemment Il est aussi possible d'ajouter ce répertoire à son PATH pour les lancer de n'importe où.
#314 Re : PL/pgSQL » execute into » 20/02/2017 15:09:49
FOUND utilisé comme en #4 fonctionne bien, mais ne pas oublier que FOUND est multi-usage.
La doc: http://docs.postgresql.fr/9.6/plpgsql-statements.html indique toutes les règles qui s'appliquent et certaines sont assez baroques (la boucle FOR par ex.)
La variable FOUND est initialisée à false au début de chaque fonction PL/pgSQL. Elle est positionnée par chacun des types d'instructions suivants :
Une instruction SELECT INTO positionne FOUND à true si une ligne est affectée, false si aucune ligne n'est renvoyée.
Une instruction PERFORM positionne FOUND à true si elle renvoie une ou plusieurs lignes, false si aucune ligne n'est produite.
Les instructions UPDATE, INSERT, et DELETE positionnent FOUND à true si au moins une ligne est affectée, false si aucune ligne n'est affectée.
Une instruction FETCH positionne FOUND à true si elle renvoie une ligne, false si aucune ligne n'est renvoyée.
Une instruction MOVE initialise FOUND à true si elle repositionne le curseur avec succès. Dans le cas contraire, elle le positionne à false.
Une instruction FOR ou FOREACH initialise FOUND à la valeur true s'il itère une ou plusieurs fois, et à false dans les autres cas. FOUND est initialisé de cette façon quand la boucle se termine : pendant l'exécution de la boucle, FOUND n'est pas modifié par la boucle, bien qu'il pourrait être modifié par l'exécution d'autres requêtes dans le corps de la boucle.
Les instructions RETURN QUERY et RETURN QUERY EXECUTE mettent à jour la variable FOUND à true si la requête renvoie au moins une ligne, et false si aucune ligne n'est renvoyée.
Les autres instructions PL/pgSQL ne changent pas l'état de FOUND. Notez que la commande EXECUTE modifie la sortie de GET DIAGNOSTICS mais ne change pas FOUND.
#315 Re : PL/pgSQL » execute into » 17/02/2017 16:57:38
Autant faire directement
IF not exists (select 1 from public."tblContacts" where audit_id = r.audit_id) THEN
...Ca économise une instruction et une variable et ça marchera dans tous les cas de figure.
#316 Re : PL/pgSQL » nom de schema comme argument d'une fonction » 13/02/2017 21:00:43
Il suffit de remplacer
for r in select * from schema_name.audit_history looppar l'équivalent avec du SQL dynamique:
for r in execute format('select * from %I.audit_history', schema_name) loop Pour la doc sur FOR LOOP, voir http://doc.postgresql.fr/9.6/plpgsql-co … tures.html
#317 Re : Migration » [Résolu] Migration 8.4 vers 9.5 : problème int4/bigint » 09/02/2017 16:44:54
1/ Comment se fait il que je n'ai pas vu d'autres erreurs de ce type alors que de nombreuses fonctions stockées sont définies avec des paramètres déclarés en int4, et appelées avec des long en paramètre ?
Les éléments de réponse sont à trouver dans l'API / la bibliothèque C++ utilisée côté client pour s'interfacer avec le serveur. Certaines APIs vont injecter les paramètres textuellement dans la requête sans indication de type, auquel cas c'est le serveur qui déduit le type et le problème en question ne se produira pas. D'autres vont déduire le type SQL du type C++, en l'occurrence "long" si 8 octets correspond à [select oid from pg_type where typname='int8'] donc le type d'OID 20. Si la lib C++ utilise en sous-main PQexecParams() de libpq et met en dur 20 dans le tableau paramTypes, alors le serveur SQL se basera dessus et ça produira l'erreur en question s'il n'y pas de fonction acceptant bigint. La même différence peut se produire selon que les APIs clientes utilisent les prepared statements ou pas. Dans certains cas il y a un switch logiciel qui permet d'activer ou non les prepared statements parce que ça a des effets sur les performances par ailleurs, et parce que les paramètres ne peuvent pas être utilisés librement dans les requêtes DDL.
2/ Pourquoi cette différence de comportement entre une version 8.4 et une version 9.5 ? (je n'ai rien vu dans les release notes)
Un large changement de cast implicit a lieu en 8.3 mais pas après, et ça concernait surtout le sens texte->entier.
Voir http://petereisentraut.blogspot.fr/2008 … resql.html
3/ Existe-t-il une façon de forcer un cast pour ce type de paramètres ?
On peut créer des CAST implicites avec CREATE CAST mais dans le cas int8->int4, ça parait une mauvaise solution puisque la majorité des valeurs de la source ne pourraient pas être converties dans la destination.
Pour moi le plus logique serait de faire l'inverse, passer le paramètre de la fonction de int en bigint puisque la taille de ce paramètre est 64-bit côté client, et "qui peut le plus peut le moins".
Il est aussi possible d'avoir deux versions de la même fonction, une prenant int, l'autre bigint. Mais elles doivent renvoyer le même type.
#318 Re : Général » Première connexion distante » 11/01/2017 18:08:24
Par contre il y a à coup sûr un lézard dans ma configuration, car lorsque je démarre psql je me fais injurier car il ne trouve pas le serveur sur un socket /var/pgsql_socket/.s.PGSQL.5432
C'est normal parce que quand on lance psql sans argument de host (-h) par défaut il prend celui avec lequel sa lib a été compilée, et dans le cas du psql compilé/pré-installé par Apple c'est le répertoire pour Unix Domain Socket se trouvant dans /var/pgsql_socket (pour une connexion locale, donc).
Il faut s'assurer d'utiliser -h et dans le cas présent d'un psql compilé par vos soins, s'assurer de lancer celui-là et non celui pré-installé dans /usr/bin.
Les versions plus de MacOS version desktop ont un client PostgreSQL pré-installé, mais pas les plus récentes (depuis au moins 2 ans je crois).
Sinon le problème de départ, comme répondu par Marc est que les règles pour pour autoriser les clients via pg_hba.conf se font sur le serveur, pas sur le client, sinon n'importe quel client pourrait s'auto-autoriser, ça n'apporterait aucune sécurité.
#319 Re : PL/pgSQL » trigger et notify » 11/11/2016 00:58:17
Comme alternative au SQL dynamique, il est aussi possible d'utiliser la fonction pg_notify().
D'après la doc:
pg_notify
Pour envoyer une notification, vous pouvez aussi utiliser la fonction pg_notify(text, text). La fonction prend en premier argument le nom du canal et en second la charge. La fonction est bien plus simple à utiliser que la commande NOTIFY si vous avez besoin de travailler avec des noms de canaux et des charges non constants.
D'ailleurs pas besoin de mettre current_schema() dans une variable en plpgsql, mais en revanche il faudra utiliser PERFORM en procédural plutôt que SELECT puisque cette fonction ne renvoie rien.
BEGIN
PERFORM pg_notify(current_schema() || '_GIService', '-');
RETURN NEW;
END#320 Re : Général » [résolu]-Comparaison de chaine de caractère » 04/11/2016 17:29:28
Vous pouvez faire une fonction qui trie par les lettres, et un index fonctionnel sur la table où se trouvent ces chaînes de caractères.
Les comparaisons futures avec cette fonction utiliseront l'index.
Imaginons une fonction qui s'appellerait tri_lettres.
tri_lettres('ICB') = 'BCI' parce que 'B' < 'C' < 'I'
tri_lettres('CBI') = 'BCI' également
...etc... toute permutation des lettres B C et I donnera 'BCI'
Etant donné une chaîne en entrée, une recherche peut se faire avec
SELECT * FROM latable WHERE tri_lettres(nom_colonne) = tri_lettres(chaine_en_entree);Et pour éviter que le moteur SQL ne réapplique la fonction à toute la table à chaque fois, créer un index:
CREATE INDEX nomindex ON latable(tri_lettres(nom_colonne));#321 Re : Réplication » Probleme pg_dump [programme d'archivage (db)] » 08/10/2016 19:40:39
Le schéma DE_17 n'est pas exclu du dump malgré l'option -N 'DE_*' parce que les règles de mise en minuscule du SQL s'appliquent sur cette option.
La doc de pg_dump ramène à celle de psql au sujet de ces "motifs", et cette dernière doc dit:
http://docs.postgresqlfr.org/9.6/app-psql.html
Les caractères à l'intérieur du motif sont normalement mis en minuscule comme pour les noms SQL ;
par exemple, \dt FOO affichera la table nommée foo.
Comme pour les noms SQL, placer des guillemets doubles autour d'un motif empêchera la mise en minuscule
Donc pour exclure ces schémas en majuscules, il faudrait ajouter des guillemets autour de la partie fixe du motif, soit
pg_dump -N '"DE_"*' [...autres options]...#322 Re : Général » Soucis avec la commande CROSSTAB » 02/05/2016 17:10:17
Il n'est pas possible de faire en une seule passe un pivot SQL avec des colonnes dynamiques.
Il faut faire 2 passes:
- une première requête qui récupère la liste des colonnes
- une deuxième requête dynamique, dans laquelle on injecte le résultat de la première. Cette deuxième requête peut être basée sur crosstab, ou une autre méthode, comme une suite de CASE... WHEN..THEN... END AS nomcolonne.
Ces 2 passes ne peuvent pas être factorisées dans une fonction plpgsql, car on ne pourrait pas appeler cette fonction sans déclarer explicitement les colonnes qu'elle retourne, ce qui fait revenir au problème de départ.
#323 Re : PL/Perl » Erreur sur fonction selectrow_array » 14/04/2016 17:26:15
Pour la partie historique, la debian 6 (etch) était associée à postgresql 8.1
C'est la debian 3 (woody) qui avait postgresql 7.2
En fait, on vous demande de faire tourner sur une debian obsolète un postgresql encore plus obsolète.
En revanche Perl 5.14 c'est vraiment récent par rapport au reste.
Mais concernant ça, ce n'est pas forcément Perl lui-même qu'il faut regarder, c'est DBD-Pg,
voir notamment ça:
http://search.cpan.org/dist/DBD-Pg/Pg.pm#prepare
Les prepared statements via le protocole n'existaient pas avant le protocole 3.
Donc quand on est en protocole 2 (avec postgresql 7.2) logiquement il faudrait les inhiber.
C'est faisable avec
$dbh = DBI->connect($DBNAME, $DBUSER, $DBPASS,
{ AutoCommit => 0,
RaiseError => 1,
pg_server_prepare => 0,
});Je ne sais pas si c'est suffisant (j'en doute) mais je pense que c'est nécessaire. dans votre configuration.
Sinon, compiler un DBD::Pg qui date de 2007 (=2002+5 ans) mais pas après, en espérant qu'un vieux DBD-Pg soit compilable avec un nouveau Perl, ce qui n'est pas non plus garanti.
#324 Re : Installation » plusieurs clusters, mise à jour du système » 04/01/2016 19:07:47
A propos de cette erreur-là avec pg_upgrade:
cannot write to log file pg_upgrade_internal.log
C'est une erreur toute bête.
Ca arrive quand on lance pg_upgrade alors qu'on n'a pas le droit d'écriture dans le répertoire courant.
C'est parce qu'il veut créer ce fichier dans le répertoire.
Il suffit de faire cd $HOME ou cd /tmp si on n'a pas l'intention de garder ce fichier de log et de relancer la commande.
#325 Re : Général » SHA différent suite à un cryptage bf (UTF8) » 28/12/2015 16:13:58
Quel est le type de la colonne name? text/varchar(N) ou bytea?
Quel est son contenu brut?
Quel est l'encodage serveur et l'encodage client (show server_encoding; et show client_encoding; )
Ces questions car le cast de TEXT en BYTEA produit un résultat qui dépend de l'encodage.
Exemple en base UTF-8:
=> select 'é'::bytea;
bytea
--------
\xc3a9
En base LATIN9:
=> select 'é'::bytea;
bytea
-------
\xe9
A ce propos quelque chose qui pique les yeux est que é est un E accentué encodé en UTF-8 mais interprété en ISO. Ca arrive soit quand le client_encoding n'est pas bon, soit parce que le contenu a été doublement converti LATIN1->UTF-8 puis encore LATIN1->UTF-8, la deuxième passe corrompant le contenu.
Ca n'explique pas le résultat montré dans la question, mais ça laisse penser que le contenu de la colonne est mal encodé dès le départ.
Quand on applique digest() à un texte, l'encodage des caractères compte aussi. Le même texte ne donnera pas le même digest dans un encodage ou un autre, car l'algorithme de digest s'applique aux octets, par aux caractères.
UTF-8:
=> select digest('é', 'SHA1');
digest
--------------------------------------------
\xbf15be717ac1b080b4f1c456692825891ff5073d
LATIN9:
=> select digest('é', 'SHA1');
digest
--------------------------------------------
\x1599e9fa41ec68c80230491902786bee889f5bcb