Postgres C功能 - 传递和传播返回数字

时间:2012-09-25 18:00:04

标签: c postgresql pointers

我刚刚开始使用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)),但结果相同。

3 个答案:

答案 0 :(得分:4)

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

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

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

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

看起来直接从C调用的Numeric的公共内容在src/include/utils/numeric.h中,所以让我们看一下。哎呀,不多,只是用于在NumericDatum以及一些助手GETARGRETURN宏之间进行转换的一些宏。看起来通过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。)