Как стать автором
Обновить

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

Смотря, что вы хотите сделать. Например, для работы с jsonb есть функции для парсинга, для вывода и др. в файле jsonb.h.
НЛО прилетело и опубликовало эту надпись здесь
Всегда инициализируйте новые объявленные структуры. Например, вызывайте memset() после palloc().

Для этого есть palloc0
Хотел бы заметить, что для Постгреса можно и на С++ писать.
Понятно, что интерфейс надо в extern «C» завернуть. Ну и в Makefile надо добавить
SHLIB_LINK = -lstdc++


Про palloc/pfree — не понял. Зачем их обязательно использовать во внешних функциях?

И еще один важный момент — в Постгресе есть концепция background worker, что делает его невероятно расширяемым и гибким в сочетании с внешними функциями.
Про palloc/pfree — не понял. Зачем их обязательно использовать во внешних функциях?

Например, вы пишете агреггирующую функцию: у вас есть state transition function, вызываемая на каждую группируемую строку. Как вы сделаете free ранее выделенной памяти если запрос вдруг упирается в какую-то ошибку не имеющую к вашей функции отношения? И следующего sfunc банально не будет? Например, в temp_file_limit запрос упёрся и потому отменён.
Если вы выделяли память через palloc — то вся эта память будет автоматически очищена в этом случае вместе со всем контекстом запроса. Вот этот доклад с pgcon можно поглядеть чуть подробнее что такое memory context: www.pgcon.org/2019/schedule/events/1275.en.html
Спасибо, посмотрю этот доклад. Смарт-поинтеры не справятся с этой задачей? Не очень представляю, как должен выглядеть код такой state transition function…
Не вспомнил в какой из штатной функции видел хороший простой пример. Например, вот так array_agg сделан: github.com/postgres/postgres/blob/REL_12_STABLE/src/backend/utils/adt/array_userfuncs.c#L534
В initArrayResultArr создаётся контекст памяти.

Зато здесь есть хороший комментарий в array_agg_array_finalfn:
/*
* Make the result. We cannot release the ArrayBuildStateArr because
* sometimes aggregate final functions are re-executed. Rather, it is
* nodeAgg.c's responsibility to reset the aggcontext when it's safe to do
* so.
*/

Даже в final function освобождение памяти может быть неуместно, а лучше полагаться на удаление этого memory context в коде executor'а, выполняющего запрос.

По поводу смарт-пойнтеров не знаю, я на плюсах не пишу, да и сварщик сишник я ненастоящий. Просто малый контрибьютор postgresql.

Чтобы смарт-поинтер справился, кто-то должен вызвать его деструктор. А его-то никто и не вызывает, потому что архитектура такая.

Речь шла о внешних функциях. Кто мешает их написать так, что б деструкторы вызывались?

А что делать с возвращаемым значением? Кто вызовет его деструктор?

С возвращаемыми, к сожалению, никак. Но это же не означает, что palloc необходимо использовать для всего остального.

А чем не нравится palloc?

всем нравится, но я пишу на С++

C++ позволяет переопределять new и писать свои аллокаторы для стандартных контейнеров. Вот пример того как можно возвращать объекты. Как указывает документация, во всю используется longjmp, а значит ваши любимые деструкторы могут не вызываться, что создаст утечку памяти.

Вы о чем, простите? Причем здесь longjmp и pallоc?
Вот, например, код, который работает около 3 лет на сервере без утечек и без явных вызовов palloc — bitbucket.org/maxfo/pg_doc2vec
Конкретно внешние функции — bitbucket.org/maxfo/pg_doc2vec/src/master/extensions/client/pg_d2v_client.cpp
Действительно, ознакомьтесь . Потом пишите. Весь стек уже раскручен и все деструкторы вызваны в моем примере
Так почему же код не безопасный, объясните уже, пожалуйста.

Кто вызывает деструкторы, когда construct_array бросит ERRCODE_PROGRAM_LIMIT_EXCEEDED?
Обращаю внимание на документацию:


Вызывая серверные функции из кода C++, убедитесь, что в стеке вызова C++ содержатся только простые структуры данных. Это необходимо, потому что в случае ошибки сервера выполняется функция longjmp(), а она не отматывает стек вызовов C++ должным образом для объектов, отличных от простых структур.
Вы, IMO, не правильно толкуете документацию. ArrayType не является сложной структурой данных.
Ну и ERRCODE_PROGRAM_LIMIT_EXCEEDED не «бросается». Где там в коде «бросание» через longjmp?

std::unique_ptr и std::vector сложные структуры у которых есть деструкторы.


Ну и ERRCODE_PROGRAM_LIMIT_EXCEEDED не «бросается».

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


Где там в коде «бросание» через longjmp?

errfinish дергает pg_re_throw, который и вызывает siglongjmp.

так где в недрах construct_array развертка стека? Ссылку на код уж пришлите, устал я спорить что-то…
std::unique_ptr и std::vector сложные структуры у которых есть деструкторы.

так и почему их деструкторы не будет вызваны, давайте ссылку на конкретный код, который будет так чудесно разворачивать стек после неудачного вызова construct_array()
А кто обработает переполнение при складывании двух int32? Сам PG_RETURN_INT32?

Исключения не будет, будет неопределённое поведение.

В БД? Звучит так себе… В случае постгреса и не очень верится, как-то они должны это обрабатывать.

Переполнение знаковых — UB в языке C.

некоторые возможности PostgreSQL и вовсе нельзя сделать кроме как на С, например, в других языках не поддерживаются типы (особенно если возвращать значение из функции) ANYELEMENT, ANYARRAY и особенно важный VARIADIC.

Не, система типов работает безотносительно того, на каком языке написана функция. В частности, и на SQL, и в PL/pgSQL все это можно использовать.
Что, конечно, не умаляет достоинств Си.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории