7.4. Creacion de tipos de datos

Entre las múltiples opciones para extender PostgreSQL, nos queda aún por ver la creación de tipos o dominios (según la nomenclatura del estándar SQL). PostgreSQL prevé dos tipos de datos definidos por el administrador:

•    Un tipo de datos compuesto, para utilizar como tipo de retorno en las funciones definidas por el usuario.

•    Un tipo de datos simple, para utilizar en las definiciones de columnas de las tablas.

A modo de ejemplo, veamos un tipo compuesto y la función que lo devuelve:

create type comptipo as (f1 int, f2 text);
create function gettipo() returns setof comptipo as
  `select id, nombre from clientes´ language sql;

Para el tipo de datos simple, la definición es más compleja, pues se debe indicar a PostgreSQL funciones que tratan con este tipo que le permitirán usarlo en operaciones, asignaciones, etc.
 

Tratar con el tipo de datos simple
Habitualmente, las funciones que tratarán con este tipo de datos se escribirán en C.

A modo de ejemplo, vamos a crear el tipo “numero complejo”, tal como lo hace la documentación de PostgreSQL. En primer lugar, debemos definir la estructura donde almacenaremos el tipo:

typedef struct Complex {
   double     x;
   double     y;
} Complex;

Después, las funciones que lo recibirán o devolverán:

PG_FUNCTION_INFO_V1(complex_in);
Datum
complex_in(PG_FUNCTION_ARGS)
{
  char     *str = PG_GETARG_CSTRING(0);
  double    x,
            y;
  Complex *result;
  if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
     ereport(ERROR,
          (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
          errmsg("invalid input syntax for complex: "%s"", str)));
 
  result = (Complex *) palloc(sizeof(Complex));
  result->x = x;
  result->y = y;
  PG_RETURN_POINTER(result);
}
PG_FUNCTION_INFO_V1(complex_out
Datum
complex_out(PG_FUNCTION_ARGS)
{
   Complex *complex = (Complex *) PG_GETARG_POINTER(0);
   char    *result;
   result = (char *) palloc(100);
   snprintf(result, 100, "(%g,%g)", complex->x, complex->y);
   PG_RETURN_CSTRING(result);
}

Ahora estamos en condiciones de definir las funciones, y el tipo:

create function complex_in(cstring)
   returns complex
   as `filename´
   language c immutable strict;
create function complex_out(complex)
   returns cstring
   as `filename´
   language c immutable strict;
create type complex (
   internallength = 16,
   input = complex_in,
   output = complex_out,
   alignment = double
);

 

El proceso es un poco farragoso, pero compensa por la gran flexibilidad que aporta al SGBD. A continuación, podríamos crear algunos operadores para trabajar con este tipo (suma, resta, etc.), mediante los pasos que ya conocemos.

La creación de un dominio en PostgreSQL consiste en un tipo (definido por el usuario o incluido en el SGBD), más un conjunto de restricciones. La sintaxis es la siguiente:

 

Se ha creado un dominio basado
en un tipo definido por el sistema donde la única restricción es su longitud.

create domain country_code char(2) not null;
create domain complejo_positivo complex not null check
      (complejo_mayor(value,(0,0)))

Evidentemente, deberíamos haber definido el operador complejo_mayor que recibiera dos números complejos e indicara si el primero es mayor que el segundo.