我正在尝试为PostgreSQL写一个小的扩展。

作为测试模块是否正确加载的一种方式,我正在void _PG_init(void)void _PG_fini(void)函数的文件中写入一些内容。这是这两个函数的代码:

#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;
 }


这些功能位于名为“ myextension.c”的文件中,该文件已编译为“ myextension.dll”。我使用以下设置在Visual Studio 2015中构建它:


配置属性->常规,“配置类型” =“动态”
库(.dll)”。
C / C ++->代码生成,“启用C ++异常” =“否”,“高级”
设置“编译为” =“编译为C代码(/ TC)”。
链接器->清单文件,“ Generate Manifest” =“ No”。
链接器->输入->其他依赖项,将“ postgres.lib”添加到
库列表。
配置属性-> C / C ++->常规,其他包括
目录,已添加:“ include \ server \ port \ win32_msvc”,“ include \ server \ port \ win32”,“ include \ server”,“ include”
解决方案配置=发布
解决方案平台= x64(在PostgreSQL 9.6上安装了64位版本
Windows 10)


在myExecutorXXX函数中,我检查是否存在以前的ExecutorXXX函数,如果存在,则调用它们;如果不存在,则调用standard_ExecutorXXX函数。这是其中一个功能的示例:

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);
}


我在“ ../PostgreSQL/9.6/lib”目录中复制了“ myextension.dll”,并在“ ../PostgreSQL/9.6/share/extension”中添加了“ myextension.control”和“ myextension--1.0.sql” “ 目录。

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


在“ postgresql.conf”中,我添加了shared_preload_libraries ='myextension'。之后,我连接到测试数据库并运行:CREATE EXTENSION myextension ;,然后重新启动服务器。

如果有人知道可能是什么原因造成的,请提供帮助。

最佳答案

以下几点评论可以使您走上正确的道路:


_PG_fini()永远不会被调用,因为模块不会被卸载。


但是,_PG_init()确实在模块加载时被调用。您的主要问题似乎是为什么没有任何内容写入F:\init.txt和其他用于日志记录的文件。


在Windows上,PostgreSQL通常作为服务运行。我怀疑操作系统用户没有写这些文件的特权。我对Windows及其权限管理知之甚少,但是我注意到您没有检查fopen()的返回码,因此它很可能已经悄然失败了。
我的建议是改用日志记录基础架构,例如与

elog(LOG, "Init started!");


这样会将消息写到PostgreSQL服务器日志中,并且更加舒适并且不易出错。


另外两个评论:


创建扩展没有任何意义,因为您的代码不提供任何SQL函数。 CREATE EXTENSION myextension是空操作。
不要忘记在更改shared_preload_libraries之后重新启动PostgreSQL服务器。

关于c - 似乎在模块加载时未调用我的_PG_init(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42578036/

10-09 23:02