Search code examples
cpostgresqldllopen-source

It seems my _PG_init() doesn't get called when the module loads


I am trying to write a small extension for PostgreSQL.

As a way to test if my module loads correctly I am writing some stuff in files in the void _PG_init(void) and void _PG_fini(void) functions. Here is the code of these two functions:

#include "postgres.h"
#include "executor\executor.h"
#include "fmgr.h"
#include "funcapi.h"
#include <stdio.h>

PG_MODULE_MAGIC;

extern void _PG_init(void);
extern void _PG_fini(void);

static void myExecutorStart(QueryDesc *queryDesc, int eflags);
static void myExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count);
static void myExecutorFinish(QueryDesc *queryDesc);
static void myExecutorEnd(QueryDesc *queryDesc);

static ExecutorStart_hook_type prevExecutorStart = NULL;
static ExecutorRun_hook_type prevExecutorRun = NULL;
static ExecutorFinish_hook_type prevExecutorFinish = NULL;
static ExecutorEnd_hook_type prevExecutorEnd = NULL;    

void _PG_init(void) {
     FILE *file = NULL;
     file = fopen("F:\\init.txt", "a+");
     fprintf(file, "Init started!\n");
     fclose(file);

     prevExecutorStart = ExecutorStart_hook;
     ExecutorStart_hook = myExecutorStart;
     prevExecutorRun = ExecutorRun_hook;
     ExecutorRun_hook = myExecutorRun;
     prevExecutorFinish = ExecutorFinish_hook;
     ExecutorFinish_hook = myExecutorFinish;
     prevExecutorEnd = ExecutorEnd_hook;
     ExecutorEnd_hook = myExecutorEnd;
}


void _PG_fini(void) {
     FILE *file = NULL;
     file = fopen("F:\\fini.txt", "a+");
     fprintf(file, "Fini started!\n");
     fclose(file);

     ExecutorStart_hook = prevExecutorStart;
     ExecutorRun_hook = prevExecutorRun;
     ExecutorFinish_hook = prevExecutorFinish;
     ExecutorEnd_hook = prevExecutorEnd;
 }

Those functions are in a file called "myextension.c", compiled into "myextension.dll". I built it in Visual Studio 2015, with following settings:

  • Configuration Properties -> General, “Configuration Type” = “Dynamic Library (.dll)”.
  • C/C++ -> Code Generation, “Enable C++ Exceptions” = “No”,“Advanced”
    set “Compile As” = “Compile as C Code (/TC)”.
  • Linker -> Manifest File, “Generate Manifest” = “No”.
  • Linker -> Input -> Additional Dependencies, added “postgres.lib” to the library list.
  • Configuration Properties -> C/C++ -> General, Additional Include
    Directories, added: “include\server\port\win32_msvc”, “include\server\port\win32”, “include\server”, “include”
  • Solution configuration = Release
  • Solution Platform = x64 (Installed 64 bit version of PostgreSQL 9.6 on Windows 10)

In myExecutorXXX functions I check if there are previous ExecutorXXX functions, call them if they exist, if they don't I call the standard_ExecutorXXX function. Here is an example of one of the functions:

static void myExecutorStart(QueryDesc *queryDesc, int eflags) {
    if (prevExecutorStart) prevExecutorStart(queryDesc, eflags);
    else standard_ExecutorStart(queryDesc, eflags);

    FILE *file = NULL;
    file = fopen("F:\\query.txt", "a+");

    fprintf(file, "Query: %s started!\n", queryDesc->sourceText);
    fclose(file);
}

I copied the "myextension.dll" in "../PostgreSQL/9.6/lib" directory, and added a "myextension.control" and "myextension--1.0.sql" to "../PostgreSQL/9.6/share/extension" directory.

myextension.control:

# pg_extension extension
comment = 'myextension!!!'
default_version = '1.0'

myextension--1.0.sql:

-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION myextension" to load this file. \quit

In the "postgresql.conf" I added shared_preload_libraries = 'myextension'. After that I connected to a test DB and ran: CREATE EXTENSION myextension;, and restarted the server.

If anyone has any idea what might be causing this, please help.


Solution

  • A couple of comments to get you on the right track:

    • _PG_fini() will never get called, because modules don't get unloaded.

    _PG_init(), however, does get called when the module is loaded. Your main question seems to be why nothing is written to F:\init.txt and other files you use for logging.

    • On Windows, PostgreSQL normally runs as service. I suspect that the operating system user doesn't have the privileges to write to these files. I know little about Windows and its permission management, but I notice that you do not check the return code of fopen(), so it might well have silently failed.

    • My recommendation is to use the logging infrastructure instead, e.g. with

      elog(LOG, "Init started!");
      

      That will write the message to the PostgreSQL server log and is much more comfortable and less error prone.

    Two more comments:

    • There is no point in creating an extension, because your code does not provide any SQL functions. CREATE EXTENSION myextension is a no-operation.

    • Don't forget to restart the PostgreSQL server after changing shared_preload_libraries.