使用嵌套结构在C中Postgres UDT

时间:2017-02-24 11:45:14

标签: sql c postgresql

您好我正在尝试创建一个用C编写的postgres UDT。它是一种分数类型。 我试图在struct mixednumber中使用int64和struct fraction进行实验。

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

问题是当我检索一个mixnumber列时,分数部分的值是错误的.. 实施例

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))"

任何专家都可以帮我理解发生了什么吗?

1 个答案:

答案 0 :(得分:3)

用户数据类型不能包含指针引用的嵌套结构,因为数据(尤其是MixedNumber - typedef struct MixedNumber { int64 wholeNumber; Fraction fraction; } MixedNumber; 结构中的指针)“按原样”存储(而不是递归地存储数据)它指向)。因此,如果在导入保存的值后指针被取消引用,则它可能不再包含原始值。

您必须提供连续内存块中的所有数据,可能是通过将定义更改为

sizeof(MixedNumber)

并相应地更改成员访问权限。另外,不要忘记将内部长度扩大到现在的24字节([15837956] [TEAM FOUNDATION]MyOffice:Version Control Code Churn Result: Failed Priority: 7 Queued Reasons: Scheduled Host: [TEAM FOUNDATION]MyOffice Job Name: Version Control Code Churn Agent: [TFS-NYM] w3wp.exe Queue Time: Friday, February 24, 2017 11:00 AM Queue Duration: 0:00:01.18 Start Time: Friday, February 24, 2017 11:00 AM Run Duration: 1:00:00.91 End Time: Friday, February 24, 2017 12:00 PM Result Message: Microsoft.TeamFoundation.Framework.Server.DatabaseOperationTimeoutException: TF246018: The database operation exceeded the timeout limit and has been cancelled. Verify that the parameters of the operation are correct. ---> System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. ---> System.ComponentModel.Win32Exception: The wait operation timed out --- End of inner exception stack trace --- at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior) at Microsoft.TeamFoundation.Framework.Server.TeamFoundationSqlResourceComponent.Execute(ExecuteType executeType, CommandBehavior behavior) --- End of inner exception stack trace --- at Microsoft.TeamFoundation.Framework.Server.TeamFoundationSqlResourceComponent.TranslateException(Int32 errorNumber, SqlException sqlException, SqlError sqlError) at Microsoft.TeamFoundation.Framework.Server.TeamFoundationSqlResourceComponent.TranslateException(SqlException sqlException) at Microsoft.TeamFoundation.Framework.Server.TeamFoundationSqlResourceComponent.MapException(SqlException ex, QueryExecutionState queryState) at Microsoft.TeamFoundation.Framework.Server.TeamFoundationSqlResourceComponent.HandleException(Exception exception) at Microsoft.TeamFoundation.Framework.Server.TeamFoundationSqlResourceComponent.Execute(ExecuteType executeType, CommandBehavior behavior) at Microsoft.TeamFoundation.Framework.Server.TeamFoundationSqlResourceComponent.ExecuteReader() at Microsoft.TeamFoundation.Framework.Server.PropertyComponent5.GetPropertyValue(ArtifactSpecDbPagingManager dbPagingManager, IEnumerable`1 propertyNameFilters, ArtifactKind artifactKind, GetPropertiesOptions options) at Microsoft.TeamFoundation.Framework.Server.CommandGetArtifactPropertyValue.ExecuteInternal(ArtifactKind artifactKind, IEnumerable`1 propertyNameFilters, ArtifactSpecDbPagingManager dbPagingManager, GetPropertiesOptions options) at Microsoft.TeamFoundation.Framework.Server.TeamFoundationPropertyService.GetProperties(TeamFoundationRequestContext requestContext, Guid kind, IEnumerable`1 propertyNameFilters) at Microsoft.TeamFoundation.VersionControl.Server.CommandQueryChurnItemPairs.Execute() at Microsoft.TeamFoundation.VersionControl.Server.TeamFoundationVersionControlService.GetFailedItemPairs(TeamFoundationRequestContext requestContext) at Microsoft.TeamFoundation.JobService.Extensions.Core.CodeChurnJobExtension.Run(TeamFoundationRequestContext requestContext, TeamFoundationJobDefinition jobDefinition, DateTime jobQueueTime, String& resultMessage) )。