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

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: 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月前
|
SQL 存储 关系型数据库
新手如何入门学习PostgreSQL?
新手如何入门学习PostgreSQL?
|
3月前
|
SQL 存储 关系型数据库
PostgreSQL核心之SQL基础学习
PostgreSQL核心之SQL基础学习
45 3
|
3月前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
376 0
|
4月前
|
SQL 存储 关系型数据库
关系型数据库PostgreSQL学习
【7月更文挑战第4天】
457 2
|
5月前
|
存储 关系型数据库 数据库
经验大分享:PostgreSQL学习之【用户权限管理】说明
经验大分享:PostgreSQL学习之【用户权限管理】说明
67 0
|
6月前
|
SQL 监控 关系型数据库
postgresql|数据库|插件学习(二)---postgresql-12的外置插件pg_profile的启用和使用
postgresql|数据库|插件学习(二)---postgresql-12的外置插件pg_profile的启用和使用
217 0
|
6月前
|
SQL 监控 关系型数据库
postgresql|数据库|插件学习(一)---postgresql-12的内置插件pg_stat_statements的启用和使用
postgresql|数据库|插件学习(一)---postgresql-12的内置插件pg_stat_statements的启用和使用
175 0
|
6月前
|
Cloud Native 关系型数据库 OLAP
从0~1,基于DMS面向AnalyticDB PostgreSQL的数据ETL链路开发
在传统数仓中,往往采用资源预购的方式,缺少面向业务的资源调整灵活性。 在数据分析这种存在明显业务波峰波谷或分时请求的场景下,实例无法按需使用,造成了大量成本浪费。云原生数仓AnalyticDB PostgreSQL产品自2022年2月正式发布了Serverless版之后,依托于内核强大的资源管理能力...
|
关系型数据库 分布式数据库 PolarDB
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
363 0
|
存储 缓存 关系型数据库