#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 показывает мои агрегатные функции, и отображается определенная.