7.4. Extensões

Esta seção apresenta um exemplo simples de como criar um novo tipo de dados para representação de coordenadas geográficas.

1. Criando um tipo denominado geo_point:

CREATE TYPE geo_point AS
(
  x    REAL,
  y    REAL,
  srid INTEGER
);

2. Criando uma tabela para armazenar a localização de escolas de primeiro e segundo grau:

CREATE TABLE escolas
(
    gid         SERIAL PRIMARY KEY,
    nome        VARCHAR(100),
    localizacao GEO_POINT
);

3. Inserindo tuplas (linhas ou registros) na tabela escolas:

INSERT INTO escolas (gid, nome, localizacao)
     VALUES (1, 'Escola Estadual Arlindo Bittencourt', '(-47.88497, -22.02557, 4326)'::GEO_POINT),
            (2, 'Colégio Arquidiocesano de Ouro Preto', '(-43.51592, -20.38144, 4326)'::GEO_POINT),
            (3, 'Instituto São José', '(-45.90245, -23.20000, 4326)'::GEO_POINT);

4. Recuperando as tuplas da tabela escolas:

SELECT * FROM escolas;

5. Criando uma função para computar a distância entre dois pontos no plano cartesiano:

CREATE OR REPLACE FUNCTION distance(first GEO_POINT, second GEO_POINT)
    RETURNS REAL AS $$
    DECLARE
        dx REAL;
        dy REAL;
    BEGIN
        dx = (first.x - second.x);

        dy = (first.y - second.y);

        RETURN sqrt(dx * dx + dy * dy);
    END;
    $$
    LANGUAGE plpgsql;

6. Utilizando a função distance para computar a distância entre dois pontos:

SELECT distance('(1, 1, 4326)'::GEO_POINT, '(2, 2, 4326)'::GEO_POINT);

7. Criando um operador para comparação entre dois pontos:

  1. Criação da função de comparação:

CREATE OR REPLACE FUNCTION less_than(first GEO_POINT, second GEO_POINT)
    RETURNS BOOL AS $$
    BEGIN
        IF(first.x < second.x) THEN
            RETURN TRUE;
        END IF;

        IF(first.x > second.x) THEN
            RETURN FALSE;
        END IF;

        IF(first.y < second.y) THEN
            RETURN TRUE;
        END IF;

        RETURN FALSE;
    END;
    $$
    LANGUAGE plpgsql;
  1. A função acima poderia ser utilizada da seguinte forma:

SELECT less_than('(1, 2, 4326)'::GEO_POINT, '(10, 20, 4326)'::GEO_POINT);
SELECT less_than('(1, 2, 4326)'::GEO_POINT, '(-1, 2, 4326)'::GEO_POINT);
  1. Criando o operador associado à função de comparação:

CREATE OPERATOR <
(
  leftarg = GEO_POINT,
  rightarg = GEO_POINT,
  procedure = less_than,
  commutator = >,
  negator = >=
);
  1. Utilizando a função less_than através do operador <:

SELECT '(1, 2, 4326)'::GEO_POINT < '(10, 2, 4326)'::GEO_POINT;