<!-- doc/src/sgml/xtypes.sgml -->
<sect1 id="xtypes">
<title>User-Defined Types</title>
<indexterm zone="xtypes">
<primary>data type</primary>
<secondary>user-defined</secondary>
</indexterm>
<para>
As described in <xref linkend="extend-type-system"/>,
<productname>PostgreSQL</productname> can be extended to support new
data types. This section describes how to define new base types,
which are data types defined below the level of the <acronym>SQL</acronym>
language. Creating a new base type requires implementing functions
to operate on the type in a low-level language, usually C.
</para>
<para>
The examples in this section can be found in
<filename>complex.sql</filename> and <filename>complex.c</filename>
in the <filename>src/tutorial</filename> directory of the source distribution.
See the <filename>README</filename> file in that directory for instructions
about running the examples.
</para>
<para>
<indexterm>
<primary>input function</primary>
</indexterm>
<indexterm>
<primary>output function</primary>
</indexterm>
A user-defined type must always have input and output functions.
These functions determine how the type appears in strings (for input
by the user and output to the user) and how the type is organized in
memory. The input function takes a null-terminated character string
as its argument and returns the internal (in memory) representation
of the type. The output function takes the internal representation
of the type as argument and returns a null-terminated character
string. If we want to do anything more with the type than merely
store it, we must provide additional functions to implement whatever
operations we'd like to have for the type.
</para>
<para>
Suppose we want to define a type <type>complex</type> that represents
complex numbers. A natural way to represent a complex number in
memory would be the following C structure:
<programlisting>
typedef struct Complex {
double x;
double y;
} Complex;
</programlisting>
We will need to make this a pass-by-reference type, since it's too
large to fit into a single <type>Datum</type> value.
</para>
<para>
As the external string representation of the type, we choose a
string of the form <literal>(x,y)</literal>.
</para>
<para>
The input and output functions are usually not hard to write,
especially the output function. But when defining the external
string representation of the type, remember that you must eventually
write a complete and robust parser for that representation as your
input function. For instance:
<programlisting><![CDATA[
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 type %s: \"%s\"",
"complex", str)));
result = (Complex *) palloc(sizeof(Complex));
result->x = x;
result->y = y;
PG_RETURN_POINTER(result);
}
]]>
</programlisting>
The output function can simply be:
<programlisting><![CDATA[
PG_FUNCTION_INFO_V1(complex_out);
Datum
complex_out(PG_FUNCTION_ARGS)
{
Complex *complex = (Complex *) PG_GETARG_POINTER(0);
char *result;
result = psprintf("(%g,%g)", complex->x, complex->y);
PG_RETURN_CSTRING(result);
}
]]>
</programlisting>
</para>
<para>
You should be careful to make the input and output functions inverses of
each other. If you do not, you will have severe problems when you
need to dump your data into a file and then read it back in. This
is a particularly common problem when floating-point numbers are
involved.
</para>
<para>
Optionally, a user-defined type can provide binary input and output
routines.