Base Types in C-Language Functions

The following table gives the C type required for parameters in the C functions that will be loaded into PostgreSQL. The "Defined In" column gives the actual header file (in the PGROOT/src/backend/ directory) where the equivalent C type is defined. Note that you should always include postgres.h first, and that in turn includes c.h.

Table 10-1. Equivalent C Types for Built-In PostgreSQL Types

Built-In TypeC TypeDefined In
abstimeAbsoluteTimeutils/nabstime.h
booleanboolpostgres.h (maybe compiler built-in)
box(BOX *)utils/geo-decls.h
bytea(bytea *)postgres.h
"char"char(compiler built-in)
characterBpChar*postgres.h
cidCIDpostgres.h
dateDateADTutils/date.h
smallint (int2)int2 or int16postgres.h
int2vectorint2vector*postgres.h
integer (int4)int4 or int32postgres.h
real (float4)float4*postgres.h
double precision (float8)float8*postgres.h
intervalInterval*utils/timestamp.h
lsegLSEG*utils/geo-decls.h
nameNamepostgres.h
oidOidpostgres.h
oidvectoroidvector*postgres.h
pathPATH*utils/geo_decls.h
pointPOINT*utils/geo_decls.h
regprocregprocpostgres.h
reltimeRelativeTimeutils/nabstime.h
texttext*postgres.h
tidItemPointerstorage/itemptr.h
timeTimeADTutils/date.h
time with time zoneTimeTzADTutils/date.h
timestampTimestamp*utils/timestamp.h
tintervalTimeIntervalutils/nabstime.h
varcharVarChar*postgres.h
xidTransactionIdpostgres.h

Internally, PostgreSQL regards a base type as a "blob of memory." The user-defined functions that you define over a type in turn define the way that PostgreSQL can operate on it. That is, PostgreSQL will store and retrieve only the data from disk and use your user-defined functions to input, process, and output the data. Base types can have one of three internal formats:

By-value types can be only 1, 2 or 4 bytes in length (also 8 bytes, if sizeof(Datum) is 8 on your machine). You should be careful to define your types such that they will be the same size (in bytes) on all architectures. For example, the long type is dangerous because it is 4 bytes on some machines and 8 bytes on others, whereas int type is 4 bytes on most Unix machines (though not on most personal computers). A reasonable implementation of the int4 type on Unix machines might be:
/* 4-byte integer, passed by value */
typedef int int4;

On the other hand, fixed-length types of any size may be passed by-reference. For example, here is a sample implementation of a PostgreSQL type:
/* 16-byte structure, passed by reference */
typedef struct
{
    double  x, y;
} Point;

Only pointers to such types can be used when passing them in and out of PostgreSQL functions. To return a value of such a type, allocate the right amount of memory with palloc(), fill in the allocated memory, and return a pointer to it. (Alternatively, you can return an input value of the same type by returning its pointer. Never modify the contents of a pass-by-reference input value, however.)

Finally, all variable-length types must also be passed by reference. All variable-length types must begin with a length field of exactly 4 bytes (VARHDRSZ), and all data to be stored within that type must be located in the memory immediately following that length field. The length field is the total length of the structure (that is, it includes the size of the length field itself). We could define the text type as follows:
typedef struct 
{
    int4 length;
    char data[1];
} text;

Obviously, the data field declared here is not long enough to hold all possible strings. Since it is impossible to declare a variable-size structure in C, we rely on the knowledge that the C compiler won't range-check array subscripts. We just allocate the necessary amount of space and then access the array as if it were declared the right length. (If this isn't a familiar trick to you, you may wish to spend some time with an introductory C programming textbook before delving deeper into PostgreSQL server programming.) When manipulating variable-length types, we must be careful to allocate the correct amount of memory and set the length field correctly. For example, if we wanted to store 40 bytes in a text structure, we might use a code fragment like this:

#include "postgres.h"

...
char buffer[40]; /* our source data */
...
text *destination = (text *) palloc(VARHDRSZ + 40);
destination->length = VARHDRSZ + 40;
memcpy(destination->data, buffer, 40);
...

VARHDRSZ is the same as sizeof(int4), but it's considered good style to use the macro VARHDRSZ to refer to the size of the overhead for a variable-length type.

Now that we've gone over all of the possible structures for base types, we can show some examples of real functions.