Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Nie można wybrać, gdzie ip=inet_pton($ip)

Najpierw poprawka, która jest dość prosta:jeśli chcesz przechowywać zarówno adresy IPv4, jak i IPv6, powinieneś użyć VARBINARY(16) zamiast BINARY(16) .

Teraz do problemu:dlaczego nie działa zgodnie z oczekiwaniami z BINARY(16) ?

Rozważmy, że mamy tabelę ips z tylko jedną kolumną ip BINARY(16) PRIMARY KEY .Domyślny lokalny adres IPv4 przechowujemy za pomocą

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

i znajdź następującą wartość w bazie danych:

0x7F000001000000000000000000000000

Jak widzisz - jest to 4-bajtowa wartość binarna (0x7F000001 ) uzupełniony zerami w prawo, aby zmieścić 16-bajtową kolumnę o stałej długości.

Kiedy teraz spróbujesz go znaleźć za pomocą

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

dzieje się tak:PHP wysyła wartość 0x7F000001 jako parametr, który jest następnie porównywany z zapisaną wartością 0x7F000001000000000000000000000000 .Ale ponieważ dwie wartości binarne o różnej długości nigdy nie są równe, warunek WHERE zawsze zwróci FALSE. Możesz to wypróbować za pomocą

SELECT 0x00 = 0x0000

co zwróci 0 (FAŁSZ).

Uwaga:zachowanie jest inne dla ciągów niebinarnych o stałej długości (CHAR(N) ).

Jako obejście możemy użyć jawnego przesyłania:

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

i znajdzie rząd. Ale jeśli spojrzymy na to, co otrzymujemy

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

zobaczymy

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

Ale to nie jest (naprawdę) to, co próbowaliśmy przechowywać. A kiedy teraz próbujemy przechowywać 7f00:1:: , pojawi się błąd zduplikowanego klucza , chociaż nigdy nie zapisaliśmy jeszcze żadnego adresu IPv6.

Więc jeszcze raz:użyj VARBINARY(16) , i możesz zachować swój kod nietknięty. Zaoszczędzisz nawet trochę miejsca, jeśli przechowujesz wiele adresów IPv4.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Tabela nie ma klucza podstawowego

  2. Jak uzyskać wiele zliczeń za pomocą pojedynczego zapytania w MySQL?

  3. mysql wybierz rekordy dłuższe niż 3 miesiące

  4. Ustaw wynik zmiennej z zapytania

  5. Modele Django:domyślna wartość dla kolumny