PostgreSQL 8.2.3 婺桺桺懼
劯锔媆锔䆹33. 欷匘 SQL媆誕嬉誕

33.9. C 臺蘔庘昄

䫘潙垔幬䔇庘昄埇傖䫘 C 喍(潡蔙滇婯C噚垹䔇臺蘔懫套C++)㔗認湙䔇庘昄赆䚡臏誕媘攕媹蘘凹茇(噌庆康)幽婫䫌橉媇単湹扞驔襕媹蘘㔗媘攕媹蘘䔇䬹攓滇"C 臺蘔庘昄"启"喙鄘庘昄"幋閘䔇寺彆婉誺垂鍙䔇䚡乕幹愇婘婴蔙幋閘垂鍙婪滇婔湙䔇㔗啹溴湺庖䔇喙鄘庘昄康婺喍䫘潙垔幬C庘昄柊冕庖崓麟橔喘䔇湙冋㔗

䕞嬉凹 C 庘昄橬婴䓉脄䫘亥垔㔗桄䔇"䬽橸-1"䔇脄䫘亥垔滇锔誺婺臖庘昄幥喍婔婻 PG_FUNCTION_INFO_V1() 垟準湺臖䔇償婋麵暫䴺䔇闼湙㔗䚺儏認婻垟臘䴺婔婻蔕鼯湚䔇("䬽橸-0")庘昄㔗婴䓉鼯湚麯婘 CREATE FUNCTION 麯弄滯䔇鄘滇 C 㔗䯄婘蔕鼯湚䔇庘昄噾䂟庘嚄庖婂襕滇啹婺䓂洉攓寘啹启䚺幟媘脘婉誺庺庯噚垹攓寘啹係䂘傉䇽櫇毕垄㔗

33.9.1. 媘攕媹蘘

嘷䫘潙垔幬䔇庘昄丸婔渇赆橉媇単嚔臺脄䫘施媘攕媹蘘単欉檪埇媹蘘凹茇桺傽麯䔇庘昄䕞湺乕媹蘘誕喙庻㔗啹溴䫘庯䫘潙垔幬 C 庘昄䔇 CREATE FUNCTION 媙釂婺庘昄弄滯婴婻媇敇埇媹蘘凹茇桺傽劉㔕婘䕞湺桺傽麯脄䫘䔇 C 庘昄劉(誂毖严埙)㔗套悩澇橬滯䇞弄滯 C 庘昄劉闼幽儌啺螆垄婯 SQL 庘昄劉䕩劯㔗

嘺庯婘 CREATE FUNCTION 变傴婺䂍庺䔇劉庖婋麵䔇䞖濘䫘庯垔嘉噌庆凹茇桺傽

  1. 套悩劉庖滇婔婻䂺凹虇冇彍媹蘘䂍庺䔇桺傽㔗

  2. 套悩劉庖傖庖严婾 $libdir 嚔崘闼幽臖鄘彖儖赆 PostgreSQL 康䕞嘘劉傼敪臖䕞嘘滇婘䚡臏施䇞垔䔇㔗

  3. 套悩劉庖婉寙劆䕞嘘鄘彖闼幽婘陉䘞埗昄 dynamic_library_path 弄滯䔇虇冇麯昖欆㔗

  4. 套悩澇橬婘虇冇麯欆彄臖桺傽潡蔙垄寙劆婔婻麂䂺凹䕞嘘鄘彖闼幽媘攕媹蘘単儌嚔臘商䕘毖拪認婻劉庖準媹蘘認湙庹幯埇傖藇垔滇襕崌蘖䔇(冺麹嘷嬉噖嘩䕞嘘滇婉埇麹䔇)㔗

套悩認婻釺废婉䞇䫘闼幽儌䂍認婻劉庖媹婪广埄䕩噿䔇噌庆康桺傽欷匘劉(锔婩滇 .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 变傴麉桄媹蘘桺傽䔇施唍欉嚔凚躘剩蘘噽嬉媹蘘䔇桺傽㔗

33.9.2. 嘺橸䌂傋䔇 C 臺蘔庘昄

襕䘖長套嘘喍 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 䌂傋垔幬婘
abstimeAbsoluteTimeutils/nabstime.h
booleanboolpostgres.h(埇脘滇䚡臏単喙䘞)
boxBOX*utils/geo_decls.h
byteabytea*postgres.h
"char"char(䚡臏単喙䘞)
characterBpChar*postgres.h
cidCommandIdpostgres.h
dateDateADTutils/date.h
smallint (int2)int2int16postgres.h
int2vectorint2vector*postgres.h
integer (int4)int4int32postgres.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

斵䇽潏傸噾䂟螘螺庖嘺橸䌂傋欔橬埇脘䔇䂷悇潏傸冪埇傖䫘垂鍙䔇庘昄婆婔底冋床㔗

33.9.3. 䬽橸-0 脄䫘亥垔

噽柊冕䯄婘噾䂟婉柊唇庖䔇"蔕鼯湚"啹婺懫膄垹滷誽庺丸婔準㔗溴鼯湚 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 埗昄䔇桹濘㔗婋麵襕螾䔇桄桹濘彍蓼喿庖認底閞鵻㔗

33.9.4. 䬽橸-1 脄䫘亥垔

䬽橸-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 毺垔㔗storagetypeplain, external, extended, main 幋婔㔗

䬽橸-1 䔇庘昄脄䫘鼯湚幘傴潏傸埇脘誫啂婔"喖"䂷悩(誗33.9.10)幽婫垂䯄蓥埏単庘昄(䆹34)启誺䘋臺蘔脄䫘崇䊖単(䆹47)㔗䬽橸-1 䔇傼乕幘敘垹滷䓂洉啹婺垄澇橬誺埉 C 湺庖凹庘昄脄䫘剟螞䔇鍊彽㔗敘崔䔇䂖誗臙埗黙溊䘋废婺䔇 src/backend/utils/fmgr/README 桺傽㔗

33.9.5. 幥喍傼乕

婘蘸彄敘晌䔇臺鵻幋嬉噽襕螘螺婔底 PostgreSQL C 臺蘔庘昄䔇䚡乕蓇彍㔗荘䇽埇傖䫘 C 傖崡䔇噽垄臺蘔(C++, FORTRAN, Pascal)幥喍䫘庯 PostgreSQL 䔇噌庆庘昄嘖锔婩鄘冽麂䄥啹婺垄傸幽婉镕冻 C 䔇脄䫘幹愇㔗幘儌滇臘噽垄臺蘔婯 C 䔇嚹锐埗昄启誫啂唚䔇桹嚟婉婔湙㔗啹溴啺螆嘹䔇䚡䘋臺蘔庘昄滇䫘 C 喍䔇㔗

幥喍启䚡臏 C 庘昄䔇嘺橸蓇彍套婋

33.9.6. 䚡臏启鷆毖媘攕媹蘘䔇庘昄

婘脘崘嘪䫘䫌 C 喍䔇 PostgreSQL 欷匘庘昄幋嬉媙釂䫘婔䓉䬹枪䔇桹濘䚡臏启鷆毖垄傸認湙欉脘䫘潊埇傖赆橉媇単媘攕媹蘘䔇桺傽㔗庖䇞婄臘滇驔襕录傺婔婻噌庆康

套悩驔襕敘崔媇敇闼幽嘹庫臖黙臂淉嘩係䂘䔇桺懼䬹彆滇 C 䚡臏単(cc)启誂毖単(ld)䔇桺懼㔗埥崡PostgreSQL 溊傼乕麯寙劆庹婻埇傖誊臯䔇冋床垄傸婘 contrib 䕞嘘麯㔗婉誺套悩嘹冺蕡認底冋床闼幽嘹䔇昇庖儖冺蕡庯 PostgreSQL 溊傼乕䔇埇䫘攓㔗

录傺噌庆康启鷆毖埇欓臯桺傽䌂嚚饡噽檪溊傼乕䚡臏潊䕞湺桺傽䇽劯檪䕞湺桺傽鷆毖蕙準㔗䕞湺桺傽驔襕录傺潊嘉䘞方噿乕(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 㔗埗蔄 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

䫘 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
Tru64 UNIX

PIC 滇䚺䩕婉驔襕嘪䫘䬹枪䔇䚡臏単锬釹㔗婥䬹枪锬釹䔇 ld 䫘庯鷆毖

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

䫘 GCC 傼敪係䂘䚡臏単施䔇誺䘋滇婔湙䔇婉驔襕䬹枪䔇锬釹㔗

UnixWare

䫘 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诙埡橬噿橉媇単鵇橘婘巻麯欆彄噌庆康䔇媇敇㔗

33.9.7. 欷匘䔇䚡臏悽悇

套悩嘹欷䞖埏婄嘹䔇 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 蓇彍㔗

埇傖螆䘞婋彖埻麟

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 䚡臏启垬輙䔇㔗

REGRESS 埻麟婺彖庺䔇臔橸䫘庯凹嘹䔇昇庖誕臯啂嘐敋臘襕嘪敋臘脘崘誊臯媙釂婘嘹䔇欷匘昇庖䔇䕞嘘婋麵傺䆋婔婻 sql/ 床䕞嘘幽婘噽婺婺橘橕誊臯䔇懟䂇敋臘櫆婔婻桺傽欷匘劉婺 .sql 䔇桺傽認底桺傽婉庫嘷寙劆婘 REGRESS 彖臘婺㔗凹懟婻敋臘鄘媙釂婘 expected/ 床䕞嘘婺寙劆婔婻欷匘劉婺 .out 䔇橘橕䂷悩桺傽㔗make installcheck 儖嚔誊臯敋臘儖膷庺䂷悩婯鵇螆䔇橘橕䂷悩桺傽凹懫噞嚗儖毬䙓 diff -c 湚嚟喍噖 regression.diffs 桺傽㔗驔襕濘懟䔇滇嚕商誊臯婔婻婵崌庖橘橕䂷悩桺傽䔇敋臘儖赆檖只婺"trouble"欔傖臙媇媙䇞媺欔橬橘橕䂷悩桺傽鄘庻婘㔗

㔊柊䴺㔏录傺橘橕䂷悩桺傽橔䞔剘䔇媂濘滇噽录傺婔婻䷺桺傽䇽劯償媄䔇演昖 results/䕞嘘婺䔇敋臘誊臯䂷悩䇞媺溼䇞傖劯儖噽崉彽彄 expected/ 床䕞嘘婺㔗

33.9.8. 崉劽䌂傋埗昄

崉劽䌂傋婉償 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 㔗

33.9.9. 誫啂臯(崉劽䌂傋)

襕傯婔婻 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_descattinmeta 庖枕)㔗

婘嘪䫘 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 埇傖䫘庯䕘毖誫啂潡蔙滇垄埇傖䫘嘩婘婔婻誫啂镖劽䔇庘昄麯䔇嘷嬉誫啂唚㔗

冋床婘婋麵䂍庺㔗

33.9.10. 誫啂镖劽

誻橬婔婻䬹枪䔇 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 诙埡敘崔橬噿誫啂镖劽䔇庘昄䔇冋床㔗

33.9.11. 崔攕埗昄启誫啂䌂傋

C 臺蘔庘昄埇傖弄滯婺毖埖启誫啂崔攕䔇䌂傋 anyelementanyarray 㔗埗黙誗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;

33.9.12. 噌庆喙庻启 LWLock

某傽埇脘媺䘍 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);
        }

劯锔饡釕嬉誕
喙鄘庘昄婪婔亓䫘潙垔幬蕔镖