4

我刚刚开始使用 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);
}

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

4

3 回答 3

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所以让我们看看那里。哎呀,不多,只是一些用于在NumericandDatum和一些帮助器GETARG和宏之间转换的RETURN宏。看起来通过 SQL 调用使用可能是唯一的方法。

如果您发现自己DirectFunctionCall2无法通过 Numeric 的 SQL 接口使用,您可以使用 C 整数为另一端创建一个 Numeric 参数int4_numeric

如果您找不到解决方案,请在 pgsql-general 邮件列表上发帖,您将在那里获得更多有 C 扩展和源代码经验的人。如果您这样做,请链接回此帖子。

于 2012-09-27T00:59:42.080 回答
0

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

不幸的是,我对 Postgres API 的了解还不够,无法提供更多帮助。希望有一个宏或函数可以将 a 转换Numeric为算术类型,或将算术运算应用于Numeric类型。

于 2012-09-25T18:14:00.747 回答
0

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

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

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

SELECT foo(12);

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

SELECT foo(12::numeric);

您的 C 代码将收到一个double. (归功于 Tom Lane,请参阅此邮件列表帖子。)

于 2018-02-23T21:36:57.513 回答