2017-02-24 59 views
3

嗨我試圖創建一個用C寫的postgres UDT。它是一種分數類型。 我試着用一個int64和struct fraction裏面的struct mixednumber做實驗。C嵌套結構的Postgres UDT

#include "postgres.h" 
#include "fmgr.h" 
#include <stdbool.h> 

PG_MODULE_MAGIC; 

typedef struct Fraction 
{ 
    int64 numerator; 
    int64 denominator; 
} Fraction; 

PG_FUNCTION_INFO_V1(fraction_in); 

Datum 
fraction_in(PG_FUNCTION_ARGS) 
{ 
    char *input = PG_GETARG_CSTRING(0); 
    int64 n, d; 
    bool valid; 

    Fraction *result; 

    valid = sscanf(input, "(%ld/%ld)", &n, &d) == 2; 

    if (!valid) 
     ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 
      errmsg("invalid input syntax for fraction: \"%s\"", input))); 

    if (d == 0) 
     ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 
       errmsg("denominator cannot be \"%ld\" in \"%s\"", d, input))); 

    result = (Fraction *) palloc(sizeof(Fraction)); 

    result->numerator = n; 
    result->denominator = d; 

    PG_RETURN_POINTER(result); 
} 

PG_FUNCTION_INFO_V1(fraction_out); 

Datum 
fraction_out(PG_FUNCTION_ARGS) 
{ 
    Fraction *fraction = (Fraction *) PG_GETARG_POINTER(0); 
    char   *result; 

    result = psprintf("(%ld/%ld)", fraction->numerator, fraction->denominator); 

    PG_RETURN_CSTRING(result); 
} 

////////////////////////////////////// 
// Mixed Fractions or Mixed Numbers // 
////////////////////////////////////// 

typedef struct MixedNumber 
{ 
    int64 wholeNumber; 
    Fraction *fraction; 
} MixedNumber; 

PG_FUNCTION_INFO_V1(mixednumber_in); 

Datum 
mixednumber_in(PG_FUNCTION_ARGS) 
{ 
    char *input = PG_GETARG_CSTRING(0); 
    int64 w, n, d; 
    bool valid; 

    MixedNumber *mixed; 

    valid = sscanf(input, "(%ld+(%ld/%ld))", &w, &n, &d) 
      == 3; 

    if (!valid) 
     ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 
      errmsg("invalid input syntax for fraction: \"%s\"", input))); 

    if (d == 0) 
     ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 
       errmsg("denominator cannot be \"%ld\" in \"%s\"", d, input))); 

    mixed = (MixedNumber *) palloc(sizeof(MixedNumber)); 

    mixed->wholeNumber   = w; 
    mixed->fraction    = (Fraction *) palloc(sizeof(Fraction)); 
    mixed->fraction->numerator = n; 
    mixed->fraction->denominator = d; 

    PG_RETURN_POINTER(mixed); 
} 

PG_FUNCTION_INFO_V1(mixednumber_out); 

Datum 
mixednumber_out(PG_FUNCTION_ARGS) 
{ 
    MixedNumber *mixed = (MixedNumber *) PG_GETARG_POINTER(0); 

    char *result; 

    result = psprintf("(%ld+(%ld/%ld))", 
     mixed->wholeNumber, mixed->fraction->numerator, mixed->fraction->denominator); 

    PG_RETURN_CSTRING(result); 
} 

存在的問題是,當我檢索mixednumber柱的小數部分的值是錯誤.. 例

CREATE TABLE mixednumber_test (val mixednumber); 

INSERT INTO mixednumber_test VALUES ('(1+(7/8))'), ('(-1+(-7/8))'), ('(+1+(7/-8))'), ('(0+(-7/-8))'), ('(-0+(+7/8))'), ('(2+(7/+8))'), ('(9+(+7/+8))');

SELECT * FROM mixednumber_test; 

結果是:..

"(1+(0/0))" 
"(-1+(32/4294967952))" 
"(1+(94284056329736/16))" 
"(0+(94284055669488/128))" 
"(0+(0/94284056646312))" 
"(2+(524/94284056644432))" 
"(9+(94284055669488/16))" 

任何專家可以幫助我瞭解這是怎麼回事?

回答

3

用戶數據類型不能包含由指針引用的嵌套結構,因爲數據(尤其是MixedNumber結構內的指針Fraction *)按原樣存儲(而不是遞歸地存儲它指向的數據)。因此,如果指針在導入保存的值後被取消引用,它可能不再包含原始值。

你將不得不提供的所有數據在一個連續的存儲塊,或許通過改變定義

typedef struct MixedNumber { 
    int64 wholeNumber; 
    Fraction fraction; 
} MixedNumber; 

和相應地改變成員訪問。另外不要忘記將內部長度放大到現在的24字節(sizeof(MixedNumber))。

+0

噢,謝謝:) – Marc