2017-02-24 6 views
3

こんにちは、Cで書かれたpostgres UDTを作成しようとしています。これは小数型です。 私は内部でint64とstructの部分を持つstruct mixednumberを試そうとしています。Postgres UDT in C with Nested struct

#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