Как написать обработчик языка Postgres с помощью MSVC

Вот код, прямо из примера. 64-битная установка, x64 build.

#include "postgres.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "fmgr.h"
#include "access/heapam.h"
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"

#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif


PGDLLEXPORT Datum plsample_call_handler(PG_FUNCTION_ARGS); // <-- the answer!!


PG_FUNCTION_INFO_V1(plsample_call_handler);

Datum
plsample_call_handler(PG_FUNCTION_ARGS)
{
  Datum          retval;
  retval = 42;
  return retval;
}

Он компилирует и ссылки ОК. Вот SQL:

CREATE FUNCTION plsample_call_handler() RETURNS language_handler
    AS 'TryPostgresPl.dll'
    LANGUAGE C;
CREATE LANGUAGE plsample
    HANDLER plsample_call_handler;

А вот и сообщение об ошибке.

ERROR: could not find function "plsample_call_handler" in file "C:/Program Files/PostgreSQL/9.5/lib/TryPostgresPl.dll"
SQL state: 42883

Так близко и еще так далеко. На самом деле не знаю, где искать.


Отредактировано, чтобы показать ответ в соответствии с Ником Барнсом. Обратите внимание на то, что при просмотре файла зависимости.exe ранее было показано 2 экспорта, а теперь - 3.

1 ответ

Решение

Пример в документации Postgres прямо ориентирован на среды Linux; по-видимому, в Windows есть что-то большее. Есть отличная статья Craig Ringer, которая объясняет, как это сделать в Visual Studio.

В этом случае, похоже, вам просто нужно добавить следующий прототип функции:

PGDLLEXPORT Datum plsample_call_handler(PG_FUNCTION_ARGS);

Для меня (Postgres 13 x64, VS2019, MSVC 14.27) достаточно было просто добавить PGDLLEXPORT перед PG_FUNCTION_INFO_V1, то есть:

PGDLLEXPORT PG_FUNCTION_INFO_V1(my_func);

Если присмотреться, это расширяется до эквивалента:

PGDLLEXPORT extern Datum my_func(PG_FUNCTION_ARGS);
... plus a bunch more stuff

Вы заметите, что это очень похоже на то, что делается вручную в принятом ответе, поэтому, похоже, этот способ позволяет избежать некоторого дублирования. Единственная разница - это externключевое слово; честно говоря, я недостаточно знаю о C, чтобы понять, почему PGDLLEXPORT до extern по-прежнему действует (а не после него, как я вижу во всех примерах), но компилятор не жалуется, и расширение работает.

YMMV, особенно если эти макросы изменятся в будущем.

Другие вопросы по тегам