PostgreSQL 8.0.0 �����ĵ���PostgreSQL �й� ������ | ||||
---|---|---|---|---|
Prev | Fast Backward | Chapter 31. ��չ SQL | Fast Forward | Next |
�û�����ĺ��������� C д����������Щ������ C ���ݵ����ԣ����� C++���� �����ĺ����DZ�����ɶ�̬װ�صĶ���ģ�Ҳ��������⣩�������ɷ�����������Ҫװ�صġ� ��̬װ�ص������� "C ����" ������"�ڲ�"����֮�������ĵط� — ʵ�ʵı���ϰ��������֮��ʵ������һ���ġ� ����ˣ������ڲ�������Ϊд�û����� C �����ṩ�˴�����õ���������
Ŀǰ�� C ���������ֵ��ô�ͳ���µ�"�汾 1"�ĵ��ô�ͳ��ͨ��Ϊ�ú�����дһ�� PG_FUNCTION_INFO_V1() ������ʶ�ģ���������ʾ��������ȱ��������ʶһ���Ϸ��ģ�"�汾 0"�������� ���ַ������CREATE FUNCTION�������Ķ��� C�� �����Ϸ��ĺ����Ѿ������ˣ���Ҫ����Ϊ��ֲ��ԭ���ȱ�����ܣ� �������ڼ�����ԭ��ϵͳ��Ȼ֧������
��ij���ض��Ŀ�װ�ض����ļ�����û�����ĺ�����һ�α��������Ự����ʱ�� ��̬װ�����Ѻ�����Ŀ����װ�����ڴ档 ��ˣ������û������ C ������ CREATE FUNCTION����Ϊ����������������Ϣ�� ��װ�ض����ļ����֣��������������Ǹ�Ŀ���ļ�����õĺ����� C ���֣����ӷ��ţ��� ���û����ȷ����C���֣���ô�ͼ�������SQL��������ͬ��
������ CREATE FUNCTION �����и���������, ������㷨���ڶ�λ��������ļ���
���������һ������·��������װ�ظ������ļ���
����������ִ� $libdir ��ͷ�� ��ô�ò��ֽ���PostgreSQL��Ŀ¼�����棬 ��Ŀ¼����������ʱ���ж��ġ�
������ֲ�����Ŀ¼���֣���ô�����ñ��� dynamic_library_path ��������·������ҡ�
����û����·�����ҵ����ļ�������������һ���Ǿ���Ŀ¼���֣��� ��ô��̬װ�����ͻ���ͼ�����������װ�أ������������Կ϶���Ҫʧ�ܵġ���������ǰ����Ŀ¼�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�����ֲ�� �����ֻ�������������֣�����·����Ҳû����չ����Ȼ�������������ṩ��Щ��Ϣ��
Ҫ֪�����д 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 ���� | ������ |
---|---|---|
abstime | AbsoluteTime | utils/nabstime.h |
boolean | bool | postgres.h �������DZ��������ã� |
box | BOX* | utils/geo_decls.h |
bytea | bytea* | postgres.h |
"char" | char | �����������ã� |
character | BpChar* | postgres.h |
cid | CommandId | postgres.h |
date | DateADT | utils/date.h |
smallint (int2) | int2 �� int16 | postgres.h |
int2vector | int2vector* | postgres.h |
integer (int4) | int4 �� int32 | postgres.h |
real (float4) | float4* | postgres.h |
double precision (float8) | float8* | postgres.h |
interval | Interval* | utils/timestamp.h |
lseg | LSEG* | utils/geo_decls.h |
name | Name | postgres.h |
oid | Oid | postgres.h |
oidvector | oidvector* | postgres.h |
path | PATH* | utils/geo_decls.h |
point | POINT* | utils/geo_decls.h |
regproc | regproc | postgres.h |
reltime | RelativeTime | utils/nabstime.h |
text | text* | postgres.h |
tid | ItemPointer | storage/itemptr.h |
time | TimeADT | utils/date.h |
time with time zone | TimeTzADT | utils/date.h |
timestamp | Timestamp* | utils/timestamp.h |
tinterval | TimeInterval | utils/nabstime.h |
varchar | VarChar* | postgres.h |
xid | TransactionId | postgres.h |
��Ȼ�����Ѿ������˻����������еĿ��ܽṹ�� ���DZ������ʵ�ʵĺ�����һЩ���ӡ�
�������ṩ"�Ϸ��"�ĵ��÷�� — �����������������Ѿ����ᳫ�ˣ� �������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�ķ�����������Щ���⡣
�汾-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��
������ת������Ļ���֮ǰ������Ҫ������һЩPostgreSQLC ���Ժ����ı������ ��Ȼ������ C �����������������д����PostgreSQL �Ĺ������� ��ͨ�����鷳����Ȼ����ȫ���ܵģ�����Ϊ������ C++��FORTRAN������ Pascal ���������Բ�����ѭ�� C һ���ĵ���ϰ�ߡ� Ҳ����˵������������C�Ĵ��ݲ����ͷ���ֵ�ķ�ʽ��һ���� ������Ǽ�����ı�����Ժ������� C д�ġ�
��д������ C �����Ļ����������£�
ʹ�� pg_config --includedir-server �ҳ�PostgreSQL��������ͷ�ļ���װ�����ϵͳ������������û������е�ϵͳ���ĺδ��� ���ѡ����PostgreSQL7.2 �����ġ����� PostgreSQL7.1�� ��Ӧ��ʹ��ѡ�� --includedir�� ���������δ֪ѡ�pg_config �����ŷ���״̬�˳����� �������� 7.1 �İ汾�����ֻ���Լ����ˣ�������Ϊ����������Ŀǰ�ĵ��÷�ʽ֮ǰ�������㲻����ܻ�ȥ֧����Щ�汾��
������洢��ʱ���� PostgreSQL �ĺ���palloc�� pfree ȡ����Ӧ�� C �⺯�� malloc��free�� ��palloc����Ĵ洢����ÿ���������ʱ���Զ��ͷţ��������ڴ�й¶��
�ǵ���memset ����Ľṹ�ֽ����㡣 �������ô�����ͺ���֧�� hash ������ hash ���ӣ���Ϊ���DZ�����Լ������ݽṹ��ѡ�����������λ������ hash�� ��ʹ���ʼ������Ľṹ����������Ȼ�п����м��������ֽڣ��ṹ�еĶ�����������ֵ��
������� PostgreSQL �ڲ����Ͷ����� postgres.h�� �������������ӿڣ�PG_FUNCTION_ARGS �ȵȡ��� ���� fmgr.h������������Ӧ�ð����������ļ��� ������ֲ��ԭ����������� postgres.h��Ȼ���ٰ�������ϵͳ�����û�ͷ�ļ��� ������ postgres.h ���Զ����� c.h�� elog.h �� palloc.h��
��Ŀ���ļ��ﶨ��ķ���һ���������ͻ��Ҳ���ܺͶ����� PostgreSQL ��������ִ�д����еķ������ֳ�ͻ�� ����㿴���������صĴ�����Ϣ����ô��������ĺ������߱�����������
�����Ŀ��������װ�سɿ��Զ�̬װ�� PostgreSQL �Ŀ��ļ�������ҪһЩ����ı�ǡ����� Section 31.9.6 ��ȡ��������ƽ̨��������µ���ϸ˵����
�����ܹ�ʹ���� C д PostgreSQL ��չ����֮ǰ�� �������һ������ķ���������������ǣ������������ɿ��Ա���������̬��װ�ص��ļ��� ȷ��˵��������Ҫ����һ���������
�����Ҫ����������������Χ����Ϣ����ô��Ӧ���Ķ���IJ���ϵͳ���ĵ��� �ر��� C ��������cc ���������� ld ���ֲ�ҳ�� ���⣬PostgreSQL Դ��������������������е����ӣ� ������ contrib Ŀ¼� �����������������Щ���ӣ���ô���Ҫ���Լ���ģ�����ú� PostgreSQL Դ�����ز��С�
�������������ӿ�ִ���ļ����ƣ����Ȱ�Դ��������Ŀ���ļ��� Ȼ���Ŀ���ļ�����������Ŀ���ļ���Ҫ������λ�����루position-independent code�� ��PIC���������Ͼ����ڿ�ִ�г���װ�����ǵ�ʱ�� ���ǿ��Է��ڿ�ִ�г�����ڴ�����κεط��� �����ڿ�ִ���ļ���Ŀ���ļ�ͨ�������������ʽ����ġ��� ���Ӷ�̬���������������־�������ӿ�ִ���ļ���������������ġ� ��������������� — ��һЩϵͳ���ʵ�����ġ���
���������������Ǽ������Դ��������� foo.c �ļ��ﲢ�ҽ����������ֽ� foo.so�Ĺ���⡣�н�Ķ����ļ������� foo.o��������������ע����һ��������������������ļ�����������������ֻ��һ����
���� PIC �ı�������־�� -fpic��������������������־�� -shared��
gcc -fpic -c foo.c ld -shared -o foo.so foo.o
���淽�������ڰ汾 4.0 �� BSD/OS��
���� PIC �ı�������־�� -fpic��������������������־�� -shared��
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
���淽�������ڰ汾 3.0 �� FreeBSD.
���� 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 ���������չ����������ϵͳ��ͬ��
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
������һ�����ӡ�������迪�������Ѿ���װ���ˡ�
cc -c foo.c cc -bundle -flat_namespace -undefined suppress -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 �ı������������� 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
PIC ��ȱʡ����˱����������ƽ�����Ǹ��� ������ѡ��� ld �������ӣ�
cc -c foo.c ld -shared -expect_unresolved '*' -o foo.so foo.o
�� GCC ����ϵͳ������ʱ�Ĺ�����һ���ģ�����Ҫ�����ѡ�
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 ��ȡ�йط����� Ԥ���������ҵ���������Ϣ��
������ڿ��Ƿ������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 ����
���������������
һ����Ҫ��ͬ������Դ�����������Ĺ��������б���Ҫ������б����������
��װ�� prefix/share/contrib ������ļ�
��Ҫ�������ģ���װ�� prefix/share/contrib ���������ļ���
��װ�� prefix/doc/contrib ���������ļ�
��װ�� prefix/bin ����Ľű��ļ����Ƕ����ƣ�
��װ�� prefix/bin ����ģ���Ҫ�������Ľű��ļ����Ƕ����ƣ���
�ع���������б�û�к���
�������������������֮һ��
һ����Ҫ�����Ķ������ļ����� OBJS �����г�Ŀ���ļ���
һ����Ҫ�����Ĺ�������� OBJS ���г�Ŀ���ļ���
�����������������
�� make clean ��ɾ���Ķ�����ļ�
�����ӵ� CPPFLAGS
�����ӵ� PROGRAM ��������
�����ӵ� MODULE_big ��������
����� makefile �� Makefile �����ַ��ڱ��������չ��Ŀ¼� Ȼ����Ϳ������� make �����룬Ȼ���� make install ��װ���ģ�顣 �����չ��Ϊ pg_config ���������·�����ҵ��ĵ�һ�� PostgreSQL ��װ����Ͱ�װ�ġ�
�������Ͳ��� 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��
Ҫ��һ�� 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 ��������ֱ�ӷ��أ� ������������������һ�����ؼ��ϵĺ�����ĵ�ǰ����ֵ��
���������������
����һ������� 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 ��ȡ�����йط��ؼ��ϵĺ��������ӡ�
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���Ҫ����Ϊ����û��������Կ����롣