我刚刚开始使用Postgres外部C函数进行测试。当我传入一个数字并返回它时,该功能正常。 (实施例)
样本函数
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)),但结果相同。
答案 0 :(得分:4)
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
而不使用spi / fmgr通过SQL
运算符调用来完成工作,正如您在评论中所示使用DirectFunctionCall2
来调用numeric_mul
运算符。
看起来直接从C调用的Numeric的公共内容在src/include/utils/numeric.h
中,所以让我们看一下。哎呀,不多,只是用于在Numeric
和Datum
以及一些助手GETARG
和RETURN
宏之间进行转换的一些宏。看起来通过SQL调用的使用可能是唯一的方法。
如果您确实发现自己因使用{JAME的SQL接口DirectFunctionCall2
而陷入困境,则可以使用int4_numeric
从C整数为另一侧创建一个Numeric参数。
如果找不到解决方案,请在pgsql-general邮件列表上发布,您将获得更多具有C扩展和源代码的人员。如果您这样做,请链接回此帖。
答案 1 :(得分:0)
*
的两个操作数必须具有算术类型(整数或浮点类型)。对于不是简单整数或浮点类型的东西,Numeric
是一个typedef,这是一个不错的选择。
不幸的是,我对Postgres API的了解不够多。希望有一个宏或函数可以将Numeric
转换为算术类型,或者将算术运算应用于Numeric
类型。
答案 2 :(得分:0)
完全回避这个问题的一种方法是使用数据类型强制。使用您要强制赋值的类型声明您的SQL函数,例如
CREATE FUNCTION foo(float8) RETURNS float8 AS 'SELECT $i' LANGUAGE SQL;
提供给该函数的任何值都将被强制转换为该值:
SELECT foo(12);
即使明确指定类型也可以:
SELECT foo(12::numeric);
您的C代码将收到double
。 (归功于Tom Lane,请参阅此mailing list post。)