Je travaille actuellement sur une table contenant des hachages, stockée au format BYTEA. La conversion des hachages aux chaînes hexagonales donne cependant le mauvais ordre des octets. Exemple:
SELECT encode(hash, 'hex') FROM mytable LIMIT 1;
Output: 1a6ee4de86143e81
Expected: 813e1486dee46e1a
Existe-t-il un moyen d'inverser l'ordre des octets pour toutes les entrées?
Voici une méthode pour le faire, cependant Je ne ferais jamais cela. Il n'y a rien de mal à stocker des octets dans une base de données bytea
. Mais, je ne me trompais pas dans la base de données, et si je le faisais, j'utilisais,
C'est SQL-ESQ et devrait travailler - voici ce que nous faisons,
Voici un exemple,
CREATE TABLE foo AS SELECT '\x813e1486dee46e1a'::bytea AS bar;
SELECT bar, string_agg(to_hex(byte), '') AS hash
FROM foo
CROSS JOIN LATERAL (
SELECT get_byte(bar,"offset") AS byte
FROM generate_series(0,octet_length(bar)-1) AS x("offset")
ORDER BY "offset" DESC
) AS x
GROUP BY bar;
Deux notes,
offset
parce que --- (c'est réservé Mais vous obtenez le point.Vous pouvez traiter une représentation codée en tant que texte et utiliser REGEXP pour inverser l'octet d'octet.
SELECT string_agg(reverse(b[1]),'')
FROM regexp_matches(reverse(encode('STUFF','hex')),'..','g')b;
Une autre méthode (plus verbose):
WITH bytes AS (
SELECT row_number() over() AS n, byte[1]
FROM regexp_matches( encode( 'STUFF', 'hex' ), '..', 'g' ) AS byte
), revbytes AS (
SELECT * FROM bytes ORDER BY n DESC
)
SELECT array_to_string(array_agg(byte),'')
FROM revbytes;
Utilisation des échantillons:
(filip@[local:/var/run/postgresql]:5432) filip=# SELECT encode( 'STUFF', 'hex' );
encode
------------
5354554646
(1 row)
(filip@[local:/var/run/postgresql]:5432) filip=# SELECT string_agg(reverse(b[1]),'')FROM regexp_matches(reverse(encode('STUFF','hex')),'..','g')b;
string_agg
------------
4646555453
(1 row)
Si vous avez besoin de renverser les octets de la valeur bytea
, la valeur (relativement) simple et rapide utilise plpythonu
:
create or replace function reverse_bytea(p_inp bytea) returns bytea stable language plpythonu as $$
b = bytearray()
b.extend(p_inp)
b.reverse()
return b
$$;
select encode(reverse_bytea('\x1a6ee4de86143e81'), 'hex');
----
813e1486dee46e1a
Cependant, je suppose que quelque chose ne va pas avec les données elles-mêmes (la voie de stockage, l'interprétation des données ...)
Solutions avec outils à Vanilla Postgres:
J'ai ajouté une colonne bytea_reverse
Aux deux solutions. Supprimez-le si vous n'en avez pas besoin.
Avec get_byte()
:
SELECT t.b, text_reverse, decode(text_reverse, 'hex') AS bytea_reverse
FROM tbl t
LEFT JOIN LATERAL (
SELECT string_agg(to_hex(get_byte(b, x)), '') AS text_reverse
FROM generate_series(octet_length(t.b) - 1, 0, -1) x
) x ON true;
Ceci est similaire à ce que @ evan fourni . La majeure partie de son excellente explication s'applique. Mais:
LEFT JOIN LATERAL ... ON true
Ou vous perdez des lignes avec des valeurs null.generate_series()
peut fournir des chiffres en sens inverse, nous n'avons donc pas besoin d'un autre ORDER BY
.LATERAL
jointure, agrégat dans la sous-requête. Moins d'erreur sujette, plus facile à intégrer avec des requêtes plus complexes et pas besoin de GROUP BY
Dans la requête extérieure.Avec regexp_matches()
:
SELECT t.b, text_reverse, decode(text_reverse, 'hex') AS bytea_reverse
FROM tbl t
LEFT JOIN LATERAL (
SELECT string_agg(byte[1], '' ORDER BY ord DESC) AS text_reverse
FROM regexp_matches(encode(t.b, 'hex' ), '..', 'g' ) WITH ORDINALITY AS x(byte, ord)
) x ON true;
Ceci est similaire à la variante "Verbose" Variante @FiliPrem fournie . Mais:
LEFT JOIN LATERAL ... ON true
Ou vous perdez des lignes avec des valeurs null.WITH ORDINALITY
Pour obtenir des numéros de ligne "gratuitement". Donc, nous n'avons pas besoin d'une autre sous-requête avec row_number()
ni un double reverse()
. Détails:Question similaire sur SO:
Grâce à toutes les suggestions, j'ai écrit cette fonction c-linguistique qui fonctionne au besoin:
#include "postgres.h"
#include "fmgr.h"
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
Datum bytea_custom_reverse(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(bytea_custom_reverse);
Datum
bytea_custom_reverse(PG_FUNCTION_ARGS) {
bytea *data = PG_GETARG_BYTEA_P_COPY(0);
unsigned char *ptr = (unsigned char *) VARDATA(data);
int32 dataLen = VARSIZE(data) - VARHDRSZ;
unsigned char *start, *end;
for ( start = ptr, end = ptr + dataLen - 1; start < end; ++start, --end ) {
unsigned char swap = *start;
*start = *end;
*end = swap;
}
PG_RETURN_BYTEA_P(data);
}
Merci d'avoir aidé ce fil. Et ceci est mon choix de convertir Bigint en bytea en peu souvent en C # en utilisant BitConverter.getBytes () Selon les réponses:
with mycte as (
select int8send(394112768534335::bigint) as conversionValue
)
SELECT decode(string_agg (
(case when get_byte(conversionValue, x)<= 15 then ('0') else '' end) ||
to_hex(get_byte(conversionValue, x))
, ''), 'hex') AS nativeId_reverse
FROM mycte, generate_series(octet_length(conversionValue) - 1, 0, -1) as x;
Pour la valeur de recherche placée dans PostgreSQL comme Petitendian Bytea par IT BIBINT PRESENTATION:
with mycte as (
select int8send(394112768534335::bigint) as conversionValue
)
Select * FROM mycte, *SomeByteaFieldTable*
where *SomeByteaId* =
(SELECT decode(string_agg (
(case when get_byte(conversionValue, x)<= 15 then ('0') else '' end) ||
to_hex(get_byte(conversionValue, x))
, ''), 'hex') AS nativeId_reverse
FROM generate_series(octet_length(conversionValue) - 1, 1, -1) x);