PostgreSQL外部C語言函數載入過程

上篇文章咱們提到:sql

quanzl-mac:postgresql.builtin_pool quanzl$ nm lib/plpgsql.so 
...
0000000000007e10 T _pg_finfo_plpgsql_call_handler
000000000001c888 s _pg_finfo_plpgsql_call_handler.my_finfo
...
0000000000007e20 T _plpgsql_call_handler
...

這是怎麼來的?直接看函數定義(src/pl/plpgsql/src/pl_handler.c):api

...
PG_FUNCTION_INFO_V1(plpgsql_call_handler);

Datum
plpgsql_call_handler(PG_FUNCTION_ARGS)
{
...

全部外掛模塊中的函數都是這種形式定義,返回值必須是Datum,參數必須使用預處理符 PG_FUNCTION_ARGS。plpgsql_call_handler是定義在pg_language中的存儲過程處理入口,調用方式與能夠在SQL中使用的函數有所不一樣,因此它直接使用return方式返回值。而通常的SQL函數好比earthdistance模塊中的geo_distancebash

...
PG_FUNCTION_INFO_V1(geo_distance);

Datum
geo_distance(PG_FUNCTION_ARGS)
{
...
  PG_RETURN_FLOAT8(result);
}

SQL定義函數

CREATE FUNCTION geo_distance (point, point)
RETURNS float8
LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE AS 'MODULE_PATHNAME';

它必須使用 PG_RETURN_xxx 系列預處理符來返回。post

返回值的使用能夠參考DirectFunctionCalln(n爲數字,表是參數個數)定義去理解,有必要的話另文再寫,這裏簡單一提,主要仍是講預處理符PG_FUNCTION_INFO_V1,下邊是它的定義:fetch

#define PG_FUNCTION_INFO_V1(funcname) \
extern Datum funcname(PG_FUNCTION_ARGS); \
extern PGDLLEXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \
const Pg_finfo_record * \
CppConcat(pg_finfo_,funcname) (void) \
{ \
	static const Pg_finfo_record my_finfo = { 1 }; \
	return &my_finfo; \
} \
extern int no_such_variable

再看earthdistance.so的symbol:ui

0000000000000de0 T _geo_distance
0000000000000dd0 T _pg_finfo_geo_distance
0000000000000fb0 s _pg_finfo_geo_distance.my_finfo

CppConcat(pg_finfo_,funcname)新定義一個前綴 pg_finfo_ 的函數,pg_finfo_geo_distance就是這麼來的,它很簡單,返回結構體 Pg_finfo_record,其成員 api_version 爲 1。postgresql

強大的PG已經爲從此擴展作好準備。code

函數加載部分(src/backend/utils/fmgr/fmgr.c)的檢查 fetch_finfo_record:io

const Pg_finfo_record *inforec;

  infofuncname = psprintf("pg_finfo_%s", funcname);

  /* Try to look up the info function */
  infofunc = (PGFInfoFunction) lookup_external_function(filehandle,
                              infofuncname);
...
  inforec = (*infofunc) ();
...

目前只容許加載V1函數,也沒有定義更多。

相關文章
相關標籤/搜索