sql >> Databasteknik >  >> RDS >> Mysql

Kan inte välja var ip=inet_pton($ip)

Först korrigeringen, som är ganska enkel:Om du vill lagra både IPv4- och IPv6-adresser, bör du använda VARBINARY(16) istället för BINARY(16) .

Nu till problemet:Varför fungerar det inte som förväntat med BINARY(16) ?

Tänk att vi har en tabell ips med endast en kolumn ip BINARY(16) PRIMARY KEY .Vi lagrar den lokala IPv4-adressen som standard med

$stmt = $db->prepare("INSERT INTO ips(ip) VALUES(?)");
$stmt->execute([inet_pton('127.0.0.1')]);

och hitta följande värde i databasen:

0x7F000001000000000000000000000000

Som du ser - det är ett 4 byte binärt värde (0x7F000001 ) högerutfylld med nollor för att passa kolumnen med fast längd på 16 bytes.

När du nu försöker hitta den med

$stmt = $db->prepare("SELECT * FROM ips WHERE ip = ?");
$stmt->execute([inet_pton('127.0.0.1')]);

följande händer:PHP skickar värdet 0x7F000001 som parameter som sedan jämförs med det lagrade värdet 0x7F000001000000000000000000000000 .Men eftersom två binära värden av olika längd aldrig är lika, kommer WHERE-villkoret alltid att returnera FALSE. Du kan prova det med

SELECT 0x00 = 0x0000

vilket returnerar 0 (FALSKT).

Obs:Beteendet är annorlunda för icke-binära strängar med fast längd (CHAR(N) ).

Vi skulle kunna använda explicit casting som en lösning:

$stmt = $db->prepare("SELECT * FROM ips WHERE ip = CAST(? as BINARY(16))");
$stmt->execute([inet_pton('127.0.0.1')]);

och den kommer att hitta raden. Men om vi tittar på vad vi får

var_dump(inet_ntop($stmt->fetch(PDO::FETCH_OBJ)->ip));

vi får se

string(8) "7f00:1::"

Men det är inte (egentligen) vad vi har försökt lagra. Och när vi nu försöker lagra 7f00:1:: , kommer vi att få ett duplicerat nyckelfel , även om vi aldrig har lagrat någon IPv6-adress ännu.

Så än en gång:Använd VARBINARY(16) , och du kan behålla din kod orörd. Du sparar till och med en del lagringsutrymme om du lagrar många IPv4-adresser.



  1. Två dubbletter av index med samma kolumner

  2. Hur man beräknar löpande totalsumma i rödförskjutning

  3. Hur man skapar kontrollbegränsning på flera kolumner i SQL Server - SQL Server / TSQL självstudie del 84

  4. Använd MySQL relationsdatabaser på Ubuntu 10.10 (Maverick)