我刚刚开始测试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(基准获取数值(p * .5)),但结果相同。
4条答案
按热度按时间flseospp1#
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调用使用可能是唯一的方法。如果您发现自己无法通过Numeric的SQL接口使用
DirectFunctionCall2
,则可以使用int4_numeric
从C整数为另一端创建Numeric参数。如果你找不到解决方案,可以在pgsql-general邮件列表上发帖,那里会有更多的人对C扩展和源代码有经验,如果你这样做了,可以链接回这篇文章。
wvyml7n52#
一个完全避免这个问题的方法是使用数据类型强制。用你想要强制一个值到的类型来声明你的SQL函数,例如。
提供给该函数的任何值都将被强制为该值:
甚至显式指定类型也可以:
你的C代码会收到一个
double
(感谢Tom Lane,请看这个mailing list post)。vhmi4jdf3#
*
的两个操作数都必须是算术类型(整型或浮点型),很有可能Numeric
是一个typedef,它的类型不是简单的整型或浮点型。不幸的是,我对Postgres API的了解还不够,希望有一个宏或函数可以将
Numeric
转换为算术类型,或者将算术运算应用于Numeric
类型。xwbd5t1u4#