2017-02-24 64 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