martes, 1 de enero de 2008

Almacenar direcciones IP como numero entero largo en Postgresql

La mejor forma de almacenar direcciones IP es como numero entero no solo en PostgreSQL sino en cualquier base de datos, ya que un numero entero siempre ocupara menos bytes que una cadena de caracteres.

Para nuestro ejemplo usaremos la direccion IP 189.142.115.28.

IP:189.142.115.28
Primer Octeto: 189
Segundo Octeto: 142
Tercer Octeto: 115
Cuarto Octeto: 28

El algoritmo es muy simple de implementar para nuestra fortuna y quedaria asi:

(Primer Octeto * 256³) + (Segundo Octeto * 256²) + (Tercer Octeto * 256) + (Cuarto Octeto) = Direccion IP representada con entero.

Por lo tanto sustituyendo quedaria:

(189 * 16777216) + (142 * 65536) + (115 * 256) + 28 = 3180229404

En donde 3180229404 es equivalente a 189.142.115.28.

Ahora bien la implementacion de una funcion en PostgreSQL usando SQL como lenguaje de programacion quedaria de la siguiente forma:


CREATE OR REPLACE FUNCTION inet_aton(text) RETURNS bigint AS '
SELECT
split_part($1,''.'',1)::int8*(256*256*256)+
split_part($1,''.'',2)::int8*(256*256)+
split_part($1,''.'',3)::int8*256+
split_part($1,''.'',4)::int8;
' LANGUAGE 'SQL';


Si creamos esta funcion en nuestro postgresql, una tipica salida quedaria asi:


geodb=> select inet_aton('189.142.115.28');
inet_aton
------------
3180229404
(1 row)




Implementando la funcion inet_ntoa, capaz de convertir una direccion IP en entero a su correspondiente direccion en cadena de texto.



Para lograrlo es muy simple, solo basta con desplazar los bits adecuados como se nota a simple vista en la siguiente funcion postgresql implementada en el lenguaje SQL.


CREATE OR REPLACE FUNCTION inet_ntoa(bigint) RETURNS text AS '
SELECT (($1>>24) & 255::int8) || ''.'' ||
(($1>>16) & 255::int8) || ''.'' ||
(($1>>8) & 255::int8) || ''.'' ||
($1 & 255::int8) as result
'
LANGUAGE 'SQL';


Y pues listo, eso es todo, nos vemos luego.

Bahia desde el balcon...

Bahia desde el balcon...
Ixtapa Zihuatanejo