libpqxx C聚合扩展返回错误的数据



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

我的toy聚合扩展有一个类型为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,PostgreSQL 12版本在Ubuntu 20.04上。

附录

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

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

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

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

我建议您逐一解决这些问题:首先让函数工作,在交互式查询中用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);

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

最新更新