3

Here is the code, straight out of the sample. 64 bit install, 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;
}

It compiles and links OK. Here is the SQL:

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

And here is the error message.

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

So near and yet so far. Really no idea where to look.


Edited to show the answer as per Nick Barnes. Note that a peek with depends.exe showed 2 exports previously, now 3.

david.pfx
  • 10,520
  • 3
  • 30
  • 63
  • @NickBarnes: Thanks! Spot on. Edited to show the answer. If you want to convert your comment to an answer I'll accept it. BTW there are other things in that article -- excellent link. – david.pfx Feb 29 '16 at 00:29

2 Answers2

2

The sample in the Postgres docs is squarely targeted at Linux environments; apparently there's a bit more involved in Windows. There is an excellent article by @CraigRinger which explains how to go about it in Visual Studio.

In this case, it looks like you just need to add the following function prototype:

PGDLLEXPORT Datum plsample_call_handler(PG_FUNCTION_ARGS);
Community
  • 1
  • 1
Nick Barnes
  • 19,816
  • 3
  • 51
  • 63
1

For me (Postgres 13 x64, VS2019, MSVC 14.27), it was enough to just add PGDLLEXPORT in front of PG_FUNCTION_INFO_V1, i.e:

PGDLLEXPORT PG_FUNCTION_INFO_V1(my_func);

Looking closer, this expands to the equivalent of:

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

You'll notice that's very similar to what's being done manually in the accepted answer, so this way seems to avoid some duplication. The only difference is the extern keyword; to be honest I don't know enough about C to know why putting PGDLLEXPORT before extern is still valid (rather than after it as I see in all the examples), but the compiler doesn't complain and the extension works.

YMMV especially if these macros change in the future.

Inkling
  • 3,544
  • 4
  • 30
  • 44
  • 1
    It just sneaks in a `__declspec (dllexport)` so it's not that surprising. Seems this issue of persuading MSVC to do the right exports is pretty well known now. Pioneers get arrows, settlers get paved roads. – david.pfx Oct 18 '20 at 09:22