2012-09-25 69 views
2

我刚刚开始用Postgres外部C函数进行测试。当我传入一个数字并返回它时,该函数可以正常工作。 (例)Postgres C函数 - 传递和返回数字

示例函数

PG_FUNCTION_INFO_V1(numericTesting); 
Datum 
numericTesting(PG_FUNCTION_ARGS) 
{ 
    Numeric  p = PG_GETARG_NUMERIC(0); 
    PG_RETURN_NUMERIC(p); 
} 

然而,当我尝试做传递的变量的任何数学函数,它不会编译。我得到

error: invalid operands to binary *

示例函数

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))但结果相同。

+0

该版本可行,但需要使用两个数字。需要弄清楚如何从一个Integer或Float8实例化一个Numeric我想。 PG_FUNCTION_INFO_V1(numericTesting); Datum numericTesting(PG_FUNCTION_ARGS) { Numeric p = PG_GETARG_NUMERIC(0);数字答案= DatumGetNumeric(DirectFunctionCall2(numeric_mul,NumericGetDatum(p_latitude),NumericGetDatum(p_latitude))); PG_RETURN_NUMERIC(answer); } – user739866

回答

0

*的两个操作数必须具有算术类型(整数或浮点类型)。这是一个非常好的选择,Numeric是一个typedef,它不是一个简单的整数或浮点类型。

不幸的是,我对Postgres API不够了解得多。希望有一个宏或函数可以将Numeric转换为算术类型,或将算术运算应用于Numeric类型。

+0

你绝对是对的。我试图找出究竟是什么。我在上面编辑了一个编辑,但只有在传入2个Numeric类型的对象时才起作用。 – user739866

+0

grep“numeric_to_double_no_overflow”和/或“PGTYPESnumeric_to_double”的源代码。代码将显示如何执行从'struct'到'double'的翻译。由于数据类型强制是我的解决方案(请参阅我的答案),因此不是完整的答案,但这至少是一个指针。 – Demitri

3

Numeric不是原始类型,所以你不能直接对它进行算术运算。 C没有运算符重载,所以没有办法为Numeric添加乘法运算符。您必须使用适当的函数调用来增加数字。

与编写Pg扩展函数的大多数情况一样,读取源代码并查看其在别处如何完成可能很有帮助。

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

不幸的是mul_varstatic所以它不能在numeric.c之外使用。刺激和令人惊讶。正如您在注释中所示,使用DirectFunctionCall2调用numeric_mul运算符时,必须有合理的方式来处理NUMERIC扩展功能中的NUMERIC,而无需使用spi/fmgr通过SQL运算符调用完成工作。

它看起来像从C直接可以调用的Numeric的公共内容在src/include/utils/numeric.h所以让我们看看那里。哎呀,不多,只是一些宏,用于在NumericDatum之间转换以及一些帮助程序GETARGRETURN宏。看起来像通过SQL调用的用法可能是唯一的方法。

如果您发现自己通过数字的SQL接口使用DirectFunctionCall2卡住,则可以使用int4_numeric从C整数为另一端创建一个数字参数。

如果您找不到解决方案,请在pgsql-general邮件列表上发帖,您将获得更多有关C扩展和源代码的经验。如果你这样做,请回到这篇文章。

0

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

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

提供该功能的任何值将被强制转换成该值:

SELECT foo(12); 

即使明确指定类型将工作:

SELECT foo(12::numeric); 

你的代码将收到一个double。 (请参阅Tom Lane,见mailing list post。)