Postgres C函数 – 传递和返回数字

我刚刚开始使用Postgres外部C函数进行测试。 当我传入一个数字并返回它时,该function正常。 (例)

样本函数

PG_FUNCTION_INFO_V1(numericTesting); Datum numericTesting(PG_FUNCTION_ARGS) { Numeric p = PG_GETARG_NUMERIC(0); PG_RETURN_NUMERIC(p); } 

但是,当我尝试对传入的变量执行任何数学函数时,它将无法编译。 我明白了

错误:二进制文件的操作数无效*

样本函数

 PG_FUNCTION_INFO_V1(numericTesting); Datum numericTesting(PG_FUNCTION_ARGS) { Numeric p = PG_GETARG_NUMERIC(0); PG_RETURN_NUMERIC(p * .5); } 

是什么造成的? 我猜测Numeric数据类型需要一些函数来允许数学。 我尝试使用:PG_RETURN_NUMERIC(DatumGetNumeric(p * .5)),但结果相同。

Numeric不是基本类型,因此您无法直接对其进行算术运算。 C没有运算符重载,因此无法为Numeric添加乘法运算符。 你必须使用适当的函数调用来乘以数字。

与编写Pg扩展函数时的大多数事情一样,阅读源代码并了解它在其他地方的完成情况会很有帮助。

在这种情况下,请查看src/backend/utils/adt/numeric.c 。 检查Datum numeric_mul(PG_FUNCTION_ARGS) ,你会看到它使用mul_var(...)来完成工作。

不幸的是, mul_varstatic所以它不能在numeric.c之外numeric.c 。 刺激和令人惊讶。 必须有一种合理的方法来处理来自C扩展函数的NUMERIC而不使用spi / fmgr通过SQL运算符调用来完成工作,正如您在注释中所示,您使用DirectFunctionCall2来调用numeric_mul运算符。

看起来直接从C调用的Numeric的公共东西在src/include/utils/numeric.h所以让我们看一下。 哎呀,不多,只是一些用于在NumericDatum之间进行转换的宏以及一些帮助GETARGRETURN宏。 看起来像通过SQL调用的用法可能是唯一的方法。

如果您确实发现自己通过Numeric的SQL接口使用DirectFunctionCall2 ,则可以使用int4_numeric从C整数为另一侧创建一个Numeric参数。

如果您找不到解决方案,请在pgsql-general邮件列表上发布,您将获得更多具有C扩展和源代码的人员。 如果您这样做,请返回此post。

*两个操作数必须具有算术类型(整数或浮点类型)。 对于不是简单整数或浮点类型的东西, Numeric是一个typedef,这是一个相当不错的选择。

不幸的是,我对Postgres API的了解不够多。 希望有一个宏或函数可以将Numeric转换为算术类型,或者将算术运算应用于Numeric类型。

完全回避这个问题的一种方法是使用数据类型强制。 使用您要强制赋值的类型声明您的SQL函数,例如

 CREATE FUNCTION foo(float8) RETURNS float8 AS 'SELECT $i' LANGUAGE SQL; 

提供给该函数的任何值都将强制转换为该值:

 SELECT foo(12); 

即使明确指定类型也可以:

 SELECT foo(12::numeric); 

您的C代码将获得double代码。 (信用证转到Tom Lane,请参阅此邮件列表post 。)