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_var
是static
所以它不能在numeric.c
之外numeric.c
。 刺激和令人惊讶。 必须有一种合理的方法来处理来自C
扩展函数的NUMERIC
而不使用spi / fmgr通过SQL
运算符调用来完成工作,正如您在注释中所示,您使用DirectFunctionCall2
来调用numeric_mul
运算符。
看起来直接从C调用的Numeric的公共东西在src/include/utils/numeric.h
所以让我们看一下。 哎呀,不多,只是一些用于在Numeric
和Datum
之间进行转换的宏以及一些帮助GETARG
和RETURN
宏。 看起来像通过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 。)