Агрегатное расширение libpqxx C возвращает неправильные данные?

#postgresql #postgresql-12 #libpq #libpqxx #postgresql-extensions

#postgresql #postgresql-12 #libpq #libpqxx #postgresql-расширения

Вопрос:

Я изучаю, как создавать C aggregate extensions и использовать 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( "" 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.

Добавление

Установка инструкции extesion 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" 
);
  

Ответ №1:

Ответ, по-видимому, заключается в том, что данные типа bytea на стороне клиента должны быть получены следующим образом в библиотеке libpqxx начиная с версии 7.0 (не тестировалось в более ранних версиях):

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

Это извлекает правильные данные bytea без каких-либо преобразований, особенностей строки или неожиданного поведения, как я видел.

Комментарии:

1. Хорошо, что вы решили проблему — я мог помочь только на стороне сервера. Но вы видите, что имеет смысл исследовать обе стороны независимо, если это возможно.

2. @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 будет работать таким образом, но лучший и более идиоматичный и надежный способ установить значение a varlena

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

Я понятия не имею, как вы получили свой результат, но поскольку представленный вами код не компилируется, я не знаю, как на самом деле выглядит ваша функция.

Комментарии:

1. Заглавные данные были опечаткой с моей стороны. Я должен был включить материал для котельной плиты для полного расширения, но тогда есть часть psql и т. Д. … Нужно где-то остановиться. Но это моя функция, я тестирую тот же самый код. Я удалил все остальное, сократил его до этого примера и протестировал его, и я получаю результат, о котором я упоминал с помощью libpqxx. Я подозреваю, что проблема может быть в libpqxx, но я не знаю, что не так. Что касается memset, я хотел установить все это равным нулю, включая заголовок, чтобы я знал, чего ожидать на стороне клиента. Возможно, в этом не было необходимости.

2. Возможно, вам следует поделиться этим CREATE FUNCTION заявлением.

3. Я добавил инструкцию sql для создания агрегатного расширения.

4. Это вызвало бы другую функцию! Так и должно быть CREATE FUNCTION ... AS '$libdir/agg_simple_func', 'simplest_func'; .

5. Нет, я уверен, что все правильно понял. Это единственные расширения, которые я определил, и я не получаю ошибок при их вызове. Кроме того, da показывает мои агрегатные функции, и отображается определенная.