Postgres C函数-传递和返回数值

j8ag8udp  于 2023-01-12  发布在  其他
关注(0)|答案(4)|浏览(139)

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

flseospp

flseospp1#

Numeric不是基元类型,所以不能直接对它进行算术运算。C没有运算符重载,所以无法为Numeric添加乘法运算符。您必须使用适当的函数调用来乘以数值。
与大多数事情一样,在编写Pg扩展函数时,阅读源代码并查看其他地方是如何完成的会很有帮助。
在本例中,请查看src/backend/utils/adt/numeric.c。检查Datum numeric_mul(PG_FUNCTION_ARGS),您将看到它使用mul_var(...)来完成此工作。
不幸的是mul_varstatic,所以它不能在numeric.c之外使用。令人恼火和惊讶。必须有一个合理的方法来处理NUMERICC扩展函数,而不使用spi/fmgr通过SQL操作符调用来完成工作。正如您在注解中使用DirectFunctionCall2调用numeric_mul操作符所示。
看起来可以直接从C调用的Numeric的公共内容在src/include/utils/numeric.h中,所以我们看看那里。哎呀,不多,只有一些用于在NumericDatum之间转换的宏和一些帮助器GETARGRETURN宏。看起来通过SQL调用使用可能是唯一的方法。
如果您发现自己无法通过Numeric的SQL接口使用DirectFunctionCall2,则可以使用int4_numeric从C整数为另一端创建Numeric参数。
如果你找不到解决方案,可以在pgsql-general邮件列表上发帖,那里会有更多的人对C扩展和源代码有经验,如果你这样做了,可以链接回这篇文章。

wvyml7n5

wvyml7n52#

一个完全避免这个问题的方法是使用数据类型强制。用你想要强制一个值到的类型来声明你的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)。

vhmi4jdf

vhmi4jdf3#

*的两个操作数都必须是算术类型(整型或浮点型),很有可能Numeric是一个typedef,它的类型不是简单的整型或浮点型。
不幸的是,我对Postgres API的了解还不够,希望有一个宏或函数可以将Numeric转换为算术类型,或者将算术运算应用于Numeric类型。

xwbd5t1u

xwbd5t1u4#

#include "utils/numeric.h"

// ....

Numeric p = PG_GETARG_NUMERIC(0);
Numeric b = int64_div_fast_to_numeric(5, 1); // 0.5

bool failed = false;
Numeric r = numeric_mul_opt_error(p, b, &failed);
if (failed) {
   // handle failure here
}

PG_RETURN_NUMERIC(r);

相关问题