2000-05-02 22:02:03 +02:00
|
|
|
<chapter id="xtypes">
|
|
|
|
<title>Extending <acronym>SQL</acronym>: Types</title>
|
2001-05-13 00:51:36 +02:00
|
|
|
|
|
|
|
<indexterm zone="xtypes">
|
|
|
|
<primary>data types</primary>
|
|
|
|
<secondary>extending</secondary>
|
|
|
|
</indexterm>
|
|
|
|
|
2000-05-02 22:02:03 +02:00
|
|
|
<para>
|
|
|
|
As previously mentioned, there are two kinds of types
|
2001-11-21 07:09:45 +01:00
|
|
|
in <productname>PostgreSQL</productname>: base types (defined in a programming language)
|
2001-01-14 00:58:55 +01:00
|
|
|
and composite types.
|
2001-05-17 23:50:18 +02:00
|
|
|
Examples in this section up to interfacing indexes can
|
2000-05-02 22:02:03 +02:00
|
|
|
be found in <filename>complex.sql</filename> and <filename>complex.c</filename>. Composite examples
|
|
|
|
are in <filename>funcs.sql</filename>.
|
|
|
|
</para>
|
|
|
|
|
2000-09-29 22:21:34 +02:00
|
|
|
<sect1 id="xtypes-userdefined">
|
2000-05-02 22:02:03 +02:00
|
|
|
<title>User-Defined Types</title>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>Functions Needed for a User-Defined Type</title>
|
|
|
|
<para>
|
1998-03-01 09:16:16 +01:00
|
|
|
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-delimited character string
|
|
|
|
as its input and returns the internal (in memory)
|
|
|
|
representation of the type. The output function takes the
|
|
|
|
internal representation of the type and returns a null
|
|
|
|
delimited character string.
|
|
|
|
Suppose we want to define a complex type which represents
|
|
|
|
complex numbers. Naturally, we choose to represent a
|
2000-05-02 22:02:03 +02:00
|
|
|
complex in memory as the following <acronym>C</acronym> structure:
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
typedef struct Complex {
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
} Complex;
|
|
|
|
</programlisting>
|
|
|
|
|
1998-03-01 09:16:16 +01:00
|
|
|
and a string of the form (x,y) as the external string
|
|
|
|
representation.
|
|
|
|
These functions are usually not hard to write, especially
|
|
|
|
the output function. However, there are a number of points
|
|
|
|
to remember:
|
|
|
|
|
2000-05-02 22:02:03 +02:00
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
|
|
<para> When defining your external (string) representation,
|
|
|
|
remember that you must eventually write a
|
|
|
|
complete and robust parser for that representation
|
|
|
|
as your input function!
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
Complex *
|
|
|
|
complex_in(char *str)
|
|
|
|
{
|
|
|
|
double x, y;
|
|
|
|
Complex *result;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
result = (Complex *)palloc(sizeof(Complex));
|
|
|
|
result->x = x;
|
|
|
|
result->y = y;
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
The output function can simply be:
|
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
char *
|
|
|
|
complex_out(Complex *complex)
|
|
|
|
{
|
|
|
|
char *result;
|
|
|
|
if (complex == NULL)
|
|
|
|
return(NULL);
|
|
|
|
result = (char *) palloc(60);
|
|
|
|
sprintf(result, "(%g,%g)", complex->x, complex->y);
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
</programlisting>
|
|
|
|
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
<listitem>
|
|
|
|
<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 (say, into someone else's database on
|
|
|
|
another computer). This is a particularly common
|
|
|
|
problem when floating-point numbers are
|
|
|
|
involved.
|
|
|
|
</para>
|
|
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
|
|
</para>
|
|
|
|
<para>
|
|
|
|
To define the <acronym>complex</acronym> type, we need to create the two
|
1998-03-01 09:16:16 +01:00
|
|
|
user-defined functions complex_in and complex_out
|
|
|
|
before creating the type:
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
<programlisting>
|
|
|
|
CREATE FUNCTION complex_in(opaque)
|
|
|
|
RETURNS complex
|
2001-10-26 23:17:03 +02:00
|
|
|
AS '<replaceable>PGROOT</replaceable>/tutorial/complex'
|
|
|
|
LANGUAGE C;
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
CREATE FUNCTION complex_out(opaque)
|
|
|
|
RETURNS opaque
|
2001-10-26 23:17:03 +02:00
|
|
|
AS '<replaceable>PGROOT</replaceable>/tutorial/complex'
|
|
|
|
LANGUAGE C;
|
2000-05-02 22:02:03 +02:00
|
|
|
|
|
|
|
CREATE TYPE complex (
|
|
|
|
internallength = 16,
|
|
|
|
input = complex_in,
|
|
|
|
output = complex_out
|
|
|
|
);
|
|
|
|
</programlisting>
|
|
|
|
</para>
|
|
|
|
|
|
|
|
<para>
|
2001-11-21 07:09:45 +01:00
|
|
|
As discussed earlier, <productname>PostgreSQL</productname> fully supports arrays of
|
|
|
|
base types. Additionally, <productname>PostgreSQL</productname> supports arrays of
|
1998-03-01 09:16:16 +01:00
|
|
|
user-defined types as well. When you define a type,
|
2001-11-21 07:09:45 +01:00
|
|
|
<productname>PostgreSQL</productname> automatically provides support for arrays of
|
1998-03-01 09:16:16 +01:00
|
|
|
that type. For historical reasons, the array type has
|
|
|
|
the same name as the user-defined type with the
|
|
|
|
underscore character _ prepended.
|
|
|
|
Composite types do not need any function defined on
|
|
|
|
them, since the system already understands what they
|
|
|
|
look like inside.
|
2000-05-02 22:02:03 +02:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
|
|
|
|
<sect2>
|
|
|
|
<title>Large Objects</title>
|
1998-03-01 09:16:16 +01:00
|
|
|
|
2000-05-02 22:02:03 +02:00
|
|
|
<para>
|
2000-08-25 01:59:38 +02:00
|
|
|
If the values of your datatype might exceed a few hundred bytes in
|
|
|
|
size (in internal form), you should be careful to mark them TOASTable.
|
|
|
|
To do this, the internal representation must follow the standard
|
|
|
|
layout for variable-length data: the first four bytes must be an int32
|
|
|
|
containing the total length in bytes of the datum (including itself).
|
|
|
|
Then, all your functions that accept values of the type must be careful
|
|
|
|
to call pg_detoast_datum() on the supplied values --- after checking
|
|
|
|
that the value is not NULL, if your function is not strict. Finally,
|
|
|
|
select the appropriate storage option when giving the CREATE TYPE
|
|
|
|
command.
|
2000-05-02 22:02:03 +02:00
|
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
|
|
|
|
<!-- 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:
|
|
|
|
-->
|