0

我正在学习如何创建 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" 
);
4

2 回答 2

1

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

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

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

于 2020-10-02T18:38:21.140 回答
0

我建议您一一解决这些问题:首先让函数工作,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方式工作,但是设置 a 值的更好、更惯用和更健壮的方法varlena

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

我不知道你是如何得到结果的,但是由于你提供的代码没有编译,我不知道你的函数看起来如何。

于 2020-10-02T06:40:59.367 回答