【问题标题】:libpqxx C Aggregate Extension returns wrong data?libpqxx C 聚合扩展返回错误数据?
【发布时间】:2020-10-03 02:38:21
【问题描述】:

我正在学习如何创建 C 聚合扩展并在客户端使用 libpqxx 和 C++ 来处理数据。

我的玩具聚合扩展有一个bytea 类型的参数,状态也是bytea 类型。以下是我的问题的最简单示例:

服务器端:

PG_FUNCTION_INFO_V1( simple_func );

Datum simple_func( PG_FUNCTION_ARGS ){

    bytea *new_state   = (bytea *) palloc( 128 + VARHDRSZ );
    memset(new_state, 0, 128 + VARHDRSZ );
    SET_VARSIZE( new_state,128 + VARHDRSZ );

    PG_RETURN_BYTEA_P( new_state );

}

客户端:

std::basic_string< std::byte > buffer;

pqxx::connection c{"postgresql://user:simplepassword@localhost/contrib_regression"};
pqxx::work w(c);
c.prepare( "simple_func", "SELECT simple_func( $1 )  FROM table" );
pqxx::result r = w.exec_prepared( "simple_func", buffer );

for (auto row: r){ 
        cout << "  Result Size: " << row[ "simple_func" ].size() << endl;
        cout << "Raw Result Data: ";
        for( int jj=0; jj < row[ "simple_func" ].size(); jj++ ) printf( "%02" PRIx8,   (uint8_t) row[ "simple_func" ].c_str()[jj] )  ;
        cout << endl;
}

客户端打印结果:

Result Size: 258
Raw Result Data: 5c783030303030303030303030303030...

30 模式重复到字符串结尾,打印的十六进制字符串为 512 个字节。

我希望收到一个长度为 128 字节的数组,其中每个字节都设置为零。我做错了什么?

libpqxx 版本是 7.2 和 Ubuntu 20.04 上的 PostgreSQL 12。

附录

安装扩展sql语句;

CREATE OR REPLACE FUNCTION agg_simple_func( state bytea, arg1 bytea)
RETURNS bytea
AS '$libdir/agg_simple_func'
LANGUAGE C IMMUTABLE STRICT;

CREATE OR REPLACE AGGREGATE simple_func( arg1 bytea)  
(
    sfunc = agg_simple_func,
    stype = bytea,
    initcond = "\xFFFF" 
);

【问题讨论】:

    标签: postgresql postgresql-12 libpq libpqxx postgresql-extensions


    【解决方案1】:

    答案似乎是客户端的bytea类型数据必须在libpqxx库中检索如下7.0(早期版本未测试):

    row[ "simple_func" ].as<std::basic_string<std::byte>>()
    

    这会检索正确的 bytea 数据,而不会像我看到的那样进行任何转换、字符串特性或意外行为。

    【讨论】:

    • 很好,你解决了这个问题——我只能在服务器端提供帮助。但是您会发现,如果可能的话,独立检查双方是有意义的。
    • @LaurenzAlbe 是的。谢谢。
    【解决方案2】:

    我建议您一一解决这些问题:首先让函数工作,在交互式查询中使用psql 对其进行测试,然后编写客户端代码(反之亦然)。

    我不能谈论 libpqxx,但我不得不抱怨你的函数:你提交的内容甚至无法编译,因为你用大写写了DATUM,忘记了标题和其他重要的东西。

    这个函数会按照你的预期编译和运行:

    #include "postgres.h"
    #include "fmgr.h"
    
    PG_MODULE_MAGIC;
    
    PG_FUNCTION_INFO_V1(simplest_func);
    
    Datum simplest_func(PG_FUNCTION_ARGS) {
        bytea *new_state = (bytea *) palloc(128 + VARHDRSZ);
        memset(new_state, 0, 128 + VARHDRSZ);
        SET_VARSIZE(new_state, 128 + VARHDRSZ);
    
        PG_RETURN_BYTEA_P(new_state);
    }
    

    memset 会以这种方式工作,但是设置 varlena 值的更好、更惯用和更健壮的方法是

        memset(VARDATA(new_state), 0, 128);
    

    我不知道您是如何得到结果的,但是由于您提供的代码无法编译,我不知道您的函数的真实外观。

    【讨论】:

    • 大写数据是我的错字。我应该包含完整扩展的样板内容,但是还有 psql 部分,等等……必须在某个地方停下来。但是,这是我的功能,我正在测试完全相同的代码。我已经删除了其他所有内容,将其简化为这个示例,并对其进行了测试,我得到了我在 libpqxx 中提到的结果。我怀疑问题可能出在 libpqxx 上,但我不知道出了什么问题。至于 memset,我想将其全部设置为零,包括标题,以便我知道在客户端会发生什么。也许,那是不必要的。
    • 也许你应该分享CREATE FUNCTION声明。
    • 我添加了 sql 语句来创建聚合扩展。
    • 那会调用不同的函数!应该是CREATE FUNCTION ... AS '$libdir/agg_simple_func', 'simplest_func';
    • 不,我很确定我做对了。这些是我定义的唯一扩展,调用它们时没有错误。另外,\da 显示了我的聚合函数,并且显示了定义的函数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 1970-01-01
    相关资源
    最近更新 更多