3

Hi Im trying to create a postgres UDT written in C. It's a fraction type. Im trying to experiment with the struct mixednumber with a int64 and struct fraction inside.

#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);
}

The Problem is when I retrieve a mixednumber column the value of the fraction part is wrong.. Ex

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;

result is :..

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

Can anyone experts help me understand what's going on?

1 Answer 1

3

The user data type cannot contain nested structures referenced by a pointer, since the data (especially the Fraction *-pointer inside the MixedNumber structure) is stored "as is" (and not recursively the data which it points to). So, if the pointer is dereferenced after importing a saved value it will probably no longer contain the original values.

You will have to provide all data in a contiguous memory block, perhaps by altering the definition to

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

and changing the member access accordingly. Also don't forget to enlarge the internal length to now 24 byte (sizeof(MixedNumber)).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.