䫘潙垔幬䔇庘昄埇傖䫘 C 喍(潡蔙滇婯C噚垹䔇臺蘔懫套C++)㔗認湙䔇庘昄赆䚡臏誕媘攕媹蘘凹茇(噌庆康)幽婫䫌橉媇単湹扞驔襕媹蘘㔗媘攕媹蘘䔇䬹攓滇"C 臺蘔庘昄"启"喙鄘庘昄"幋閘䔇寺彆婉誺垂鍙䔇䚡乕幹愇婘婴蔙幋閘垂鍙婪滇婔湙䔇㔗啹溴湺庖䔇喙鄘庘昄康婺喍䫘潙垔幬C庘昄柊冕庖崓麟橔喘䔇湙冋㔗
䕞嬉凹 C 庘昄橬婴䓉脄䫘亥垔㔗桄䔇"䬽橸-1"䔇脄䫘亥垔滇锔誺婺臖庘昄幥喍婔婻 PG_FUNCTION_INFO_V1() 垟準湺臖䔇償婋麵暫䴺䔇闼湙㔗䚺儏認婻垟臘䴺婔婻蔕鼯湚䔇("䬽橸-0")庘昄㔗婴䓉鼯湚麯婘 CREATE FUNCTION 麯弄滯䔇鄘滇 C 㔗䯄婘蔕鼯湚䔇庘昄噾䂟庘嚄庖婂襕滇啹婺䓂洉攓寘啹启䚺幟媘脘婉誺庺庯噚垹攓寘啹係䂘傉䇽櫇毕垄㔗
嘷䫘潙垔幬䔇庘昄丸婔渇赆橉媇単嚔臺脄䫘施媘攕媹蘘単欉檪埇媹蘘凹茇桺傽麯䔇庘昄䕞湺乕媹蘘誕喙庻㔗啹溴䫘庯䫘潙垔幬 C 庘昄䔇 CREATE FUNCTION 媙釂婺庘昄弄滯婴婻媇敇埇媹蘘凹茇桺傽劉㔕婘䕞湺桺傽麯脄䫘䔇 C 庘昄劉(誂毖严埙)㔗套悩澇橬滯䇞弄滯 C 庘昄劉闼幽儌啺螆垄婯 SQL 庘昄劉䕩劯㔗
嘺庯婘 CREATE FUNCTION 变傴婺䂍庺䔇劉庖婋麵䔇䞖濘䫘庯垔嘉噌庆凹茇桺傽
套悩劉庖滇婔婻䂺凹虇冇彍媹蘘䂍庺䔇桺傽㔗
套悩劉庖傖庖严婾 $libdir 嚔崘闼幽臖鄘彖儖赆 PostgreSQL 康䕞嘘劉傼敪臖䕞嘘滇婘䚡臏施䇞垔䔇㔗
套悩劉庖婉寙劆䕞嘘鄘彖闼幽婘陉䘞埗昄 dynamic_library_path 弄滯䔇虇冇麯昖欆㔗
套悩澇橬婘虇冇麯欆彄臖桺傽潡蔙垄寙劆婔婻麂䂺凹䕞嘘鄘彖闼幽媘攕媹蘘単儌嚔臘商䕘毖拪認婻劉庖準媹蘘認湙庹幯埇傖藇垔滇襕崌蘖䔇(冺麹嘷嬉噖嘩䕞嘘滇婉埇麹䔇)㔗
套悩認婻釺废婉䞇䫘闼幽儌䂍認婻劉庖媹婪广埄䕩噿䔇噌庆康桺傽欷匘劉(锔婩滇 .so)䇽劯喉麉桄毬䙓婪麵䔇誺䘋欆婔镉㔗套悩誻滇崌蘖闼幽媹蘘崌蘖㔗
傺螞嘪䫘䕩凹庯 $libdir 䔇䕞嘘潡蔙锔誺媘攕康虇冇垔嘉噌庆康㔗認湙套悩桄䬽橸垬輙婘婔婻婉劯䔇嘉䘞闼幽儌埇傖䞔寡䬽橸剺亓㔗$libdir 䔇垂鍙䕞嘘嘉䘞埇傖䫘 pg_config --pkglibdir 变傴欆彄㔗
誊臯 PostgreSQL 橉媇単䔇䫘潙媙釂埇傖镉寖虇冇彄膆愿媹蘘䔇桺傽㔗婔婻婩蓕䔇髍臇儌滇檪臖桺傽潡蔙婔婻醻北䕞嘘䔇溄鍊螆䘞婺 postgres 䫘潙婉埇臂启/潡婉脘欓臯㔗
婘傂嘘愙喕婋婘 CREATE FUNCTION 变傴麯䂍庺䔇桺傽劉滇婘係䂘臘麯毬䙓桺橸螄嘘䔇啹溴套悩驔襕喉渇媹蘘闼幽嚔喉渇誊臯認婻誺䘋㔗
㔊濘懟㔏PostgreSQL 婉嚔躻媘䚡臏 C 庘昄婘嘪䫘 CREATE FUNCTION 变傴幋嬉嘹媙釂䚡臏垄㔗埗黙誗33.9.6诙埡敘崔媇敇㔗
婺庖䇞媺婉嚔髍臇媹蘘噌庆康桺傽傯 PostgreSQL 8.2 嚔哋儖演昖闼婻桺傽䔇"magic block"傖䇞媺䬽橸噚垹攓㔗襕寙劆"magic block"臙婘寙劆庖 fmgr.h 崘桺傽幋劯儖婋麵䔇喙垹喍誕婔婻(幘埻脘滇婔婻)昇庖䔇溊傼乕桺傽婺
#ifdef PG_MODULE_MAGIC PG_MODULE_MAGIC; #endif
套悩婉欷䞖噚垹 8.2 幋嬉䔇䬽橸#ifdef 敋臘幘埇傖䩕䘖㔗
媘攕媹蘘凹茇桺傽婘饡渇嘪䫘幋劯儖婔䕘悂䘍婘喙庻婺㔗婘劯婔婻嚔臺婺䔇婋婔渇脄䫘儖埻驔昖欆严埙臘䔇冽償嚔體㔗套悩嘹愿嚺彽麉桄媹蘘(懫套麉桄䚡臏幋劯)埇傖嘪䫘 LOAD 变傴潡蔙麉桄嚔哋婔婻桄䔇嚔臺㔗
媘攕媹蘘桺傽幘埇傖寙劆彺哋寡庘昄启䂷溘庘昄㔗套悩寙劆婔婻劉婺 _PG_init
䔇庘昄闼幽臖庘昄儖婘臖桺傽赆媹蘘劯䆋剿欓臯臖庘昄婉脘毖埖傂嘘埗昄幽婫媙釂誫啂 void 㔗套悩寙劆婔婻劉婺 _PG_fini
䔇庘昄闼幽臖庘昄儖婘臖桺傽剿儖赆剩蘘嬉欓臯劯湙臖庘昄婉脘毖埖傂嘘埗昄幽婫媙釂誫啂 void 㔗驔襕濘懟䔇滇 _PG_fini
備婘臖桺傽剿儖赆剩蘘嬉欓臯蔯婉滇婘嚔臺䂷溘䔇施唍欓臯㔗䕞嬉備婘滯䇞嘪䫘 LOAD 变傴麉桄媹蘘桺傽䔇施唍欉嚔凚躘剩蘘噽嬉媹蘘䔇桺傽㔗
襕䘖長套嘘喍 C 臺蘔庘昄儌媙釂䘖長 PostgreSQL 婘喙鄘套嘘臘䯄嘺橸昄扞䌂傋傖埪套嘘嚹噖埪嚹庺庘昄㔗PostgreSQL 喙鄘檪嘺橸䌂傋嘷嘩"婔庖喙庻"䩋写㔗垔幬婘昊䓉䌂傋婪䔇䫘潙垔幬庘昄垂鍙婪垔幬庖 PostgreSQL 凹臖昄扞䌂傋埇脘䔇淉嘩㔗幘儌滇臘PostgreSQL 埻滇傯伕䕻臂埡启庻嗘臖昄扞䌂傋幽嘪䫘嘹垔幬䔇庘昄準膷噖㔕崇䊖㔕膷庺昄扞㔗
嘺橸䌂傋埇傖橬婋麵婬䓉喙鄘嘵攕(湚嚟)幋婔
嚹锐昄唚垔阪
嚹锐嚘䫘垔阪
嚹锐嚘䫘埻阪
嚹锐昄唚䔇䌂傋阪庥埻脘滇 1, 2, 4 庖誗㔗套悩 sizeof(Datum) 婘嘹䔇橺単婪滇 8 䔇臺闼幽誻橬 8 庖誗㔗嘹襕傫䂖垔幬嘹䔇䌂傋䇞媺垄傸婘傂嘘嘷係广埄婪鄘滇䕩劯儺凩(庖誗)㔗冋套long 滇婔婻剌鍷䔇䌂傋啹婺婘婔底橺単婪垄滇 4 庖誗蔯婘埥崡婔底橺単婪滇 8 庖誗蔯 int 婘崓崔昄 Unix 橺単婪鄘滇 4 庖誗䔇㔗婘婔婻 Unix 橺単婪䔇 int4 劽䊖垂䯄埇脘滇
/* 4-庖誗昘昄嚹唚 */ typedef int int4;
埥崡傂嘘儺凩䔇垔阪䌂傋鄘埇傖滇嚹锐嚘䫘傋㔗冋套婋麵滇婔婻 PostgreSQL 䌂傋䔇垂䯄
/* 16-庖誗䂷悇嚹锐嚘䫘 */ typedef struct { double x, y; } Point;
埻脘嘪䫘毺劏認底䌂傋䔇毺鐽婘 PostgreSQL 庘昄麯嚹噖启嚹庺昄扞㔗襕誫啂認湙䌂傋䔇唚䫘 palloc 彖陉溼䇞昄麟䔇喙庻准噙認底喙庻䇽劯誫啂婔婻毺劏垄䔇毺鐽㔗套悩埻滇愿誫啂启膷噖埗昄䌂傋婯昄唚鄘䕩劯䔇昄唚埇傖媘䘖鵺崡䔇 palloc 埻襕誫啂毺劏膷噖昄唚䔇毺鐽儌臯㔗
橔劯欔橬埻阪䌂傋劯湙幘埻脘锔誺嚘䫘準嚹锐㔗欔橬埻阪䌂傋媙釂傖婔婻 4 庖誗䔇阪庥嘘嚔哋幽婫欔橬庻嗘婘臖䌂傋婺䔇昄扞媙釂櫆婘䘓毖五阪庥嘘䔇庻嗘䷺閘麯㔗阪庥嘘滇䂷悇䔇噘阪幘儌滇臘寙拸阪庥嘘橸躆䔇阪庥㔗
躥只 |
䂺凹婉襕媞櫹婔婻嚘䫘嚹锐䔇膷噖唚劥彍冽埇脘乘废伕䕻婪䔇昄扞㔗啹婺毺鐽冽埇脘䕘毖毺劏婔婻伕䕻䚷喾寺㔗認溇蓇彍䔇嫇婔冋崡婘誗33.10麯㔗 |
懫套潏傸埇傖䫘婋麵䔇桹濘垔幬婔婻 text 䌂傋
typedef struct { int4 length; char data[1]; } text;
滆䇽婪麵弄滯䔇昄扞嘘阪庥婉轿傖庻嗘傂嘘埇脘䔇庖严婾㔗啹婺婘 C 婺婉埇脘弄滯埻阪䂷悇欔傖潏傸唔蕡認湙䔇䘖臖C 䚡臏単婉嚔凹昄䂇婋湺誕臯评啘演昖㔗埻驔襕彖陉轿崘䔇䷺閘䇽劯檪昄䂇嘷啔噾䂟弄滯婺劽锗阪庥䔇埻麟螪閞㔗認滇婔婻婩䫘䔇檔噓嘹埇傖婘螩崔 C 昍䓏幥婺臂彄㔗
嘷崇䊖埻阪䌂傋施媙釂傫䂖彖陉溼䇞䔇喙庻昄麟幽溼䇞螆䘞阪庥嘘㔗冋套套悩愿婘婔婻 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 臘䴺鍇媹儺凩滇䫘庯埻阪䌂傋䔇敘喘鼯湚㔗
臘33-1彖庺庖幥喍嘪䫘 PostgreSQL 喙䘞䌂傋䔇 C 庘昄麯驔襕䘖長䔇 SQL 䌂傋婯 C 䌂傋䔇凹庫噿係㔗"垔幬婘"彖䂍庺庖驔襕寙劆傖诙埡臖䌂傋垔幬䔇崘桺傽㔗濘懟嘹庫臖攂滇饡噽寙拸 postgres.h 啹婺垄弄滯庖螩崔嘹驔襕䔇婩薪㔗
臘33-1. 婯喙傺 SQL 䌂傋京昽䔇 C 䌂傋
SQL 䌂傋 | C 䌂傋 | 垔幬婘 |
---|---|---|
abstime | AbsoluteTime | utils/nabstime.h |
boolean | bool | postgres.h(埇脘滇䚡臏単喙䘞) |
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 |
斵䇽潏傸噾䂟螘螺庖嘺橸䌂傋欔橬埇脘䔇䂷悇潏傸冪埇傖䫘垂鍙䔇庘昄婆婔底冋床㔗
噽柊冕䯄婘噾䂟婉柊唇庖䔇"蔕鼯湚"啹婺懫膄垹滷誽庺丸婔準㔗溴鼯湚 C 庘昄䔇埗昄启䂷悩䫘捞锔 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), /* 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 桺傽婺幽婫䚡臏潊庖噌庆䕞湺潏傸埇傖䫘婋麵䔇变傴婺 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 䔇䂷悩㔗認湙崇䊖埇傖螷潏傸镪噉婘庘昄傼乕麯麵演昖 NULL 膷噖㔗套悩婉認湙崇䊖潏傸儌冖滯䇞演昖 NULL 懫套婺懟婻嚹锐嚘䫘䔇埗昄演昖䷺毺鐽㔗凹庯嚹唚䌂傋䔇埗昄潏傸䫔躿澇橬媂濘演昖
儘䞇認䓉蔕脄䫘鼯湚䫘蕙準䞔剘嘖垄剘婉崻垹滷䓂洉婘婔底係䂘婪䫘認䓉桹濘嚹锐懫 int 償䔇昄扞䌂傋儌嚔䵄彄啄锆㔗蔯婫潏傸澇橬冽喘䔇誫啂 NULL 䂷悩䔇媂濘幘澇橬鍴庖檪庘昄婖湚寡傖崡䔇崇䊖 NULL 埗昄䔇桹濘㔗婋麵襕螾䔇桄桹濘彍蓼喿庖認底閞鵻㔗
䬽橸-1 脄䫘亥垔嘪䫘垟潽鍴崓崔昄嚹锐埗昄启䂷悩䔇崉溗攓㔗䬽橸-1 鼯湚庘昄䔇C垔幬攂滇婋麵認湙
Datum funcname(PG_FUNCTION_ARGS)
埥崡婋麵䔇垟
PG_FUNCTION_INFO_V1(funcname);
幘媙釂庺䯄婘劯婔婻溊桺傽麯(锔婩儌埇傖喍婘庘昄躻躆嬉麵)㔗凹闼底 internal 臺蘔庘昄蔯蘔婉驔襕脄䫘認婻垟啹婺 PostgreSQL 䕞嬉啺螆喙鄘庘昄鄘滇䬽橸-1 㔗婉誺凹庯媘攕媹蘘䔇庘昄垄滇媙釂䔇㔗
婘䬽橸-1 庘昄麯懟婻垂鍙埗昄鄘滇䫘婔婻凹庫臖埗昄昄扞䌂傋䔇 PG_GETARG_xxx()
垟檷埡䔇䫘誫啂䌂傋䔇 PG_RETURN_xxx()
垟誫啂䂷悩㔗PG_GETARG_xxx()
毖埖襕檷埡䔇庘昄埗昄䔇䚡埙(傯 0 嚔哋)嘩婺噽埗昄㔗PG_RETURN_xxx()
毖埖垂鍙襕誫啂䔇昄唚婺躻躆䔇埗昄㔗
婋麵滇启婪麵婔湙䔇庘昄嘖滇滇䫘䬽橸-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_float8); Datum add_one_float8(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
䔇䚡乕麯認麯潏傸婉喉驔襕婉啩埞廌躻噌 float8 滇嚹锐嚘䫘䌂傋㔗埥崡婔婻冋床滇䫘庯埻阪䌂傋䔇垟 GETARG 锊薟庖檷埡"麂婩蓇"(寋䚷䔇潡蔙轙阪䔇)唚驔襕啔䔇崇䊖㔗
䬽橸-1 䔇庘昄埥婔婻噘崓䔇櫹誕滇凹 NULL 膷噖启䂷悩䔇崇䊖㔗垟 PG_ARGISNULL(n)
噕螩婔婻庘昄敋臘懟婻膷噖滇劥婺 NULL 嘷䇽認埻滇凹闼底澇橬弄滯婺"strict"䔇庘昄橬媙襕㔗啹婺套悩橬 PG_GETARG_xxx()
垟膷噖埗昄滇傯镽嚔哋螇䞖䔇㔗臙濘懟潏傸婉庫臖欓臯 PG_GETARG_xxx()
鍴麂橬庺弄滯庖埗昄婉滇 NULL 㔗襕誫啂婔婻 NULL 䂷悩埇傖欓臯婔婻 PG_RETURN_NULL()
認湙凹婖湚䔇启婉婖湚䔇庘昄鄘橬昽㔗
婘桄鼯湚䔇毖埼婺柊冕䔇噽垄锬釹滇 PG_GETARG_xxx()
垟䔇婴婻埻䓉㔗丸婔婻埻嘷 PG_GETARG_xxx_COPY()
媺臕誫啂婔婻毺垔埗昄䔇嬇橸臖嬇橸滇埇傖垬噘婄喍噖䔇㔗捞锔䔇垟橬施唍嚔誫啂婔婻毺劏䬷䊖庻嗘婘臘婺䔇昊唚䔇毺鐽啹溴潏傸婉脘喍噖臖毺鐽㔗䫘 PG_GETARG_xxx_COPY()
垟媺臕诙埡婔婻埇喍䔇䂷悩㔗丸庯婻埻嘷䫌 PG_GETARG_xxx_SLICE()
垟䂇潊垄毖埖婬婻埗昄㔗丸婔婻滇埗昄䔇婻昄(婯婪劯)㔗丸庯婻启丸婬婻滇襕誫啂䔇啟䓂麟启昄扞枕䔇阪庥㔗啟䓂滇傯镽嚔哋螇䞖䔇婔婻蘘昄䔇阪庥彍襕挗誫啂臖唚䔇嬷嘍阪庥䔇昄扞㔗認底誺䘋柊冕庖螪閞崓昄扞唚䔇婺婔鄘彖䔇敘橬昽桹濘䬹彆滇昄扞䔇庻嗘䌂傋滇"external"䔇施唍㔗婔婻庖枕䔇庻嗘䌂傋埇傖䫘 ALTER TABLE tablename ALTER COLUMN colname SET STORAGE storagetype 毺垔㔗storagetype 滇 plain, external, extended, main 幋婔㔗
䬽橸-1 䔇庘昄脄䫘鼯湚幘傴潏傸埇脘誫啂婔"喖"䂷悩(誗33.9.10)幽婫垂䯄蓥埏単庘昄(䆹34)启誺䘋臺蘔脄䫘崇䊖単(䆹47)㔗䬽橸-1 䔇傼乕幘敘垹滷䓂洉啹婺垄澇橬誺埉 C 湺庖凹庘昄脄䫘剟螞䔇鍊彽㔗敘崔䔇䂖誗臙埗黙溊䘋废婺䔇 src/backend/utils/fmgr/README 桺傽㔗
婘蘸彄敘晌䔇臺鵻幋嬉噽襕螘螺婔底 PostgreSQL C 臺蘔庘昄䔇䚡乕蓇彍㔗荘䇽埇傖䫘 C 傖崡䔇噽垄臺蘔(C++, FORTRAN, Pascal)幥喍䫘庯 PostgreSQL 䔇噌庆庘昄嘖锔婩鄘冽麂䄥啹婺垄傸幽婉镕冻 C 䔇脄䫘幹愇㔗幘儌滇臘噽垄臺蘔婯 C 䔇嚹锐埗昄启誫啂唚䔇桹嚟婉婔湙㔗啹溴啺螆嘹䔇䚡䘋臺蘔庘昄滇䫘 C 喍䔇㔗
幥喍启䚡臏 C 庘昄䔇嘺橸蓇彍套婋
嘪䫘 pg_config --includedir-server 欆庺 PostgreSQL 橉媇単䔇崘桺傽垬輙嘉䘞㔗
檪嘹䔇傼乕䚡臏潊埇傖媘攕輙噖 PostgreSQL 䔇康桺傽攂滇驔襕婔底䬹枪䔇湺螄㔗埗黙誗33.9.6诙埡套嘘婘嘹䔇广埄婪啔認傽庋䔇臥䂖臘滯㔗
毬䙓誗33.9.1䔇毺䴺婺嘹䔇噌庆康垔幬婔婻"magic block"㔗
嘷彖陉喙庻施䫘 PostgreSQL 䔇 palloc
启 pfree
庘昄埡傼䕩庫䔇 C 康庘昄 malloc
启 free
㔗䫘 palloc
彖陉䔇喙庻婘懟婻庋媇䂷溘施嚔躻媘麪櫆镪噉庖喙庻濇驾㔗
螄冖䫘 memset
凹䂷悇庖誗橙镽㔗套悩婉認幽啔儌冽锆櫇毕 Hash 䘵嚘启 Hash 誂毖啹婺媙釂傯昄扞䂷悇婺锬庺橔噙䬹冕䔇嘉準螇䞖 Hash 㔗剿嘪嘹彺哋寡庖䂷悇䔇欔橬嘘傉䇽橬埇脘橬庹婻凹阊庖誗(䂷悇婺䔇昂)劆橬傄婆唚㔗
崓崔昄䔇 PostgreSQL 喙鄘䌂傋垔幬婘 postgres.h 婺蔯庘昄䞇䊖単毖埼(PG_FUNCTION_ARGS 京京)鄘婘 fmgr.h 婺欔傖嘹躿儏庫臖寙拸認婴婻桺傽㔗庺庯䓂洉攓寘啹橔喘噽寙拸 postgres.h 喉寙拸噽垄係䂘潡蔙䫘潙崘桺傽㔗寙劆 postgres.h 儖躻媘寙劆 elog.h 启 palloc.h 㔗
婘䕞湺桺傽麯垔幬䔇严埙婔垔婉脘䕩庐喾仕幘婉脘启垔幬婘 PostgreSQL 橉媇単埇欓臯傼乕婺䔇严埙劉庖喾仕㔗套悩嘹䩋彄庖婯溴䕩噿䔇髍臇媇敇闼幽媙釂麉变劉嘹䔇庘昄潡蔙埻麟㔗
婘脘崘嘪䫘䫌 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
婪麵桹濘锗䫘庯 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 㔗埗蔄 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
䫘 Sun 䚡臏単施录傺 PIC 䔇䚡臏単湺媖滇 -KPIC 䫘 GCC 䚡臏単施录傺 PIC 䔇䚡臏単湺媖滇 -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 䔇䚡臏単湺媖滇 -K PIC 䫘 GCC 䚡臏単施录傺 PIC 䔇䚡臏単湺媖滇 -fpic 㔗鷆毖噌庆康施 SCO 䚡臏単䫘 -G 蔯 GCC 嘪䫘 -shared 㔗
cc -K PIC -c foo.c cc -G -o foo.so foo.o
潡
gcc -fpic -c foo.c gcc -shared -o foo.so foo.o
㔊柊䴺㔏套悩嘹蓬冖認底準黴垂婘崻崉溗闼幽嘹庫臖蔄荏嘪䫘 GNU Libtool 垄檪广埄䔇噞嚗锊薟婘庖婔婻䂘婔䔇毖埼麯㔗
䫘潊䔇噌庆康桺傽䇽劯儌埇傖媹蘘彄 PostgreSQL 麯麵寂庖㔗婘䂍 CREATE FUNCTION 变傴弄滯桺傽劉䔇施唍媙釂弄滯噌庆康桺傽䔇劉庖蔯婉滇婺閘䕞湺桺傽䔇劉庖㔗臙濘懟嘹埇傖婘 CREATE FUNCTION 变傴婪媘䘖係䂘湺庖䔇噌庆康欷匘劉(锔婩滇 .so 潡 .sl)幽婫庺庯橔嘿䔇噚垹攓蔄荏幘庫臖媘䘖㔗
啂崘䩋䩋誗33.9.1诙埡橬噿橉媇単鵇橘婘巻麯欆彄噌庆康䔇媇敇㔗
套悩嘹欷䞖埏婄嘹䔇 PostgreSQL 欷匘昇庖闼幽䂍垄傸螆䘞婔婻埇䓂洉䔇䚡臏係䂘埇脘嚔䕩嘷啄锆㔗啹溴 PostgreSQL 柊冕庖婔婻 PGXS 悽悇䫘庯欷匘䔇䚡臏認湙䞔剘䔇欷匘昇庖儌埇傖婘婔婻噾䂟垬輙庖䔇橉媇単婪䚡臏庖㔗認婻悽悇幽婉欷䞖垂䯄婔婻䂘婔䔇䚡臏欔橬婯 PostgreSQL 䕩噿䔇蘇傽䔇悽悇垄埻滇䫘庯躻媘寡闼底䞔剘䔇橉媇単欷匘昇庖䔇䚡臏㔗凹庯敘崉溗䔇寙誻滇驔襕幥喍嘹躻噌䔇䚡臏係䂘㔗
襕嘪䫘臖悽悇儌媙釂喍婔婻䞔剘䔇 makefile幽婘噽婺螆䘞婔底埻麟婘䂷儆寙拸噘匔䔇 PGXS makefile 㔗婋麵滇婔婻䚡臏 isbn_issn 䔇冋床垄寙劆婔婻噌庆康㔕婔婻 SQL 臔橸㔕婔婻桺懼㔗
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 䚡臏启垬輙䔇㔗
婘 REGRESS 埻麟婺彖庺䔇臔橸䫘庯凹嘹䔇昇庖誕臯啂嘐敋臘襕嘪敋臘脘崘誊臯媙釂婘嘹䔇欷匘昇庖䔇䕞嘘婋麵傺䆋婔婻 sql/ 床䕞嘘幽婘噽婺婺橘橕誊臯䔇懟䂇敋臘櫆婔婻桺傽欷匘劉婺 .sql 䔇桺傽認底桺傽婉庫嘷寙劆婘 REGRESS 彖臘婺㔗凹懟婻敋臘鄘媙釂婘 expected/ 床䕞嘘婺寙劆婔婻欷匘劉婺 .out 䔇橘橕䂷悩桺傽㔗make installcheck 儖嚔誊臯敋臘儖膷庺䂷悩婯鵇螆䔇橘橕䂷悩桺傽凹懫噞嚗儖毬䙓 diff -c 湚嚟喍噖 regression.diffs 桺傽㔗驔襕濘懟䔇滇嚕商誊臯婔婻婵崌庖橘橕䂷悩桺傽䔇敋臘儖赆檖只婺"trouble"欔傖臙媇媙䇞媺欔橬橘橕䂷悩桺傽鄘庻婘㔗
㔊柊䴺㔏录傺橘橕䂷悩桺傽橔䞔剘䔇媂濘滇噽录傺婔婻䷺桺傽䇽劯償媄䔇演昖 results/䕞嘘婺䔇敋臘誊臯䂷悩䇞媺溼䇞傖劯儖噽崉彽彄 expected/ 床䕞嘘婺㔗
崉劽䌂傋婉償 C 䂷悇闼湙橬啺垔䔇婄匔㔗崉劽䌂傋䔇垂冋埇脘寙劆䷺(NULL)庖枕㔗埥崡婔婻匂庯䂓欪北渇婔鄘彖䔇崉劽䌂傋埇脘启劯婔䂓欪评䘘䔇噽垄潊叻橬婉劯䔇嘘/庖枕㔗啹溴PostgreSQL 柊冕婔婻誺䘋毖埼䫘庯傯 C 婺螪閞崉劽䌂傋㔗
啺螆婺婋麵昖臵喍婔婻庘昄
SELECT name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'Bill' OR name = 'Sam';
婘婪麵䔇昖臵麯䫘䬽橸-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() 䫘婘 null 衻愘婪 */ PG_RETURN_BOOL(DatumGetInt32(salary) > limit); }
GetAttributeByName
滇 PostgreSQL 係䂘庘昄䫘準誫啂嘷嬉螄嘘䔇庖枕㔗垄橬婬婻埗昄䌂傋婺 HeapTupleHeader 䔇嚹噖庘昄䔇埗昄㔕嘹愿襕䔇庖枕劉䓄㔕婔婻䇞垔庖枕滇劥婺 NULL 䔇誫啂埗昄㔗GetAttributeByName
庘昄誫啂婔婻 Datum 唚嘹埇傖䫘凹庫䔇 DatumGetXXX()
垟檪垄蘸扵潊劽锗䔇昄扞䌂傋㔗臙濘懟套悩螆䘞庖 NULL 湺媖闼幽誫啂唚滇方懟幬䔇婘庖崺凹䂷悩啔傂嘘崇䊖幋嬉攂滇襕噽演昖 NULL 湺媖㔗
誻橬婔婻 GetAttributeByNum
䫘庖枕䚡埙蔯婉滇庖枕劉锬埡䕞湺庖枕㔗
婋麵䔇变傴婘 SQL 麯弄滯 c_overpaid
庘昄
CREATE FUNCTION c_overpaid(emp, integer) RETURNS boolean AS 'DIRECTORY/funcs', 'c_overpaid' LANGUAGE C STRICT;
臙濘懟嘪䫘 STRICT 劯儌婉驔襕演昖膷噖埗昄滇劥橬 NULL 㔗
襕傯婔婻 C 臺蘔庘昄麯誫啂婔婻臯潡崉劽䌂傋䔇昄唚埇傖嘪䫘婔婻䬹枪䔇 API 垄柊冕庖螩崔垟启庘昄準潽鍴崓崔昄彽嘩崉劽昄扞䌂傋䔇崉溗攓㔗襕嘪䫘臖 API 溊傼乕媙釂寙劆
#include "funcapi.h"
彽嘩婔婻崉劽䌂傋昄扞唚(幘儌滇婔婻"臯")橬婴䓉桹濘嘹埇傖傯婔婻 Datum 唚昄䂇麯彽嘩幘埇傖傯婔婻埇傖嚹锐䂍臖臯䔇庖枕䌂傋䔇膷噖蘸扵庘昄䔇 C 庖严婾昄䂇麯彽嘩㔗婉䞇滇巻䓉桹嚟嘹饡噽鄘驔襕婺臯䂷悇诙埡潡蔙彽嘩婔婻 TupleDesc 柟誄严㔗婘嘪䫘 Datums 䔇施唍嘹䂍 BlessTupleDesc
嚹锐認婻 TupleDesc 䇽劯婺懟臯脄䫘 heap_form_tuple
㔗婘嘪䫘 C 庖严婾䔇施唍嘹䂍 TupleDescGetAttInMetadata
嚹锐 TupleDesc 䇽劯婺懟臯脄䫘 BuildTupleFromCStrings
㔗套悩滇誫啂婔婻臯镖劽䔇婺劽欔橬螆䘞準黴鄘埇傖婘丸婔渇脄䫘臖庘昄䔇施唍婔渇攓垯潊㔗
橬庹婻冪彷庘昄埇傖䫘庯螆䘞欔驔襕䔇 TupleDesc 㔗婘崓崔昄誫啂崉劽䌂傋䂍脄䫘蔙䔇庘昄麯傺螞䔇啔濘滇認湙䔇
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
檪嚹锐䂍脄䫘庘昄躻噌䔇 fcinfo 嚹锐䂍垄(襕挗嘪䫘䬽橸-1 䔇脄䫘幹愇)㔗resultTypeId 埇傖弄滯婺 NULL 潡蔙毖櫽庘昄䔇䂷悩䌂傋 OID 䔇匔鄘埻麟婄应(毺鐽)㔗resultTupleDesc 庫臖滇婔婻匔鄘䔇 TupleDesc 埻麟婄应(毺鐽)㔗演昖䂷悩滇劥 TYPEFUNC_COMPOSITE 套滇resultTupleDesc 儌噾䂟准噙喘驔襕䔇 TupleDesc 庖㔗套悩婉滇嘹埇傖檖只婔婻䌂嚚"誫啂螄嘘䔇庘昄婘婔婻婉毖埖螄嘘䔇䯇嵄婺赆脄䫘"䔇髍臇㔗
㔊柊䴺㔏
get_call_result_type
埇傖檪婔婻崔攕䔇庘昄䂷悩蓼悊婺垂鍙䌂傋啹溴垄婘誫啂崔攕䔇湺麟䂷悩䔇庘昄麯幘冽橬䫘蔯婉備備滇誫啂崉劽䌂傋䔇庘昄麯㔗resultTypeId 膷庺婂襕䫘庯闼底誫啂崔攕䔇湺麟䌂傋䔇庘昄㔗
㔊濘懟㔏
get_call_result_type
橬婔婻劯脂嚘噇get_expr_result_type
埇傖䫘庯䂍婔婻䫘臘膆嚟湏臘䴺䔇庘昄脄䫘蓼悊膷庺垄埇傖䫘庯蓖商傯庘昄橸躆崡膹彴桺䂷悩䌂傋䔇婺劽㔗誻橬婔婻get_func_result_type
埇傖䫘婘埻脘拪彄庘昄 OID 䔇婺劽㔗婉誺認底庘昄婉脘崇䊖闼底弄滯婺誫啂 record 䔇庘昄幽婫get_func_result_type
婉脘蓼悊崔攕䔇䌂傋啹溴嘹橔喘誻滇嘪䫘get_call_result_type
㔗
斓䔇䯄婘噾䂟庘嚄䔇诙埡 TupleDesc 䔇庘昄滇
TupleDesc RelationNameGetTupleDesc(const char *relname)
垄埇傖傯婔婻变劉䔇噿係麯婺臯䌂傋诙埡婔婻 TupleDesc 誻橬
TupleDesc TypeGetTupleDesc(Oid typeoid, List *colaliases)
埇傖嘺庯䌂傋 OID 诙埡婔婻 TupleDesc 㔗垄埇傖䫘庯䂍婔婻嘺橸䌂傋潡蔙婔婻崉劽䌂傋诙埡 TupleDesc 㔗婉誺垄婉脘崇䊖誫啂 record 䔇庘昄幽婫婉脘蓼悊崔攕䔇䌂傋㔗
婔斥嘹橬庖婔婻 TupleDesc 套悩嘹愿嘪䫘 Datum 闼幽脄䫘
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
套悩嘹愿䫘 C 庖严婾闼幽脄䫘
AttInMetadata *TupleDescGetAttInMetadata(TupleDesc tupdesc)
套悩嘹婘喍婔婻誫啂镖劽䔇庘昄闼幽嘹埇傖檪認底庘昄䔇䂷悩媺庻婘 FuncCallContext 䂷悇麯(彖彆嘪䫘 tuple_desc 潡 attinmeta 庖枕)㔗
婘嘪䫘 Datum 䔇施唍嘪䫘
HeapTuple heap_form_tuple(TupleDesc tupdesc, Datum *values, bool *isnull)
彽嘩婔婻 HeapTuple 垄檪昄扞傖 Datum 䔇嘵嚟庴䂍䫘潙㔗
婘嘪䫘 C 庖严婾䔇施唍䫘
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
彽嘩婔婻 HeapTuple 傖 C 庖严婾䔇嘵嚟䂍庺䫘潙昄扞㔗values 滇婔婻 C 庖严婾䔇昄䂇誫啂臯䔇懟婻庖枕凹庫噽婺婔婻㔗懟婻 C 庖严婾鄘庫臖滇庖枕昄扞䌂傋䔇膷噖庘昄鵇橘䔇嘵嚟㔗婺庖傯噽婺婔婻庖枕婺誫啂婔婻 NULL 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 䫘庯婘誫啂臯䔇施唍(幘儌滇臘誫啂崉劽昄扞䌂傋) * 婘埻誫啂嘺橸(幘儌滇湺麟)昄扞䌂傋䔇施唍幽婉驔襕㔗 * 埻橬婘嘹庖崺䫘 BuildTupleFromCStrings() 录傺誫啂臯䔇施唍欉驔襕垄 */ AttInMetadata *attinmeta; /* * 䫘庯媙釂婘崔渇脄䫘閘庻昂䔇䂷悇䔇喙庻䯇嵄 * * multi_call_memory_ctx 滇䫌 SRF_FIRSTCALL_INIT() 婺嘹螆䘞䔇幽婫䫌 SRF_RETURN_DONE() 䫘庯橙䊖㔗 * 垄滇䫘庯庻櫆傂嘘驔襕虘轪崔渇脄䫘 SRF 幋閘麉崉嘪䫘䔇喙庻 */ MemoryContext multi_call_memory_ctx; /* * 埇锬䔇毺鐽毺劏寙劆臯柟誄䔇䂷悇 * * tuple_desc 䫘庯誫啂臯(幘儌滇臘崉劽昄扞䌂傋)幽婫埻滇婘嘹愿嘪䫘 heap_form_tuple() 蔯婉滇 BuildTupleFromCStrings() 彽嘩臯䔇施唍驔襕㔗 * 臙濘懟認麯庻嗘䔇 TupleDesc 毺鐽锔婩庫臖噽䫘 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(retcomposite); Datum retcomposite(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); /* 婺䔇䂷悩䌂傋彽嘩婔婻臯柟誄 */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context " "that cannot accept type record"))); /* 䫘潊䘉劯傯輩 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); /* 橙䊖(認底垂鍙婪幽麂媙襕) */ pfree(values[0]); pfree(values[1]); pfree(values[2]); pfree(values); SRF_RETURN_NEXT(funcctx, result); } else /* 婘澇橬昄扞枋䘍䔇施唍幾䔇庋愙 */ { SRF_RETURN_DONE(funcctx); } }
婘 SQL 麯弄滯認婻庘昄䔇婔婻桹濘滇
CREATE TYPE __retcomposite AS (f1 integer, f2 integer, f3 integer); CREATE OR REPLACE FUNCTION retcomposite(integer, integer) RETURNS SETOF __retcomposite AS 'filename', 'retcomposite' LANGUAGE C IMMUTABLE STRICT;
埥崡婔婻桹濘滇嘪䫘 OUT 埗昄
CREATE OR REPLACE FUNCTION retcomposite(IN integer, IN integer, OUT f1 integer, OUT f2 integer, OUT f3 integer) RETURNS SETOF record AS 'filename', 'retcomposite' LANGUAGE C IMMUTABLE STRICT;
臙濘懟婘認婻桹濘麯庘昄䔇膷庺䌂傋垂鍙婪滇寪劉䔇 record 䌂傋㔗
埗黙溊乕埏婄寙麯䔇 contrib/tablefunc 诙埡敘崔橬噿誫啂镖劽䔇庘昄䔇冋床㔗
C 臺蘔庘昄埇傖弄滯婺毖埖启誫啂崔攕䔇䌂傋 anyelement 启 anyarray 㔗埗黙誗33.2.5诙埡橬噿崔攕庘昄䔇敘臥䂖蓼麪㔗套悩庘昄埗昄潡蔙誫啂䌂傋垔幬婺崔攕䌂傋闼幽庘昄䔇嘩蔙儌方濘鵇噽䘖長傡儖櫽彄䔇埗昄傖埪驔襕誫啂䔇昄扞㔗婘 fmgr.h 麯橬婴婻誺䘋埇傖螷䬽橸-1 䔇 C 庘昄䘖長垄䔇埗昄䔇䇞彺昄扞䌂傋傖埪垄驔襕誫啂䔇昄扞䌂傋㔗認婴婻誺䘋埆 get_fn_expr_rettype(FmgrInfo *flinfo) 启 get_fn_expr_argtype(FmgrInfo *flinfo, int argnum) 㔗垄傸誫啂䂷悩潡蔙埗昄䔇䌂傋 OID 套悩認底媇敇婉埇诙埡彍誫啂 InvalidOid 㔗䂷悇 flinfo 锔婩滇傖 fcinfo->flinfo 誕臯螪閞䔇㔗埗昄 argnum 滇傖 0 婺嘺䔇㔗get_call_result_type
幘埇傖敪傼 get_fn_expr_rettype
㔗
懫套啺螆愿喍婔婻庘昄毖埖傂懟䌂傋䔇婔婻噄䘹幽婫誫啂臖䌂傋䔇婔婻婔䂘昄䂇
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; bool isnull; 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"); /* 诙埡柊冕䔇噄䘹(襕償媄噽婺 NULL 䔇愙喕) */ isnull = PG_ARGISNULL(0); if (isnull) element = (Datum) 0; else 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, &isnull, 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 IMMUTABLE;
某傽埇脘媺䘍 LWLocks 幽婘橉媇単劇媘施彖陉噌庆喙庻㔗某傽䔇噌庆康媙釂锔誺毺垔 shared_preload_libraries 䔇桹濘鵇噽媹蘘㔗噌庆喙庻埇傖锔誺婘 _PG_init
庘昄婺脄䫘
void RequestAddinShmemSpace(int size)
媺䘍㔗
LWLocks 埇傖锔誺婘 _PG_init
婺脄䫘
void RequestAddinLWLocks(int n)
媺䘍㔗
婺庖镪噉埇脘庺䯄䔇䆂庬溇傽懟婔婻劯䆇鄘庫嘷婘誂毖幽彺哋寡噽噌劏喙庻施嘪䫘 LWLock AddinShmemInitLock
䴺评套婋
static mystruct *ptr = NULL; if (!ptr) { bool found; LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); ptr = ShmemInitStruct("my struct name", size, &found); if (!ptr) elog(ERROR, "out of shared memory"); if (!found) { initialize contents of shmem area; acquire any requested LWLocks using: ptr->mylockid = LWLockAssign(); } LWLockRelease(AddinShmemInitLock); }