PostgreSQL服务端开发学习 -- fmgr.h

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
简介: fmgr按官方的解释就是Postgres函数管理器和函数调用接口,在使用C语言开发PostgreSQL后端应用时,所以与backend交互时必须遵循fmgr.h中定义的一些规范。

fmgr按官方的解释就是Postgres函数管理器和函数调用接口,在使用C语言开发PostgreSQL后端应用时,所有与backend交互的函数都必须遵循fmgr.h中定义的一些规范。fmgr.h中定义了很多函数跟宏,如果要学习backend开发,一定要了解这些函数跟宏的用法。

所有可被fmgr直接调用的函数必须有如下签名:

typedefstructFunctionCallInfoBaseData*FunctionCallInfo;
typedefDatum (*PGFunction) (FunctionCallInfofcinfo);

什么叫被fmgr调用?还记得之前分析过的pgpool-recovery扩展,用C语言实现了一些用户自定义函数,比如:pgpool_recovery函数,当执行select pgpool_recovery(...)时,Postgres backend就会调用我们用C语言实现的函数,这个函数就是被fmgr调用的函数。pgpool_recovery的函数原型:

Datumpgpool_recovery(PG_FUNCTION_ARGS)

遵循上面说的函数签名,PG_FUNCTION_ARGS是个宏,展开后就是FunctionCallInfofcinfo。

FmgrInfo结构

typedefstructFmgrInfo{
PGFunctionfn_addr;        /* pointer to function or handler to be called */Oidfn_oid;         /* OID of function (NOT of handler, if any) */shortfn_nargs;       /* number of input args (0..FUNC_MAX_ARGS) */boolfn_strict;      /* function is "strict" (NULL in => NULL out) */boolfn_retset;      /* function returns a set */unsignedcharfn_stats;     /* collect stats if track_functions > this */void*fn_extra;       /* extra space for use by handler */MemoryContextfn_mcxt;      /* memory context to store fn_extra in */fmNodePtrfn_expr;        /* expression parse tree for call, or NULL */} FmgrInfo;

FmgrInfo是最基本的结构,记录了函数的基本信息(system-catalog information),fmgr在调用函数前会先查阅这些信息。

FunctionCallInfoBaseData结构

typedefstructFunctionCallInfoBaseData{
FmgrInfo*flinfo;         /* ptr to lookup info used for this call */fmNodePtrcontext;        /* pass info about context of call */fmNodePtrresultinfo;     /* pass or return extra info about result */Oidfncollation;    /* collation for function to use */#define FIELDNO_FUNCTIONCALLINFODATA_ISNULL 4boolisnull;         /* function must set true if result is NULL */shortnargs;          /* # arguments actually passed */#define FIELDNO_FUNCTIONCALLINFODATA_ARGS 6NullableDatumargs[FLEXIBLE_ARRAY_MEMBER];
} FunctionCallInfoBaseData;

很重要的结构,实际传送到被fmgr调用函数的数据。

InitFunctionCallInfoData宏

填充除args[]数组之外的所有字段:

#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \do { \(Fcinfo).flinfo = (Flinfo); \(Fcinfo).context = (Context); \(Fcinfo).resultinfo = (Resultinfo); \(Fcinfo).fncollation = (Collation); \(Fcinfo).isnull = false; \(Fcinfo).nargs = (Nargs); \} while (0)

FunctionCallInvoke宏

调用FunctionCallInfoBaseData结构中定义的函数。

#define FunctionCallInvoke(fcinfo)  ((* (fcinfo)->flinfo->fn_addr) (fcinfo))

所以被FunctionCallInvoke调用的函数必须有如下签名:

Datumfunction_name(PG_FUNCTION_ARGS)
{
    ...
}

常用的几个基础宏

/* fmgr兼容函数标准参数列表 */#define PG_FUNCTION_ARGS    FunctionCallInfo fcinfo/** 取得字符集*/#define PG_GET_COLLATION()  (fcinfo->fncollation)/** 取得参数个数*/#define PG_NARGS() (fcinfo->nargs)/** 参数是否为空*/#define PG_ARGISNULL(n)  (fcinfo->args[n].isnull)

获取标准类型数据相关的宏定义

#define PG_GETARG_DATUM(n)   (fcinfo->args[n].value)#define PG_GETARG_INT32(n)   DatumGetInt32(PG_GETARG_DATUM(n))#define PG_GETARG_UINT32(n)  DatumGetUInt32(PG_GETARG_DATUM(n))#define PG_GETARG_INT16(n)   DatumGetInt16(PG_GETARG_DATUM(n))#define PG_GETARG_UINT16(n)  DatumGetUInt16(PG_GETARG_DATUM(n))#define PG_GETARG_CHAR(n)    DatumGetChar(PG_GETARG_DATUM(n))#define PG_GETARG_BOOL(n)    DatumGetBool(PG_GETARG_DATUM(n))#define PG_GETARG_OID(n)     DatumGetObjectId(PG_GETARG_DATUM(n))#define PG_GETARG_POINTER(n) DatumGetPointer(PG_GETARG_DATUM(n))#define PG_GETARG_CSTRING(n) DatumGetCString(PG_GETARG_DATUM(n))#define PG_GETARG_NAME(n)    DatumGetName(PG_GETARG_DATUM(n))#define PG_GETARG_TRANSACTIONID(n)  DatumGetTransactionId(PG_GETARG_DATUM(n))/* these macros hide the pass-by-reference-ness of the datatype: */#define PG_GETARG_FLOAT4(n)  DatumGetFloat4(PG_GETARG_DATUM(n))#define PG_GETARG_FLOAT8(n)  DatumGetFloat8(PG_GETARG_DATUM(n))#define PG_GETARG_INT64(n)   DatumGetInt64(PG_GETARG_DATUM(n))/* use this if you want the raw, possibly-toasted input datum: */#define PG_GETARG_RAW_VARLENA_P(n)  ((struct varlena *) PG_GETARG_POINTER(n))/* use this if you want the input datum de-toasted: */#define PG_GETARG_VARLENA_P(n) PG_DETOAST_DATUM(PG_GETARG_DATUM(n))/* and this if you can handle 1-byte-header datums: */#define PG_GETARG_VARLENA_PP(n) PG_DETOAST_DATUM_PACKED(PG_GETARG_DATUM(n))/* DatumGetFoo macros for varlena types will typically look like this: */#define DatumGetByteaPP(X)          ((bytea *) PG_DETOAST_DATUM_PACKED(X))#define DatumGetTextPP(X)           ((text *) PG_DETOAST_DATUM_PACKED(X))#define DatumGetBpCharPP(X)         ((BpChar *) PG_DETOAST_DATUM_PACKED(X))#define DatumGetVarCharPP(X)        ((VarChar *) PG_DETOAST_DATUM_PACKED(X))#define DatumGetHeapTupleHeader(X)  ((HeapTupleHeader) PG_DETOAST_DATUM(X))/* And we also offer variants that return an OK-to-write copy */#define DatumGetByteaPCopy(X)       ((bytea *) PG_DETOAST_DATUM_COPY(X))#define DatumGetTextPCopy(X)        ((text *) PG_DETOAST_DATUM_COPY(X))#define DatumGetBpCharPCopy(X)      ((BpChar *) PG_DETOAST_DATUM_COPY(X))#define DatumGetVarCharPCopy(X)     ((VarChar *) PG_DETOAST_DATUM_COPY(X))#define DatumGetHeapTupleHeaderCopy(X)  ((HeapTupleHeader) PG_DETOAST_DATUM_COPY(X))/* Variants which return n bytes starting at pos. m */#define DatumGetByteaPSlice(X,m,n)  ((bytea *) PG_DETOAST_DATUM_SLICE(X,m,n))#define DatumGetTextPSlice(X,m,n)   ((text *) PG_DETOAST_DATUM_SLICE(X,m,n))#define DatumGetBpCharPSlice(X,m,n) ((BpChar *) PG_DETOAST_DATUM_SLICE(X,m,n))#define DatumGetVarCharPSlice(X,m,n) ((VarChar *) PG_DETOAST_DATUM_SLICE(X,m,n))/* GETARG macros for varlena types will typically look like this: */#define PG_GETARG_BYTEA_PP(n)       DatumGetByteaPP(PG_GETARG_DATUM(n))#define PG_GETARG_TEXT_PP(n)        DatumGetTextPP(PG_GETARG_DATUM(n))#define PG_GETARG_BPCHAR_PP(n)      DatumGetBpCharPP(PG_GETARG_DATUM(n))#define PG_GETARG_VARCHAR_PP(n)     DatumGetVarCharPP(PG_GETARG_DATUM(n))#define PG_GETARG_HEAPTUPLEHEADER(n)    DatumGetHeapTupleHeader(PG_GETARG_DATUM(n))/* And we also offer variants that return an OK-to-write copy */#define PG_GETARG_BYTEA_P_COPY(n)   DatumGetByteaPCopy(PG_GETARG_DATUM(n))#define PG_GETARG_TEXT_P_COPY(n)    DatumGetTextPCopy(PG_GETARG_DATUM(n))#define PG_GETARG_BPCHAR_P_COPY(n)  DatumGetBpCharPCopy(PG_GETARG_DATUM(n))#define PG_GETARG_VARCHAR_P_COPY(n) DatumGetVarCharPCopy(PG_GETARG_DATUM(n))#define PG_GETARG_HEAPTUPLEHEADER_COPY(n)   DatumGetHeapTupleHeaderCopy(PG_GETARG_DATUM(n))/* And a b-byte slice from position a -also OK to write */#define PG_GETARG_BYTEA_P_SLICE(n,a,b) DatumGetByteaPSlice(PG_GETARG_DATUM(n),a,b)#define PG_GETARG_TEXT_P_SLICE(n,a,b)  DatumGetTextPSlice(PG_GETARG_DATUM(n),a,b)#define PG_GETARG_BPCHAR_P_SLICE(n,a,b) DatumGetBpCharPSlice(PG_GETARG_DATUM(n),a,b)#define PG_GETARG_VARCHAR_P_SLICE(n,a,b) DatumGetVarCharPSlice(PG_GETARG_DATUM(n),a,b)

字符串、varchar相关宏定义

#define DatumGetByteaP(X)           ((bytea *) PG_DETOAST_DATUM(X))#define DatumGetTextP(X)            ((text *) PG_DETOAST_DATUM(X))#define DatumGetBpCharP(X)          ((BpChar *) PG_DETOAST_DATUM(X))#define DatumGetVarCharP(X)         ((VarChar *) PG_DETOAST_DATUM(X))#define PG_GETARG_BYTEA_P(n)        DatumGetByteaP(PG_GETARG_DATUM(n))#define PG_GETARG_TEXT_P(n)         DatumGetTextP(PG_GETARG_DATUM(n))#define PG_GETARG_BPCHAR_P(n)       DatumGetBpCharP(PG_GETARG_DATUM(n))#define PG_GETARG_VARCHAR_P(n)      DatumGetVarCharP(PG_GETARG_DATUM(n))

函数返回标准类型相关宏定义

#define PG_RETURN_DATUM(x)   return (x)#define PG_RETURN_INT32(x)   return Int32GetDatum(x)#define PG_RETURN_UINT32(x)  return UInt32GetDatum(x)#define PG_RETURN_INT16(x)   return Int16GetDatum(x)#define PG_RETURN_UINT16(x)  return UInt16GetDatum(x)#define PG_RETURN_CHAR(x)    return CharGetDatum(x)#define PG_RETURN_BOOL(x)    return BoolGetDatum(x)#define PG_RETURN_OID(x)     return ObjectIdGetDatum(x)#define PG_RETURN_POINTER(x) return PointerGetDatum(x)#define PG_RETURN_CSTRING(x) return CStringGetDatum(x)#define PG_RETURN_NAME(x)    return NameGetDatum(x)#define PG_RETURN_TRANSACTIONID(x)  return TransactionIdGetDatum(x)/* these macros hide the pass-by-reference-ness of the datatype: */#define PG_RETURN_FLOAT4(x)  return Float4GetDatum(x)#define PG_RETURN_FLOAT8(x)  return Float8GetDatum(x)#define PG_RETURN_INT64(x)   return Int64GetDatum(x)#define PG_RETURN_UINT64(x)  return UInt64GetDatum(x)/* RETURN macros for other pass-by-ref types will typically look like this: */#define PG_RETURN_BYTEA_P(x)   PG_RETURN_POINTER(x)#define PG_RETURN_TEXT_P(x)    PG_RETURN_POINTER(x)#define PG_RETURN_BPCHAR_P(x)  PG_RETURN_POINTER(x)#define PG_RETURN_VARCHAR_P(x) PG_RETURN_POINTER(x)#define PG_RETURN_HEAPTUPLEHEADER(x)  return HeapTupleHeaderGetDatum(x)

函数调用相关宏定义

#define DirectFunctionCall1(func, arg1) \DirectFunctionCall1Coll(func, InvalidOid, arg1)#define DirectFunctionCall2(func, arg1, arg2) \DirectFunctionCall2Coll(func, InvalidOid, arg1, arg2)#define DirectFunctionCall3(func, arg1, arg2, arg3) \DirectFunctionCall3Coll(func, InvalidOid, arg1, arg2, arg3)#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4) \DirectFunctionCall4Coll(func, InvalidOid, arg1, arg2, arg3, arg4)#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5) \DirectFunctionCall5Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5)#define DirectFunctionCall6(func, arg1, arg2, arg3, arg4, arg5, arg6) \DirectFunctionCall6Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)#define DirectFunctionCall7(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \DirectFunctionCall7Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)#define DirectFunctionCall8(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \DirectFunctionCall8Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)#define DirectFunctionCall9(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \DirectFunctionCall9Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)#define FunctionCall1(flinfo, arg1) \FunctionCall1Coll(flinfo, InvalidOid, arg1)#define FunctionCall2(flinfo, arg1, arg2) \FunctionCall2Coll(flinfo, InvalidOid, arg1, arg2)#define FunctionCall3(flinfo, arg1, arg2, arg3) \FunctionCall3Coll(flinfo, InvalidOid, arg1, arg2, arg3)#define FunctionCall4(flinfo, arg1, arg2, arg3, arg4) \FunctionCall4Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4)#define FunctionCall5(flinfo, arg1, arg2, arg3, arg4, arg5) \FunctionCall5Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5)#define FunctionCall6(flinfo, arg1, arg2, arg3, arg4, arg5, arg6) \FunctionCall6Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)#define FunctionCall7(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \FunctionCall7Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)#define FunctionCall8(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \FunctionCall8Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)#define FunctionCall9(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \FunctionCall9Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)#define OidFunctionCall0(functionId) \OidFunctionCall0Coll(functionId, InvalidOid)#define OidFunctionCall1(functionId, arg1) \OidFunctionCall1Coll(functionId, InvalidOid, arg1)#define OidFunctionCall2(functionId, arg1, arg2) \OidFunctionCall2Coll(functionId, InvalidOid, arg1, arg2)#define OidFunctionCall3(functionId, arg1, arg2, arg3) \OidFunctionCall3Coll(functionId, InvalidOid, arg1, arg2, arg3)#define OidFunctionCall4(functionId, arg1, arg2, arg3, arg4) \OidFunctionCall4Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4)#define OidFunctionCall5(functionId, arg1, arg2, arg3, arg4, arg5) \OidFunctionCall5Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5)#define OidFunctionCall6(functionId, arg1, arg2, arg3, arg4, arg5, arg6) \OidFunctionCall6Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)#define OidFunctionCall7(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \OidFunctionCall7Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)#define OidFunctionCall8(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \OidFunctionCall8Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)#define OidFunctionCall9(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \OidFunctionCall9Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)




相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
3月前
|
Cloud Native 关系型数据库 分布式数据库
|
5月前
|
关系型数据库 数据库 C语言
PostgreSQL服务端开发学习 -- Datum
在使用C语言开发PostgreSQL后端、客户端应用时,Datum无处不在,所以必须要对Datum有很清楚的了解。
139 2
|
5月前
|
关系型数据库 C语言 PostgreSQL
PostgreSQL服务端开发学习 --- 常用结构及宏定义1
本篇主要讲解使用C语言开发PostgreSQL服务端应用(libpq、自定义函数、扩展)常用到的结构及宏定义。
96 0
|
19天前
|
Docker 容器 关系型数据库
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
本期课程将于4月11日19:00开始直播,内容包括源码编译基础知识和实践操作,课程目标是使学员掌握源码编译部署技能,为未来发展奠定基础,期待大家在课程中取得丰富的学习成果!
【PolarDB-X从入门到精通】 第四讲:PolarDB分布式版安装部署(源码编译部署)
|
2月前
|
SQL 存储 关系型数据库
MySQL技能完整学习列表——1、数据库基础概念——1、关系型数据库(Relational Database)
MySQL技能完整学习列表——1、数据库基础概念——1、关系型数据库(Relational Database)
179 0
|
3月前
|
关系型数据库 分布式数据库 数据库
阿里云PolarDB开发者大会首度召开,让数据库开发像“搭积木”一样简单
阿里云PolarDB开发者大会首度召开,让数据库开发像“搭积木”一样简单
109 0
|
3月前
|
关系型数据库 分布式数据库 数据库
家人们谁懂啊?为了让你们免费体验PolarDB,我们开发了一个动手体验搭子!
抢鲜体验赢好礼,阿里云定制折叠伞和定制双肩包等你拿!
家人们谁懂啊?为了让你们免费体验PolarDB,我们开发了一个动手体验搭子!
|
4月前
|
SQL 监控 关系型数据库
postgresql|数据库|插件学习(二)---postgresql-12的外置插件pg_profile的启用和使用
postgresql|数据库|插件学习(二)---postgresql-12的外置插件pg_profile的启用和使用
71 0
|
4月前
|
SQL 监控 关系型数据库
postgresql|数据库|插件学习(一)---postgresql-12的内置插件pg_stat_statements的启用和使用
postgresql|数据库|插件学习(一)---postgresql-12的内置插件pg_stat_statements的启用和使用
85 0
|
1月前
|
关系型数据库 分布式数据库 数据库
成都晨云信息技术完成阿里云PolarDB数据库产品生态集成认证
近日,成都晨云信息技术有限责任公司(以下简称晨云信息)与阿里云PolarDB PostgreSQL版数据库产品展开产品集成认证。测试结果表明,晨云信息旗下晨云-站群管理系统(V1.0)与阿里云以下产品:开源云原生数据库PolarDB PostgreSQL版(V11),完全满足产品兼容认证要求,兼容性良好,系统运行稳定。