2012-09-25 25 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。)