2015-03-13 19 views
7

Sto memorizzando gli indirizzi IPv6 come BINARY(16) e cercando di cercarli attraverso la rappresentazione esadecimale, ad esempio: FFFFFFFF000000000000000000000000.Perché questa conversione da stringa a binario non funziona?

Questo funziona:

SELECT * FROM ipv6 WHERE HEX(address) = 'FFFFFFFF000000000000000000000000' 

Tuttavia, questo non lo fa:

SELECT * FROM ipv6 WHERE address = CONV('FFFFFFFF000000000000000000000000', 16, 2) 

Nessun messaggio di errore, solo non restituisce alcun risultato. MySQL non è in grado di gestire la conversione utilizzando CONV()?

Potrei utilizzare la prima opzione, ma immagino che la seconda opzione sia molto più veloce in un database di grandi dimensioni in quanto non è necessario convertire tutti gli indirizzi nella tabella.

Aggiornamento:

UNHEX() sembra funzionare grande come sottolineato da Jack. Le conversioni standard (a partire da 5.6) che utilizzano CONV() sembrano massimi a 8 byte (64 bit) o ​​in forma esadecimale FFFFFFFFFFFFFFFF in modo che non possa gestire un indirizzo IPv6 completo a 128 bit.

Dopo alcune riflessioni, credo che la risposta di Salman sia il modo migliore per gestire gli esadecimali (utilizzando letterali esadecimali). Tuttavia, è necessario unhex(), afaik, se si utilizza il bind del parametro in PHP poiché le virgolette verranno aggiunte e impedirà a MySQL di valutarlo come una stringa letterale rispetto a una stringa char.

Quindi dovrai scegliere la soluzione migliore per te. I valori letterali esadecimali sono un po 'più veloci, ma se si sta gestendo l'input dell'utente, non disporne il binding dei parametri potrebbe essere la soluzione migliore.

+1

Si prega di dare un esempio di stessi valori si sta salvando, e come si' reinserendoli – Bohemian

risposta

2

È possibile utilizzare hexadecimal literals:

SELECT * FROM ipv6 WHERE address = 0xFFFFFFFF000000000000000000000000; 
SELECT * FROM ipv6 WHERE address = X'FFFFFFFF000000000000000000000000'; 

Se si utilizza DOP, si può semplicemente fare questo:

# insert packed address 
$stmt = $db->prepare("INSERT INTO ipv6(address) VALUES (?)"); 
$stmt->execute(array(inet_pton("2001:0DB8:85A3:0000:0000:8A2E:0370:7334"))); 

# select packed address  
$stmt = $db->prepare("SELECT * FROM ipv6 WHERE address = ?"); 
$stmt->execute(array(inet_pton("2001:0DB8:85A3:0000:0000:8A2E:0370:7334"))); 
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC); 

# verify the result 
echo inet_ntop($rows[0]["address"]); 
# 2001:db8:85a3::8a2e:370:7334 
+0

Questa soluzione in realtà è un po ' più veloce dell'uso di unhex. L'unico problema è che non riesco a capire come usarlo con le istruzioni preparate da PDO. Ho provato 'WHERE address = X?' Ma ottengo un errore di sintassi. Potrei convalidare l'esagono separatamente e usarlo direttamente nella query, ma presumo che la validazione manuale annullerebbe i piccoli risparmi ottenuti contro l'unsex. – Devon

+0

Penso che "WHERE address =?" Dovrebbe essere sufficiente. –

+0

Purtroppo no. Il binding del parametro aggiunge virgolette. Quindi non lo valuta come un letterale esadecimale, solo una stringa di caratteri. – Devon

3

Se non si desidera convertire ogni elemento per esadecimale, è possibile fare il contrario:

SELECT * 
FROM ipv6 
WHERE address = UNHEX('FFFFFFFF000000000000000000000000'); 

Questo farà binari confronti di stringhe come ci si aspetterebbe.

+0

Funziona alla grande. Grazie, non avevo nemmeno realizzato che UNHEX esistesse, ma questo ha sicuramente un senso. Sembra che CONV non possa gestire alcuna conversione di queste dimensioni. – Devon

+0

@Devon 'CONV()' è una funzione matematica mentre quello di cui hai bisogno è una funzione di stringa. –

+0

Anche se CONV funziona con numeri più piccoli, sembra che si estenda al massimo a 64 bit, o in forma esadecimale 'FFFFFFFFFFFFFFFFFF' – Devon

Problemi correlati