C言語で書かれた関数は動的にロード可能オブジェクト(シェアードライブラリ)に コンパイルすることができ、ユーザ定義されたSQL関数の実効の際に 使用されます。バックエンドセッションで、特定のロード可能 オブジェクトファイルで初めてユーザ定義関数が呼ばれた時、動的ローダは、 関数を呼び出し可能とするために、そのオブジェクトファイルをメモリにロードします。 したがって、ユーザ定義関数のためのCREATE FUNCTIONでは 関数に関する2つの情報、ロード可能オブジェクトファイル名と そのオブジェクトファイル内で呼び出すための、特定の関数のC言語名(リンクシンボル)、 を明記する必要があります。C言語名が明記されていない場合は、 SQL関数名と同じ関数名として認識されます。
Note: その関数が一度使用されたら、動的にロードされたユーザ関数はメモリに 記憶され、その関数が後に同じセッション内で呼ばれた時には シンボルテーブルを参照するための、極わずかなオーバーヘッドが かかるだけとなります。
オブジェクトファイルを指定する文字列(AS句の最初の文字列)は その関数のオブジェクトコードファイルの絶対パス であり、シングルクォーテーションで囲われている必要があります。 AS句でリンクシンボルが与えられている場合は、そのリンクシンボルも シングルクォーテーションで囲われている必要があり、 Cのソースコード内に記述されている関数名と全く等しくなければなりません。 Unixシステムのnmコマンドは、動的にロード可能な オブジェクトのすべてのリンクシンボルを表示させます。
Note: Postgresでは、自動的に関数を コンパイルしません。CREATE FUNCTIONコマンドで使用される前に コンパイルされる必要があります。詳細は下記をご覧下さい。
C言語関数では、現在2つの呼び出し規約が使用されています。 新しい"version 1"呼び出し規約は、下記のように、関数の PG_FUNCTION_INFO_V1()マクロ呼び出しを記述して 示されています。このようなマクロの欠如は古いスタイル("version 0")関数を 示します。CREATE FUNCTIONで指定された言語名は、どちらの場合ともC言語です。 古いスタイルの関数は、移植性の問題と機能の不足のために、 互換性の理由のためのみに現在存在しています。
下記のテーブルはPostgresにロードされるC言語関数の引数で 必要とされるC言語の型です。"Defined In"列では、同等のC言語の型が 定義されている実際のヘッダーファイル (.../src/backend/ディレクトリ)を示しています。 必ず始めにpostgres.hを含め、それが c.hを含めることにご注意下さい。
Table 13-1. Postgresの基本型(組み込まれている型)と同等なC言語型
組み込まれている型 | C言語型 | 定義場所 |
---|---|---|
abstime | AbsoluteTime | utils/nabstime.h |
bool | bool | include/c.h |
box | (BOX *) | utils/geo-decls.h |
bytea | (bytea *) | include/postgres.h |
"char" | char | N/A |
cid | CID | include/postgres.h |
datetime | (DateTime *) | include/c.h or include/postgres.h |
int2 | int2 or int16 | include/postgres.h |
int2vector | (int2vector *) | include/postgres.h |
int4 | int4 or int32 | include/postgres.h |
float4 | (float4 *) | include/c.h or include/postgres.h |
float8 | (float8 *) | include/c.h or include/postgres.h |
lseg | (LSEG *) | include/geo-decls.h |
name | (Name) | include/postgres.h |
oid | oid | include/postgres.h |
oidvector | (oidvector *) | include/postgres.h |
path | (PATH *) | utils/geo-decls.h |
point | (POINT *) | utils/geo-decls.h |
regproc | regproc or REGPROC | include/postgres.h |
reltime | RelativeTime | utils/nabstime.h |
text | (text *) | include/postgres.h |
tid | ItemPointer | storage/itemptr.h |
timespan | (TimeSpan *) | include/c.h or include/postgres.h |
tinterval | TimeInterval | utils/nabstime.h |
xid | (XID *) | include/postgres.h |
Postgresの内部では、基本型を "blob of memory(メモリの斑点)"と見なしています。 ある型について定義したユーザ定義関数は、同様に Postgresがその型をどのように 実装するかを定義しています。つまり、Postgresは データをディスクに保存し、ディスクからデータを受取り、 ユーザ定義関数でそのデータを入力値として受け取り、 処理/出力するために使用します。基本型は下記の3つのいずれかの 内部フォーマットを使用しています。
値として渡す。固定長
参照として渡す。固定長
参照として渡す。可変長
値として渡す型は1、2、又は4バイト長のみ可能です。 (使用するマシンのsizeof(Datum)が8の場合は8バイトも可能です。) データ型を定義する際、その型が全てのアーキテクチャにおいて 同一の大きさ(バイト数)となるように定義することに注意して下さい。 例えば、long型はマシンによっては4バイトであったり、 8バイトであったりして危険ですが、int型はほとんどの Unixマシンでは4バイトです(しかし、多くのパーソナルコンピュータでは異ります)。 Unixマシンの一般的なint4型の実装は 下記のようなものとなります。
/* 4-byte integer, passed by value */ typedef int int4;
一方、任意の大きさの固定長の型は参照として引き渡すことが 可能です。下記の、Postgresの型の 実装サンプルをご覧下さい。
/* 16-byte structure, passed by reference */ typedef struct { double x, y; } Point;
それらの型のポインタのみがPostgres関数の 入出力時に使用できます。それらの型を返すためには、palloc() を使用して正しい大きさのメモリ領域を割り当て、そのメモリ領域に 値を入力し、それのポインタを返します。(あるいは、ポインタを 返すことによって同じ型の入力値を返すことも可能です。しかし、 参照として渡すものの入力値の内容を決して変更しないで下さい。)
すべての可変長型は参照として引き渡す必要があります。 また、すべての可変長型は正確に4バイトのlengthフィールドから 必ず始まる必要があり、その型に格納されるすべてのデータは lengthフィールドのすぐ後のメモリ領域に置かれる必要があります。 lengthフィールドはその構造体の総長です。(つまり、lengthフィールド そのものもその大きさに含まれます。)text型を定義するには、 下記のように行えます。
typedef struct { int4 length; char data[1]; } text;
ここで示されているデータフィールドは、明かにすべての取り得る 文字列を保持できる長さではありません。C言語では このような構造を定義することは不可能です。可変長型を操作する場合、 正しいメモリ領域を割り当て、lengthフィールドを初期化しなければ なりません。例えば、text構造に40バイト保持したい場合は、 下記のようなコードを実行します。
#include "postgres.h" ... char buffer[40]; /* our source data */ ... text *destination = (text *) palloc(VARHDRSZ + 40); destination->length = VARHDRSZ + 40; memmove(destination->data, buffer, 40); ...
これで基本型用の全てのあり得る構造体についての説明が 完了しましたので、実 際の関数の例を幾つか示します。
まず最初に使用できませんが、理解しやすいので、 "古いスタイル(old style)"の呼び出し規約を記述します。 version-0メソッドでは、C言語関数の引数を結果は、通常のCのプログラムの 記述の方法と同じような形式で行いますが、上記の説明のように、 各SQLのデータ型を示すC言語を使用する際にはご注意下さい。
ここに例を記します。
#include "postgres.h" #include <string.h> /* By Value */ int add_one(int arg) { return arg + 1; } /* By Reference, Fixed Length */ float8 * add_one_float8(float8 *arg) { float8 *result = (float8 *) palloc(sizeof(float8)); *result = *arg + 1.0; return result; } Point * makepoint(Point *pointx, Point *pointy) { Point *new_point = (Point *) palloc(sizeof(Point)); new_point->x = pointx->x; new_point->y = pointy->y; return new_point; } /* By Reference, Variable Length */ text * copytext(text *t) { /* * VARSIZE is the total size of the struct in bytes. */ text *new_t = (text *) palloc(VARSIZE(t)); VARATT_SIZEP(new_t) = VARSIZE(t); /* * VARDATA is a pointer to the data region of the struct. */ memcpy((void *) VARDATA(new_t), /* destination */ (void *) VARDATA(t), /* source */ VARSIZE(t)-VARHDRSZ); /* how many bytes */ return new_t; } text * concat_text(text *arg1, text *arg2) { int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ; text *new_text = (text *) palloc(new_text_size); VARATT_SIZEP(new_text) = new_text_size; memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ); memcpy(VARDATA(new_text) + (VARSIZE(arg1)-VARHDRSZ), VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ); return new_text; }
上記のコードがfuncs.cというファイルに 予め用意され、シェアードオブジェクトにコンパイルされていたとし、 Postgresには下記のコマンドを 使って定義できます。
CREATE FUNCTION add_one(int4) RETURNS int4 AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c' WITH (isStrict); -- note overloading of SQL function name add_one() CREATE FUNCTION add_one(float8) RETURNS float8 AS 'PGROOT/tutorial/funcs.so', 'add_one_float8' LANGUAGE 'c' WITH (isStrict); CREATE FUNCTION makepoint(point, point) RETURNS point AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c' WITH (isStrict); CREATE FUNCTION copytext(text) RETURNS text AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c' WITH (isStrict); CREATE FUNCTION concat_text(text, text) RETURNS text AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c' WITH (isStrict);
ここでPGROOTはPostgresの ソースツリーの絶対パスを意味します。システムによっては、 シェアードオブジェクトのファイル名の拡張子が.so ではなく、.slの場合や、それ以外の可能性も あるので、システムによって変更しなければならないことにご注意下さい。
ここで、関数を"精密"と特定していることに注目して下さい。 それは、もし入力された値がNULLであった場合に、システムが自動的に 返り値がNULLであると推定しないことを意味します。これを 行うことによって、関数のコードで入力値がNULLであるかどうかの チェックを行う必要がありません。これがなければ、各参照渡しの要素に 対してそれがNULLのポインタであるかどうかのチェックを 行うなどの、NULLの明示的なチェックを行う必要性が出てきます。 (値渡しに関しては、チェックを行う方法は存在しません。)
これらの呼び出し規約は容易ですが、この方法は、int型のより 小さいデータ型を引き渡す部分で問題を抱えているアーキテクチャでは、 移植性の面ではあまり優れていません。また、関数の結果として NULLを返す簡単な方法はありません。その上、引数としてNULLを 処理する方法としては、関数を精密なものにする 以外方法はありません。次に説明のあるversion-1の規約では これらの問題が解決されています。
version-1の呼び出し規約では、引数と結果の引き渡しの複雑さを 無くすためにマクロを使用しています。version-1関数の C言語宣言は必ず下記のように行います。
Datum funcname(PG_FUNCTION_ARGS)また、下記のマクロの呼び出し
PG_FUNCTION_INFO_V1(funcname);が必ず同じソースファイルに書かれている必要があります (規約では、関数の直前で書かれています)。現在Postgresでは すべての内部関数はversion-1であると認識するので、 このマクロの呼び出しは内部言語関数では必要ありません。 しかし、動的にロードされる関数では必要です。
version-1関数では、それぞれの実際の引数は、引数の型に合った PG_GETARG_xxx()マクロ を使用して呼び出され、結果は返り型に合った PG_RETURN_xxx()マクロ を使用して返されます。
下記は上記と同じ関数をversion-1形式で記述したものです。
#include "postgres.h" #include <string.h> #include "fmgr.h" /* By Value */ PG_FUNCTION_INFO_V1(add_one); Datum add_one(PG_FUNCTION_ARGS) { int32 arg = PG_GETARG_INT32(0); PG_RETURN_INT32(arg + 1); } /* By Reference, Fixed Length */ PG_FUNCTION_INFO_V1(add_one_float8); Datum add_one_float8(PG_FUNCTION_ARGS) { /* The macros for FLOAT8 hide its pass-by-reference nature */ float8 arg = PG_GETARG_FLOAT8(0); PG_RETURN_FLOAT8(arg + 1.0); } PG_FUNCTION_INFO_V1(makepoint); Datum makepoint(PG_FUNCTION_ARGS) { /* Here, the pass-by-reference nature of Point is not hidden */ Point *pointx = PG_GETARG_POINT_P(0); Point *pointy = PG_GETARG_POINT_P(1); Point *new_point = (Point *) palloc(sizeof(Point)); new_point->x = pointx->x; new_point->y = pointy->y; PG_RETURN_POINT_P(new_point); } /* By Reference, Variable Length */ PG_FUNCTION_INFO_V1(copytext); Datum copytext(PG_FUNCTION_ARGS) { text *t = PG_GETARG_TEXT_P(0); /* * VARSIZE is the total size of the struct in bytes. */ text *new_t = (text *) palloc(VARSIZE(t)); VARATT_SIZEP(new_t) = VARSIZE(t); /* * VARDATA is a pointer to the data region of the struct. */ memcpy((void *) VARDATA(new_t), /* destination */ (void *) VARDATA(t), /* source */ VARSIZE(t)-VARHDRSZ); /* how many bytes */ PG_RETURN_TEXT_P(new_t); } PG_FUNCTION_INFO_V1(concat_text); Datum concat_text(PG_FUNCTION_ARGS) { text *arg1 = PG_GETARG_TEXT_P(0); text *arg2 = PG_GETARG_TEXT_P(1); int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ; text *new_text = (text *) palloc(new_text_size); VARATT_SIZEP(new_text) = new_text_size; memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ); memcpy(VARDATA(new_text) + (VARSIZE(arg1)-VARHDRSZ), VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ); PG_RETURN_TEXT_P(new_text); }
CREATE FUNCTIONコマンドは、 version-0同等と同じものです。
一見version-1のコードは無意味なものに見えるかもしれませんが、 マクロが必要のない情報を伏せているので、多数の改良が行われています。 例として、add_one_float8のコードでは、float8が参照渡しであることを 意識する必要が無くなっています。また別の例としては、可変長型の GETARGマクロは"toasted"値(圧縮、または行外)を呼び出す詳細を伏せます。 上記にある、古いスタイルのcopytext関数と concat_text関数は、toasted値としては、 入力にpg_detoast_datum()を使用しないので、 実際は誤ったものとなります。(古いスタイルの動的にロードされる関数 のハンドラーは、現在、この問題に対処していますが、 version-1関数で実行可能なことよりも劣ります。)
version-1関数の1つの大きな改善点は、NULLの入力/結果の 処理能力です。PG_ARGISNULL(n)マクロ関数は 各入力がNULLであるかどうかのテストを可能としています。 (これは、"精密に"関数が定義されていない場合のみ必要です。) PG_GETARG_xxx()マクロでは、 入力された引数は始まり値をゼロとし、数え上げられます。結果としてNULLを 返す場合は、PG_RETURN_NULL()を実行します。 これは、精密/精密でない関数の両方で使用可能です。
version-1関数呼び出し規約では、"セット(set)"の 結果を返すことが可能で、トリガ関数と手続型言語の呼び出しハンドラを 実行しています。また、Version-1コードはANSI C制約が関数呼び出しプロトコルで 守られているので、version-0よりも移植性があります。 詳細はソースディストリビューションの src/backend/utils/fmgr/READMEをご覧下さい。
複合型では、C言語のような固定のレイアウトがありません。 複合型のインスタンスはNULLフィールドを持つ可能性があります。 また、複合型で、継承階層の一部であるものは同じ継承の階層の 他のメンバとは異なるフィールドを持つ可能性もあります。 そのため、Postgresは C言語から複合型のフィールドにアクセスするための手続きの インタフェースを提供します。Postgres が行の集合を処理するにつれ、各行は不明瞭なTUPLE 型の構造体として引き渡されます。下記の問い合わせを答える 関数を書こうとしていると仮定します。
SELECT name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'Bill' OR name = 'Sam';上記の問い合わせでは、 c_overpaidを下記のように定義することが できます。
#include "postgres.h" #include "executor/executor.h" /* for GetAttributeByName() */ bool c_overpaid(TupleTableSlot *t, /* the current row of EMP */ int32 limit) { bool isnull; int32 salary; salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull)); if (isnull) return (false); return salary > limit; } /* In version-1 coding, the above would look like this: */ PG_FUNCTION_INFO_V1(c_overpaid); Datum c_overpaid(PG_FUNCTION_ARGS) { TupleTableSlot *t = (TupleTableSlot *) PG_GETARG_POINTER(0); int32 limit = PG_GETARG_INT32(1); bool isnull; int32 salary; salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull)); if (isnull) PG_RETURN_BOOL(false); /* Alternatively, we might prefer to do PG_RETURN_NULL() for null salary */ PG_RETURN_BOOL(salary > limit); }
GetAttributeByNameは、現在の行から属性を返す、 Postgresシステム関数です。これには3つの 引数があります。それらはTupleTableSlot*型が関数に 引き渡された時の引数、求められた属性の名前、属性がNULLであるかどうかの 返りパラメーターです。GetAttributeByNameは 適切なDatumGetXXX() マクロを使用して適切なデータ型に転換させれるデータの値を返します。
下記の問い合わせはPostgresに c_overpaid関数を認識させるものです。
CREATE FUNCTION c_overpaid(emp, int4) RETURNS bool AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
C言語を用いて、新しい行を作成したり、現存する行を変更させたりする 方法がありますが、このマニュアルで述べるには難易度がとても 高いので、省略します。
ここからは、より難易度の高い、プログラミング言語関数の 説明となります。注意して頂きたいのは、このセクションの主旨は、 プログラマを養成することではありません。 PostgresでC関数を 書く前に、C言語についてよく理解している (ポインタやmallocメモリ管理も含めて)必要があります。 C言語以外の言語で記述した関数を Postgresに組み込むことは可能ですが、 例えばFORTRANやPascalといった 言語はC言語と同じ呼び出し規定 ではないので、多くの場合、困難です。それはつまり、 他の言語では同じ方法で引数を渡したり結果を返すことを行わないという ことです。このため、プログラミング言語関数はC 言語で書かれているものと仮定します。
C関数を作成する時の基本的な規則は下記のものです。
適切なヘッダー(インクルード)ファイルが /usr/local/pgsql/include、もしくはそれと 同等な場所にインストールされている必要があります。 ご利用のシステム(または利用予定のシステム)での場所は pg_config --includedir を使用して 見つけることが可能です。とても低レベルの作業を行うには、 完全なPostgreSQLのソースツリーが 必要になるかもしれません。
メモリを割り当てる際、Cライブラリの mallocとfreeではなく、 Postgresのpallocと pfreeを使用して下さい。 pallocで割り当てられたメモリは 各トランザクションの終りに自動的に解放され、メモリリークを 防ぎます。
memsetまたはbzeroを 使用して、構造を必ずゼロクリアにして下さい。複数のルーチン (ハッシュアクセスメソッド、ハッシュ結合、ソートアルゴリズム)は 構造に含まれている生のビットの関数を計算します。すべての フィールドを初期化しても必要の無い値を持っている、 数バイトの提携されたものが残っている可能性があります。
ほとんどのPostgresの内部型は postgres.hに定義されています。 一方、関数管理インターフェース(PG_FUNCTION_ARGSなど)は fmgr.hで定義されています。したがって、 おそらくこの2つのファイルは含める必要があります。 移植性に関する理由により、postgres.hを その他のシステムファイルよりも先に含めることをお勧めします。 postgres.hを含めると言うことは c.h、elog.h、 palloc.hも含めることとなります。
オブジェクトファイルで定義されているシンボル名は 互いに異る必要があり、また、PostgreSQL サーバ実行で定義されているものと異っている必要があります。 これに関するエラーが表示されたら、関数名、または変数を 変更する必要があります。
Postgresにオブジェクトコードを 動的にロードが可能とするためにオブジェクトコードを コンパイル/リンクする時には、特別なフラグが必ず必要となります。 その方法を特有のオペレーティングシステムで行う時の 詳細はSection 13.4.6を参照して下さい。
Cで書かれたPostgreSQLの拡張関数を使うためには、 コンパイルし、サーバの要求があった時に動的にロードできるように特別な方法で リンクする必要があります。正確に言うと、共有ライブラリ を作る必要があるのです。
詳しい情報は、オペレーティングシステムのドキュメント、特にCコンパイラ cc、リンクエディタ ld、を読んで ください。 更にPostgreSQLのソースコードに contribディレクトリにいくつか実例があります。しかし、 もしこれらの例に頼るとPostgreSQLソースコード の有効性に依存したモジュールが作られてしまいます。
共有ライブラリの作成は実行プログラムのリンクと似ています。まずソースファイルがオブジェクト ファイルにコンパイルされ、そのオブジェクトファイル同士がリンクされるのです。 これらのオブジェクトファイルはポジションインディペンデントコード (PIC)として作られる必要があります。それは概念的には、実行プログラム から呼び出される時にメモリの適当な場所に置くことができるということです。 (実行プログラムとして作られたオブジェクトファイルはそのようにはコンパイル されません。)少なくとも理論上では、共有ライブラリをリンクするコマンドは実行プログラムの リンクと区別するための特別なフラグを持っています。他のシステムではもっとわかりにくい物も あります。
次の例ではソースコードはファイルfoo.cにあるものと 仮定し、foo.soという共有ライブラリを作ります。 中間のオブジェクトファイルは特別な記述がない限りfoo.oと と呼ばれます。共有ライブラリは一つ以上のオブジェクトファイルを持つことが できますが、ここでは一つしか使われていません。
PICを作るコンパイラフラグは-fpic です。共有ライブラリを作るリンカフラグは-sharedです。
gcc -fpic -c foo.c ld -shared -o foo.so foo.oこれはBSD/OSのバージョン4.0に適用されます。
PICを作るコンパイラフラグは-fpic です。共有ライブラリを作るリンカフラグは-sharedです。
gcc -fpic -c foo.c gcc -shared -o foo.so foo.oこれはFreeBSDのバージョン3.0に適用されます。
PICを作るためのシステムコンパイラのコンパイラ フラグは+zです。GCC を使う場合は-fpicです。共有ライブラリのための リンカフラグは-bです。ですから
cc +z -c foo.cもしくは
gcc -fpic -c foo.cそして
ld -b -o foo.sl foo.oHP-UXは、他のほとんどのシステムと 違い共有ライブラリに.slという拡張子を使います。
PICがデフォルトで、特別なコンパイラ オプションは何も必要ありません。共有ライブラリを作るための リンカーオプションは-sharedです。
cc -c foo.c ld -shared -o foo.so foo.o
PIC を作るためのコンパイラフラグは -fpicです。いくつかのプラットフォームでは 状況によって-fpicが動かない場合 -fPICを使わなければいけません。さらに詳しい 情報については GCC マニュアルを参照して下さい。共有ライブラリ を作るコンパイラフラグは-sharedです。 完全な例は下記のようになります。
cc -fpic -c foo.c cc -shared -o foo.so foo.o
PIC を作るためのコンパイラフラグは -fpicです。ELFシステムでは フラグ-sharedがついたコンパイラが 共有ライブラリをリンクするために使われます。より古い非 ELF システムではld -Bshareableが使われます。
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
PIC を作るためのコンパイラフラグは -fpicです。共有ライブラリをリンクするためには ld -Bshareable が使われます。
gcc -fpic -c foo.c ld -Bshareable -o foo.so foo.o
PICがデフォルトですから、コンパイルのコマンド は通常のままでよいです。リンクするためには特別なオプションがついた ldが使われます。
cc -c foo.c ld -shared -expect_unresolved '*' -o foo.so foo.oシステムコンパイラの代わりに、GCC と一緒に同じプロシージャが使われます。 特別なオプションは要求されません。
PIC を作るためのコンパイラフラグは Sun コンパイラでは-KPICで、 GCCでは-fpic です。共有ライブラリをリンクするためには、どちらのコンパイラ でも-Gで、GCC では代わりに-sharedです。
cc -KPIC -c foo.c cc -G -o foo.so foo.oor
gcc -fpic -c foo.c gcc -G -o foo.so foo.o
PICを作るためのコンパイラフラグは SCO コンパイラでは-KPICで、 GCCでは-fpic です。共有ライブラリのリンクには、SCO コンパイラでは -Gで、GCCでは -shared です。
cc -K PIC -c foo.c cc -G -o foo.so foo.oor
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
Tip: もし作った拡張モジュールをより広く配布するためのパッケージ にしたい場合、GNU Libtoolを共有ライブラリの構築に使う ことを見当するべきです。これはプラットフォームの違いを 一般的で力強いインタフェースにカプセル化します。 真剣なパッケージ作成はさらにライブラリバージョン、シンボル 分解メソッド、その他の検討も必要になります。
その結果できた共有メモリファイルはPostgres にロードすることができます。CREATE FUNCTIONコマンド にファイル名を指定する時は、単純なオブジェクトファイルではなく 共有ライブラリ名の名前(.soで終るもの)を 渡して下さい。
Note: 実際はPostgresはそのファイルが 共有ライブラリファイルである限り名前が何であっても構いません。