Creo que encontré la solución. Implica modificar los datos primero y luego un poco de masaje de la entrada. Esto es lo que funcionó.
Primero, los datos deben convertirse para que todas las direcciones estén completas, sin acortar, sin los separadores de punto y coma. Los datos de muestra que se muestran en mi pregunta se convierten en:
t_start | t_end | t_country_code
----------------------------------+----------------------------------+----------------
00000000000000000000000000000000 | 00ffffffffffffffffffffffffffffff | ZZ
01000000000000000000000000000000 | 01ffffffffffffffffffffffffffffff | ZZ
...
20000000000000000000000000000000 | 2000ffffffffffffffffffffffffffff | ZZ
...
20011200000000000000000000000000 | 20011200ffffffffffffffffffffffff | MX
...
Esto es lo que se almacena en la base de datos.
El siguiente paso fue convertir la dirección IP recibida en el código para que tuviera el mismo formato. Esto se hace en PHP con el siguiente código (suponga que $ip_address
es la dirección IPv6 entrante):
$addr_bin = inet_pton($ip_address);
$bytes = unpack('n*', $addr_bin);
$ip_address = implode('', array_map(function ($b) {return sprintf("%04x", $b); }, $bytes));
Ahora la variable $ip_adress
contendrá la dirección IPv6 completa, por ejemplo
:: => 00000000000000000000000000000000
2001:1200::ab => 200112000000000000000000000000ab
y así sucesivamente.
Ahora puede simplemente comparar esta dirección completa con los rangos en la base de datos. Agregué una segunda función a la base de datos para manejar las direcciones IPv6, que se ve así:
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;
Finalmente, en mi código php agregué el código que llama a una u otra función de Postgres en función de la dirección_ip de entrada.