sql >> Databáze >  >> RDS >> Mysql

Nelze vybrat, kde ip=inet_pton($ip)

Nejprve oprava, která je docela jednoduchá:Pokud chcete ukládat adresy IPv4 i IPv6, měli byste použít VARBINARY(16) místo BINARY(16) .

Nyní k problému:Proč to nefunguje podle očekávání s BINARY(16) ?

Uvažujme, že máme tabulku ips pouze s jedním sloupcem ip BINARY(16) PRIMARY KEY .Výchozí místní adresu IPv4 ukládáme pomocí

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

a najděte v databázi následující hodnotu:

0x7F000001000000000000000000000000

Jak vidíte – je to 4bajtová binární hodnota (0x7F000001 )doplněno vpravo nulami, aby se vešly do 16bajtového sloupce s pevnou délkou.

Když se jej nyní pokusíte najít pomocí

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

stane se následující:PHP odešle hodnotu 0x7F000001 jako parametr, který je poté porovnán s uloženou hodnotou 0x7F0000010000000000000000000000000000000000 .Ale protože dvě binární hodnoty různé délky nejsou nikdy stejné, podmínka WHERE vždy vrátí FALSE. Můžete to zkusit pomocí

SELECT 0x00 = 0x0000

což vrátí 0 (NEPRAVDA).

Poznámka:Chování se liší pro nebinární řetězce s pevnou délkou (CHAR(N) ).

Jako řešení bychom mohli použít explicitní casting:

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

a najde řádek. Ale když se podíváme na to, co dostaneme

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

uvidíme

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

Ale to není (ve skutečnosti) to, co jsme se snažili uložit. A když se nyní pokoušíme uložit 7f00:1:: ,objeví se chyba duplicitního klíče , i když jsme ještě nikdy neuložili žádnou adresu IPv6.

Takže ještě jednou:Použijte VARBINARY(16) a svůj kód můžete ponechat nedotčený. Ušetříte dokonce nějaké úložiště, pokud budete ukládat mnoho adres IPv4.



  1. Jak resetovat databázi SqLite v Androidu?

  2. Jak smazat celou databázi MySQL

  3. Jak přidat cizí klíč do SQL?

  4. ORA-12516, TNS:listener nemohl najít dostupnou obsluhu