How to create a PostgreSQL function calling Mac OS X frameworks ?

Thursday, July 08 2004 @ 10:44 PM BST

Contributed by: unix

I need to call some Foundation code from a new external PostgreSQL function, how to set-up my make files and how to avoid the compilation errors when including Foundation headers ?

The errors at compile time are generated by a conflictingSize data type declared both by PosgreSQL (in header "c.h") and by MacTypes.h.
The only way to solve the problem is to split your code in two parts: a glue file will contain all your PostgreSQL specific code (the entry points of your library) that will pop the arguments and cast/convert them to external functions that will do the real job (calling Foundation).
These functions will be in another source files and of course must not depend on PostgreSQL headers. The result of the functions will be converted (if needed) back into the expected result type for the PostgreSQL backend.
Example with an external function generating an Universal ID:
The PostgreSQL glue:

#include "postgres.h"

#include "fmgr.h"				/* for argument/result macros */
#include "cfuuid.h"				/* our "real" job functions */

Datum	uuid_createstr(PG_FUNCTION_ARGS);


Datum uuid_createstr(PG_FUNCTION_ARGS)
	BpChar *result = (BpChar *) palloc( sizeof(int) + 60 ); // 60 is big enough for a CFUUID string
	cfuuid_createstr( result->vl_dat, 60 )	;
	result->vl_len = strlen( result->vl_dat )	;
The header declaring our "real" function:

#ifndef _CFUUID_H_
#define _CFUUID_H_

void 	cfuuid_createstr(char *outBuffer, int inLen);

The code performing the real job:

#include "cfuuid.h"

#include <CoreFoundation/CFUUID.h>

void cfuuid_createstr(char *outBuffer, int inLen)
	CFUUIDRef uuidRef = CFUUIDCreate( kCFAllocatorDefault )	;
	CFStringRef	stringRef = CFUUIDCreateString( kCFAllocatorDefault, uuidRef)	;
	CFStringGetCString( stringRef, outBuffer, inLen, kCFStringEncodingASCII);
	CFRelease(stringRef)	;
	CFRelease(uuidRef)	;
Assuming you put the source code in ../src/tutorial of the PostgreSQL source distribution, you compile with:

gcc -no-cpp-precomp -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declarations 
 -I../../src/include -I/usr/include -c -o uuid.o uuid.c
gcc -no-cpp-precomp -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declarations  
-I../../src/include -I/usr/include -c -o cfuuid.o cfuuid.c
gcc -no-cpp-precomp -framework Foundation -bundle -o uuid.o cfuuid.o 
-bundle_loader ../../src/backend/postgres
You install the dynamic library as usual for your set-up (example: sudo cp /usr/local/pgsql/lib).

The installation of the function in a database is as usual: (change /usr/local/pgsql/lib/ to where you put the library on your system)
CREATE FUNCTION uuid_createstr() RETURNS character AS '/usr/local/pgsql/lib/uuid' LANGUAGE C IMMUTABLE STRICT ;
Executing select uuid_createstr(); will return something like