31.9. C ���Ժ���

�û�����ĺ��������� C д����������Щ������ C ���ݵ����ԣ����� C++���� �����ĺ����DZ�����ɶ�̬װ�صĶ���ģ�Ҳ��������⣩�������ɷ�����������Ҫװ�صġ� ��̬װ�ص������� "C ����" ������"�ڲ�"����֮���໥����ĵط� — ʵ�ʵı���ϰ��������֮��ʵ������һ���ġ� ����ˣ���׼���ڲ�������Ϊд�û����� C �����ṩ�˴�����õ���������

Ŀǰ�� C ���������ֵ��ô�ͳ���µ�"�汾 1"�ĵ��ô�ͳ��ͨ��Ϊ�ú�����дһ�� PG_FUNCTION_INFO_V1() ������ʶ�ģ���������ʾ��������ȱ��������ʶһ���Ϸ��ģ�"�汾 0"�������� ���ַ������CREATE FUNCTION�������Ķ��� C�� �����Ϸ��ĺ����Ѿ������ˣ���Ҫ����Ϊ��ֲ��ԭ���ȱ�����ܣ� �������ڼ�����ԭ��ϵͳ��Ȼ֧������

31.9.1. ��̬װ��

��ij���ض��Ŀ�װ�ض����ļ�����û�����ĺ�����һ�α��������Ự����ʱ�� ��̬װ�����Ѻ�����Ŀ����װ�����ڴ档 ��ˣ������û������ C ������ CREATE FUNCTION����Ϊ����������������Ϣ�� ��װ�ض����ļ����֣��������������Ǹ�Ŀ���ļ�����õĺ����� C ���֣����ӷ��ţ��� ���û����ȷ����C���֣���ô�ͼ�������SQL��������ͬ��

������ CREATE FUNCTION �����и���������, ������㷨���ڶ�λ��������ļ���

  1. ���������һ������·��������װ�ظ������ļ���

  2. ����������ִ� $libdir ��ͷ�� ��ô�ò��ֽ���PostgreSQL��Ŀ¼�����棬 ��Ŀ¼����������ʱ���ж��ġ�

  3. ������ֲ�����Ŀ¼���֣���ô�����ñ��� dynamic_library_path ��������·������ҡ�

  4. ����û����·�����ҵ����ļ�������������һ���Ǿ���Ŀ¼���֣��� ��ô��̬װ�����ͻ���ͼ�����������װ�أ������������Կ϶���Ҫʧ�ܵġ���������ǰ����Ŀ¼�Dz��ɿ��ġ���

������˳�򲻹��ã���ô�͸�������������ָ�����ƽ̨��صĹ�����ļ�����չ��ͨ���� .so���� Ȼ�������°�������Ĺ�����һ�㡣�������ʧ�ܣ���ôװ��ʧ�ܡ�

ע��: PostgreSQL ����������ʱ���û� ID ������Ա���·����������װ�ص��ļ���һ�������Ĵ�����ǰѸ��ļ�����һ���߲�Ŀ¼��Ȩ������Ϊ postgres �û����ɶ���/����ִ�С�

���κ�����£��� CREATE FUNCTION ������������ļ�������ϵͳ���ﰴ���ı���¼�ģ���ˣ� �����Ҫ�ٴ�װ�أ���ô���ٴ�����������̡�

ע��: PostgreSQL �����Զ�����һ�������� ��ʹ�� CREATE FUNCTION ����֮ǰ������������ ���� Section 31.9.6 ��ȡ������Ϣ��

ע��: �ڵ�һ��ʹ��֮�����ڴ��ж�̬װ����һ��Ŀ���ļ��� ��ͬһ�λỰ�еĺ�̵ĺ������ý�ֻ�������С�ķ��ű��ѯ�Ĺ��ȡ� �������Ҫǿ�ƶ����ļ������أ����������±����˸��ļ�����ô����ʹ�� LOAD ������߿�ʼһ���µĻỰ��

���ǽ���ʹ���� $libdir ��Ե�Ŀ¼����ͨ����̬��·����λ����⡣����������°汾��װ��һ����ͬ�� λ�ã���ô�Ϳ��Լ򻯰汾������$libdir ��ʾ��ʵ��Ŀ¼λ�ÿ��������� pg_config --pkglibdir �ҵ���

�� PostgreSQL �汾 7.2 ֮ǰ�� ����ֻ���� CREATE FUNCTION ������Ŀ���ļ���׼ȷ�ľ���·���� Ŀǰ��������Ѿ���ʱ�ˣ���Ϊ������������������IJ�����ֲ�� �����ֻ�������������֣�����·����Ҳû����չ����Ȼ�������������ṩ��Щ��Ϣ��

31.9.2. �������͵� C ���Ժ���

Ҫ֪�����д C ���Եĺ���������Ҫ֪�� PostgreSQL ���ڲ�����α��ֻ����������͵ģ��Լ���������δ��뺯���Լ����������ġ� PostgreSQL �ڲ��ѻ������͵���"һƬ�ڴ�"������ ������ij�������ϵ��û����庯��ʵ���϶����� PostgreSQL �ԣ����������ͣ����ܵIJ����� Ҳ����˵��PostgreSQL ֻ�ǴӴ��̶�ȡ�ʹ洢���������ͣ� ��ʹ���㶨��ĺ��������룬�����������ݡ��������Ϳ��������������ڲ���̬����ʽ��֮һ��

������ֵ�����͵ij���ֻ����1��2 �� 4 �ֽڡ� ������ 8 �ֽڣ���� sizeof(Datum) ����Ļ������� 8 �Ļ������� ��Ҫ��ϸ����������ͣ�ȷ���������κ���ϵƽ̨�϶�����ͬ�ߴ磨�ֽڣ��� ���磬long ����һ��Σ�յ�������Ϊ��һЩ���������� 4 �ֽڶ�������һЩ�������� 8 �ֽڣ� �� int���ڴ���� Unix �����϶���4�ֽڵġ� ��һ�� Unix �����ϵ� integer �����ʵ�ֿ����ǣ�

/* 4-�ֽ���������ֵ */
typedef int integer;

���⣬�κγߴ�Ķ������Ͷ������Ǵ��������͡����磬������һ�� PostgreSQL ���͵�ʵ�֣�

/* 16-�ֽڽṹ���������� */
typedef struct
{
    double  x, y;
} Point;

ֻ��ʹ��ָ����Щ���͵�ָ������ PostgreSQL �����ﴫ��ʹ������ݡ� Ҫ�������������͵�ֵ���� palloc() ������ȷ�����Ĵ洢���������Щ�洢����Ȼ�󷵻�һ��ָ������ָ�롣 �����⣬�����ͨ������ָ��ķ�������һ������������ͬ���͵�ֵ�� ���ǣ����Բ�Ҫ �޸Ĵ������õ�������ֵ����

������б䳤����ͬ��Ҳֻ��ͨ���������õķ��������ݡ� ���б䳤���ͱ�����һ������ 4 �ֽڳ��ij�����ʼ�� �������д洢�ڸ����͵����ݱ�����ڽ����ų�����Ĵ洢�ռ�� �������ǽṹ��ȫ����Ҳ����˵��������������ij��ȡ�

���磬���ǿ��������淽������һ�� text ���ͣ�

typedef struct {
    integer length;
    char data[1];
} text;

��Ȼ������������������ij��Ȳ����Դ洢�κο��ܵ��ִ�����Ϊ�� C�в����������䳤�ȵĽṹ�� ������������������֪ʶ��C ����������������±���з�Χ��顣 ����ֻ��Ҫ�����㹻�Ŀռ䣬Ȼ������鵱���Ѿ�����Ϊ���ʳ��ȵı������ʡ� ������һ�����õļ��ɣ����������� C �Ľ̿����ж�������

������䳤����ʱ�����DZ�����ϸ������ȷ�Ĵ洢����������ȷ���ó����� ���磬�����������һ�� text �ṹ��洢 40 �ֽڣ� ���ǿ��ܻ�ʹ��������Ĵ���Ƭ�Σ�

#include "postgres.h"
...
char buffer[40]; /* ���ǵ�Դ���� */
...
text *destination = (text *) palloc(VARHDRSZ + 40);
destination->length = VARHDRSZ + 40;
memcpy(destination->data, buffer, 40);
...

VARHDRSZ �� sizeof(int4) һ���� ����������Ϊ�ú� VARHDRSZ ��ʾ���ӳߴ������ڱ䳤���͵ĸ��õķ��

��Table 31-1 �г�����дһ��ʹ���� PostgreSQL �������͵� C ��������Ҫ��֪�����ĸ� SQL ���Ͷ�Ӧ�ĸ� C ���͡� "������" �и�������Ҫ�����Ի�ȡ�����Ͷ����ͷ�ļ���ʵ�ʵĶ���������ڰ������г����ļ����������ļ��С� ���ǽ����û�ֻʹ�����ﶨ��Ľӿڡ��� ע�⣬��Ӧ���������Ȱ��� postgres.h�� ��Ϊ���������������Ҫ�Ķ�����

Table 31-1. ���ڽ������͵�Ч�� C ����

�ڽ����� C ���� ������
abstimeAbsoluteTimeutils/nabstime.h
booleanboolpostgres.h �������DZ��������ã�
boxBOX*utils/geo_decls.h
byteabytea*postgres.h
"char"char�����������ã�
characterBpChar*postgres.h
cidCommandIdpostgres.h
dateDateADTutils/date.h
smallint (int2)int2 �� int16postgres.h
int2vectorint2vector*postgres.h
integer (int4)int4 �� 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

��Ȼ�����Ѿ������˻����������еĿ��ܽṹ�� ���DZ������ʵ�ʵĺ�����һЩ���ӡ�

31.9.3. C ���Ժ����İ汾-0 ���÷��

�������ṩ"�Ϸ��"�ĵ��÷�� — �����������������Ѿ����ᳫ�ˣ� �������DZȽ�����������һ�����ڰ汾-0����� C �����IJ����ͽ��ֻ������ͨ C �������������ҪС��ʹ��������ʾ��SQL�������͵� C ������ʽ��

������һЩ���ӣ�

#include "postgres.h"
#include <string.h>

/* ������ֵ */

int
add_one(int arg)
{
    return arg + 1;
}

/* ����������� */

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;
}

/* �������ã��䳤 */

text *
copytext(text *t)
{
    /*
     * VARSIZE �ǽṹ���ֽڼƵ��ܳ���
     */
    text *new_t = (text *) palloc(VARSIZE(t));
    VARATT_SIZEP(new_t) = VARSIZE(t);
    /*
     * VARDATA �ǽṹ��һ��ָ����������ָ��
     */
    memcpy((void *) VARDATA(new_t), /* Ŀ�� */
           (void *) VARDATA(t),     /* Դ */
           VARSIZE(t)-VARHDRSZ);    /* �����ֽ� */
    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 ���ұ�����˹���Ŀ�꣬ ���ǿ��������������Ϊ PostgreSQL ������Щ������

CREATE FUNCTION add_one(integer) RETURNS integer
     AS 'DIRECTORY/funcs', 'add_one'
     LANGUAGE C STRICT;

-- ע�⣺����������Ϊ add_one() �� SQL ����
CREATE FUNCTION add_one(double precision) RETURNS double precision
     AS 'DIRECTORY/funcs', 'add_one_float8'
     LANGUAGE C STRICT;

CREATE FUNCTION makepoint(point, point) RETURNS point
     AS 'DIRECTORY/funcs', 'makepoint'
     LANGUAGE C STRICT;

CREATE FUNCTION copytext(text) RETURNS text
     AS 'DIRECTORY/funcs', 'copytext'
     LANGUAGE C STRICT;

CREATE FUNCTION concat_text(text, text) RETURNS text
     AS 'DIRECTORY/funcs', 'concat_text',
     LANGUAGE C STRICT;

����� DIRECTORY ��������ļ���Ŀ¼ ������PostgreSQL�̳�Ŀ¼�������������ʹ�õ����ӵĴ��롣�� �����õķ��Ӧ�����ڼ��� DIRECTORY ������·��֮�� �� AS �Ӿ���ֻʹ�� 'funcs'�� �������������Ƕ�����ʡ�Ժ�ϵͳ��صĹ������չ��ͨ���� .so �� .sl����

��ע�����ǰѺ�������Ϊ"strict"���ϸ񣩣���˼��˵����κ�����ֵΪ NULL�� ��ôϵͳӦ���Զ�����һ�� NULL �Ľ��������������������DZ����ں������������� NULL ���롣 ����������������Ǿ͵���ȷ����ֵ�� ����Ϊÿ���������õIJ�������ָ�롣�����ڴ�ֵ���͵IJ�������������û�а취��飡��

���������Ϸ��ĵ��÷���������򵥣���ȷ��̫������ֲ����һЩϵͳ�ϣ� ���������ַ������ݱ� int С���������;ͻ��������ѡ� ���ң�����û�кܺõķ��� NULL ����İ취�� Ҳû�г��˰Ѻ����ϸ�����Ĵ��� NULL �����ķ���������Ҫ���İ汾-1�ķ�����������Щ���⡣

31.9.4. C ���Ժ����İ汾-1���÷��

�汾-1 ���÷����������������������ݲ����ͽ���ĸ����ԡ��汾-1 ������� C ����������������

Datum funcname(PG_FUNCTION_ARGS)

���⣬����ĺ�

PG_FUNCTION_INFO_V1(funcname);

Ҳ���������ͬһ��Դ�ļ��ͨ���Ϳ���д�ں�������ǰ�棩�� ����Щ�ڲ�-���Ժ������ԣ�����Ҫ��������꣬ ��ΪPostgreSQLĿǰ�����ڲ��������ǰ汾-1�� ���������ڶ�̬���ӵĺ��������������ġ�

�ڰ汾-1����� ÿ��ʵ�ʲ���������һ����Ӧ�ò������������͵� PG_GETARG_xxx()��ץȡ�ģ�������÷������͵� PG_RETURN_xxx()�귵�صġ� PG_GETARG_xxx() ����Ҫץȡ�ĺ��������ı����Ϊ�����������Ǵ� 0 ��ʼ�ġ� PG_RETURN_xxx() ����ʵ��Ҫ���ص���ֵΪ����IJ�����

�����Ǻ�����һ���ĺ������������ð汾-1����ģ�

#include "postgres.h"
#include <string.h>
#include "fmgr.h"

/* ������ֵ */

PG_FUNCTION_INFO_V1(add_one);
         
Datum
add_one(PG_FUNCTION_ARGS)
{
    int32   arg = PG_GETARG_INT32(0);

    PG_RETURN_INT32(arg + 1);
}

/* ����������� */

PG_FUNCTION_INFO_V1(add_one_double precision);

Datum
add_one_float8 precision(PG_FUNCTION_ARGS)
{
    /* ���� FLOAT8 �ĺ꣬�����䴫�����õı��� */
    float8   arg = PG_GETARG_FLOAT8(0);

    PG_RETURN_FLOAT8(arg + 1.0);
}

PG_FUNCTION_INFO_V1(makepoint);

Datum
makepoint(PG_FUNCTION_ARGS)
{
    /* �������û������ Point �Ĵ������õı��� */
    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);
}

/* �������ã��䳤 */

PG_FUNCTION_INFO_V1(copytext);

Datum
copytext(PG_FUNCTION_ARGS)
{
    text     *t = PG_GETARG_TEXT_P(0);
    /*
     * VARSIZE �ǽṹ���ֽڼƵ��ܳ���
     */
    text     *new_t = (text *) palloc(VARSIZE(t));
    VARATT_SIZEP(new_t) = VARSIZE(t);
    /*
     * VARDATA �ǽṹ��ָ����������һ��ָ��
     */
    memcpy((void *) VARDATA(new_t), /* Ŀ�� */
           (void *) VARDATA(t),     /* Դ */
           VARSIZE(t)-VARHDRSZ);    /* �����ֽ� */
    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 ����������Ϸ��ĵ�Ч������һ����

�͵�һ�����汾-1�ı������ֻ����Ŀ�ĵ����ˡ��������ǵ�ȷ���������Ľ�����Ϊ�����������಻��Ҫ��ϸ�ڡ� һ��������add_one_float8�ı�����������Dz�����Ҫ��ͣ�����Լ� float8 �Ǵ����������͡� ����һ�����������ڱ䳤���͵ĺ� GETARG ������ץȡ"toasted"����¯����ѹ���Ļ��߳����ģ�ֵ��Ҫ���Ĵ���

�汾-1�ĺ�����һ���޴�ĸĽ��Ƕ� NULL ����ͽ���Ĵ��� �� PG_ARGISNULL(n) ����һ����������ÿ�������Ƿ�Ϊ NULL ����Ȼ�������ֻ�Ƕ���Щû������Ϊ "strict" �ĺ����б�Ҫ���� ��Ϊ�����PG_GETARG_xxx() �꣬��������Ǵ��㿪ʼ����ġ���ע�����Dz�Ӧ��ִ�� PG_GETARG_xxx()�� �������������˲������� NULL�� Ҫ����һ�� NULL �����ִ��һ�� PG_RETURN_NULL()���������ϸ�ĺͲ��ϸ�ĺ�������Ч��

���·��Ľӿ����ṩ��������ѡ���� PG_GETARG_xxx() ����������֡���һ���� PG_GETARG_xxx_COPY() ��֤����һ��ָ�������ĸ������ø����ǿ��԰�ȫ��д��ġ� ����ͨ�ĺ���ʱ��᷵��һ��ָ������洢�ڱ��е�ijֵ��ָ�룬������Dz���д���ָ�롣 �� PG_GETARG_xxx_COPY() �걣֤��ȡһ����д�Ľ������ �ڶ��������� PG_GETARG_xxx_SLICE() ����ɣ�������������������һ���Dz����ĸ���������ͬ���� �ڶ����͵�������Ҫ���ص�ƫ���������ݶεij��ȡ� ƫ���Ǵ��㿪ʼ����ģ�һ�������ij�����Ҫ�󷵻ظ�ֵ��ʣ�೤�ȵ����ݡ� ��Щ�����ṩ�˷��ʴ�����ֵ���в��ֵĸ���Ч�ķ������ر������ݵĴ洢������"external"��ʱ�� ��һ���ֶεĴ洢���Ϳ����� ALTER TABLE tablename ALTER COLUMN colname SET STORAGE storagetypeָ����storagetype �� plain��external�� extended �� main ֮һ����

�汾-1�ĺ������÷��Ҳ�����ǿ��ܷ���һ"��"��� ��Section 31.9.10������ʵ�ִ�����������Chapter 32���͹������Ե��þ����Chapter 45���� �汾-1 �Ĵ���Ҳ�Ȱ汾-0�ĸ�������ֲ����Ϊ��û��Υ�� C ��׼�Ժ�������Э������ơ������ϸ������� Դ�����е�src/backend/utils/fmgr/README��

31.9.5. �����

������ת������Ļ���֮ǰ������Ҫ������һЩPostgreSQLC ���Ժ����ı������ ��Ȼ������ C �����������������д����PostgreSQL �Ĺ������� ��ͨ�����鷳����Ȼ����ȫ���ܵģ�����Ϊ������ C++��FORTRAN������ Pascal ���������Բ�����ѭ�� C һ���ĵ���ϰ�ߡ� Ҳ����˵������������C�Ĵ��ݲ����ͷ���ֵ�ķ�ʽ��һ���� ������Ǽ�����ı�����Ժ������� C д�ġ�

��д������ C �����Ļ����������£�

31.9.6. ��������Ӷ�̬���ӵĺ���

�����ܹ�ʹ���� C д PostgreSQL ��չ����֮ǰ�� �������һ������ķ���������������ǣ������������ɿ��Ա���������̬��װ�ص��ļ��� ׼ȷ��˵��������Ҫ����һ���������

�����Ҫ����������������Χ����Ϣ����ô��Ӧ���Ķ���IJ���ϵͳ���ĵ��� �ر��� C ��������cc ���������� ld ���ֲ�ҳ�� ���⣬PostgreSQL Դ��������������������е����ӣ� ������ contrib Ŀ¼� �����������������Щ���ӣ���ô���Ҫ���Լ���ģ�����ú� PostgreSQL Դ�����޹ز��С�

�������������ӿ�ִ���ļ����ƣ����Ȱ�Դ��������Ŀ���ļ��� Ȼ���Ŀ���ļ�����������Ŀ���ļ���Ҫ������λ���޹��루position-independent code�� ��PIC���������Ͼ����ڿ�ִ�г���װ�����ǵ�ʱ�� ���ǿ��Է��ڿ�ִ�г�����ڴ�����κεط��� �����ڿ�ִ���ļ���Ŀ���ļ�ͨ�������������ʽ����ġ��� ���Ӷ�̬���������������־�������ӿ�ִ���ļ���������������ġ� ��������������� — ��һЩϵͳ���ʵ�����ġ���

���������������Ǽ������Դ��������� foo.c �ļ��ﲢ�ҽ����������ֽ� foo.so�Ĺ���⡣�н�Ķ����ļ������� foo.o��������������ע����һ���������԰�����������ļ�����������������ֻ��һ����

BSD/OS

���� PIC �ı�������־�� -fpic��������������������־�� -shared��

gcc -fpic -c foo.c
ld -shared -o foo.so foo.o

���淽�������ڰ汾 4.0 �� BSD/OS��

FreeBSD

���� PIC �ı�������־�� -fpic��������������������־�� -shared��

gcc -fpic -c foo.c
gcc -shared -o foo.so foo.o

���淽�������ڰ汾 3.0 �� FreeBSD.

HP-UX

���� PIC ��ϵͳ��������־�� +z�����ʹ�� GCC ���� -fpic�� ������������������־�� -b�����

cc +z -c foo.c

��

gcc -fpic -c foo.c

Ȼ��

ld -b -o foo.sl foo.o

HP-UX ʹ�� .sl ���������չ���������󲿷�ϵͳ��ͬ��

IRIX

PIC ��ȱʡ������Ҫʹ������ı�����ѡ� ���ɹ�����������ѡ���� -shared.

cc -c foo.c
ld -shared -o foo.so foo.o

Linux

���� PIC �ı�������־�� -fpic����һЩƽ̨�ϵ�һЩ�����£� ��� -fpic ��������ô����ʹ��-fPIC�� �ο� GCC ���ֲ��ȡ������Ϣ�� ���������ı�������־�� -shared��һ�����������ӿ�������

cc -fpic -c foo.c
cc -shared -o foo.so foo.o

MacOS X

������һ�����ӡ�������迪�������Ѿ���װ���ˡ�

cc -c foo.c
cc -bundle -flat_namespace -undefined suppress -o foo.so foo.o

NetBSD

���� PIC �ı�������־�� -fpic������ ELF ϵͳ�� �� -shared ��־�ı��������������ӹ���⡣ ���ϵķ� ELF ϵͳ�ʹ��ld -Bshareable��

gcc -fpic -c foo.c
gcc -shared -o foo.so foo.o

OpenBSD

���� PIC �ı�������־�� -fpic. ld -Bshareable �������ӹ���⡣

gcc -fpic -c foo.c
ld -Bshareable -o foo.so foo.o

Solaris

���� PIC �ı������������� Sun ������ʱΪ -KPIC ���� GCC ʱΪ -fpic�����ӹ����ʱ������������������ -G ������ GCC ʱ�������� -shared��

cc -KPIC -c foo.c
cc -G -o foo.so foo.o

��

gcc -fpic -c foo.c
gcc -G -o foo.so foo.o

Tru64 UNIX

PIC ��ȱʡ����˱����������ƽ�����Ǹ��� ������ѡ��� ld �������ӣ�

cc -c foo.c
ld -shared -expect_unresolved '*' -o foo.so foo.o

�� GCC ����ϵͳ������ʱ�Ĺ�����һ���ģ�����Ҫ�����ѡ�

UnixWare

SCO ���������� PIC �ı�־��-KPIC GCC �� -fpic�� ���ӹ����ʱ SCO �������� -G �� GCC ��-shared��

cc -K PIC -c foo.c
cc -G -o foo.so foo.o

or

gcc -fpic -c foo.c
gcc -shared -o foo.so foo.o

����: ����������Щ����ʵ��̫���ӣ���ô��Ӧ�ÿ���ʹ�� GNU Libtool������ƽ̨�IJ�����������һ��ͳһ�Ľӿ��

���ɵĹ�����ļ�Ȼ��Ϳ���װ�ص� PostgreSQL����ȥ�ˡ��ڸ� CREATE FUNCTION ���������ļ�����ʱ�����DZ������� ������ļ������ֶ������м�Ŀ���ļ������֡���ע��������� CREATE FUNCTION �����Ϻ��� ϵͳ��׼�Ĺ������չ (ͨ����.so��.sl)�� ���ҳ�����ѵļ����Կ���ҲӦ�ú��ԡ�

��ȥ���� Section 31.9.1 ��ȡ�йط����� Ԥ���������ҵ���������Ϣ��

31.9.7. ��չ�������ܹ�

������ڿ��Ƿ������PostgreSQL��չģ�飬��ô����������һ������ֲ������ϵͳ���ܻ��൱���ѡ� ���PostgreSQL��װ�ṩ��һ��������չ�������ܹ������� PGXS�� �������򵥵���չģ�������һ���Ѿ���װ�˵ķ������������ˡ� ��ע������ܹ���������ͼ����ʵ��һ��ͳһ�ġ�������������������PostgreSQL��ص�����ļܹ��� ��ֻ�������Զ�����Щ�򵥵ķ�������չģ������������ڸ����ӵİ����㻹����Ҫ��д�Լ�������ϵͳ��

Ҫ�������չ��ʹ�øüܹ��������дһ���򵥵� makefile�� �ڸ�makefile�����Ҫ����һЩ��������������ȫ�ֵ� PGXS makefile�� ������һ������һ������һ������⣬һ�� SQL �ű�����һ���ĵ��ı��ļ��Ľ��� isbn_issn �����ӣ�

MODULES = isbn_issn
DATA_built = isbn_issn.sql
DOCS = README.isbn_issn

PGXS := $(shell pg_config --pgxs)
include $(PGXS)

�������Ӧ������һ���ġ����ļ���ǰ�棬�㸳������������ӿͻ����� make ����

���������������

MODULES

һ����Ҫ��ͬ������Դ�����������Ĺ��������б���Ҫ������б��������׺��

DATA

��װ�� prefix/share/contrib ������ļ�

DATA_built

��Ҫ�������ģ���װ�� prefix/share/contrib ���������ļ���

DOCS

��װ�� prefix/doc/contrib ���������ļ�

SCRIPTS

��װ�� prefix/bin ����Ľű��ļ����Ƕ����ƣ�

SCRIPTS_built

��װ�� prefix/bin ����ģ���Ҫ�������Ľű��ļ����Ƕ����ƣ���

REGRESS

�ع���԰������б�û�к�׺��

�������������������֮һ��

PROGRAM

һ����Ҫ�����Ķ������ļ����� OBJS �����г�Ŀ���ļ���

MODULE_big

һ����Ҫ�����Ĺ�������� OBJS ���г�Ŀ���ļ���

�����������������

EXTRA_CLEAN

�� make clean ��ɾ���Ķ�����ļ�

PG_CPPFLAGS

�����ӵ� CPPFLAGS

PG_LIBS

�����ӵ� PROGRAM ��������

SHLIB_LINK

�����ӵ� MODULE_big ��������

����� makefile �� Makefile �����ַ��ڱ��������չ��Ŀ¼� Ȼ����Ϳ������� make �����룬Ȼ���� make install ��װ���ģ�顣 �����չ��Ϊ pg_config ���������·�����ҵ��ĵ�һ�� PostgreSQL ��װ����Ͱ�װ�ġ�

31.9.8. �������͵� C ���Ժ���

�������Ͳ��� C �ṹ�����й̶��IJ��֡� �������͵�ʵ�����ܰ����գ�null���� ���⣬һ�����ڼ̳в��һ���ֵĸ����� �Ϳ��ܺ�ͬһ�̳з����������Ա�в�ͬ����/�ֶΡ� ��ˣ�PostgreSQL �ṩһ�����̽ӿ����ڴ� C ������ʸ������͡�

��������Ϊ�����ѯдһ������

SELECT name, c_overpaid(emp, 1500) AS overpaid
	FROM emp
	WHERE name = 'Bill' OR name = 'Sam';

������IJ�ѯ��ð汾 0 �ĵ��ýӿڣ����ǿ�����������c_overpaid��

#include "postgres.h"
#include "executor/executor.h"  /* �� GetAttributeByName() */

bool
c_overpaid(HeapTupleHeader t, /* emp �ĵ�ǰ��*/
           int32 limit)
{
    bool isnull;
    int32 salary;

    salary = DatumGetInt32(GetAttributeByName(t, "salary", &isnull));
    if (isnull)
        return (false);
    return salary > limit;
}

�ڰ汾-1���룬����Ķ�����д������������

#include "postgres.h"
#include "executor/executor.h"  /* �� GetAttributeByName() */

PG_FUNCTION_INFO_V1(c_overpaid);

Datum
c_overpaid(PG_FUNCTION_ARGS)
{
    HeapTupleHeader  t = PG_GETARG_HEAPTUPLEHEADER(0);
    int32            limit = PG_GETARG_INT32(1);
    bool isnull;
    Datum salary;

    salary = GetAttributeByName(t, "salary", &isnull);
    if (isnull)
        PG_RETURN_BOOL(false);
    /* ���⣬���ǿ��ܸ�ϣ���� PG_RETURN_NULL() ���ڿ�нˮ�� */

    PG_RETURN_BOOL(DatumGetInt32(salary) > limit);
}

GetAttributeByName �� PostgreSQL ϵͳ������ �������ص�ǰ��¼���ֶΡ�������������������Ϊ HeapTupleHeader �Ĵ��뺯���IJ���������Ҫ���ֶ����ƣ� �Լ�һ������ȷ���ֶ��Ƿ�Ϊ�գ�null���ķ��ز����� GetAttributeByName ��������һ��Datumֵ�� ������ö�Ӧ�� DatumGetXXX() �����ת���ɺ��ʵ��������͡� ��ע�⣬��������˿ձ�־����ô����ֵ��������ģ� ��׼���Խ�����κδ���֮ǰ������Ҫ�ȼ��ձ�־��

����һ�� GetAttributeByNum�������ֶα�Ŷ������ֶ���ѡȡĿ���ֶΡ�

����������� SQL ������ c_overpaid ������

CREATE FUNCTION c_overpaid(emp, integer) 
	RETURNS bool
	AS 'DIRECTORY/funcs', 'c_overpaid'
	LANGUAGE C STRICT;

��ע������ʹ���� STRICT���������ǾͲ���Ҫ�����������Ƿ��� NULL��

31.9.9. �� C �����ﷵ���У��������ͣ�

Ҫ��һ�� C ���Ժ����ﷵ��һ���л���һ���������͵���ֵ�����ǿ���ʹ��һ������� API�� ���ṩ������ͺ�����������������������������͵ĸ����ԡ� Ҫʹ�ø� API��Դ������������

#include "funcapi.h"

����һ��������������ֵ��Ҳ����һ��"Ԫ��"�������ַ����� ����Դ�һ�� Datum ֵ������������Ҳ���Դ�һ�����Դ��ݸ���Ԫ����ֶ����͵�����ת�������� C �ִ������������� ���������ַ�ʽ�������ȶ���ҪΪԪ��ṹ��ȡ��������һ�� TupleDesc �������� ��ʹ�� Datum ��ʱ����� BlessTupleDesc ������� TupleDesc Ȼ��Ϊÿ�е��� heap_formtuple�� ��ʹ�� C �ִ���ʱ����� TupleDescGetAttInMetadata ���� TupleDesc�� Ȼ��Ϊÿ�е��� BuildTupleFromCStrings�� �����һ����������һ��Ԫ�鼯�ϵij��ϣ��������ò��趼�����ڵ�һ�ε��øú�����ʱ��һ������ɡ�

�м�����㺯�����԰��������ó�ʼ�� TupleDesc�� �������ʹ�������ĸ������ͣ�����Դ�ϵͳ�����ȡ��Ϣ����

TupleDesc RelationNameGetTupleDesc(const char *relname)

����һ�����ֻ�ȡ TupleDesc������

TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)

һ������һ������ OID ��ȡTupleDesc�� ����������Ϊһ�����������������ͻ��߸��ϣ���ϵ�����ͻ�ȡһ�� TupleDesc�� ����дһ������ record �ĺ�����ʱ����ôԤ�ڵ� TupleDesc �����ɵ����ߴ��ݽ�����

һ��������һ�� TupleDesc���������ʹ�� Datum����ô����

TupleDesc BlessTupleDesc(TupleDesc tupdesc)

��������� C �ִ�����ô����

AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)

�������дһ�����ؼ��ϵĺ�������ô����԰���Щ�����Ľ�������� FuncCallContext �ṹ�� — �ֱ�ʹ�� tuple_desc ���� attinmeta �ֶΡ�

��ʹ�� Datum ��ʱ��ʹ��

HeapTuple heap_formtuple(TupleDesc tupdesc, Datum *values, char *nulls)

����һ�� HeapTuple������������ Datum ����ʽ�����û���

��ʹ�� C �ִ���ʱ����

HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)

����һ�� HeapTuple���� C �ִ�����ʽ�����û����ݡ� "values" ��һ�� C �ִ������飬�����е�ÿ���ֶζ�Ӧ����һ���� ÿ�� C �ִ���Ӧ�����ֶ��������͵����뺯��Ԥ�ڵ���ʽ��Ϊ�˴�����һ���ֶ��з���һ����ֵ�� values �����ж�Ӧ��ָ��Ӧ������Ϊ NULL���������������ҪΪ�㷵�ص�ÿ��Ԫ�����һ�Ρ�

һ����������һ������ĺ����з��ص�Ԫ�飬��ô��Ԫ�����ת����һ�� Datum��ʹ��

HeapTupleGetDatum(HeapTuple tuple)

��һ�� HeapTuple ת��Ϊһ����Ч�� Datum�� �������ֻ����һ�У���ô��� Datum ��������ֱ�ӷ��أ� ������������������һ�����ؼ��ϵĺ�����ĵ�ǰ����ֵ��

���������������

31.9.10. �� C ���Ժ����ﷵ�ؼ���

����һ������� API �����ṩ�� C ���Ժ����з��ؼ��ϣ����У���֧�֡� һ�����ؼ��ϵĺ���������ѭ�汾��1�ĵ��÷�ʽ��ͬ����Դ���������� funcapi.h����������˵��������

һ�����ؼ��ϵĺ�����SRF��ͨ��Ϊ�����ص�ÿ�������һ�Ρ� ��� SRF ���뱣���㹻��״̬���ڼ�ס���������������Լ���ÿ�ε��õ�ʱ�򷵻���һ��� ���� API �ṩ�� FuncCallContext �ṹ���ڰ�������������̡� fcinfo->flinfo->fn_extra ���ڱ���һ����Խ��ε��õ�ָ�� FuncCallContext ��ָ�롣

typedef struct
{
    /*
     * ����ǰ���Ѿ������õĴ���
     *
     * ��ʼ��ʱ��call_cntr �� SRF_FIRSTCALL_INIT() ��Ϊ�� 0������
     * ÿ������� SRF_RETURN_NEXT() ��ʱ�򶼵���
     */
    uint32 call_cntr;

    /*
     * ��ѡ������������
     *
     * ����� max_calls ֻ��Ϊ�˷��㣬������Ҳ�ǿ�ѡ��
     * ���û�����ã�������ṩ��ѡ�ķ�����֪��������ʱ����
     * 
     */
    uint32 max_calls;

    /*
     * ָ������λ�Ŀ�ѡָ��
     *
     * ������������Ѿ���ʱ��ֻ�������¼��ݡ�Ҳ������Щʹ��
     * ������ TupleDescGetSlot() ���û����� SRF
     */
    TupleTableSlot *slot;

    /*
     * ��ѡ��ָ���û��ṩ���������Ϣ��ָ��
     *
     * user_fctx ����һ��ָ�����Լ��Ľṹ��ָ�룬���������ṩ����ĺ����ĵ��ü�Ļ�����Ϣ
     * 
     */
    void *user_fctx;

    /*
     * ��ѡ��ָ�����������������Ԫ��Ϣ�Ľṹ�����ָ��
     * 
     *
     * attinmeta �����ڷ���Ԫ���ʱ��Ҳ����˵���ظ����������ͣ�
     * ��ֻ���ػ�����Ҳ���DZ������������͵�ʱ�򲢲���Ҫ��
     * ֻ������׼���� BuildTupleFromCStrings() ��������Ԫ���ʱ�����Ҫ��
     * 
     */
    AttInMetadata *attinmeta;

    /*
     * ���ڱ����ڶ�ε��ü���Ľṹ���ڴ滷��
     *
     * multi_call_memory_ctx ���� SRF_FIRSTCALL_INIT() Ϊ�����õģ�������
     * SRF_RETURN_DONE() ���������������ڴ���κ���Ҫ��Խ��ε��� SRF ֮���ظ�ʹ�õ��ڴ�
     * 
     * 
     */
    MemoryContext multi_call_memory_ctx;

    /*
     * ��ѡ��ָ�룬ָ�����Ԫ�������Ľṹ
     *
     * tuple_desc ���ڷ���Ԫ�飨Ҳ����˵�����������ͣ�
     * ����ֻ��������ʹ�� heap_formtuple() ������  BuildTupleFromCStrings() ����Ԫ���
     * ʱ����Ҫ����ע������洢�� TupleDesc ָ��ͨ��Ӧ������heap_formtuple()
     * BlessTupleDesc() ����
     */
    TupleDesc tuple_desc;

} FuncCallContext;

һ�� SRF ʹ���Զ����� FuncCallContext �ṹ�����ǿ���ͨ�� fn_extra �ҵ����������ɸ������ͺꡣ��

SRF_IS_FIRSTCALL()

���ж���ĺ����ǵ�һ�ε��û��Ǻ�̵ĵ��á���ֻ�У��ڵ�һ�ε��õ�ʱ����

SRF_FIRSTCALL_INIT()

��ʼ�� FuncCallContext����ÿ�κ�������ʱ��������һ�Σ���ʹ��

SRF_PERCALL_SETUP()

Ϊʹ�� FuncCallContext ��ǡ���������Լ������κ�ǰ��Ļغ�����ʣ�µ��ѷ��ص����ݡ�

�����ĺ���������Ҫ���أ�ʹ��

SRF_RETURN_NEXT(funcctx, result)

���ظ������ߡ���result �����Ǹ� Datum�� Ҫô�ǵ���ֵ��Ҫô����ǰ����ܵ�����׼����Ԫ�顣����������ĺ������������ݷ��أ�ʹ��

SRF_RETURN_DONE(funcctx)

��������SRF��

�� SRF �����õ�ʱ����ڴ滷����һ����ʱ�Ļ����� �ڵ���֮�佫�ᱻ�����������ζ���㲻��Ҫ pfree ������ palloc �Ķ����������Զ���ʧ�ġ������������������κο�Խ���ô��ڵ����ݽṹ�� �������Ҫ�����Ƿ�������ʲô�ط����� multi_call_memory_ctx ���õĻ����ʺ����ڱ�����Щ��Ҫֱ�� SRF ����ǰ���������ݡ� �ڴ��������£�����ζ����������һ�ε��õ����õ�ʱ��Ӧ���л��� multi_call_memory_ctx��

һ��������α�������ӿ�����������������

Datum
my_Set_Returning_Function(PG_FUNCTION_ARGS)
{
    FuncCallContext  *funcctx;
    Datum             result;
    MemoryContext     oldcontext;
    ����������

    if (SRF_IS_FIRSTCALL())
    {
        funcctx = SRF_FIRSTCALL_INIT();
        oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
        /* ����ų���һ�ε����ô��룺*/
        �û��������
        if ���ظ���
            ���� TupleDesc���Լ����ܻ��� AttInMetadata
        endif ���ظ���
        �û��������
        MemoryContextSwitchTo(oldcontext);
    }

    /* ÿ�ζ�ִ�е����ô�����������֣�*/
    �û��������
    funcctx = SRF_PERCALL_SETUP();
    �û��������

    /* ����ֻ���������������Ƿ���ɵ�һ��������*/
    if (funcctx->call_cntr < funcctx->max_calls)
    {
        /* ���������뷵������һ����Ŀ��*/
         �û�����
         ��ȡ��� Datum
         SRF_RETURN_NEXT(funcctx, result);
     }
     else
     {
         /* ����������ɷ�����Ŀ�Ĺ����ˣ�ֻ��Ҫ�����OK�ˣ�*/
         �û�����
         SRF_RETURN_DONE(funcctx);
     }
 }
 

һ�����ظ������͵����� SRF ���ӿ�������������

 PG_FUNCTION_INFO_V1(testpassbyval);

 Datum
 testpassbyval(PG_FUNCTION_ARGS)
 {
     FuncCallContext     *funcctx;
     int                  call_cntr;
     int                  max_calls;
     TupleDesc            tupdesc;
     AttInMetadata       *attinmeta;

      /* ֻ���ڵ�һ�ε��ú�����ʱ��ɵ����� */
      if (SRF_IS_FIRSTCALL())
      {
         MemoryContext   oldcontext;

         /* ����һ�����������������ڵ��ü䱣��ס */
         funcctx = SRF_FIRSTCALL_INIT();

         /* �л����ʺ϶�κ������õ��ڴ滷�� */
         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

         /* Ҫ���ص�Ԫ������ */
         funcctx->max_calls = PG_GETARG_UINT32(0);

         /*
          * Ϊ __testpassbyval Ԫ������һ��Ԫ������
          */
         tupdesc = RelationNameGetTupleDesc("__testpassbyval");

         /*
          * �����Ժ���� C �ִ�����Ԫ�������Ԫ����
          * 
          */
         attinmeta = TupleDescGetAttInMetadata(tupdesc);
         funcctx->attinmeta = attinmeta;

         MemoryContextSwitchTo(oldcontext);
     }

     /* ÿ�κ������ö�Ҫ�������� */
     funcctx = SRF_PERCALL_SETUP();

     call_cntr = funcctx->call_cntr;
     max_calls = funcctx->max_calls;
     attinmeta = funcctx->attinmeta;

     if (call_cntr < max_calls)    /* �ڻ�����Ҫ���͵Ķ���ʱ�������� */
     {
         char       **values;
         HeapTuple    tuple;
         Datum        result;

         /*
          * ׼��һ����ֵ�������ڰ汾�ķ���Ԫ�顣
          * ��Ӧ����һ�� C �ִ����飬�Ժ���Ա����ʵ��������뺯������
          * 
          */
         values = (char **) palloc(3 * sizeof(char *));
         values[0] = (char *) palloc(16 * sizeof(char));
         values[1] = (char *) palloc(16 * sizeof(char));
         values[2] = (char *) palloc(16 * sizeof(char));

         snprintf(values[0], 16, "%d", 1 * PG_GETARG_INT32(1));
         snprintf(values[1], 16, "%d", 2 * PG_GETARG_INT32(1));
         snprintf(values[2], 16, "%d", 3 * PG_GETARG_INT32(1));

         /* ����һ��Ԫ�� */
         tuple = BuildTupleFromCStrings(attinmeta, values);

         /* ��Ԫ������ datum */
	 result = HeapTupleGetDatum(tuple);

         /* ������Щʵ���ϲ��DZ�Ҫ�� */
         pfree(values[0]);
         pfree(values[1]);
         pfree(values[2]);
         pfree(values);

          SRF_RETURN_NEXT(funcctx, result);
     }
     else    /* ��û�����ݲ�����ʱ��ɵ����� */
     {
          SRF_RETURN_DONE(funcctx);
     }
 }
 

����������֧�ֵ� SQL ����

 CREATE TYPE __testpassbyval AS (f1 integer, f2 integer, f3 integer);

 CREATE OR REPLACE FUNCTION testpassbyval(integer, integer) RETURNS setof __testpassbyval
   AS 'filename','testpassbyval' LANGUAGE 'c' IMMUTABLE STRICT;
 

����Դ�뷢������� contrib/tablefunc ��ȡ�����йط��ؼ��ϵĺ��������ӡ�

31.9.11. ��̬�����ͷ�������

C ���Ժ�����������Ϊ���ܺͷ��ض�̬������ anyelement �� anyarray�� ���� Section 31.2.5 ��ȡ�йض�̬�����ĸ���ϸ�Ľ��͡� ��������������߷������Ͷ���Ϊ��̬���ͣ���ô���������߾��޷�Ԥ��֪�������յ��IJ����� �Լ���Ҫ���ص����ݡ��� fmgr.h �����������̣������ð汾��1�� C ����֪�����IJ�����ȷ�����������Լ�����Ҫ���ص��������͡� ���������̽� get_fn_expr_rettype(FmgrInfo *flinfo) �� get_fn_expr_argtype(FmgrInfo *flinfo, int argnum)�� ���Ƿ��ؽ�����߲��������� OID�������Щ��Ϣ���ɻ�ȡ���򷵻� InvalidOid�� �ṹ flinfo ͨ������ fcinfo->flinfo ���з��ʵġ����� argnum ���� 0 Ϊ���ġ�

���磬����������дһ�����������������͵�һ��Ԫ�أ����ҷ��ظ����͵�һ��һά���飺

PG_FUNCTION_INFO_V1(make_array);
Datum
make_array(PG_FUNCTION_ARGS)
{
    ArrayType  *result;
    Oid         element_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
    Datum       element;
    int16       typlen;
    bool        typbyval;
    char        typalign;
    int         ndims;
    int         dims[MAXDIM];
    int         lbs[MAXDIM];

    if (!OidIsValid(element_type))
        elog(ERROR, "could not determine data type of input");

    /* ��ȡ�ṩ��Ԫ�� */
    element = PG_GETARG_DATUM(0);

    /* ���ǵ�ά���� 1 */
    ndims = 1;
    /* ��һ��Ԫ�� */
    dims[0] = 1;
    /* �����½��� 1*/
    lbs[0] = 1;

    /* ��ȡ�й�Ԫ��������Ҫ����Ϣ */
    get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);

    /* Ȼ���������� */
    result = construct_md_array(&element, ndims, dims, lbs,
                                element_type, typlen, typbyval, typalign);

    PG_RETURN_ARRAYTYPE_P(result);
}

����������� SQL �������� make_array��

CREATE FUNCTION make_array(anyelement) RETURNS anyarray
    AS 'DIRECTORY/funcs', 'make_array'
    LANGUAGE C STRICT;

��ע��ʹ�� STRICT����һ��dz���Ҫ����Ϊ����û��������Կ����롣