2003-04-10 03:22:45 +02:00
|
|
|
<!--
|
|
|
|
$Header: /cvsroot/pgsql/doc/src/sgml/xtypes.sgml,v 1.17 2003/04/10 01:22:45 petere Exp $
|
|
|
|
-->
|
|
|
|
|
|
|
|
<sect1 id="xtypes">
|
|
|
|
<title>User-Defined Types</title>
|
2001-05-13 00:51:36 +02:00
|
|
|
|
|
|
|
<indexterm zone="xtypes">
|
|
|
|
<primary>data types</primary>
|
|
|
|
<secondary>extending</secondary>
|
|
|
|
</indexterm>
|
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<comment>
|
2003-04-10 03:22:45 +02:00
|
|
|
This section needs to be updated for the version-1 function manager
|
2002-01-07 03:29:15 +01:00
|
|
|
interface.
|
|
|
|
</comment>
|
|
|
|
|
2000-05-02 22:02:03 +02:00
|
|
|
<para>
|
2003-04-10 03:22:45 +02:00
|
|
|
As described above, there are two kinds of data types in
|
|
|
|
<productname>PostgreSQL</productname>: base types and composite
|
|
|
|
types. This section describes how to define new base types.
|
2000-05-02 22:02:03 +02:00
|
|
|
</para>
|
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<para>
|
|
|
|
The examples in this section can be found in
|
|
|
|
<filename>complex.sql</filename> and <filename>complex.c</filename>
|
2003-04-10 03:22:45 +02:00
|
|
|
in the tutorial directory.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<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
|
2003-04-10 03:22:45 +02:00
|
|
|
as its argument and returns the internal (in memory) representation of
|
2002-01-07 03:29:15 +01:00
|
|
|
the type. The output function takes the internal representation of
|
2003-04-10 03:22:45 +02:00
|
|
|
the type as argument and returns a null-terminated character string.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2003-04-10 03:22:45 +02:00
|
|
|
Suppose we want to define a type <type>complex</> that represents
|
|
|
|
complex numbers. A natural way to to represent a complex number in
|
|
|
|
memory would be the following C structure:
|
2002-01-07 03:29:15 +01:00
|
|
|
|
|
|
|
<programlisting>
|
2000-05-02 22:02:03 +02:00
|
|
|
typedef struct Complex {
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
} Complex;
|
2002-01-07 03:29:15 +01:00
|
|
|
</programlisting>
|
|
|
|
|
2003-04-10 03:22:45 +02:00
|
|
|
As the external string representation of the type, we choose a
|
|
|
|
string of the form <literal>(x,y)</literal>.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2003-04-10 03:22:45 +02:00
|
|
|
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:
|
2002-01-07 03:29:15 +01:00
|
|
|
|
|
|
|
<programlisting>
|
2000-05-02 22:02:03 +02:00
|
|
|
Complex *
|
|
|
|
complex_in(char *str)
|
|
|
|
{
|
|
|
|
double x, y;
|
|
|
|
Complex *result;
|
2003-04-10 03:22:45 +02:00
|
|
|
|
|
|
|
if (sscanf(str, " ( %lf , %lf )", &x, &y) != 2)
|
|
|
|
{
|
2000-08-25 01:59:38 +02:00
|
|
|
elog(ERROR, "complex_in: error in parsing %s", str);
|
2000-05-02 22:02:03 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
2003-04-10 03:22:45 +02:00
|
|
|
result = (Complex *) palloc(sizeof(Complex));
|
2000-05-02 22:02:03 +02:00
|
|
|
result->x = x;
|
|
|
|
result->y = y;
|
2003-04-10 03:22:45 +02:00
|
|
|
return result;
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
2002-01-07 03:29:15 +01:00
|
|
|
</programlisting>
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2003-04-10 03:22:45 +02:00
|
|
|
The output function can simply be:
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<programlisting>
|
2000-05-02 22:02:03 +02:00
|
|
|
char *
|
|
|
|
complex_out(Complex *complex)
|
|
|
|
{
|
|
|
|
char *result;
|
2003-04-10 03:22:45 +02:00
|
|
|
|
2000-05-02 22:02:03 +02:00
|
|
|
if (complex == NULL)
|
|
|
|
return(NULL);
|
|
|
|
result = (char *) palloc(60);
|
|
|
|
sprintf(result, "(%g,%g)", complex->x, complex->y);
|
2003-04-10 03:22:45 +02:00
|
|
|
return result;
|
2000-05-02 22:02:03 +02:00
|
|
|
}
|
2002-01-07 03:29:15 +01:00
|
|
|
</programlisting>
|
2003-04-10 03:22:45 +02:00
|
|
|
</para>
|
2002-01-07 03:29:15 +01:00
|
|
|
|
2003-04-10 03:22:45 +02:00
|
|
|
<para>
|
|
|
|
You should try 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.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<para>
|
|
|
|
To define the <type>complex</type> type, we need to create the two
|
|
|
|
user-defined functions <function>complex_in</function> and
|
|
|
|
<function>complex_out</function> before creating the type:
|
|
|
|
|
|
|
|
<programlisting>
|
2002-08-22 02:01:51 +02:00
|
|
|
CREATE FUNCTION complex_in(cstring)
|
2000-05-02 22:02:03 +02:00
|
|
|
RETURNS complex
|
2003-04-10 03:22:45 +02:00
|
|
|
AS '<replaceable>filename</replaceable>'
|
2001-10-26 23:17:03 +02:00
|
|
|
LANGUAGE C;
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2002-08-22 02:01:51 +02:00
|
|
|
CREATE FUNCTION complex_out(complex)
|
|
|
|
RETURNS cstring
|
2003-04-10 03:22:45 +02:00
|
|
|
AS '<replaceable>filename</replaceable>'
|
2001-10-26 23:17:03 +02:00
|
|
|
LANGUAGE C;
|
2002-01-07 03:29:15 +01:00
|
|
|
</programlisting>
|
2003-04-10 03:22:45 +02:00
|
|
|
|
|
|
|
Notice that the declarations of the input and output functions must
|
|
|
|
reference the not-yet-defined type. This is allowed, but will draw
|
|
|
|
warning messages that may be ignored.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<para>
|
|
|
|
Finally, we can declare the data type:
|
|
|
|
<programlisting>
|
2000-05-02 22:02:03 +02:00
|
|
|
CREATE TYPE complex (
|
|
|
|
internallength = 16,
|
|
|
|
input = complex_in,
|
|
|
|
output = complex_out
|
|
|
|
);
|
2002-01-07 03:29:15 +01:00
|
|
|
</programlisting>
|
|
|
|
</para>
|
2000-05-02 22:02:03 +02:00
|
|
|
|
2002-01-07 03:29:15 +01:00
|
|
|
<para>
|
2003-04-10 03:22:45 +02:00
|
|
|
When you define a new base type,
|
2002-01-07 03:29:15 +01:00
|
|
|
<productname>PostgreSQL</productname> automatically provides support
|
2003-04-10 03:22:45 +02:00
|
|
|
for arrays of that
|
|
|
|
type.<indexterm><primary>array</primary><secondary>of user-defined
|
|
|
|
type</secondary></indexterm> For historical reasons, the array type
|
|
|
|
has the same name as the base type with the underscore character
|
|
|
|
(<literal>_</>) prepended.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2003-04-10 03:22:45 +02:00
|
|
|
If the values of your data type might exceed a few hundred bytes in
|
|
|
|
size (in internal form), you should mark them
|
|
|
|
TOAST-able.<indexterm><primary>TOAST</primary><secondary>and
|
|
|
|
user-defined types</secondary></indexterm> To do this, the internal
|
|
|
|
representation must follow the standard layout for variable-length
|
|
|
|
data: the first four bytes must be an <type>int32</type> containing
|
|
|
|
the total length in bytes of the datum (including itself). Also,
|
|
|
|
when running the <command>CREATE TYPE</command> command, specify the
|
|
|
|
internal length as <literal>variable</> and select the appropriate
|
|
|
|
storage option.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2003-04-10 03:22:45 +02:00
|
|
|
For further details see the description of the <command>CREATE
|
|
|
|
TYPE</command> command in <xref linkend="reference">.
|
2002-01-07 03:29:15 +01:00
|
|
|
</para>
|
2003-04-10 03:22:45 +02:00
|
|
|
</sect1>
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
|
|
Local variables:
|
|
|
|
mode:sgml
|
|
|
|
sgml-omittag:nil
|
|
|
|
sgml-shorttag:t
|
|
|
|
sgml-minimize-attributes:nil
|
|
|
|
sgml-always-quote-attributes:t
|
|
|
|
sgml-indent-step:1
|
|
|
|
sgml-indent-data:t
|
|
|
|
sgml-parent-document:nil
|
|
|
|
sgml-default-dtd-file:"./reference.ced"
|
|
|
|
sgml-exposed-tags:nil
|
|
|
|
sgml-local-catalogs:("/usr/lib/sgml/catalog")
|
|
|
|
sgml-local-ecat-files:nil
|
|
|
|
End:
|
|
|
|
-->
|