Мне кажется, я нашел решение. Это включает в себя изменение данных, а затем некоторый массаж ввода. Вот что сработало.
Во-первых, необходимо преобразовать данные так, чтобы все адреса были полными, без сокращения, с удалением разделителей точки с запятой. Образцы данных, показанные в моем вопросе, преобразуются в:
t_start | t_end | t_country_code
----------------------------------+----------------------------------+----------------
00000000000000000000000000000000 | 00ffffffffffffffffffffffffffffff | ZZ
01000000000000000000000000000000 | 01ffffffffffffffffffffffffffffff | ZZ
...
20000000000000000000000000000000 | 2000ffffffffffffffffffffffffffff | ZZ
...
20011200000000000000000000000000 | 20011200ffffffffffffffffffffffff | MX
...
Это то, что хранится в базе данных.
Следующим шагом было преобразование IP-адреса, полученного в коде, в тот же формат. Это делается в PHP с помощью следующего кода (предположим, что $ip_address
является входящим адресом IPv6):
$addr_bin = inet_pton($ip_address);
$bytes = unpack('n*', $addr_bin);
$ip_address = implode('', array_map(function ($b) {return sprintf("%04x", $b); }, $bytes));
Теперь переменная $ip_adress
будет содержать полный адрес IPv6, например
:: => 00000000000000000000000000000000
2001:1200::ab => 200112000000000000000000000000ab
и т. Д.
Теперь вы можете просто сравнить этот полный адрес с диапазонами в базе данных. Я добавил в базу данных вторую функцию для работы с адресами IPv6, которая выглядит следующим образом:
CREATE OR REPLACE FUNCTION get_country_for_ipv6(character varying)
RETURNS character varying AS
$BODY$
declare
ip ALIAS for $1;
ccode varchar;
begin
select into ccode t_country_code from ipv6_to_country where addr between n_from and n_to limit 1;
if ccode is null then
ccode := '';
end if;
return ccode;
end;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
Наконец, в своем php-коде я добавил код, который вызывает ту или иную функцию Postgres на основе ввода ip_address.