2013-03-24 6 views
5

Mentre testare PostgreSQL's md5() function ho notato molto bizzarro comportamento:md5() funziona con letterale, ma non con i dati della colonna

funziona come previsto

SELECT md5('abc') 
--"900150983cd24fb0d6963f7d28e17f72" 

Ma usando la funzione md5() in una query:

SELECT request_id, md5(request_id) 
FROM Request 
ORDER BY request_id 

risultati in questo errore:

ERROR: function md5(integer) does not exist 
LINE 1: SELECT request_id, md5(request_id) 
         ^
HINT: No function matches the given name and argument types. You might need to add explicit type casts. 

********** Error ********** 

ERROR: function md5(integer) does not exist 
SQL state: 42883 
Hint: No function matches the given name and argument types. You might need to add explicit type casts. 
Character: 20 

Come può la funzione non esistere se ha funzionato nella prima query? Cosa sto sbagliando; qual è il modo corretto di utilizzare md5() in una query SELECT?

+2

Questo non sembra affatto strano. Nella prima query, hai passato il testo, mentre nel secondo stai cercando di passare interi. – us2012

+0

@ us2012: sì, questa è la differenza. –

+0

In generale non ha molto senso prendere l'md5 di un intero, quindi sarei interessato al motivo per cui stai provando a farlo. –

risposta

10

La funzione prevede il testo come parametro. Cast:

SELECT request_id, md5(request_id::text) 
FROM Request 
ORDER BY request_id 

Una funzione con nome md5 accetta un parametro intero non esiste, ma lo si può creare:

create function md5(integer) 
returns text as $$ 

select md5($1::text); 

$$ language sql immutable; 

Poi ci saranno 3 firme per md5:

=> \df md5 
          List of functions 
    Schema | Name | Result data type | Argument data types | Type 
------------+------+------------------+---------------------+-------- 
pg_catalog | md5 | text    | bytea    | normal 
pg_catalog | md5 | text    | text    | normal 
public  | md5 | text    | integer    | normal 

Come indicato nei commenti a questa risposta, l'hash md5 della rappresentazione del testo dell'intero potrebbe non essere quello che vuoi. Per avere l'hash del binario deve essere utilizzata la firma MD5 accettare un parametro bytea:

select md5(('\x' || right('0000000' || to_hex(200), 8))::bytea); 
       md5     
---------------------------------- 
b7b436d004c1cc0501bee9e296d2eaa4 

e sostituire la funzione creata in precedenza:

create or replace function md5(integer) 
returns text as $$ 

select md5(('\x' || right('0000000' || to_hex($1), 8))::bytea); 

$$ language sql immutable; 
+0

Storia vera. L'ho capito subito dopo aver postato la domanda. Grazie Clodoaldo. –

+2

Nota che il casting dell'intero in testo significa che stai prendendo l'md5 della * rappresentazione testuale dell'intero *. Questo potrebbe non essere ciò che intendi quando comunichi con altri sistemi. Se vuoi veramente prendere l'md5 della rappresentazione binaria dell'intero devi usare un linguaggio procedurale come pl/perl, pl/python, ecc per prendere l'md5 della rappresentazione binaria appropriata (firmato little endian a 32 bit, per esempio). –

+1

@Craig Buon punto. Ma sembra che un linguaggio procedurale non sia necessario. O mi sta sfuggendo qualcosa? –

0

L'errore è un po 'fuorviante; esiste la funzione md5(), non solo per lavorare sugli interi . Utilizzare un incorporato funzione di CAST() per convertire il campo intero in testo, e funzionerà:

SELECT request_id, md5(CAST(request_id AS TEXT)) 
FROM Request 
ORDER BY request_id 

--1;"c4ca4238a0b923820dcc509a6f75849b" 
--2;"c81e728d9d4c2f636f067f89cc14862c" 
--etc 
3

In generale, non ha molto senso prendere l'MD5 di un numero intero. Sembra probabile che tu stia cercando di oscurare una sequenza in modo che appaia semi-casuale in ordine. In tal caso, c'è un modo molto migliore:

Utilizzare pseudo_encrypt function listed on the PostgreSQL wiki. È molto più saggio che provare a prendere l'MD5 di un numero intero, quindi (presumibilmente) troncarlo.

Quanto sopra fa non fornisce una forte casualità crittografica, ma nemmeno il tuo approccio. Se hai bisogno dei tuoi ID di richiesta per essere veramente imprevedibili per ragioni di sicurezza piuttosto che ovvio, dovresti utilizzare un potente generatore di numeri casuali crittografici ed essere pronto a gestire duplicati utilizzando finestre temporali, ecc.

+0

Sto solo provando a generare un valore non ovvio, non ripetibile, che può essere utilizzato per cercare un record. Quindi la mia brillante (?) Idea è di fare una sorta di crittografia sul PL della tt. È la sicurezza per anonimato resa necessaria dal fatto che gli utenti occasionali (richiedenti ticket) non hanno accesso. Ad ogni modo, sono arrivato a usare 'REPLACE (request_id :: text, '1234567890', 'abcdefghij')' per fare questa "crittografia". –

+0

PS: il tuo "Awooga! Awooga!" mi fa ancora male. –

+1

@JeromyFrench Cosa posso dire, amo Holly e mi piace fare scherzi solo noi vecchi otterremo ;-). Come un conferenziere che ho fatto all'università che avrebbe reso estremamente divertenti i riferimenti alle Scimmie nei suoi discorsi; quattro o cinque di noi nel teatro si sarebbero messi a ridere e tutti gli altri ci avrebbero guardato come se fossimo impazziti. –

0

I'm just trying to generate a non-obvious, non-repeating, value which can be used to look-up a record.

Quello che ti serve è un hash biettivo. Io uso la funzione CPU CRC in una funzione C personalizzata. Per le CPU che non hanno la funzione, si può usare una tabella di ricerca.

Questo approccio garantisce un numero "casuale" unico per ogni ingresso univoco a 32 bit.

Se si sa come generare funzioni C (non banali), sarà semplice cercare il modo in cui utilizzare CRC.

Problemi correlati